{"id":499149,"date":"2026-10-18T21:28:18","date_gmt":"2026-10-18T18:28:18","guid":{"rendered":"https:\/\/savepearlharbor.com\/?p=499149"},"modified":"2026-10-18T21:28:18","modified_gmt":"2026-10-18T18:28:18","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=499149","title":{"rendered":"\u0413\u0440\u0430\u0432\u0438\u0446\u0430\u043f\u0430 \u0434\u043b\u044f GPU: OpenGL ES \u043d\u0430 Kotlin DSL \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 3D-\u201c\u0416\u0438\u0437\u043d\u0438\u201d \u041a\u043e\u043d\u0432\u0435\u044f"},"content":{"rendered":"<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440! \u041d\u0430\u043a\u043e\u043d\u0435\u0446-\u0442\u043e \u044f \u0437\u0430\u043a\u043e\u043d\u0447\u0438\u043b \u0440\u0430\u0431\u043e\u0442\u0443 \u043d\u0430\u0434 \u043d\u043e\u0432\u044b\u043c \u0431\u043e\u043b\u044c\u0448\u0438\u043c \u0431\u043b\u043e\u043a\u043e\u043c RedByteFX, \u0442\u0435\u043c \u0441\u0430\u043c\u044b\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432 \u043f\u043b\u0430\u043d\u0430\u0445 \u0437\u0432\u0443\u0447\u0430\u043b \u0441\u043a\u0440\u043e\u043c\u043d\u043e: \u201c\u0430 \u0435\u0449\u0451 \u0431\u044b\u043b\u043e \u0431\u044b \u043d\u0435\u043f\u043b\u043e\u0445\u043e OpenGL ES\u201d. \u201c\u041d\u0435\u043f\u043b\u043e\u0445\u043e\u201d \u0440\u0430\u0441\u0442\u044f\u043d\u0443\u043b\u043e\u0441\u044c \u043d\u0430 \u043c\u043d\u043e\u0433\u043e \u0432\u0435\u0447\u0435\u0440\u043e\u0432 \u0438 \u0432\u044b\u043b\u0438\u043b\u043e\u0441\u044c \u0432 \u0432\u0435\u0440\u0441\u0438\u044e 1.2.0, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0443\u0436\u0435 \u043b\u0435\u0436\u0438\u0442 \u0432 Maven Central. \u0415\u0441\u043b\u0438 \u043a\u043e\u0440\u043e\u0442\u043a\u043e: \u0442\u0435\u043f\u0435\u0440\u044c \u043d\u0430 Kotlin DSL \u043c\u043e\u0436\u043d\u043e \u043f\u0438\u0441\u0430\u0442\u044c \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u044d\u0444\u0444\u0435\u043a\u0442\u044b \u0434\u043b\u044f Compose, \u043d\u043e \u0438 \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u0443\u044e 3D-\u0433\u0440\u0430\u0444\u0438\u043a\u0443 \u0438 \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u044f \u043d\u0430 GPU. \u0415\u0441\u043b\u0438 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e, \u0442\u043e \u0447\u0438\u0442\u0430\u0439\u0442\u0435 \u0434\u0430\u043b\u044c\u0448\u0435: \u044f \u043f\u043e\u043a\u0430\u0436\u0443 \u0432\u0441\u0451 \u043d\u0430 \u0436\u0438\u0432\u043e\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0438 \u0441\u0440\u0430\u0432\u043d\u044e \u0441 \u0442\u0435\u043c, \u043a\u0430\u043a \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u0431\u044b \u043f\u0438\u0441\u0430\u0442\u044c \u0431\u0435\u0437 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438.<\/p>\n<p>\u041d\u0435\u043c\u043d\u043e\u0433\u043e \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430. \u0412 <a href=\"https:\/\/habr.com\/ru\/articles\/1022546\/\" rel=\"noopener nofollow\">\u043f\u0435\u0440\u0432\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435<\/a> \u044f \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u043b, \u043a\u0430\u043a RedByteFX \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0435\u0442 AGSL \u0438\u0437 \u201c\u043d\u0435 \u0442\u0440\u043e\u0433\u0430\u0439, \u044d\u0442\u043e \u043d\u0430 \u041d\u043e\u0432\u044b\u0439 \u0433\u043e\u0434\u201d \u0432 \u043e\u0431\u044b\u0447\u043d\u044b\u0439 Kotlin-\u043a\u043e\u0434. \u0422\u043e\u0433\u0434\u0430 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0443\u043c\u0435\u043b\u0430 \u043a\u0440\u0430\u0441\u0438\u0442\u044c \u0442\u043e, \u0447\u0442\u043e \u0443\u0436\u0435 \u043d\u0430\u0440\u0438\u0441\u043e\u0432\u0430\u043b Compose, \u0438 \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430 Android 13+. \u041f\u0435\u043f\u0435\u043b\u0430\u0446 \u0431\u044b\u043b, \u043d\u043e \u043b\u0435\u0442\u0430\u043b \u0431\u0435\u0437 \u0433\u0440\u0430\u0432\u0438\u0446\u0430\u043f\u044b.<\/p>\n<p>\u0412 \u0432\u0435\u0440\u0441\u0438\u0438 1.2.0 \u0443 RedByteFX \u0432\u044b\u0440\u043e\u0441\u043b\u0430 \u0432\u0442\u043e\u0440\u0430\u044f \u043f\u043e\u043b\u043e\u0432\u0438\u043d\u0430: \u0442\u043e\u0442 \u0436\u0435 Kotlin DSL \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442 <strong>GLSL ES 3.0\u20133.2<\/strong>. \u042d\u0442\u043e \u0432\u0435\u0440\u0448\u0438\u043d\u043d\u044b\u0435, \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u043d\u044b\u0435 \u0438 compute-\u0448\u0435\u0439\u0434\u0435\u0440\u044b, \u043f\u043b\u044e\u0441 \u0440\u0430\u043d\u0442\u0430\u0439\u043c \u043f\u043e\u0432\u0435\u0440\u0445 GLES \u0438 Compose-\u0445\u043e\u0441\u0442\u044b <code>GlSurface<\/code>\/<code>GlCompute<\/code>. \u0412\u0441\u0451 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0441 API 24.<\/p>\n<p>\u0420\u0430\u0441\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043f\u0440\u043e \u044d\u0442\u043e \u043d\u0430 \u043e\u0447\u0435\u0440\u0435\u0434\u043d\u043e\u043c \u201c\u0432\u043e\u043b\u043d\u043e\u0432\u043e\u043c \u044d\u0444\u0444\u0435\u043a\u0442\u0435\u201d \u0441\u043a\u0443\u0447\u043d\u043e. \u041f\u043e\u0440\u0430\u0441\u043a\u0438\u043d\u0443\u0432 \u043c\u043e\u0437\u0433\u0430\u043c\u0438 \u043d\u0430\u0434 \u0442\u0435\u043c, \u0447\u0442\u043e \u043c\u043e\u0433\u043b\u043e \u0431\u044b\u0442\u044c \u043a\u0440\u0430\u0441\u0438\u0432\u043e\u0439 \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u0435\u0439 \u0438 \u0432 \u0442\u043e \u0436\u0435 \u0432\u0440\u0435\u043c\u044f \u043d\u0435 \u0441\u043e\u0432\u0441\u0435\u043c \u0442\u0440\u0438\u0432\u0438\u0430\u043b\u044c\u043d\u044b\u043c, \u044f \u043f\u0440\u0438\u0448\u0435\u043b \u043a \u0432\u044b\u0432\u043e\u0434\u0443 \u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043b \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0438\u0433\u0440\u044b: <a href=\"https:\/\/ru.wikipedia.org\/wiki\/%D0%98%D0%B3%D1%80%D0%B0_%C2%AB%D0%96%D0%B8%D0%B7%D0%BD%D1%8C%C2%BB\" rel=\"noopener nofollow\"><strong>\u201c\u0416\u0438\u0437\u043d\u044c\u201d \u041a\u043e\u043d\u0432\u0435\u044f<\/strong><\/a>, \u043d\u043e \u043d\u0435 \u0432 \u0434\u0432\u0443\u043c\u0435\u0440\u043d\u043e\u043c \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u0435, \u0430 \u0432 \u0442\u0440\u0451\u0445\u043c\u0435\u0440\u043d\u043e\u043c. \u041f\u043e\u043a\u043e\u043b\u0435\u043d\u0438\u044f \u0441\u0447\u0438\u0442\u0430\u0435\u0442 compute-\u0448\u0435\u0439\u0434\u0435\u0440, \u0442\u044b\u0441\u044f\u0447\u0438 \u043a\u043b\u0435\u0442\u043e\u043a \u0440\u0438\u0441\u0443\u044e\u0442\u0441\u044f \u0438\u043d\u0441\u0442\u0430\u043d\u0441\u0430\u043c\u0438 \u0432 \u0432\u044f\u0437\u043a\u043e\u0439 \u0441\u0432\u0435\u0442\u044f\u0449\u0435\u0439\u0441\u044f \u0436\u0438\u0434\u043a\u043e\u0441\u0442\u0438. \u0410 \u043f\u043e \u0445\u043e\u0434\u0443 \u0441\u0442\u0430\u0442\u044c\u0438 \u044f \u0447\u0435\u0441\u0442\u043d\u043e \u0441\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u044e \u043a\u0430\u0436\u0434\u044b\u0439 \u0448\u0430\u0433 \u0441 \u0442\u0435\u043c, \u043a\u0430\u043a \u0442\u043e \u0436\u0435 \u0441\u0430\u043c\u043e\u0435 \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u0431\u044b \u043f\u0438\u0441\u0430\u0442\u044c <strong>\u043f\u043e \u0441\u0442\u0430\u0440\u0438\u043d\u043a\u0435<\/strong>, \u043d\u0430 \u0433\u043e\u043b\u043e\u043c <code>GLES31<\/code> \u0438 GLSL \u0432 \u0441\u0442\u0440\u043e\u043a\u043e\u0432\u044b\u0445 \u043b\u0438\u0442\u0435\u0440\u0430\u043b\u0430\u0445.<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/extt\/18\/fb\/e8\/18fbe8f010f0235a2699b6bf3e93a65d.gif\" alt=\"\u0416\u0438\u0437\u043d\u044c 3D: \u043f\u0440\u0430\u0432\u0438\u043b\u043e &quot;\u041b\u0430\u0432\u0430&quot; \u043d\u0430 \u0442\u043e\u0440\u0435\" width=\"300\" height=\"642\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/extt\/18\/fb\/e8\/18fbe8f010f0235a2699b6bf3e93a65d.gif 780w,&#10;       https:\/\/habrastorage.org\/extt\/18\/fb\/e8\/18fbe8f010f0235a2699b6bf3e93a65d.gif 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u0416\u0438\u0437\u043d\u044c 3D: \u043f\u0440\u0430\u0432\u0438\u043b\u043e &#171;\u041b\u0430\u0432\u0430&#187; \u043d\u0430 \u0442\u043e\u0440\u0435<\/figcaption><\/div>\n<\/figure>\n<p>\u0420\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0441 \u0438\u0433\u0440\u043e\u0439: <a href=\"https:\/\/github.com\/i-redbyte\/life3d\" rel=\"noopener nofollow\">github.com\/i-redbyte\/life3d<\/a>. \u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430: <a href=\"https:\/\/github.com\/i-redbyte\/redbytefx\" rel=\"noopener nofollow\">github.com\/i-redbyte\/redbytefx<\/a>.<\/p>\n<h3>\u0427\u0442\u043e \u0437\u043d\u0430\u0447\u0438\u0442 \u201c\u043f\u043e \u0441\u0442\u0430\u0440\u0438\u043d\u043a\u0435\u201d<\/h3>\n<p>\u041a\u0442\u043e \u043f\u0438\u0441\u0430\u043b OpenGL ES \u043d\u0430 Android \u0440\u0443\u043a\u0430\u043c\u0438, \u043f\u043e\u043c\u043d\u0438\u0442 \u044d\u0442\u043e\u0442 \u043d\u0430\u0431\u043e\u0440:<\/p>\n<ul>\n<li>\n<p>\u0448\u0435\u0439\u0434\u0435\u0440 \u0436\u0438\u0432\u0451\u0442 \u0432 \u0441\u0442\u0440\u043e\u043a\u0435, \u0438 \u043e\u043f\u0435\u0447\u0430\u0442\u043a\u0430 \u0432 \u0438\u043c\u0435\u043d\u0438 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 \u0432\u0441\u043f\u043b\u044b\u0432\u0430\u0435\u0442 \u0432 \u0440\u0430\u043d\u0442\u0430\u0439\u043c\u0435, \u0432 \u043b\u043e\u0433\u0435 \u0434\u0440\u0430\u0439\u0432\u0435\u0440\u0430, \u043d\u0430 \u0447\u0443\u0436\u043e\u043c \u0442\u0435\u043b\u0435\u0444\u043e\u043d\u0435;<\/p>\n<\/li>\n<li>\n<p>uniform-\u044b \u0438\u0449\u0443\u0442\u0441\u044f \u043f\u043e \u0441\u0442\u0440\u043e\u043a\u043e\u0432\u043e\u043c\u0443 \u0438\u043c\u0435\u043d\u0438 (<code>glGetUniformLocation(program, \"u_sise\")<\/code>), \u0430 \u043d\u0435\u0432\u0435\u0440\u043d\u043e\u0435 \u0438\u043c\u044f \u0434\u0440\u0430\u0439\u0432\u0435\u0440 \u043c\u043e\u043b\u0447\u0430 \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0432 <code>-1<\/code>, \u0438 \u0437\u0430\u043f\u0438\u0441\u044c \u0432 \u043d\u0435\u0433\u043e &#8212; \u0442\u0438\u0445\u0438\u0439 no-op;<\/p>\n<\/li>\n<li>\n<p>\u0440\u0430\u0441\u043a\u043b\u0430\u0434\u043a\u0443 std140 \u0441\u0447\u0438\u0442\u0430\u0435\u0448\u044c \u043d\u0430 \u043f\u0430\u043b\u044c\u0446\u0430\u0445: <code>float[27]<\/code> \u0432 uniform-\u0431\u043b\u043e\u043a\u0435 \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442 \u043d\u0435 108 \u0431\u0430\u0439\u0442, \u0430 432;<\/p>\n<\/li>\n<li>\n<p><code>ByteBuffer.allocateDirect(...).order(ByteOrder.nativeOrder())<\/code> &#8212; \u043d\u0430 \u043a\u0430\u0436\u0434\u044b\u0439 \u0431\u0443\u0444\u0435\u0440;<\/p>\n<\/li>\n<li>\n<p>\u0432\u0441\u0451 \u0434\u043e\u043b\u0436\u043d\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442\u044c \u043d\u0430 GL-\u043f\u043e\u0442\u043e\u043a\u0435, \u0430 UI \u0436\u0438\u0432\u0451\u0442 \u043d\u0430 \u0441\u0432\u043e\u0451\u043c, \u0438 \u043c\u043e\u0441\u0442 \u043c\u0435\u0436\u0434\u0443 \u043d\u0438\u043c\u0438 \u0441\u0442\u0440\u043e\u0438\u0448\u044c \u0441\u0430\u043c;<\/p>\n<\/li>\n<li>\n<p><code>GLSurfaceView<\/code>, \u0435\u0433\u043e \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u044b\u0439 \u0446\u0438\u043a\u043b, \u043f\u043e\u0442\u0435\u0440\u044f EGL-\u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430 \u0438 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043d\u0430 GL-\u043f\u043e\u0442\u043e\u043a\u0435, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0440\u043e\u043d\u044f\u0435\u0442 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0446\u0435\u043b\u0438\u043a\u043e\u043c.<\/p>\n<\/li>\n<\/ul>\n<p>\u041d\u0438\u0447\u0435\u0433\u043e \u0438\u0437 \u044d\u0442\u043e\u0433\u043e \u043d\u0435 \u0441\u043b\u043e\u0436\u043d\u043e \u043f\u043e \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438. \u0421\u043b\u043e\u0436\u043d\u043e \u0432\u0441\u0451 \u044d\u0442\u043e \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e, \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437 \u0437\u0430\u043d\u043e\u0432\u043e. RedByteFX \u0437\u0430\u0431\u0438\u0440\u0430\u0435\u0442 \u0440\u0443\u0442\u0438\u043d\u0443, \u043d\u043e \u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0432\u0430\u043c \u043f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044c: \u0438\u0442\u043e\u0433\u043e\u0432\u044b\u0439 GLSL \u0432\u0441\u0435\u0433\u0434\u0430 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c.<\/p>\n<h3>\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/h3>\n<pre><code>dependencies {    implementation(\"io.github.i-redbyte:redbytefx-core:1.2.0\")    implementation(\"io.github.i-redbyte:redbytefx-stdlib:1.2.0\")    implementation(\"io.github.i-redbyte:redbytefx-gl:1.2.0\")    implementation(\"io.github.i-redbyte:redbytefx-gl-compose:1.2.0\")    implementation(\"io.github.i-redbyte:redbytefx-3d:1.2.0\")}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper\"><\/span><\/a><\/div><\/pre>\n<div>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<th>\n<p align=\"left\">\u041c\u043e\u0434\u0443\u043b\u044c<\/p>\n<\/th>\n<th>\n<p align=\"left\">\u0427\u0442\u043e \u0434\u0430\u0451\u0442<\/p>\n<\/th>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\"><code>redbytefx-core<\/code><\/p>\n<\/td>\n<td>\n<p align=\"left\">DSL \u0438 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f AGSL \/ GLSL ES 3.0\u20133.2<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\"><code>redbytefx-stdlib<\/code><\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0440\u0435\u0446\u0435\u043f\u0442\u044b: \u0441\u0432\u0435\u0442, \u043c\u0430\u0441\u043a\u0438, \u0448\u0443\u043c\u044b, SDF<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\"><code>redbytefx-gl<\/code><\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0440\u0430\u043d\u0442\u0430\u0439\u043c: \u043b\u0438\u043d\u043a\u043e\u0432\u043a\u0430, uniform-\u044b, \u0431\u043b\u043e\u043a\u0438, dispatch, \u0447\u0442\u0435\u043d\u0438\u0435 \u0431\u0443\u0444\u0435\u0440\u043e\u0432<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\"><code>redbytefx-gl-compose<\/code><\/p>\n<\/td>\n<td>\n<p align=\"left\"><code>GlSurface<\/code>, <code>GlCompute<\/code>, <code>GlController<\/code>, \u043c\u0435\u0448\u0438 \u0438 \u043f\u0440\u0438\u043c\u0438\u0442\u0438\u0432\u044b<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\"><code>redbytefx-3d<\/code><\/p>\n<\/td>\n<td>\n<p align=\"left\">\u043c\u0430\u0442\u0440\u0438\u0446\u044b \u0438 \u043a\u0430\u043c\u0435\u0440\u0430: <code>lookAt<\/code>, <code>perspective<\/code><\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p>Compute-\u0448\u0435\u0439\u0434\u0435\u0440\u0430\u043c \u043d\u0443\u0436\u0435\u043d OpenGL ES 3.1, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432 \u043c\u0430\u043d\u0438\u0444\u0435\u0441\u0442 \u0441\u0440\u0430\u0437\u0443 \u043f\u0438\u0448\u0435\u043c:<\/p>\n<pre><code>&lt;uses-feature    android:glEsVersion=\"0x00030001\"    android:required=\"true\" \/&gt;<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p><strong>\u0413\u0440\u0430\u0431\u043b\u044f \u21161, \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u0430\u044f.<\/strong> \u042d\u043c\u0443\u043b\u044f\u0442\u043e\u0440 Android \u043d\u0430 Apple Silicon \u043e\u0442\u0434\u0430\u0451\u0442 \u0442\u043e\u043b\u044c\u043a\u043e OpenGL ES 3.0. Compute \u0442\u0430\u043c \u043d\u0435 \u0437\u0430\u0432\u0435\u0434\u0451\u0442\u0441\u044f. \u041e\u0442\u043b\u0430\u0436\u0438\u0432\u0430\u043b\u0441\u044f \u044f \u043d\u0430 Galaxy S21. \u042d\u043c\u0443\u043b\u044f\u0442\u043e\u0440 \u043d\u0430 \u043c\u0430\u043a\u0435 \u0432 \u044d\u0442\u043e\u0439 \u0438\u0441\u0442\u043e\u0440\u0438\u0438 \u044d\u0442\u043e \u043f\u0430\u0446\u0430\u043a \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u0437\u0430\u0431\u044b\u043b\u0438 \u0432\u044b\u0434\u0430\u0442\u044c \u0446\u0430\u043a!<\/p>\n<h3>\u0418\u0433\u0440\u0430 \u0432 \u0434\u0432\u0443\u0445 \u0441\u043b\u043e\u0432\u0430\u0445<\/h3>\n<p>\u0423 \u043a\u043b\u0435\u0442\u043a\u0438 \u0432 3D 26 \u0441\u043e\u0441\u0435\u0434\u0435\u0439 (\u043a\u0443\u0431 3\u00d73\u00d73 \u0431\u0435\u0437 \u0446\u0435\u043d\u0442\u0440\u0430). \u041f\u0440\u0430\u0432\u0438\u043b\u043e \u043f\u0438\u0448\u0435\u0442\u0441\u044f \u0432 \u043d\u043e\u0442\u0430\u0446\u0438\u0438 <strong>B\/S\/C<\/strong> (\u0432 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 \u043e\u0431\u044b\u0447\u043d\u043e\u0439 \u201c\u0416\u0438\u0437\u043d\u0438\u201d, \u0433\u0434\u0435 \u043a\u043b\u0435\u0442\u043a\u0430 \u043f\u0440\u043e\u0441\u0442\u043e \u0436\u0438\u0432\u0430 \u0438\u043b\u0438 \u043c\u0435\u0440\u0442\u0432\u0430, \u0437\u0434\u0435\u0441\u044c \u0443 \u043a\u043b\u0435\u0442\u043a\u0438 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439, \u0447\u0442\u043e \u0438 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0438\u043c\u0438\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u201c\u0442\u043b\u0435\u043d\u0438\u0435\u201d \u0438 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0441\u043b\u043e\u0436\u043d\u044b\u0435 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b): \u043f\u0440\u0438 \u043a\u0430\u043a\u043e\u043c \u0447\u0438\u0441\u043b\u0435 \u0441\u043e\u0441\u0435\u0434\u0435\u0439 \u043a\u043b\u0435\u0442\u043a\u0430 \u0440\u043e\u0436\u0434\u0430\u0435\u0442\u0441\u044f, \u043f\u0440\u0438 \u043a\u0430\u043a\u043e\u043c \u0432\u044b\u0436\u0438\u0432\u0430\u0435\u0442 \u0438 \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0443 \u043d\u0435\u0451 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439. \u0415\u0441\u043b\u0438 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439 \u0431\u043e\u043b\u044c\u0448\u0435 \u0434\u0432\u0443\u0445, \u0443\u043c\u0435\u0440\u0448\u0430\u044f \u043a\u043b\u0435\u0442\u043a\u0430 \u043d\u0435 \u0438\u0441\u0447\u0435\u0437\u0430\u0435\u0442 \u0441\u0440\u0430\u0437\u0443, \u0430 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u043a\u043e\u043b\u0435\u043d\u0438\u0439 \u201c\u0442\u043b\u0435\u0435\u0442\u201d: \u043d\u0435 \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044f \u0441\u043e\u0441\u0435\u0434\u043e\u043c \u0438 \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0440\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u0437\u0430\u043d\u043e\u0432\u043e. \u0418\u043c\u0435\u043d\u043d\u043e \u044d\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442 \u0438\u0437 \u043a\u0430\u0448\u0438 \u0432\u043e\u043b\u043d\u044b, \u043e\u0431\u043e\u043b\u043e\u0447\u043a\u0438 \u0438 \u043a\u043e\u0440\u0430\u043b\u043b\u044b. \u0413\u043b\u0430\u0432\u043d\u0430\u044f \u0433\u0435\u0440\u043e\u0438\u043d\u044f &#8212; \u201c\u041b\u0430\u0432\u0430\u201d, <strong>B6-8\/S4-7\/C10<\/strong>.<\/p>\n<p>\u041c\u0438\u0440 &#8212; <strong>\u0442\u043e\u0440<\/strong>: \u0440\u0435\u0448\u0451\u0442\u043a\u0430 N\u00b3, \u0443 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043f\u0440\u043e\u0442\u0438\u0432\u043e\u043f\u043e\u043b\u043e\u0436\u043d\u044b\u0435 \u0433\u0440\u0430\u043d\u0438 \u0441\u043a\u043b\u0435\u0435\u043d\u044b. \u041a\u043b\u0430\u0441\u0441\u0438\u043a\u0430 \u201c\u0416\u0438\u0437\u043d\u0438\u201d: \u0443\u0448\u0451\u043b \u0437\u0430 \u043a\u0440\u0430\u0439 &#8212; \u043f\u0440\u0438\u0448\u0451\u043b \u0441 \u0434\u0440\u0443\u0433\u043e\u0439 \u0441\u0442\u043e\u0440\u043e\u043d\u044b.<\/p>\n<p>\u042d\u043a\u0440\u0430\u043d\u043e\u0432 \u0434\u0432\u0430: \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0438 \u043f\u043e\u043b\u0435. \u0411\u0430\u0440\u044b \u0432 \u0446\u0432\u0435\u0442 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0442\u0435\u043a\u0441\u0442\u044b \u043d\u0430 \u0434\u0432\u0443\u0445 \u044f\u0437\u044b\u043a\u0430\u0445, \u043a\u043d\u043e\u043f\u043a\u0430 \u201c\u041d\u0430\u0437\u0430\u0434\u201d \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043a \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u043c.<\/p>\n<figure class=\"full-width \"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/extt\/f4\/59\/06\/f4590643b97f0f97e02f9a868b7f8900.png\" alt=\"\u0421\u043b\u0435\u0432\u0430 \u044d\u043a\u0440\u0430\u043d \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a, \u0441\u043f\u0440\u0430\u0432\u0430 \u043f\u043e\u043b\u0435.\" title=\"\u0421\u043b\u0435\u0432\u0430 \u044d\u043a\u0440\u0430\u043d \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a, \u0441\u043f\u0440\u0430\u0432\u0430 \u043f\u043e\u043b\u0435.\" width=\"1152\" height=\"1252\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/extt\/f4\/59\/06\/f4590643b97f0f97e02f9a868b7f8900.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/extt\/f4\/59\/06\/f4590643b97f0f97e02f9a868b7f8900.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u0421\u043b\u0435\u0432\u0430 \u044d\u043a\u0440\u0430\u043d \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a, \u0441\u043f\u0440\u0430\u0432\u0430 \u043f\u043e\u043b\u0435.<\/figcaption><\/div>\n<\/figure>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u043e \u0440\u0430\u0443\u043d\u0434\u0430\u043c: \u0441\u0442\u0430\u0440\u044b\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u043f\u0440\u043e\u0442\u0438\u0432 DSL.<\/p>\n<h3>\u0420\u0430\u0443\u043d\u0434 1. \u0428\u0435\u0439\u0434\u0435\u0440<\/h3>\n<h4>\u041f\u043e \u0441\u0442\u0430\u0440\u0438\u043d\u043a\u0435<\/h4>\n<pre><code>private const val LIFE_COMPUTE = \"\"\"#version 310 eslayout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in;layout(std430, binding = 0) buffer world { float cells[]; };layout(std140, binding = 0) uniform rules { float birth[27]; float survive[27]; };uniform int u_size;uniform int u_read_offset;uniform int u_write_offset;void main() {    ...}\"\"\"val shader = GLES31.glCreateShader(GLES31.GL_COMPUTE_SHADER)GLES31.glShaderSource(shader, LIFE_COMPUTE)GLES31.glCompileShader(shader)val status = IntArray(1)GLES31.glGetShaderiv(shader, GLES31.GL_COMPILE_STATUS, status, 0)if (status[0] == 0) error(GLES31.glGetShaderInfoLog(shader))val program = GLES31.glCreateProgram()GLES31.glAttachShader(program, shader)GLES31.glLinkProgram(program)GLES31.glGetProgramiv(program, GLES31.GL_LINK_STATUS, status, 0)if (status[0] == 0) error(GLES31.glGetProgramInfoLog(program))val sizeLocation = GLES31.glGetUniformLocation(program, \"u_size\")val readLocation = GLES31.glGetUniformLocation(program, \"u_read_offset\")val writeLocation = GLES31.glGetUniformLocation(program, \"u_write_offset\")<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u041c\u043d\u043e\u0433\u043e\u0442\u043e\u0447\u0438\u0435 \u0432 <code>main()<\/code> &#8212; \u044d\u0442\u043e \u0435\u0449\u0451 40 \u0441\u0442\u0440\u043e\u043a GLSL, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 IDE \u0441\u0447\u0438\u0442\u0430\u0435\u0442 \u043f\u0440\u043e\u0441\u0442\u043e \u0442\u0435\u043a\u0441\u0442\u043e\u043c. \u0420\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u043d\u0433 \u0438\u043c\u0435\u043d\u0438 uniform-\u0430? \u041f\u043e\u0438\u0441\u043a \u043f\u043e \u0441\u0442\u0440\u043e\u043a\u0430\u043c \u0438 \u043c\u043e\u043b\u0438\u0442\u0432\u0430.<\/p>\n<h4>\u0412 RedByteFX<\/h4>\n<pre><code>val program = shader(ShaderTarget.Gles31) {    size = uniformInt(\"size\", 0)    readOffset = uniformInt(\"read_offset\", 0)    writeOffset = uniformInt(\"write_offset\", 0)    lateinit var birth: StorageArray&lt;Flt&lt;High&gt;&gt;    lateinit var survive: StorageArray&lt;Flt&lt;High&gt;&gt;    rules = uniformBlock(\"rules\") {        birth = floatArray(\"birth\", NEIGHBOUR_COUNTS)        survive = floatArray(\"survive\", NEIGHBOUR_COUNTS)    }    lateinit var cells: StorageArray&lt;Flt&lt;High&gt;&gt;    world = storageBlock(\"world\") {        cells = floatArray(\"cells\")    }    compute(WORKGROUP_EDGE, WORKGROUP_EDGE, WORKGROUP_EDGE) {        val n = size.expr        val wrap = fn(0.intLit, 0.intLit, name = \"wrap\") { value, edge -&gt;            ifElse(value lt 0.intLit, value + edge, ifElse(value ge edge, value - edge, value))        }        val block = local(0.intLit, \"block\")        repeat(3) { dz -&gt;            repeat(3) { dy -&gt;                repeat(3) { dx -&gt;                    val neighbour = read(x + dx - 1.intLit, y + dy - 1.intLit, z + dz - 1.intLit)                    block.set(block.expr + ifElse(neighbour gt ALIVE, 1.intLit, 0.intLit))                }            }        }        val self = local(read(x, y, z), \"self\")        val alive = self.expr gt ALIVE        val neighbours = block.expr - ifElse(alive, 1.intLit, 0.intLit)        val lives = ifElse(alive, survive[neighbours] gt 0.5f, birth[neighbours] gt 0.5f)        cells[writeOffset.expr + here].store(nextValue)    }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>(\u0424\u0440\u0430\u0433\u043c\u0435\u043d\u0442 \u0441\u043e\u043a\u0440\u0430\u0449\u0451\u043d: \u0432 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438 \u0435\u0449\u0451 \u0435\u0441\u0442\u044c \u043e\u0441\u0442\u044b\u0432\u0430\u043d\u0438\u0435 \u043a\u043b\u0435\u0442\u043e\u043a, \u201c\u0432\u0441\u043f\u044b\u0448\u043a\u0430 \u0436\u0438\u0437\u043d\u0438\u201d \u043e\u0442 \u0442\u0430\u043f\u0430 \u0438 \u0440\u0435\u0436\u0438\u043c \u0431\u0435\u0441\u043a\u043e\u043d\u0435\u0447\u043d\u043e\u0433\u043e \u043f\u043e\u043b\u044f.)<\/p>\n<p>\u0427\u0442\u043e \u0438\u0437\u043c\u0435\u043d\u0438\u043b\u043e\u0441\u044c \u043f\u043e \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443:<\/p>\n<ul>\n<li>\n<p><strong>\u0422\u0438\u043f\u044b \u0432\u043c\u0435\u0441\u0442\u043e \u0441\u0442\u0440\u043e\u043a.<\/strong> <code>size<\/code> &#8212; \u044d\u0442\u043e <code>Uniform&lt;IntS&gt;<\/code>, \u0430 \u043d\u0435 <code>\"u_size\"<\/code>. \u0422\u043e\u0442 \u0436\u0435 \u043e\u0431\u044a\u0435\u043a\u0442 \u043f\u043e\u0442\u043e\u043c \u043f\u0435\u0440\u0435\u0434\u0430\u0451\u0442\u0441\u044f \u0432 <code>controller.set(compute.size, n)<\/code>. \u041e\u043f\u0435\u0447\u0430\u0442\u043a\u0443 \u043f\u043e\u0439\u043c\u0430\u0435\u0442 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440 Kotlin, \u0430 \u043f\u0435\u0440\u0435\u0438\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u0435 \u043c\u043e\u0436\u043d\u043e \u043b\u0435\u0433\u043a\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0432 IDE.<\/p>\n<\/li>\n<li>\n<p><strong>\u041e\u0448\u0438\u0431\u043a\u0438 \u0434\u043e GPU.<\/strong> \u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c <code>compute { }<\/code> \u0438\u043b\u0438 \u043e\u0431\u044a\u044f\u0432\u0438\u0442\u044c storage-\u0431\u0443\u0444\u0435\u0440 \u0432 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0435 \u043f\u043e\u0434 <code>ShaderTarget.Gles30<\/code>: DSL \u043e\u0442\u043a\u0430\u0436\u0435\u0442 \u0435\u0449\u0451 \u043f\u0440\u0438 \u0441\u0431\u043e\u0440\u043a\u0435 \u0448\u0435\u0439\u0434\u0435\u0440\u0430 \u0432 Kotlin, \u0430 \u043d\u0435 \u0432 \u043b\u043e\u0433\u0435 \u0434\u0440\u0430\u0439\u0432\u0435\u0440\u0430 \u043d\u0430 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f.<\/p>\n<\/li>\n<li>\n<p><strong>\u041d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u044b\u0435 \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0446\u0438\u0438.<\/strong> <code>fn<\/code> \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e GLSL-\u0444\u0443\u043d\u043a\u0446\u0438\u044e, <code>local<\/code> &#8212; \u0432 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u0443\u044e \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e, <code>repeat(3)<\/code> &#8212; \u0432 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0438\u0439 <code>for<\/code>. \u041f\u043e\u0447\u0435\u043c\u0443 \u0432 \u0448\u0435\u0439\u0434\u0435\u0440\u0435 \u0441\u0432\u043e\u0439 <code>wrap<\/code>, \u0430 \u043d\u0435 <code>%<\/code>? \u041f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0432 GLSL <code>-1 % n<\/code> \u043d\u0435 \u0434\u0430\u0451\u0442 <code>n - 1<\/code>, \u0438 \u0442\u043e\u0440 \u0440\u0432\u0451\u0442\u0441\u044f \u043f\u043e \u0448\u0432\u0430\u043c.<\/p>\n<\/li>\n<li>\n<p><strong>\u041f\u0440\u043e\u0437\u0440\u0430\u0447\u043d\u043e\u0441\u0442\u044c.<\/strong> <code>program.computeSource()<\/code> \u043e\u0442\u0434\u0430\u0451\u0442 \u0438\u0442\u043e\u0433\u043e\u0432\u044b\u0439 GLSL. \u041d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u0441\u043f\u0440\u044f\u0442\u0430\u043d\u043e:<\/p>\n<\/li>\n<\/ul>\n<pre><code>#version 310 esprecision highp float;uniform int u_size;uniform int u_read_offset;uniform int u_write_offset;layout(std140, binding = 0) uniform rules {  highp float birth[27];  highp float survive[27];} b_rules;layout(std430, binding = 0) buffer world {  highp float cells[];} b_world;layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in;int wrap(int p0, int p1) {  return ((p0 &lt; 0) ? (p0 + p1) : ((p0 &gt;= p1) ? (p0 - p1) : p0));}void main() {  int block;  highp float self;  block = 0;  for (int i = 0; i &lt; 3; ++i) {<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u0411\u0438\u043d\u0434\u0438\u043d\u0433\u0438 \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u044b, std140\/std430 \u0440\u0430\u0441\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u044b, \u0430 \u043f\u043e\u0432\u0442\u043e\u0440\u044f\u044e\u0449\u0438\u0435\u0441\u044f \u043f\u043e\u0434\u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0441\u0430\u043c\u0430 \u0432\u044b\u043d\u043e\u0441\u0438\u0442 \u0432 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435.<\/p>\n<h3>\u0420\u0430\u0443\u043d\u0434 2. \u0411\u0443\u0444\u0435\u0440\u044b \u0438 std140<\/h3>\n<p>\u041f\u043e\u043b\u0435 N\u00b3 \u043b\u0435\u0436\u0438\u0442 \u0432 \u043e\u0434\u043d\u043e\u043c storage-\u0431\u0443\u0444\u0435\u0440\u0435, \u0433\u0434\u0435 <strong>\u0434\u0432\u0435 \u0440\u0435\u0448\u0451\u0442\u043a\u0438 \u043f\u043e\u0434\u0440\u044f\u0434<\/strong>: \u043f\u043e\u043a\u043e\u043b\u0435\u043d\u0438\u0435 \u0447\u0438\u0442\u0430\u0435\u0442 \u043e\u0434\u043d\u0443 \u043f\u043e\u043b\u043e\u0432\u0438\u043d\u0443 \u0438 \u043f\u0438\u0448\u0435\u0442 \u0434\u0440\u0443\u0433\u0443\u044e, \u043f\u043e\u0442\u043e\u043c \u043f\u043e\u043b\u043e\u0432\u0438\u043d\u044b \u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f \u0440\u043e\u043b\u044f\u043c\u0438. \u041f\u043b\u044e\u0441 uniform-\u0431\u043b\u043e\u043a \u0441 \u043f\u0440\u0430\u0432\u0438\u043b\u0430\u043c\u0438: 27 \u0444\u043b\u0430\u0433\u043e\u0432 \u0440\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u0438 27 \u0444\u043b\u0430\u0433\u043e\u0432 \u0432\u044b\u0436\u0438\u0432\u0430\u043d\u0438\u044f.<\/p>\n<h4>\u041f\u043e \u0441\u0442\u0430\u0440\u0438\u043d\u043a\u0435<\/h4>\n<pre><code>val buffers = IntArray(2)GLES31.glGenBuffers(2, buffers, 0)val cells = ByteBuffer.allocateDirect(world.size * 4).order(ByteOrder.nativeOrder())cells.asFloatBuffer().put(world)GLES31.glBindBuffer(GLES31.GL_SHADER_STORAGE_BUFFER, buffers[0])GLES31.glBufferData(GLES31.GL_SHADER_STORAGE_BUFFER, cells.capacity(), cells, GLES31.GL_DYNAMIC_COPY)GLES31.glBindBufferBase(GLES31.GL_SHADER_STORAGE_BUFFER, 0, buffers[0])val rules = ByteBuffer.allocateDirect(54 * 16).order(ByteOrder.nativeOrder())for (i in values.indices) rules.putFloat(i * 16, values[i])GLES31.glBindBuffer(GLES31.GL_UNIFORM_BUFFER, buffers[1])GLES31.glBufferData(GLES31.GL_UNIFORM_BUFFER, rules.capacity(), rules, GLES31.GL_STATIC_DRAW)GLES31.glBindBufferBase(GLES31.GL_UNIFORM_BUFFER, 0, buffers[1])<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u0412\u0438\u0434\u0438\u0442\u0435 <code>i * 16<\/code>? \u0412 std140 \u043a\u0430\u0436\u0434\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u043c\u0430\u0441\u0441\u0438\u0432\u0430 <code>float<\/code> \u0432\u044b\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0434\u043e 16 \u0431\u0430\u0439\u0442. \u0417\u0430\u0431\u0443\u0434\u0435\u0442\u0435 &#8212; \u0438 \u043f\u0440\u0430\u0432\u0438\u043b\u043e \u201c\u0440\u043e\u0436\u0434\u0435\u043d\u0438\u0435 \u043f\u0440\u0438 5 \u0441\u043e\u0441\u0435\u0434\u044f\u0445\u201d \u043f\u0440\u0435\u0432\u0440\u0430\u0442\u0438\u0442\u0441\u044f \u0432 \u201c\u0440\u043e\u0436\u0434\u0435\u043d\u0438\u0435 \u043f\u0440\u0438 1, 5 \u0438 9\u201d. \u041a\u043e\u043b\u043e\u043d\u0438\u044f \u043d\u0430\u0447\u043d\u0451\u0442 \u0436\u0438\u0442\u044c \u043f\u043e \u0437\u0430\u043a\u043e\u043d\u0430\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u044b \u0435\u0439 \u043d\u0435 \u0434\u0430\u0432\u0430\u043b\u0438.<\/p>\n<h4>\u0412 RedByteFX<\/h4>\n<pre><code>controller.set(compute.world, world)controller.set(compute.rules, rule.uniformValues())<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u041f\u043b\u043e\u0441\u043a\u0438\u0439 <code>FloatArray<\/code> \u043d\u0430 \u0432\u0445\u043e\u0434\u0435. \u0420\u0430\u0441\u043a\u043b\u0430\u0434\u043a\u0443 std140\/std430, \u0432\u044b\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u043d\u0438\u0435, \u0432\u044b\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0431\u0443\u0444\u0435\u0440\u043e\u0432 \u0438 \u0438\u0445 \u043f\u0440\u0438\u0432\u044f\u0437\u043a\u0443 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u0435\u043b\u0430\u0435\u0442 \u0441\u0430\u043c\u0430. \u041f\u043e\u0432\u0442\u043e\u0440\u043d\u044b\u0435 \u0437\u0430\u043f\u0438\u0441\u0438 \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0435 \u043c\u0430\u0441\u0441\u0438\u0432\u044b \u0438 \u043d\u0435 \u0430\u043b\u043b\u043e\u0446\u0438\u0440\u0443\u044e\u0442 \u043d\u043e\u0432\u044b\u0435.<\/p>\n<h3>\u0420\u0430\u0443\u043d\u0434 3. \u0417\u0430\u043f\u0443\u0441\u043a, \u043f\u043e\u0442\u043e\u043a\u0438 \u0438 \u0447\u0442\u0435\u043d\u0438\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430<\/h3>\n<h4>\u041f\u043e \u0441\u0442\u0430\u0440\u0438\u043d\u043a\u0435<\/h4>\n<pre><code>glSurfaceView.queueEvent {    GLES31.glUseProgram(program)    GLES31.glUniform1i(sizeLocation, n)    GLES31.glUniform1i(readLocation, read)    GLES31.glUniform1i(writeLocation, write)    GLES31.glDispatchCompute(n \/ 4, n \/ 4, n \/ 4)    GLES31.glMemoryBarrier(GLES31.GL_BUFFER_UPDATE_BARRIER_BIT)    GLES31.glBindBuffer(GLES31.GL_SHADER_STORAGE_BUFFER, buffers[0])    val mapped = GLES31.glMapBufferRange(        GLES31.GL_SHADER_STORAGE_BUFFER, 0, cells.capacity(), GLES31.GL_MAP_READ_BIT,    ) as ByteBuffer    mapped.order(ByteOrder.nativeOrder()).asFloatBuffer().get(into)    GLES31.glUnmapBuffer(GLES31.GL_SHADER_STORAGE_BUFFER)    mainHandler.post { onGeneration(into) }}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u043f\u0440\u0438\u0442\u0430\u0438\u043b\u0430\u0441\u044c \u043a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u043b\u043e\u0432\u0443\u0448\u043a\u0430. \u0411\u0430\u0440\u044c\u0435\u0440 \u0434\u043b\u044f <em>\u043c\u0430\u043f\u043f\u0438\u043d\u0433\u0430<\/em> &#8212; <code>GL_BUFFER_UPDATE_BARRIER_BIT<\/code>. \u041c\u043d\u043e\u0433\u0438\u0435 \u0441\u0442\u0430\u0432\u044f\u0442 \u043f\u0440\u0438\u0432\u044b\u0447\u043d\u044b\u0439 <code>GL_SHADER_STORAGE_BARRIER_BIT<\/code>, \u0438 \u043d\u0430 \u043e\u0434\u043d\u0438\u0445 GPU \u0432\u0441\u0451 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442, \u0430 \u043d\u0430 \u0434\u0440\u0443\u0433\u0438\u0445 \u043f\u0440\u0438\u0445\u043e\u0434\u044f\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u0440\u043e\u0448\u043b\u043e\u0433\u043e \u043f\u043e\u043a\u043e\u043b\u0435\u043d\u0438\u044f. \u041e\u0442\u043b\u0430\u0436\u0438\u0432\u0430\u0442\u044c \u0442\u0430\u043a\u043e\u0435 &#8212; \u0443\u0434\u043e\u0432\u043e\u043b\u044c\u0441\u0442\u0432\u0438\u0435 \u0443\u0440\u043e\u0432\u043d\u044f \u043f\u0440\u043e\u0441\u0438\u0434\u0435\u0442\u044c \u0432 \u044d\u0446\u0438\u0445\u0435 \u0441 \u0433\u0432\u043e\u0437\u0434\u044f\u043c\u0438 \u043f\u043e\u0436\u0438\u0437\u043d\u0435\u043d\u043d\u043e, \u0434\u043e \u0432\u044b\u043f\u043b\u0430\u0442\u044b.<\/p>\n<h4>\u0412 RedByteFX<\/h4>\n<pre><code>val computeController = rememberGlController(compute.program)GlCompute(controller = computeController, modifier = Modifier.size(1.dp), overlay = {})controller.set(compute.readOffset, read)controller.set(compute.writeOffset, write)controller.dispatch(groups, groups, groups)controller.read(compute.world, into) { count -&gt; onGeneration() }<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u0427\u0442\u043e \u0437\u0434\u0435\u0441\u044c \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0437\u0430 \u043a\u0430\u0434\u0440\u043e\u043c:<\/p>\n<ul>\n<li>\n<p><code>GlCompute<\/code> &#8212; \u043d\u0435\u0432\u0438\u0434\u0438\u043c\u044b\u0439 \u0445\u043e\u0441\u0442 \u0441 EGL-\u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043e\u043c \u043d\u0443\u0436\u043d\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438. \u041e\u043d \u0441\u0430\u043c \u0441\u0442\u0430\u0432\u0438\u0442 \u043d\u0430 \u043f\u0430\u0443\u0437\u0443 \u0438 \u0432\u043e\u0437\u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0443 \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u044b\u043c \u0446\u0438\u043a\u043b\u043e\u043c \u044d\u043a\u0440\u0430\u043d\u0430.<\/p>\n<\/li>\n<li>\n<p><code>set<\/code>, <code>dispatch<\/code> \u0438 <code>read<\/code> \u043c\u043e\u0436\u043d\u043e \u0437\u0432\u0430\u0442\u044c \u0441 \u043b\u044e\u0431\u043e\u0433\u043e \u043f\u043e\u0442\u043e\u043a\u0430. \u041e\u043d\u0438 \u0441\u0442\u0430\u0432\u044f\u0442\u0441\u044f \u0432 \u043e\u0447\u0435\u0440\u0435\u0434\u044c GL-\u043f\u043e\u0442\u043e\u043a\u0430 \u0438 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f \u0432 \u0442\u043e\u043c \u043f\u043e\u0440\u044f\u0434\u043a\u0435, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0432\u044b \u0438\u0445 \u0441\u0434\u0435\u043b\u0430\u043b\u0438.<\/p>\n<\/li>\n<li>\n<p><code>dispatch<\/code> \u0441\u0442\u0430\u0432\u0438\u0442 \u0431\u0430\u0440\u044c\u0435\u0440 \u0434\u043b\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u0448\u0435\u0439\u0434\u0435\u0440\u043e\u0432, \u0430 <code>read<\/code> \u043f\u0435\u0440\u0435\u0434 \u043c\u0430\u043f\u043f\u0438\u043d\u0433\u043e\u043c \u0441\u0442\u0430\u0432\u0438\u0442 \u0438\u043c\u0435\u043d\u043d\u043e <code>GL_BUFFER_UPDATE_BARRIER_BIT<\/code>. \u041b\u043e\u0432\u0443\u0448\u043a\u0430 \u0432\u044b\u0448\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u043d\u0435 \u0441\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f.<\/p>\n<\/li>\n<li>\n<p>\u0415\u0441\u043b\u0438 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u043f\u0435\u0440\u0435\u0441\u043e\u0437\u0434\u0430\u043d, \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f uniform-\u043e\u0432 \u0438 \u0431\u043b\u043e\u043a\u043e\u0432 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f \u043a \u043d\u043e\u0432\u043e\u0439 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0435 \u0437\u0430\u043d\u043e\u0432\u043e.<\/p>\n<\/li>\n<li>\n<p>\u0421\u0442\u0430\u0442\u0443\u0441 \u043b\u0438\u043d\u043a\u043e\u0432\u043a\u0438 &#8212; \u044d\u0442\u043e Compose-<code>State<\/code> (<code>controller.linkState<\/code>). \u041d\u0435 \u0442\u044f\u043d\u0435\u0442 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e ES 3.1? \u041f\u043e\u043b\u0443\u0447\u0438\u0442\u0435 <code>GlLinkState.Failed<\/code> \u0438 \u043f\u043e\u043a\u0430\u0436\u0435\u0442\u0435 \u0432\u0435\u0436\u043b\u0438\u0432\u044b\u0439 \u044d\u043a\u0440\u0430\u043d \u0432\u043c\u0435\u0441\u0442\u043e \u043f\u0430\u0434\u0435\u043d\u0438\u044f.<\/p>\n<\/li>\n<\/ul>\n<p><strong>\u0413\u0440\u0430\u0431\u043b\u044f \u21162, \u0443\u0436\u0435 \u043c\u043e\u044f.<\/strong> \u0417\u0430\u043f\u0438\u0441\u0438 <code>set(...)<\/code> \u0432 <code>GlController<\/code> <strong>\u0441\u043a\u043b\u0435\u0438\u0432\u0430\u044e\u0442\u0441\u044f<\/strong>: \u0435\u0441\u043b\u0438 \u0437\u0430\u043f\u0438\u0441\u0430\u0442\u044c uniform \u0434\u0432\u0430\u0436\u0434\u044b \u0434\u043e \u0442\u043e\u0433\u043e, \u043a\u0430\u043a GL-\u043f\u043e\u0442\u043e\u043a \u0438\u0445 \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u043b, \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u0442\u0441\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435. \u0422\u0430\u043a UI-\u043f\u043e\u0442\u043e\u043a \u043d\u0438\u043a\u043e\u0433\u0434\u0430 \u043d\u0435 \u0436\u0434\u0451\u0442 \u0434\u0440\u0430\u0439\u0432\u0435\u0440, \u0438 \u0434\u043b\u044f \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u044d\u0442\u043e \u0438\u0434\u0435\u0430\u043b\u044c\u043d\u043e. \u041d\u043e \u0434\u043b\u044f \u043f\u043e\u043a\u043e\u043b\u0435\u043d\u0438\u0439 \u044d\u0442\u043e \u043b\u043e\u0432\u0443\u0448\u043a\u0430: \u0442\u0438\u043a N+1 \u043c\u043e\u0433 \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u043c\u0435\u0449\u0435\u043d\u0438\u044f \u0440\u0430\u043d\u044c\u0448\u0435, \u0447\u0435\u043c \u043e\u0442\u0440\u0430\u0431\u043e\u0442\u0430\u043b dispatch \u0442\u0438\u043a\u0430 N, \u0438 \u043e\u0431\u0430 \u043f\u043e\u043a\u043e\u043b\u0435\u043d\u0438\u044f \u0447\u0438\u0442\u0430\u043b\u0438 \u043e\u0434\u043d\u0443 \u043f\u043e\u043b\u043e\u0432\u0438\u043d\u0443. \u041f\u043e\u043b\u0443\u0447\u0430\u043b\u0430\u0441\u044c \u201c\u0416\u0438\u0437\u043d\u044c\u201d \u0441 \u0430\u043c\u043d\u0435\u0437\u0438\u0435\u0439. \u041b\u0435\u0447\u0438\u0442\u0441\u044f \u043e\u0434\u043d\u0438\u043c \u0444\u043b\u0430\u0433\u043e\u043c: \u043d\u043e\u0432\u044b\u0439 \u0442\u0438\u043a \u0441\u0442\u0430\u0440\u0442\u0443\u0435\u0442, \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u043e\u0433\u0434\u0430 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0435 \u043f\u043e\u043a\u043e\u043b\u0435\u043d\u0438\u0435 \u0432\u0435\u0440\u043d\u0443\u043b\u043e\u0441\u044c \u0441 GPU.<\/p>\n<pre><code>fun tick(): Boolean {    if (!inFlight.compareAndSet(false, true)) return false    val started = epoch    val previous = latest    val read = current    val write = if (read == 0) total else 0    gpu.offsets(read, write)    gpu.dispatch(n \/ WORKGROUP_EDGE)    gpu.readBack(readBack) {        if (started == epoch) {            latest = Generation.of(readBack, write, n, previous.origin, previous.number + 1)            latestAt = clock()            current = write            inFlight.set(false)        }    }    return true}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>(\u0423\u043f\u0440\u043e\u0449\u0435\u043d\u043e. <code>epoch<\/code> \u0432\u044b\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u0435\u0442 \u043f\u043e\u043a\u043e\u043b\u0435\u043d\u0438\u0435, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043f\u0440\u0438\u043b\u0435\u0442\u0435\u043b\u043e \u0443\u0436\u0435 \u043f\u043e\u0441\u043b\u0435 \u043d\u0430\u0436\u0430\u0442\u0438\u044f \u201c\u0417\u0430\u043d\u043e\u0432\u043e\u201d.)<\/p>\n<p>\u041c\u043e\u0440\u0430\u043b\u044c: \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0446\u0438\u044f \u0441\u043d\u0438\u043c\u0430\u0435\u0442 \u0440\u0443\u0442\u0438\u043d\u0443, \u043d\u043e \u043d\u0435 \u043e\u0442\u043c\u0435\u043d\u044f\u0435\u0442 \u043c\u044b\u0448\u043b\u0435\u043d\u0438\u0435. \u0417\u0430\u0442\u043e \u0434\u0443\u043c\u0430\u0442\u044c \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043e \u043b\u043e\u0433\u0438\u043a\u0435 \u0438\u0433\u0440\u044b, \u0430 \u043d\u0435 \u043e \u0431\u0430\u0439\u0442\u0430\u0445.<\/p>\n<h3>\u0420\u0430\u0443\u043d\u0434 4. \u0422\u0435\u0441\u0442\u044b<\/h3>\n<h4>\u041f\u043e \u0441\u0442\u0430\u0440\u0438\u043d\u043a\u0435<\/h4>\n<p>\u0428\u0435\u0439\u0434\u0435\u0440 \u0432 \u0441\u0442\u0440\u043e\u043a\u0435 \u043f\u0440\u043e\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043c\u043e\u0436\u043d\u043e \u043e\u0434\u043d\u0438\u043c \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u043c: \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0438 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c. Unit-\u0442\u0435\u0441\u0442 \u043d\u0430 JVM \u0434\u0430\u0436\u0435 \u043d\u0435 \u0441\u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u0443\u0435\u0442 \u0435\u0433\u043e, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u043d\u0435\u0442 \u0434\u0440\u0430\u0439\u0432\u0435\u0440\u0430.<\/p>\n<h4>\u0412 RedByteFX<\/h4>\n<p>\u0428\u0435\u0439\u0434\u0435\u0440 \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u043d\u0430 JVM, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043e\u0431\u044b\u0447\u043d\u044b\u0435 unit-\u0442\u0435\u0441\u0442\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u044e\u0442 \u0435\u0433\u043e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443:<\/p>\n<pre><code>@Testfun theGenerationRunsInFourCubedWorkgroups() {    val source = lifeCompute().program.computeSource()    assertTrue(source, source.contains(\"local_size_x = 4, local_size_y = 4, local_size_z = 4\"))}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u0410 \u0433\u043b\u0430\u0432\u043d\u043e\u0435 &#8212; \u0440\u0430\u043d\u0442\u0430\u0439\u043c <code>GlProgramRuntime<\/code> \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0438 \u0431\u0435\u0437 Compose, \u0441 \u043b\u044e\u0431\u044b\u043c EGL-\u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043e\u043c. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0435\u0441\u0442\u044c \u0442\u0435\u0441\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0430 <strong>\u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c GPU<\/strong> \u043f\u0440\u043e\u0433\u043e\u043d\u044f\u0435\u0442 \u043f\u043e\u043a\u043e\u043b\u0435\u043d\u0438\u0435 \u0438 \u0441\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u0435\u0442 \u043a\u0430\u0436\u0434\u0443\u044e \u043a\u043b\u0435\u0442\u043a\u0443 \u0441 \u044d\u0442\u0430\u043b\u043e\u043d\u043e\u043c \u043d\u0430 Kotlin, \u0442\u0440\u0435\u0431\u0443\u044f \u0442\u043e\u0447\u043d\u043e\u0433\u043e \u0441\u043e\u0432\u043f\u0430\u0434\u0435\u043d\u0438\u044f:<\/p>\n<pre><code>val runtime = GlProgramRuntime(compute.program, Gles30Device())runtime.link()runtime.set(compute.world, world)runtime.set(compute.rules, rule.uniformValues())runtime.set(compute.size, n)runtime.set(compute.readOffset, 0)runtime.set(compute.writeOffset, total)runtime.dispatch(groups, groups, groups)runtime.read(compute.world, back)assertArrayEquals(CpuLife.step(seed, n, rule), back.copyOfRange(total, 2 * total), 0f)<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u042d\u0442\u0430\u043b\u043e\u043d &#8212; \u043f\u044f\u0442\u044c \u0441\u0442\u0440\u043e\u043a <code>when<\/code> \u043d\u0430 Kotlin. \u041d\u0430 Samsung Galaxy S21 \u0448\u0435\u0439\u0434\u0435\u0440 \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u0435\u0442 \u0441 \u043d\u0438\u043c \u0434\u043e \u0431\u0438\u0442\u0430 \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u043f\u0440\u0430\u0432\u0438\u043b. \u041a\u043e\u0433\u0434\u0430 \u043a\u0442\u043e-\u0442\u043e \u0441\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0435\u0442 \u201c\u0430 \u043e\u043d\u043e \u0442\u043e\u0447\u043d\u043e \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e \u0441\u0447\u0438\u0442\u0430\u0435\u0442?\u201d, \u043e\u0442\u0432\u0435\u0442 \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442 \u043e\u0434\u043d\u0443 \u043a\u043e\u043c\u0430\u043d\u0434\u0443: <code>.\/gradlew connectedDebugAndroidTest<\/code>.<\/p>\n<h3>\u0420\u0430\u0443\u043d\u0434 5. \u041e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0430 \u0442\u044b\u0441\u044f\u0447 \u043a\u043b\u0435\u0442\u043e\u043a<\/h3>\n<p>\u041a\u043b\u0435\u0442\u043a\u0438 &#8212; \u044d\u0442\u043e \u0438\u043d\u0441\u0442\u0430\u043d\u0441\u044b \u0441\u0444\u0435\u0440\u044b. \u041a\u0430\u0436\u0434\u043e\u0439 \u043d\u0443\u0436\u043d\u044b \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b \u0438 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435, \u0430 \u0432\u0441\u0435\u043c \u0432\u043c\u0435\u0441\u0442\u0435 &#8212; \u043e\u0434\u0438\u043d draw call.<\/p>\n<h4>\u041f\u043e \u0441\u0442\u0430\u0440\u0438\u043d\u043a\u0435<\/h4>\n<pre><code>val data = ByteBuffer.allocateDirect(instances.size * 4).order(ByteOrder.nativeOrder())data.asFloatBuffer().put(instances)GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, instanceBuffer)GLES30.glBufferData(GLES30.GL_ARRAY_BUFFER, data.capacity(), data, GLES30.GL_STREAM_DRAW)for (column in 0 until 4) {    val location = modelLocation + column    GLES30.glEnableVertexAttribArray(location)    GLES30.glVertexAttribPointer(location, 4, GLES30.GL_FLOAT, false, 64, column * 16)    GLES30.glVertexAttribDivisor(location, 1)}GLES30.glDrawElementsInstanced(GLES30.GL_TRIANGLES, indexCount, GLES30.GL_UNSIGNED_SHORT, 0, count)<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u0418 \u043f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u043d\u0435 \u0437\u0430\u0431\u044b\u0442\u044c \u0432\u0435\u0440\u043d\u0443\u0442\u044c divisor \u0432 \u043d\u043e\u043b\u044c, \u0438\u043d\u0430\u0447\u0435 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043c\u0435\u0448 \u043d\u0430\u0440\u0438\u0441\u0443\u0435\u0442\u0441\u044f \u043e\u0447\u0435\u043d\u044c \u043a\u0440\u0435\u0430\u0442\u0438\u0432\u043d\u043e.<\/p>\n<h4>\u0412 RedByteFX<\/h4>\n<pre><code>frame.draw(backgroundMesh, model = background, pipeline = liquidPipeline)frame.draw(cellMesh, instances = drawn.instances, pipeline = cellPipeline)<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p><code>instances<\/code> &#8212; \u043f\u043b\u043e\u0441\u043a\u0438\u0439 <code>FloatArray<\/code>, \u043f\u043e 16 \u0447\u0438\u0441\u0435\u043b \u043d\u0430 \u0438\u043d\u0441\u0442\u0430\u043d\u0441. \u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u0435\u0440\u0436\u0438\u0442 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u0438\u043d\u0441\u0442\u0430\u043d\u0441-\u0431\u0443\u0444\u0435\u0440 \u043d\u0430 \u043a\u0430\u0436\u0434\u044b\u0439 \u043c\u0435\u0448, \u0440\u0430\u0441\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u043e \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0430\u043c <code>model0..model3<\/code> \u0441 divisor 1 \u0438 \u043f\u0440\u0438\u0431\u0438\u0440\u0430\u0435\u0442 \u0437\u0430 \u0441\u043e\u0431\u043e\u0439 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435. <code>GlPipeline(depthMask = false)<\/code> &#8212; \u044d\u0442\u043e \u201c\u0444\u043e\u043d \u043d\u0435 \u043f\u0438\u0448\u0435\u0442 \u0433\u043b\u0443\u0431\u0438\u043d\u0443\u201d \u043e\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u043e\u0439 \u0432\u043c\u0435\u0441\u0442\u043e \u043f\u0430\u0447\u043a\u0438 <code>glDepthMask<\/code>\/<code>glEnable<\/code>\/<code>glDisable<\/code>. \u0421\u0444\u0435\u0440\u0430 \u0438 \u043a\u0432\u0430\u0434 &#8212; \u0433\u043e\u0442\u043e\u0432\u044b\u0435 \u043f\u0440\u0438\u043c\u0438\u0442\u0438\u0432\u044b <code>sphere(1f, 6, 10)<\/code> \u0438 <code>quad(2f, 2f)<\/code>.<\/p>\n<p>\u041c\u0430\u0442\u0440\u0438\u0446\u044b \u0441\u0447\u0438\u0442\u0430\u0435\u0442 <code>redbytefx-3d<\/code> \u043f\u0440\u044f\u043c\u043e \u0432 \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0435 \u043c\u0430\u0441\u0441\u0438\u0432\u044b, \u0431\u0435\u0437 \u0430\u043b\u043b\u043e\u043a\u0430\u0446\u0438\u0439 \u043d\u0430 \u043a\u0430\u0434\u0440:<\/p>\n<pre><code>lookAt(eye[0], eye[1], eye[2], camera.targetX, camera.targetY, camera.targetZ, 0f, 1f, 0f, viewMatrix)perspective(OrbitCamera.verticalFov(frame.aspect), frame.aspect, NEAR, FAR, projection)<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u0412 \u0432\u0435\u0440\u0448\u0438\u043d\u043d\u043e\u043c \u0448\u0435\u0439\u0434\u0435\u0440\u0435 \u043c\u0430\u0442\u0440\u0438\u0446\u0430 \u0438\u043d\u0441\u0442\u0430\u043d\u0441\u0430 \u043d\u0430\u043c \u0432\u043e\u043e\u0431\u0449\u0435 \u043d\u0435 \u043d\u0443\u0436\u043d\u0430. \u0412 \u043f\u0435\u0440\u0432\u044b\u0439 \u0441\u0442\u043e\u043b\u0431\u0435\u0446 \u043c\u044b \u043a\u043b\u0430\u0434\u0451\u043c <code>(x, y, z, value)<\/code> \u0438 \u0441\u0430\u043c\u0438 \u0440\u0435\u0448\u0430\u0435\u043c, \u0447\u0442\u043e \u0441 \u044d\u0442\u0438\u043c \u0434\u0435\u043b\u0430\u0442\u044c. \u0428\u0435\u0439\u0434\u0435\u0440 \u043d\u0430\u0448, \u043c\u044b \u0442\u0443\u0442 \u043f\u0440\u0430\u0432\u0438\u0442\u0435\u043b\u044c\u0441\u0442\u0432\u043e:<\/p>\n<pre><code>val column0 = attributeVec4(\"model0\")val cell = vec3(column0.x, column0.y, column0.z)val value = column0.wval grow = smoothstep(0f, 1f, phase.expr)val life = ifElse(value lt -0.5f, fadingLife, ifElse(value lt 1.5f, grow, 1f.lit))<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u041d\u043e\u0432\u043e\u0440\u043e\u0436\u0434\u0451\u043d\u043d\u0430\u044f \u043a\u043b\u0435\u0442\u043a\u0430 \u0432\u044b\u0440\u0430\u0441\u0442\u0430\u0435\u0442 \u0437\u0430 \u043f\u043e\u043a\u043e\u043b\u0435\u043d\u0438\u0435, \u0443\u043c\u0435\u0440\u0448\u0430\u044f \u0441\u0436\u0438\u043c\u0430\u0435\u0442\u0441\u044f \u0432 \u0442\u0451\u043c\u043d\u043e\u0433\u043e \u201c\u043f\u0440\u0438\u0437\u0440\u0430\u043a\u0430\u201d \u0438 \u0442\u0430\u0435\u0442. \u0421\u0432\u0435\u0442 \u0432\u0437\u044f\u0442 \u0438\u0437 stdlib, \u0431\u0435\u0437 \u0435\u0434\u0438\u043d\u043e\u0439 \u0444\u043e\u0440\u043c\u0443\u043b\u044b, \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u0430\u043d\u043d\u043e\u0439 \u0438\u0437 \u0443\u0447\u0435\u0431\u043d\u0438\u043a\u0430:<\/p>\n<pre><code>val diffuse = wrapLambert(n, lightDir, 0.3f)val rim = fresnel(n, toEye, 2.4f)<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p><code>fresnel<\/code> \u0434\u0430\u0451\u0442 \u0441\u0432\u0435\u0442\u044f\u0449\u0438\u0439\u0441\u044f \u043e\u0431\u043e\u0434\u043e\u043a, \u0438 \u043d\u0435\u043f\u0440\u043e\u0437\u0440\u0430\u0447\u043d\u044b\u0435 \u0441\u0444\u0435\u0440\u044b \u0432\u044b\u0433\u043b\u044f\u0434\u044f\u0442 \u0432\u043b\u0430\u0436\u043d\u044b\u043c\u0438, \u0431\u0435\u0437 \u0431\u043b\u0435\u043d\u0434\u0438\u043d\u0433\u0430.<\/p>\n<figure class=\"full-width \"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/extt\/47\/4c\/3d\/474c3ddb1f6d0fc1a02770019d17409e.png\" alt=\"\u041e\u0431\u043e\u043b\u043e\u0447\u043a\u0430 \u201c\u041b\u0430\u0432\u044b\u201d \u043d\u0430 31-\u043c \u043f\u043e\u043a\u043e\u043b\u0435\u043d\u0438\u0438 \u0438 \u0432\u0438\u0434 \u0438\u0437\u043d\u0443\u0442\u0440\u0438 \u0441\u0440\u0435\u0434\u044b \u043d\u0430 96-\u043c\" title=\"\u041e\u0431\u043e\u043b\u043e\u0447\u043a\u0430 \u201c\u041b\u0430\u0432\u044b\u201d \u043d\u0430 31-\u043c \u043f\u043e\u043a\u043e\u043b\u0435\u043d\u0438\u0438 \u0438 \u0432\u0438\u0434 \u0438\u0437\u043d\u0443\u0442\u0440\u0438 \u0441\u0440\u0435\u0434\u044b \u043d\u0430 96-\u043c\" width=\"1152\" height=\"1252\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/extt\/47\/4c\/3d\/474c3ddb1f6d0fc1a02770019d17409e.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/extt\/47\/4c\/3d\/474c3ddb1f6d0fc1a02770019d17409e.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041e\u0431\u043e\u043b\u043e\u0447\u043a\u0430 \u201c\u041b\u0430\u0432\u044b\u201d \u043d\u0430 31-\u043c \u043f\u043e\u043a\u043e\u043b\u0435\u043d\u0438\u0438 \u0438 \u0432\u0438\u0434 \u0438\u0437\u043d\u0443\u0442\u0440\u0438 \u0441\u0440\u0435\u0434\u044b \u043d\u0430 96-\u043c<\/figcaption><\/div>\n<\/figure>\n<p>\u0410 \u0432\u043e\u0442 \u043f\u0440\u0430\u0432\u0438\u043b\u043e \u201c\u0412\u043e\u043b\u043d\u044b\u201d (B4\/S4\/C5): \u0432\u043e\u043b\u043d\u0430 \u0440\u0430\u0441\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043e\u0442 \u0438\u0441\u043a\u0440\u044b \u0438 \u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0433\u0430\u0441\u043d\u0443\u0449\u0438\u0439 \u0441\u043b\u0435\u0434.<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/extt\/ed\/16\/52\/ed1652208f9bb3f5a1897caddca8712b.gif\" alt=\"\u0412\u043e\u043b\u043d\u044b\" width=\"300\" height=\"642\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/extt\/ed\/16\/52\/ed1652208f9bb3f5a1897caddca8712b.gif 780w,&#10;       https:\/\/habrastorage.org\/extt\/ed\/16\/52\/ed1652208f9bb3f5a1897caddca8712b.gif 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u0412\u043e\u043b\u043d\u044b<\/figcaption><\/div>\n<\/figure>\n<h3>\u0420\u0430\u0443\u043d\u0434 6. Kotlin \u043a\u0430\u043a \u043c\u0430\u043a\u0440\u043e\u044f\u0437\u044b\u043a \u0434\u043b\u044f GLSL<\/h3>\n<p>\u041f\u0435\u0440\u0432\u044b\u0439 \u0444\u043e\u043d-\u201c\u0436\u0438\u0434\u043a\u043e\u0441\u0442\u044c\u201d \u044f \u0441\u043e\u0431\u0440\u0430\u043b \u0437\u0430 \u043f\u044f\u0442\u044c \u043c\u0438\u043d\u0443\u0442 \u0438\u0437 stdlib: <code>domainWarp<\/code> + <code>fbm<\/code>. \u041d\u0430 \u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440\u0435 \u0432\u044b\u0448\u043b\u0430 \u0432\u044f\u0437\u043a\u0430\u044f \u0436\u0438\u0434\u043a\u043e\u0441\u0442\u044c. \u041d\u0430 Galaxy S21 &#8212; \u043f\u043b\u0438\u0442\u043a\u0430 \u0432 \u0432\u0430\u043d\u043d\u043e\u0439:<\/p>\n<figure class=\"full-width \"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/extt\/ee\/d3\/d5\/eed3d5b4b474b29d8daf436b1def443c.png\" alt=\"\u041a\u0432\u0430\u0434\u0440\u0430\u0442\u043d\u0430\u044f \u0436\u0438\u0434\u043a\u043e\u0441\u0442\u044c \u043d\u0430 Mali\" width=\"540\" height=\"1152\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/extt\/ee\/d3\/d5\/eed3d5b4b474b29d8daf436b1def443c.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/extt\/ee\/d3\/d5\/eed3d5b4b474b29d8daf436b1def443c.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041a\u0432\u0430\u0434\u0440\u0430\u0442\u043d\u0430\u044f \u0436\u0438\u0434\u043a\u043e\u0441\u0442\u044c \u043d\u0430 Mali<\/figcaption><\/div>\n<\/figure>\n<p><strong>\u0413\u0440\u0430\u0431\u043b\u044f \u21163.<\/strong> \u0428\u0443\u043c\u044b \u0441\u0442\u0440\u043e\u044f\u0442\u0441\u044f \u043d\u0430 \u0445\u0435\u0448\u0435 <code>fract(sin(x) * 43758.5)<\/code>, \u0430 \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u044b\u0435 GPU \u0441\u0447\u0438\u0442\u0430\u044e\u0442 <code>sin<\/code> \u043e\u0442 \u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u043d\u0435\u0442\u043e\u0447\u043d\u043e. \u041b\u0435\u0447\u0438\u0442\u0441\u044f \u0436\u0438\u0434\u043a\u043e\u0441\u0442\u044c\u044e, \u0433\u0434\u0435 \u0432\u0441\u0435 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u044b \u0441\u0438\u043d\u0443\u0441\u0430 \u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0438\u0435:<\/p>\n<pre><code>private fun liquidFlow(point: Expr&lt;Vec2&lt;Flt&lt;High&gt;&gt;&gt;, time: Expr&lt;Flt&lt;High&gt;&gt;): Expr&lt;Flt&lt;High&gt;&gt; {    var q = point    for (pass in 1..LIQUID_PASSES) {        val k = pass.toFloat()        val push = vec2(            sin(q.y * (0.9f + 0.2f * k) + time * 0.23f + k),            cos(q.x * (0.8f + 0.25f * k) - time * 0.19f + k * 1.7f),        )        q = q + push * (0.55f \/ k)    }    return sin(q.x * 1.3f + q.y * 0.7f) * 0.5f + 0.5f}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u0413\u043b\u0430\u0432\u043d\u043e\u0435 \u0442\u0443\u0442 \u043d\u0435 \u043c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u043a\u0430, \u0430 \u0442\u043e, <strong>\u043a\u0430\u043a<\/strong> \u044d\u0442\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043e. \u042d\u0442\u043e \u043e\u0431\u044b\u0447\u043d\u0430\u044f Kotlin-\u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0441 \u043e\u0431\u044b\u0447\u043d\u044b\u043c <code>for<\/code>. \u0426\u0438\u043a\u043b \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u043f\u0440\u0438 \u0441\u0431\u043e\u0440\u043a\u0435 \u0448\u0435\u0439\u0434\u0435\u0440\u0430 \u0438 \u0440\u0430\u0437\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0432 \u043f\u044f\u0442\u044c \u043f\u0440\u043e\u0445\u043e\u0434\u043e\u0432 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439, \u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c, \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0438 \u043f\u043e\u043a\u0440\u044b\u0442\u044c \u0442\u0435\u0441\u0442\u043e\u043c. \u041f\u043e \u0441\u0442\u0430\u0440\u0438\u043d\u043a\u0435 \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u0431\u044b \u043b\u0438\u0431\u043e \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u0443\u0441\u043a\u0438 GLSL \u043f\u044f\u0442\u044c \u0440\u0430\u0437, \u043b\u0438\u0431\u043e \u0441\u043a\u043b\u0435\u0438\u0432\u0430\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0438 \u0447\u0435\u0440\u0435\u0437 <code>buildString<\/code>, \u043f\u0440\u043e\u0449\u0430\u044f\u0441\u044c \u0441 \u043f\u043e\u0434\u0441\u0432\u0435\u0442\u043a\u043e\u0439 \u0438 \u0437\u0434\u0440\u0430\u0432\u044b\u043c \u0441\u043c\u044b\u0441\u043b\u043e\u043c.<\/p>\n<p>\u0412 DSL \u0443 \u0432\u0430\u0441 \u0434\u0432\u0430 \u0432\u0438\u0434\u0430 \u0446\u0438\u043a\u043b\u043e\u0432, \u0438 \u044d\u0442\u043e \u0444\u0438\u0447\u0430. <code>repeat<\/code> \u0438\u0437 DSL &#8212; \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0438\u0439 <code>for<\/code> \u043d\u0430 GPU (\u043a\u0430\u043a \u043f\u043e\u0434\u0441\u0447\u0451\u0442 \u0441\u043e\u0441\u0435\u0434\u0435\u0439). Kotlin-<code>for<\/code> &#8212; \u0440\u0430\u0437\u0432\u0451\u0440\u0442\u043a\u0430 \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0441\u0431\u043e\u0440\u043a\u0438 (\u043a\u0430\u043a \u0436\u0438\u0434\u043a\u043e\u0441\u0442\u044c). \u0412\u044b\u0431\u0438\u0440\u0430\u0435\u0442\u0435 \u043f\u043e \u0437\u0430\u0434\u0430\u0447\u0435.<\/p>\n<h3>\u0420\u0430\u0443\u043d\u0434 7. Compose<\/h3>\n<h4>\u041f\u043e \u0441\u0442\u0430\u0440\u0438\u043d\u043a\u0435<\/h4>\n<pre><code>AndroidView(factory = { context -&gt;    GLSurfaceView(context).apply {        setEGLContextClientVersion(3)        preserveEGLContextOnPause = true        setRenderer(LifeRenderer())    }})<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>\u0414\u0430\u043b\u044c\u0448\u0435 \u0432\u0440\u0443\u0447\u043d\u0443\u044e: <code>DisposableEffect<\/code> \u0441 \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0442\u0435\u043b\u0435\u043c \u0437\u0430 \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u044b\u043c \u0446\u0438\u043a\u043b\u043e\u043c, \u0447\u0442\u043e\u0431\u044b \u0437\u0432\u0430\u0442\u044c <code>onPause<\/code>\/<code>onResume<\/code>; \u043c\u043e\u0441\u0442 \u043c\u0435\u0436\u0434\u0443 \u043f\u043e\u0442\u043e\u043a\u0430\u043c\u0438; \u043f\u0435\u0440\u0435\u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u043f\u043e\u0441\u043b\u0435 \u043f\u043e\u0442\u0435\u0440\u0438 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430. \u0418 try-catch \u043d\u0430 GL-\u043f\u043e\u0442\u043e\u043a\u0435, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0442\u0430\u043c \u0443\u0431\u0438\u0432\u0430\u0435\u0442 \u043f\u0440\u043e\u0446\u0435\u0441\u0441, \u0430 \u043d\u0435 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u043e\u0448\u0438\u0431\u043a\u0443.<\/p>\n<h4>\u0412 RedByteFX<\/h4>\n<pre><code>GlSurface(    controller = sceneController,    mesh = renderer.backgroundMesh,    modifier = Modifier        .fillMaxSize()        .fieldGestures(camera) { renderer.touchedAt = System.nanoTime() }        .pointerInput(engine) {            detectTapGestures { tap -&gt;                val point = camera.pick(tap.x, tap.y, size.width.toFloat(), size.height.toFloat())                engine.spark(torusCell(worldToCell(point), engine.n))            }        },    onFrame = renderer::draw,)<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><span class=\"sc-logo-wrapper icon-only\"><\/span><\/a><\/div><\/pre>\n<p>(\u041d\u0435\u043c\u043d\u043e\u0433\u043e \u0443\u043f\u0440\u043e\u0449\u0435\u043d\u043e \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f.)<\/p>\n<p><code>GlSurface<\/code> &#8212; \u043e\u0431\u044b\u0447\u043d\u044b\u0439 composable:<\/p>\n<ul>\n<li>\n<p>\u043e\u043d \u0441\u0430\u043c \u0441\u043b\u0435\u0434\u0438\u0442 \u0437\u0430 \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u044b\u043c \u0446\u0438\u043a\u043b\u043e\u043c \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442 EGL-\u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u043d\u0430 \u043f\u0430\u0443\u0437\u0435: \u043f\u043e\u0441\u043b\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0442\u0430 \u0438\u0437 \u0444\u043e\u043d\u0430 \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u043f\u0435\u0440\u0435\u043b\u0438\u043d\u043a\u043e\u0432\u044b\u0432\u0430\u0435\u0442\u0441\u044f;<\/p>\n<\/li>\n<li>\n<p>\u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0432 <code>onFrame<\/code> \u043d\u0435 \u0440\u043e\u043d\u044f\u0435\u0442 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435: \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0430 \u043e\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442\u0441\u044f, \u043e\u0448\u0438\u0431\u043a\u0430 \u043f\u0443\u0431\u043b\u0438\u043a\u0443\u0435\u0442\u0441\u044f \u0432 <code>controller.failure<\/code> \u0438 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 <code>failureOverlay<\/code>;<\/p>\n<\/li>\n<li>\n<p>\u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u044b Compose &#8212; \u0436\u0435\u0441\u0442\u044b, <code>pointerInput<\/code>, \u043e\u0442\u0441\u0442\u0443\u043f\u044b &#8212; \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u043a\u0430\u043a \u0441 \u043b\u044e\u0431\u044b\u043c \u0434\u0440\u0443\u0433\u0438\u043c composable.<\/p>\n<\/li>\n<\/ul>\n<p>\u0422\u0430\u043f \u0440\u043e\u0436\u0434\u0430\u0435\u0442 \u201c\u0432\u0441\u043f\u044b\u0448\u043a\u0443 \u0436\u0438\u0437\u043d\u0438\u201d: \u0442\u043e\u0447\u043a\u0430 \u043a\u0430\u0441\u0430\u043d\u0438\u044f \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u0432 \u043b\u0443\u0447 \u0438\u0437 \u043a\u0430\u043c\u0435\u0440\u044b, \u043b\u0443\u0447 &#8212; \u0432 \u043a\u043b\u0435\u0442\u043a\u0443 \u0442\u043e\u0440\u0430, \u0438 \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c \u043f\u043e\u043a\u043e\u043b\u0435\u043d\u0438\u0438 \u0432\u043e\u043a\u0440\u0443\u0433 \u043d\u0435\u0451 \u043e\u0436\u0438\u0432\u0430\u0435\u0442 \u043e\u0431\u043b\u0430\u043a\u043e.<\/p>\n<figure class=\"\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/extt\/e9\/36\/3d\/e9363d927024fd939aac84341a28fba0.gif\" alt=\"\u0412\u0441\u043f\u044b\u0448\u043a\u0438 \u0436\u0438\u0437\u043d\u0438 \u043e\u0442 \u0442\u0430\u043f\u043e\u0432\" width=\"300\" height=\"642\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/extt\/e9\/36\/3d\/e9363d927024fd939aac84341a28fba0.gif 780w,&#10;       https:\/\/habrastorage.org\/extt\/e9\/36\/3d\/e9363d927024fd939aac84341a28fba0.gif 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u0412\u0441\u043f\u044b\u0448\u043a\u0438 \u0436\u0438\u0437\u043d\u0438 \u043e\u0442 \u0442\u0430\u043f\u043e\u0432<\/figcaption><\/div>\n<\/figure>\n<p>\u0426\u0432\u0435\u0442\u0430 \u043a\u043b\u0435\u0442\u043e\u043a \u043f\u0435\u0440\u0435\u0434\u0430\u044e\u0442\u0441\u044f \u0432 \u0448\u0435\u0439\u0434\u0435\u0440 \u0434\u0432\u0443\u043c\u044f uniform-\u0430\u043c\u0438. \u041a\u0440\u043e\u043c\u0435 \u043e\u0434\u043d\u043e\u0442\u043e\u043d\u043d\u044b\u0445, \u0435\u0441\u0442\u044c \u0433\u0440\u0430\u0434\u0438\u0435\u043d\u0442 \u201c\u0421\u0438\u044f\u043d\u0438\u0435\u201d \u0438 \u0441\u0432\u043e\u0439 \u0433\u0440\u0430\u0434\u0438\u0435\u043d\u0442, \u0441\u043e\u0431\u0440\u0430\u043d\u043d\u044b\u0439 \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u043c \u0434\u0438\u0430\u043b\u043e\u0433\u0435. \u0412\u0435\u0441\u044c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u043f\u043e\u0434\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u043e\u0434 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0439 \u0446\u0432\u0435\u0442:<\/p>\n<figure class=\"full-width \"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/extt\/fe\/81\/f8\/fe81f8615738fd1e4318493e1ecc8f0f.png\" alt=\"\u0421\u043b\u0435\u0432\u0430: \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u043f\u043e\u0434\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u043e\u0434 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0439 \u0446\u0432\u0435\u0442 \u043a\u043b\u0435\u0442\u043e\u043a. \u0421\u043f\u0440\u0430\u0432\u0430: \u0434\u0438\u0430\u043b\u043e\u0433 \u201c\u0421\u0432\u043e\u0439 \u0433\u0440\u0430\u0434\u0438\u0435\u043d\u0442\u201d, \u0433\u0434\u0435 \u043e\u0442\u0442\u0435\u043d\u043e\u043a, \u043d\u0430\u0441\u044b\u0449\u0435\u043d\u043d\u043e\u0441\u0442\u044c \u0438 \u044f\u0440\u043a\u043e\u0441\u0442\u044c \u0437\u0430\u0434\u0430\u044e\u0442\u0441\u044f \u0434\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0438 \u043a\u043e\u043d\u0446\u0430.\" title=\"\u0421\u043b\u0435\u0432\u0430: \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u043f\u043e\u0434\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u043e\u0434 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0439 \u0446\u0432\u0435\u0442 \u043a\u043b\u0435\u0442\u043e\u043a. \u0421\u043f\u0440\u0430\u0432\u0430: \u0434\u0438\u0430\u043b\u043e\u0433 \u201c\u0421\u0432\u043e\u0439 \u0433\u0440\u0430\u0434\u0438\u0435\u043d\u0442\u201d, \u0433\u0434\u0435 \u043e\u0442\u0442\u0435\u043d\u043e\u043a, \u043d\u0430\u0441\u044b\u0449\u0435\u043d\u043d\u043e\u0441\u0442\u044c \u0438 \u044f\u0440\u043a\u043e\u0441\u0442\u044c \u0437\u0430\u0434\u0430\u044e\u0442\u0441\u044f \u0434\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0438 \u043a\u043e\u043d\u0446\u0430.\" width=\"1152\" height=\"1256\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/extt\/fe\/81\/f8\/fe81f8615738fd1e4318493e1ecc8f0f.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/extt\/fe\/81\/f8\/fe81f8615738fd1e4318493e1ecc8f0f.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u0421\u043b\u0435\u0432\u0430: \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u043f\u043e\u0434\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u043e\u0434 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0439 \u0446\u0432\u0435\u0442 \u043a\u043b\u0435\u0442\u043e\u043a. \u0421\u043f\u0440\u0430\u0432\u0430: \u0434\u0438\u0430\u043b\u043e\u0433 \u201c\u0421\u0432\u043e\u0439 \u0433\u0440\u0430\u0434\u0438\u0435\u043d\u0442\u201d, \u0433\u0434\u0435 \u043e\u0442\u0442\u0435\u043d\u043e\u043a, \u043d\u0430\u0441\u044b\u0449\u0435\u043d\u043d\u043e\u0441\u0442\u044c \u0438 \u044f\u0440\u043a\u043e\u0441\u0442\u044c \u0437\u0430\u0434\u0430\u044e\u0442\u0441\u044f \u0434\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0438 \u043a\u043e\u043d\u0446\u0430.<\/figcaption><\/div>\n<\/figure>\n<h3>\u041f\u0435\u0440\u0432\u044b\u0439 \u0431\u043b\u0438\u043d, \u043a\u044e!<\/h3>\n<p>\u041f\u0435\u0440\u0432\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f \u0438\u0433\u0440\u044b \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u043b\u0430 \u0432\u043e\u0442 \u0442\u0430\u043a:<\/p>\n<figure class=\"full-width \"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/extt\/db\/b3\/f8\/dbb3f8193cbd26e91f9dd44060bfc91a.png\" alt=\"\u041f\u0435\u0440\u0432\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f: \u043a\u0443\u0431\" width=\"540\" height=\"1152\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/extt\/db\/b3\/f8\/dbb3f8193cbd26e91f9dd44060bfc91a.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/extt\/db\/b3\/f8\/dbb3f8193cbd26e91f9dd44060bfc91a.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/p>\n<div><figcaption>\u041f\u0435\u0440\u0432\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f: \u043a\u0443\u0431<\/figcaption><\/div>\n<\/figure>\n<p>\u201c\u0427\u0442\u043e-\u0442\u043e, \u043a\u0430\u043a-\u0442\u043e \u043d\u0435 \u0442\u0430\u043a\u2026\u201d, \u043f\u043e\u0434\u0443\u043c\u0430\u043b \u044f. \u041d\u0435\u043c\u043d\u043e\u0433\u043e \u043f\u043e\u0440\u044b\u0432\u0448\u0438\u0441\u044c \u0438 \u043f\u043e\u043c\u0443\u0447\u0430\u0432 \u043d\u0435\u0439\u0440\u043e\u043d\u043a\u0443, \u044f \u043d\u0430\u0448\u0435\u043b, \u0447\u0442\u043e \u0431\u044b\u043b\u0438 \u0432\u0438\u043d\u043e\u0432\u0430\u0442\u044b \u0434\u0432\u0435 \u0432\u0435\u0449\u0438.<\/p>\n<ol>\n<li>\n<p><strong>\u041f\u0440\u0430\u0432\u0438\u043b\u0430.<\/strong> \u041a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a\u0438\u0435 3D-\u043f\u0440\u0430\u0432\u0438\u043b\u0430 \u0441 \u0434\u0432\u0443\u043c\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f\u043c\u0438 \u043b\u0438\u0431\u043e \u0437\u0430\u0441\u044b\u043f\u0430\u044e\u0442 \u0432\u0441\u0451 \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e, \u043b\u0438\u0431\u043e \u0437\u0430\u043b\u0438\u0432\u0430\u044e\u0442 \u0435\u0433\u043e \u043a\u0430\u0448\u0435\u0439, \u0442\u0430\u043a \u0447\u0442\u043e \u043a\u0430\u0448\u0430 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0444\u043e\u0440\u043c\u0443 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430. \u041f\u0440\u0430\u0432\u0438\u043b\u0430 \u0441 \u0437\u0430\u0442\u0443\u0445\u0430\u043d\u0438\u0435\u043c (C &gt; 2) \u0434\u0430\u044e\u0442 \u0444\u043e\u0440\u043c\u0443.<\/p>\n<\/li>\n<li>\n<p><strong>\u041f\u043e\u0434\u0430\u0447\u0430.<\/strong> \u041a\u0430\u043c\u0435\u0440\u0430 \u0441\u043c\u043e\u0442\u0440\u0435\u043b\u0430 \u043d\u0430 \u0442\u043e\u0440 \u0441\u043d\u0430\u0440\u0443\u0436\u0438, \u0430 \u0442\u043e\u0440 \u044d\u0442\u043e \u043c\u0438\u0440 \u0431\u0435\u0437 \u043a\u0440\u0430\u0451\u0432. \u0427\u0435\u0441\u0442\u043d\u043e \u0435\u0433\u043e \u0440\u0438\u0441\u043e\u0432\u0430\u0442\u044c \u043a\u0430\u043a \u0431\u0435\u0441\u043a\u043e\u043d\u0435\u0447\u043d\u0443\u044e \u043f\u0435\u0440\u0438\u043e\u0434\u0438\u0447\u0435\u0441\u043a\u0443\u044e \u0441\u0440\u0435\u0434\u0443: \u043a\u0430\u043c\u0435\u0440\u0430 \u0432\u043d\u0443\u0442\u0440\u0438, \u043a\u043b\u0435\u0442\u043a\u0438 \u043f\u043e\u0432\u0442\u043e\u0440\u044f\u044e\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 \u043a\u0430\u0436\u0434\u044b\u0435 N \u043f\u043e \u043a\u0430\u0436\u0434\u043e\u0439 \u043e\u0441\u0438, \u0434\u0430\u043b\u044c\u043d\u0438\u0435 \u0442\u043e\u043d\u0443\u0442 \u0432 \u0442\u0443\u043c\u0430\u043d\u0435. \u0413\u043e\u0442\u043e\u0432\u0438\u043c \u0440\u043e\u0432\u043d\u043e \u0441\u0442\u043e\u043b\u044c\u043a\u043e \u0438\u043d\u0441\u0442\u0430\u043d\u0441\u043e\u0432, \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u0438\u0434\u043d\u043e, \u043d\u043e \u043d\u0435 \u0431\u043e\u043b\u044c\u0448\u0435 16 000. \u041b\u0438\u043c\u0438\u0442 \u0434\u0435\u0440\u0436\u0438\u0442\u0441\u044f \u0431\u0435\u0437 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438: \u0433\u0438\u0441\u0442\u043e\u0433\u0440\u0430\u043c\u043c\u0430 \u0440\u0430\u0441\u0441\u0442\u043e\u044f\u043d\u0438\u0439 \u0437\u0430 \u043e\u0434\u0438\u043d \u043f\u0440\u043e\u0445\u043e\u0434, \u0438 \u043b\u0438\u0448\u043d\u0438\u0435 \u0434\u0430\u043b\u044c\u043d\u0438\u0435 \u201c\u0441\u043a\u043e\u0440\u043b\u0443\u043f\u043a\u0438\u201d \u043e\u0442\u0440\u0435\u0437\u0430\u044e\u0442\u0441\u044f.<\/p>\n<\/li>\n<\/ol>\n<p>\u041a\u0443\u0431\u0430 \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0435\u0442. \u042d\u0446\u0438\u043b\u043e\u043f \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0435 \u0438\u043c\u0435\u0435\u0442 \u043f\u0440\u0430\u0432\u043e \u0431\u0438\u0442\u044c \u043c\u0435\u043d\u044f \u043f\u043e \u043d\u043e\u0447\u0430\u043c. \u041d\u0438\u043a\u043e\u0433\u0434\u0430.<\/p>\n<h3>\u0418\u0442\u043e\u0433\u043e\u0432\u043e\u0435 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0435<\/h3>\n<div>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<th>\n<p align=\"left\">\n<\/th>\n<th>\n<p align=\"left\">\u041f\u043e \u0441\u0442\u0430\u0440\u0438\u043d\u043a\u0435<\/p>\n<\/th>\n<th>\n<p align=\"left\">RedByteFX<\/p>\n<\/th>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">\u0428\u0435\u0439\u0434\u0435\u0440<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0441\u0442\u0440\u043e\u043a\u0430, \u043e\u0448\u0438\u0431\u043a\u0438 \u0432 \u0440\u0430\u043d\u0442\u0430\u0439\u043c\u0435<\/p>\n<\/td>\n<td>\n<p align=\"left\">Kotlin, \u0442\u0438\u043f\u044b, \u043e\u0448\u0438\u0431\u043a\u0438 \u043f\u0440\u0438 \u0441\u0431\u043e\u0440\u043a\u0435 \u0448\u0435\u0439\u0434\u0435\u0440\u0430<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">Uniform-\u044b<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0438\u043c\u0435\u043d\u0430-\u0441\u0442\u0440\u043e\u043a\u0438, <code>-1<\/code> \u043f\u0440\u0438 \u043e\u043f\u0435\u0447\u0430\u0442\u043a\u0435<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0442\u0438\u043f\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0434\u0435\u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0440\u044b<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">std140\/std430<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0432\u044b\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u043d\u0438\u0435 \u0440\u0443\u043a\u0430\u043c\u0438<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u043f\u043b\u043e\u0441\u043a\u0438\u0439 <code>FloatArray<\/code><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">\u041f\u043e\u0442\u043e\u043a\u0438<\/p>\n<\/td>\n<td>\n<p align=\"left\"><code>queueEvent<\/code>, <code>Handler<\/code>, \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u044f<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u043e\u0447\u0435\u0440\u0435\u0434\u044c <code>GlController<\/code> \u0441 \u043b\u044e\u0431\u043e\u0433\u043e \u043f\u043e\u0442\u043e\u043a\u0430<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">\u0411\u0430\u0440\u044c\u0435\u0440\u044b \u0438 \u0447\u0442\u0435\u043d\u0438\u0435<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u043b\u0435\u0433\u043a\u043e \u043f\u0435\u0440\u0435\u043f\u0443\u0442\u0430\u0442\u044c \u0431\u0438\u0442\u044b<\/p>\n<\/td>\n<td>\n<p align=\"left\"><code>dispatch<\/code>\/<code>read<\/code> \u0441\u0442\u0430\u0432\u044f\u0442 \u043d\u0443\u0436\u043d\u044b\u0435<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">\u0418\u043d\u0441\u0442\u0430\u043d\u0441\u0438\u043d\u0433<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b, divisor, \u0443\u0431\u043e\u0440\u043a\u0430 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f<\/p>\n<\/td>\n<td>\n<p align=\"left\"><code>draw(instances = \u2026)<\/code><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">\u0416\u0438\u0437\u043d\u0435\u043d\u043d\u044b\u0439 \u0446\u0438\u043a\u043b \u0438 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0432\u0440\u0443\u0447\u043d\u0443\u044e<\/p>\n<\/td>\n<td>\n<p align=\"left\"><code>GlSurface<\/code>\/<code>GlCompute<\/code><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">\u041e\u0448\u0438\u0431\u043a\u0438 \u043d\u0430 GL-\u043f\u043e\u0442\u043e\u043a\u0435<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u043f\u0430\u0434\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430<\/p>\n<\/td>\n<td>\n<p align=\"left\"><code>failure<\/code> \u0438 overlay<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">\u0422\u0435\u0441\u0442\u044b<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u0442\u043e\u043b\u044c\u043a\u043e \u0433\u043b\u0430\u0437\u0430\u043c\u0438<\/p>\n<\/td>\n<td>\n<p align=\"left\">JVM-\u0442\u0435\u0441\u0442\u044b \u0448\u0435\u0439\u0434\u0435\u0440\u0430 \u0438 \u043f\u043e\u0431\u0438\u0442\u043e\u0432\u0430\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043d\u0430 GPU<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">\u041f\u0440\u043e\u0437\u0440\u0430\u0447\u043d\u043e\u0441\u0442\u044c<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u043f\u043e\u043b\u043d\u0430\u044f<\/p>\n<\/td>\n<td>\n<p align=\"left\">\u043f\u043e\u043b\u043d\u0430\u044f: <code>computeSource()<\/code>, <code>vertexSource()<\/code>, <code>fragmentSource()<\/code><\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<h3>\u0427\u0435\u0441\u0442\u043d\u044b\u0435 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f<\/h3>\n<ul>\n<li>\n<p><strong>\u041d\u0443\u0436\u0435\u043d OpenGL ES 3.1 \u0434\u043b\u044f compute.<\/strong> \u041f\u043e\u0447\u0442\u0438 \u0432\u0441\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0441 2016 \u0433\u043e\u0434\u0430, \u043d\u043e \u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440\u0430 \u043d\u0430 Apple Silicon \u043d\u0435\u0442\u0443 (\u0438\u043b\u0438 \u044f \u043d\u0435 \u043d\u0430\u0448\u0435\u043b).<\/p>\n<\/li>\n<li>\n<p><strong>\u0414\u0432\u0430 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430 &#8212; \u0434\u0432\u0430 \u043c\u0438\u0440\u0430.<\/strong> <code>GlCompute<\/code> \u0438 <code>GlSurface<\/code> \u043d\u0435 \u0434\u0435\u043b\u044f\u0442 \u0431\u0443\u0444\u0435\u0440\u044b, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043f\u043e\u043a\u043e\u043b\u0435\u043d\u0438\u044f \u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044f \u043d\u0430 CPU. \u0414\u043b\u044f \u043f\u043e\u043b\u044f 48\u00b3 \u044d\u0442\u043e \u043e\u043a\u043e\u043b\u043e 885 \u041a\u0411 \u043d\u0430 \u043f\u043e\u043a\u043e\u043b\u0435\u043d\u0438\u0435, \u043f\u0440\u0438 \u0448\u0435\u0441\u0442\u0438 \u043f\u043e\u043a\u043e\u043b\u0435\u043d\u0438\u044f\u0445 \u0432 \u0441\u0435\u043a\u0443\u043d\u0434\u0443 &#8212; \u043a\u043e\u043f\u0435\u0439\u043a\u0438, \u043d\u043e \u0434\u043b\u044f \u0433\u0438\u0433\u0430\u043d\u0442\u0441\u043a\u0438\u0445 \u043f\u043e\u043b\u0435\u0439 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u043e\u0431\u0449\u0438\u0439 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442.<\/p>\n<\/li>\n<li>\n<p><strong>DSL \u043d\u0443\u0436\u043d\u043e \u043e\u0441\u0432\u043e\u0438\u0442\u044c \u043e\u0434\u0438\u043d \u0440\u0430\u0437.<\/strong> \u0412\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0432\u043c\u0435\u0441\u0442\u043e \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u043e\u0432, <code>ifElse<\/code> \u0432\u043c\u0435\u0441\u0442\u043e <code>if<\/code>, \u0434\u0432\u0430 \u0432\u0438\u0434\u0430 \u0446\u0438\u043a\u043b\u043e\u0432. \u042d\u0442\u043e \u0446\u0435\u043d\u0430 \u0432\u0445\u043e\u0434\u0430, \u0438, \u043f\u043e-\u043c\u043e\u0435\u043c\u0443, \u043e\u043d\u0430 \u043e\u043a\u0443\u043f\u0430\u0435\u0442\u0441\u044f \u0443\u0436\u0435 \u043d\u0430 \u0432\u0442\u043e\u0440\u043e\u043c \u0448\u0435\u0439\u0434\u0435\u0440\u0435.<\/p>\n<\/li>\n<\/ul>\n<h3>\u0418\u0442\u043e\u0433\u0438<\/h3>\n<p>\u0418\u0437 26 \u0441\u043e\u0441\u0435\u0434\u0435\u0439, \u0434\u0432\u0443\u0445 \u043f\u043e\u043b\u043e\u0432\u0438\u043d \u0431\u0443\u0444\u0435\u0440\u0430 \u0438 \u043f\u044f\u0442\u0438 \u0441\u0442\u0440\u043e\u043a <code>when<\/code> \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0430\u0441\u044c \u0438\u0433\u0440\u0430, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u043b\u0438\u043f\u043d\u0443\u0442\u044c \u043c\u0438\u043d\u0443\u0442 \u043d\u0430 \u0434\u0432\u0430\u0434\u0446\u0430\u0442\u044c, \u0430 \u0442\u043e \u0438 \u0447\u0430\u0441. \u041f\u0440\u0438 \u044d\u0442\u043e\u043c:<\/p>\n<ul>\n<li>\n<p>\u043d\u0438 \u043e\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0438 \u0448\u0435\u0439\u0434\u0435\u0440\u0430 \u0432 \u0441\u0442\u0440\u043e\u043a\u043e\u0432\u043e\u043c \u043b\u0438\u0442\u0435\u0440\u0430\u043b\u0435;<\/p>\n<\/li>\n<li>\n<p>\u043d\u0438 \u043e\u0434\u043d\u043e\u0433\u043e <code>glGetUniformLocation<\/code>, <code>allocateDirect<\/code> \u0438 \u0440\u0443\u0447\u043d\u043e\u0433\u043e \u0432\u044b\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u043d\u0438\u044f;<\/p>\n<\/li>\n<li>\n<p>\u0448\u0435\u0439\u0434\u0435\u0440 \u043f\u043e\u043a\u0440\u044b\u0442 \u0442\u0435\u0441\u0442\u0430\u043c\u0438, \u0432\u043a\u043b\u044e\u0447\u0430\u044f \u043f\u043e\u0431\u0438\u0442\u043e\u0432\u0443\u044e \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u043d\u0430 \u0436\u0438\u0432\u043e\u043c GPU;<\/p>\n<\/li>\n<li>\n<p>\u0438\u0442\u043e\u0433\u043e\u0432\u044b\u0439 GLSL \u043e\u0442\u043a\u0440\u044b\u0442 \u0438 \u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044f \u043a\u0430\u043a \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0439 \u0440\u0443\u043a\u0430\u043c\u0438.<\/p>\n<\/li>\n<\/ul>\n<p>\u0415\u0441\u043b\u0438 \u043f\u0435\u0440\u0432\u0430\u044f \u0441\u0442\u0430\u0442\u044c\u044f \u0431\u044b\u043b\u0430 \u043f\u0440\u043e \u0442\u043e, \u0447\u0442\u043e AGSL \u043c\u043e\u0436\u043d\u043e \u043f\u0438\u0441\u0430\u0442\u044c \u043f\u043e-\u0447\u0435\u043b\u043e\u0432\u0435\u0447\u0435\u0441\u043a\u0438, \u0442\u043e \u044d\u0442\u0430 \u043f\u0440\u043e \u0442\u043e, \u0447\u0442\u043e \u0438 OpenGL ES \u043c\u043e\u0436\u043d\u043e. \u041f\u0435\u043f\u0435\u043b\u0430\u0446 \u0442\u0435\u043f\u0435\u0440\u044c \u043b\u0435\u0442\u0430\u0435\u0442 \u0441 \u0433\u0440\u0430\u0432\u0438\u0446\u0430\u043f\u043e\u0439.<\/p>\n<ul>\n<li>\n<p>\u0418\u0433\u0440\u0430: <a href=\"https:\/\/github.com\/i-redbyte\/life3d\" rel=\"noopener nofollow\">github.com\/i-redbyte\/life3d<\/a><\/p>\n<\/li>\n<li>\n<p>\u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430: <a href=\"https:\/\/github.com\/i-redbyte\/redbytefx\" rel=\"noopener nofollow\">github.com\/i-redbyte\/redbytefx<\/a><\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u0440\u0438\u0445\u043e\u0434\u0438\u0442\u0435 \u0432 issues: \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0439\u0442\u0435, \u0447\u0442\u043e \u0441\u043e\u0431\u0440\u0430\u043b\u0438, \u0438 \u0440\u0443\u0433\u0430\u0439\u0442\u0435 \u043f\u043e \u0434\u0435\u043b\u0443. \u041a\u0443!<\/p>\n<\/div>\n<p>\u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/1095948\/\">https:\/\/habr.com\/ru\/articles\/1095948\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440! \u041d\u0430\u043a\u043e\u043d\u0435\u0446-\u0442\u043e \u044f \u0437\u0430\u043a\u043e\u043d\u0447\u0438\u043b \u0440\u0430\u0431\u043e\u0442\u0443 \u043d\u0430\u0434 \u043d\u043e\u0432\u044b\u043c \u0431\u043e\u043b\u044c\u0448\u0438\u043c \u0431\u043b\u043e\u043a\u043e\u043c RedByteFX, \u0442\u0435\u043c \u0441\u0430\u043c\u044b\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432 \u043f\u043b\u0430\u043d\u0430\u0445 \u0437\u0432\u0443\u0447\u0430\u043b \u0441\u043a\u0440\u043e\u043c\u043d\u043e: \u201c\u0430 \u0435\u0449\u0451 \u0431\u044b\u043b\u043e \u0431\u044b \u043d\u0435\u043f\u043b\u043e\u0445\u043e OpenGL ES\u201d. \u201c\u041d\u0435\u043f\u043b\u043e\u0445\u043e\u201d \u0440\u0430\u0441\u0442\u044f\u043d\u0443\u043b\u043e\u0441\u044c \u043d\u0430 \u043c\u043d\u043e\u0433\u043e \u0432\u0435\u0447\u0435\u0440\u043e\u0432 \u0438 \u0432\u044b\u043b\u0438\u043b\u043e\u0441\u044c \u0432 \u0432\u0435\u0440\u0441\u0438\u044e 1.2.0, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0443\u0436\u0435 \u043b\u0435\u0436\u0438\u0442 \u0432 Maven Central. \u0415\u0441\u043b\u0438 \u043a\u043e\u0440\u043e\u0442\u043a\u043e: \u0442\u0435\u043f\u0435\u0440\u044c \u043d\u0430 Kotlin DSL \u043c\u043e\u0436\u043d\u043e \u043f\u0438\u0441\u0430\u0442\u044c \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u044d\u0444\u0444\u0435\u043a\u0442\u044b \u0434\u043b\u044f Compose, \u043d\u043e \u0438 \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u0443\u044e 3D-\u0433\u0440\u0430\u0444\u0438\u043a\u0443 \u0438 \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u044f \u043d\u0430 GPU. \u0415\u0441\u043b\u0438 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e, \u0442\u043e \u0447\u0438\u0442\u0430\u0439\u0442\u0435 \u0434\u0430\u043b\u044c\u0448\u0435: \u044f \u043f\u043e\u043a\u0430\u0436\u0443 \u0432\u0441\u0451 \u043d\u0430 \u0436\u0438\u0432\u043e\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0438 \u0441\u0440\u0430\u0432\u043d\u044e \u0441 \u0442\u0435\u043c, \u043a\u0430\u043a \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u0431\u044b \u043f\u0438\u0441\u0430\u0442\u044c \u0431\u0435\u0437 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438.\u041d\u0435\u043c\u043d\u043e\u0433\u043e \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430. \u0412 \u043f\u0435\u0440\u0432\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u043b, \u043a\u0430\u043a RedByteFX \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0435\u0442 AGSL \u0438\u0437 \u201c\u043d\u0435 \u0442\u0440\u043e\u0433\u0430\u0439, \u044d\u0442\u043e \u043d\u0430 \u041d\u043e\u0432\u044b\u0439 \u0433\u043e\u0434\u201d \u0432 \u043e\u0431\u044b\u0447\u043d\u044b\u0439 Kotlin-\u043a\u043e\u0434. \u0422\u043e\u0433\u0434\u0430 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0443\u043c\u0435\u043b\u0430 \u043a\u0440\u0430\u0441\u0438\u0442\u044c \u0442\u043e, \u0447\u0442\u043e \u0443\u0436\u0435 \u043d\u0430\u0440\u0438\u0441\u043e\u0432\u0430\u043b Compose, \u0438 \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430 Android 13+. \u041f\u0435\u043f\u0435\u043b\u0430\u0446 \u0431\u044b\u043b, \u043d\u043e \u043b\u0435\u0442\u0430\u043b \u0431\u0435\u0437 \u0433\u0440\u0430\u0432\u0438\u0446\u0430\u043f\u044b.\u0412 \u0432\u0435\u0440\u0441\u0438\u0438 1.2.0 \u0443 RedByteFX \u0432\u044b\u0440\u043e\u0441\u043b\u0430 \u0432\u0442\u043e\u0440\u0430\u044f \u043f\u043e\u043b\u043e\u0432\u0438\u043d\u0430: \u0442\u043e\u0442 \u0436\u0435 Kotlin DSL \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442 GLSL ES 3.0\u20133.2. \u042d\u0442\u043e \u0432\u0435\u0440\u0448\u0438\u043d\u043d\u044b\u0435, \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u043d\u044b\u0435 \u0438 compute-\u0448\u0435\u0439\u0434\u0435\u0440\u044b, \u043f\u043b\u044e\u0441 \u0440\u0430\u043d\u0442\u0430\u0439\u043c \u043f\u043e\u0432\u0435\u0440\u0445 GLES \u0438 Compose-\u0445\u043e\u0441\u0442\u044b GlSurface\/GlCompute. \u0412\u0441\u0451 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0441 API 24.\u0420\u0430\u0441\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043f\u0440\u043e \u044d\u0442\u043e \u043d\u0430 \u043e\u0447\u0435\u0440\u0435\u0434\u043d\u043e\u043c \u201c\u0432\u043e\u043b\u043d\u043e\u0432\u043e\u043c \u044d\u0444\u0444\u0435\u043a\u0442\u0435\u201d \u0441\u043a\u0443\u0447\u043d\u043e. \u041f\u043e\u0440\u0430\u0441\u043a\u0438\u043d\u0443\u0432 \u043c\u043e\u0437\u0433\u0430\u043c\u0438 \u043d\u0430\u0434 \u0442\u0435\u043c, \u0447\u0442\u043e \u043c\u043e\u0433\u043b\u043e \u0431\u044b\u0442\u044c \u043a\u0440\u0430\u0441\u0438\u0432\u043e\u0439 \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u0435\u0439 \u0438 \u0432 \u0442\u043e \u0436\u0435 \u0432\u0440\u0435\u043c\u044f \u043d\u0435 \u0441\u043e\u0432\u0441\u0435\u043c \u0442\u0440\u0438\u0432\u0438\u0430\u043b\u044c\u043d\u044b\u043c, \u044f \u043f\u0440\u0438\u0448\u0435\u043b \u043a \u0432\u044b\u0432\u043e\u0434\u0443 \u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043b \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0438\u0433\u0440\u044b: \u201c\u0416\u0438\u0437\u043d\u044c\u201d \u041a\u043e\u043d\u0432\u0435\u044f, \u043d\u043e \u043d\u0435 \u0432 \u0434\u0432\u0443\u043c\u0435\u0440\u043d\u043e\u043c \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u0435, \u0430 \u0432 \u0442\u0440\u0451\u0445\u043c\u0435\u0440\u043d\u043e\u043c. \u041f\u043e\u043a\u043e\u043b\u0435\u043d\u0438\u044f \u0441\u0447\u0438\u0442\u0430\u0435\u0442 compute-\u0448\u0435\u0439\u0434\u0435\u0440, \u0442\u044b\u0441\u044f\u0447\u0438 \u043a\u043b\u0435\u0442\u043e\u043a \u0440\u0438\u0441\u0443\u044e\u0442\u0441\u044f \u0438\u043d\u0441\u0442\u0430\u043d\u0441\u0430\u043c\u0438 \u0432 \u0432\u044f\u0437\u043a\u043e\u0439 \u0441\u0432\u0435\u0442\u044f\u0449\u0435\u0439\u0441\u044f \u0436\u0438\u0434\u043a\u043e\u0441\u0442\u0438. \u0410 \u043f\u043e \u0445\u043e\u0434\u0443 \u0441\u0442\u0430\u0442\u044c\u0438 \u044f \u0447\u0435\u0441\u0442\u043d\u043e \u0441\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u044e \u043a\u0430\u0436\u0434\u044b\u0439 \u0448\u0430\u0433 \u0441 \u0442\u0435\u043c, \u043a\u0430\u043a \u0442\u043e \u0436\u0435 \u0441\u0430\u043c\u043e\u0435 \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u0431\u044b \u043f\u0438\u0441\u0430\u0442\u044c \u043f\u043e \u0441\u0442\u0430\u0440\u0438\u043d\u043a\u0435, \u043d\u0430 \u0433\u043e\u043b\u043e\u043c GLES31 \u0438 GLSL \u0432 \u0441\u0442\u0440\u043e\u043a\u043e\u0432\u044b\u0445 \u043b\u0438\u0442\u0435\u0440\u0430\u043b\u0430\u0445.\u0416\u0438\u0437\u043d\u044c 3D: \u043f\u0440\u0430\u0432\u0438\u043b\u043e &#171;\u041b\u0430\u0432\u0430&#187; \u043d\u0430 \u0442\u043e\u0440\u0435\u0420\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0441 \u0438\u0433\u0440\u043e\u0439: github.com\/i-redbyte\/life3d. \u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430: github.com\/i-redbyte\/redbytefx.\u0427\u0442\u043e \u0437\u043d\u0430\u0447\u0438\u0442 \u201c\u043f\u043e \u0441\u0442\u0430\u0440\u0438\u043d\u043a\u0435\u201d\u041a\u0442\u043e \u043f\u0438\u0441\u0430\u043b OpenGL ES \u043d\u0430 Android \u0440\u0443\u043a\u0430\u043c\u0438, \u043f\u043e\u043c\u043d\u0438\u0442 \u044d\u0442\u043e\u0442 \u043d\u0430\u0431\u043e\u0440:\u0448\u0435\u0439\u0434\u0435\u0440 \u0436\u0438\u0432\u0451\u0442 \u0432 \u0441\u0442\u0440\u043e\u043a\u0435, \u0438 \u043e\u043f\u0435\u0447\u0430\u0442\u043a\u0430 \u0432 \u0438\u043c\u0435\u043d\u0438 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 \u0432\u0441\u043f\u043b\u044b\u0432\u0430\u0435\u0442 \u0432 \u0440\u0430\u043d\u0442\u0430\u0439\u043c\u0435, \u0432 \u043b\u043e\u0433\u0435 \u0434\u0440\u0430\u0439\u0432\u0435\u0440\u0430, \u043d\u0430 \u0447\u0443\u0436\u043e\u043c \u0442\u0435\u043b\u0435\u0444\u043e\u043d\u0435;uniform-\u044b \u0438\u0449\u0443\u0442\u0441\u044f \u043f\u043e \u0441\u0442\u0440\u043e\u043a\u043e\u0432\u043e\u043c\u0443 \u0438\u043c\u0435\u043d\u0438 (glGetUniformLocation(program, &#171;u_sise&#187;)), \u0430 \u043d\u0435\u0432\u0435\u0440\u043d\u043e\u0435 \u0438\u043c\u044f \u0434\u0440\u0430\u0439\u0432\u0435\u0440 \u043c\u043e\u043b\u0447\u0430 \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0432 -1, \u0438 \u0437\u0430\u043f\u0438\u0441\u044c \u0432 \u043d\u0435\u0433\u043e &#8212; \u0442\u0438\u0445\u0438\u0439 no-op;\u0440\u0430\u0441\u043a\u043b\u0430\u0434\u043a\u0443 std140 \u0441\u0447\u0438\u0442\u0430\u0435\u0448\u044c \u043d\u0430 \u043f\u0430\u043b\u044c\u0446\u0430\u0445: float[27] \u0432 uniform-\u0431\u043b\u043e\u043a\u0435 \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442 \u043d\u0435 108 \u0431\u0430\u0439\u0442, \u0430 432;ByteBuffer.allocateDirect(&#8230;).order(ByteOrder.nativeOrder()) &#8212; \u043d\u0430 \u043a\u0430\u0436\u0434\u044b\u0439 \u0431\u0443\u0444\u0435\u0440;\u0432\u0441\u0451 \u0434\u043e\u043b\u0436\u043d\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442\u044c \u043d\u0430 GL-\u043f\u043e\u0442\u043e\u043a\u0435, \u0430 UI \u0436\u0438\u0432\u0451\u0442 \u043d\u0430 \u0441\u0432\u043e\u0451\u043c, \u0438 \u043c\u043e\u0441\u0442 \u043c\u0435\u0436\u0434\u0443 \u043d\u0438\u043c\u0438 \u0441\u0442\u0440\u043e\u0438\u0448\u044c \u0441\u0430\u043c;GLSurfaceView, \u0435\u0433\u043e \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u044b\u0439 \u0446\u0438\u043a\u043b, \u043f\u043e\u0442\u0435\u0440\u044f EGL-\u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430 \u0438 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043d\u0430 GL-\u043f\u043e\u0442\u043e\u043a\u0435, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0440\u043e\u043d\u044f\u0435\u0442 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0446\u0435\u043b\u0438\u043a\u043e\u043c.\u041d\u0438\u0447\u0435\u0433\u043e \u0438\u0437 \u044d\u0442\u043e\u0433\u043e \u043d\u0435 \u0441\u043b\u043e\u0436\u043d\u043e \u043f\u043e \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438. \u0421\u043b\u043e\u0436\u043d\u043e \u0432\u0441\u0451 \u044d\u0442\u043e \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e, \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437 \u0437\u0430\u043d\u043e\u0432\u043e. RedByteFX \u0437\u0430\u0431\u0438\u0440\u0430\u0435\u0442 \u0440\u0443\u0442\u0438\u043d\u0443, \u043d\u043e \u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0432\u0430\u043c \u043f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044c: \u0438\u0442\u043e\u0433\u043e\u0432\u044b\u0439 GLSL \u0432\u0441\u0435\u0433\u0434\u0430 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c.\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435dependencies {    implementation(&#171;io.github.i-redbyte:redbytefx-core:1.2.0&#187;)    implementation(&#171;io.github.i-redbyte:redbytefx-stdlib:1.2.0&#187;)    implementation(&#171;io.github.i-redbyte:redbytefx-gl:1.2.0&#187;)    implementation(&#171;io.github.i-redbyte:redbytefx-gl-compose:1.2.0&#187;)    implementation(&#171;io.github.i-redbyte:redbytefx-3d:1.2.0&#8243;)}\u041c\u043e\u0434\u0443\u043b\u044c\u0427\u0442\u043e \u0434\u0430\u0451\u0442redbytefx-coreDSL \u0438 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f AGSL \/ GLSL ES 3.0\u20133.2redbytefx-stdlib\u0440\u0435\u0446\u0435\u043f\u0442\u044b: \u0441\u0432\u0435\u0442, \u043c\u0430\u0441\u043a\u0438, \u0448\u0443\u043c\u044b, SDFredbytefx-gl\u0440\u0430\u043d\u0442\u0430\u0439\u043c: \u043b\u0438\u043d\u043a\u043e\u0432\u043a\u0430, uniform-\u044b, \u0431\u043b\u043e\u043a\u0438, dispatch, \u0447\u0442\u0435\u043d\u0438\u0435 \u0431\u0443\u0444\u0435\u0440\u043e\u0432redbytefx-gl-composeGlSurface, GlCompute, GlController, \u043c\u0435\u0448\u0438 \u0438 \u043f\u0440\u0438\u043c\u0438\u0442\u0438\u0432\u044bredbytefx-3d\u043c\u0430\u0442\u0440\u0438\u0446\u044b \u0438 \u043a\u0430\u043c\u0435\u0440\u0430: lookAt, perspectiveCompute-\u0448\u0435\u0439\u0434\u0435\u0440\u0430\u043c \u043d\u0443\u0436\u0435\u043d OpenGL ES 3.1, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432 \u043c\u0430\u043d\u0438\u0444\u0435\u0441\u0442 \u0441\u0440\u0430\u0437\u0443 \u043f\u0438\u0448\u0435\u043c:&lt;uses-feature    android:glEsVersion=&#187;0x00030001&#8243;    android:required=&#187;true&#187; \/&gt;\u0413\u0440\u0430\u0431\u043b\u044f \u21161, \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u0430\u044f. \u042d\u043c\u0443\u043b\u044f\u0442\u043e\u0440 Android \u043d\u0430 Apple Silicon \u043e\u0442\u0434\u0430\u0451\u0442 \u0442\u043e\u043b\u044c\u043a\u043e OpenGL ES 3.0. Compute \u0442\u0430\u043c \u043d\u0435 \u0437\u0430\u0432\u0435\u0434\u0451\u0442\u0441\u044f. \u041e\u0442\u043b\u0430\u0436\u0438\u0432\u0430\u043b\u0441\u044f \u044f \u043d\u0430 Galaxy S21. \u042d\u043c\u0443\u043b\u044f\u0442\u043e\u0440 \u043d\u0430 \u043c\u0430\u043a\u0435 \u0432 \u044d\u0442\u043e\u0439 \u0438\u0441\u0442\u043e\u0440\u0438\u0438 \u044d\u0442\u043e \u043f\u0430\u0446\u0430\u043a \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u0437\u0430\u0431\u044b\u043b\u0438 \u0432\u044b\u0434\u0430\u0442\u044c \u0446\u0430\u043a!\u0418\u0433\u0440\u0430 \u0432 \u0434\u0432\u0443\u0445 \u0441\u043b\u043e\u0432\u0430\u0445\u0423 \u043a\u043b\u0435\u0442\u043a\u0438 \u0432 3D 26 \u0441\u043e\u0441\u0435\u0434\u0435\u0439 (\u043a\u0443\u0431 3\u00d73\u00d73 \u0431\u0435\u0437 \u0446\u0435\u043d\u0442\u0440\u0430). \u041f\u0440\u0430\u0432\u0438\u043b\u043e \u043f\u0438\u0448\u0435\u0442\u0441\u044f \u0432 \u043d\u043e\u0442\u0430\u0446\u0438\u0438 B\/S\/C (\u0432 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 \u043e\u0431\u044b\u0447\u043d\u043e\u0439 \u201c\u0416\u0438\u0437\u043d\u0438\u201d, \u0433\u0434\u0435 \u043a\u043b\u0435\u0442\u043a\u0430 \u043f\u0440\u043e\u0441\u0442\u043e \u0436\u0438\u0432\u0430 \u0438\u043b\u0438 \u043c\u0435\u0440\u0442\u0432\u0430, \u0437\u0434\u0435\u0441\u044c \u0443 \u043a\u043b\u0435\u0442\u043a\u0438 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439, \u0447\u0442\u043e \u0438 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0438\u043c\u0438\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u201c\u0442\u043b\u0435\u043d\u0438\u0435\u201d \u0438 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0441\u043b\u043e\u0436\u043d\u044b\u0435 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b): \u043f\u0440\u0438 \u043a\u0430\u043a\u043e\u043c \u0447\u0438\u0441\u043b\u0435 \u0441\u043e\u0441\u0435\u0434\u0435\u0439 \u043a\u043b\u0435\u0442\u043a\u0430 \u0440\u043e\u0436\u0434\u0430\u0435\u0442\u0441\u044f, \u043f\u0440\u0438 \u043a\u0430\u043a\u043e\u043c \u0432\u044b\u0436\u0438\u0432\u0430\u0435\u0442 \u0438 \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0443 \u043d\u0435\u0451 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439. \u0415\u0441\u043b\u0438 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439 \u0431\u043e\u043b\u044c\u0448\u0435 \u0434\u0432\u0443\u0445, \u0443\u043c\u0435\u0440\u0448\u0430\u044f \u043a\u043b\u0435\u0442\u043a\u0430 \u043d\u0435 \u0438\u0441\u0447\u0435\u0437\u0430\u0435\u0442 \u0441\u0440\u0430\u0437\u0443, \u0430 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u043a\u043e\u043b\u0435\u043d\u0438\u0439 \u201c\u0442\u043b\u0435\u0435\u0442\u201d: \u043d\u0435 \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044f \u0441\u043e\u0441\u0435\u0434\u043e\u043c \u0438 \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0440\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u0437\u0430\u043d\u043e\u0432\u043e. \u0418\u043c\u0435\u043d\u043d\u043e \u044d\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442 \u0438\u0437 \u043a\u0430\u0448\u0438 \u0432\u043e\u043b\u043d\u044b, \u043e\u0431\u043e\u043b\u043e\u0447\u043a\u0438 \u0438 \u043a\u043e\u0440\u0430\u043b\u043b\u044b. \u0413\u043b\u0430\u0432\u043d\u0430\u044f \u0433\u0435\u0440\u043e\u0438\u043d\u044f &#8212; \u201c\u041b\u0430\u0432\u0430\u201d, B6-8\/S4-7\/C10.\u041c\u0438\u0440 &#8212; \u0442\u043e\u0440: \u0440\u0435\u0448\u0451\u0442\u043a\u0430 N\u00b3, \u0443 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043f\u0440\u043e\u0442\u0438\u0432\u043e\u043f\u043e\u043b\u043e\u0436\u043d\u044b\u0435 \u0433\u0440\u0430\u043d\u0438 \u0441\u043a\u043b\u0435\u0435\u043d\u044b. \u041a\u043b\u0430\u0441\u0441\u0438\u043a\u0430 \u201c\u0416\u0438\u0437\u043d\u0438\u201d: \u0443\u0448\u0451\u043b \u0437\u0430 \u043a\u0440\u0430\u0439 &#8212; \u043f\u0440\u0438\u0448\u0451\u043b \u0441 \u0434\u0440\u0443\u0433\u043e\u0439 \u0441\u0442\u043e\u0440\u043e\u043d\u044b.\u042d\u043a\u0440\u0430\u043d\u043e\u0432 \u0434\u0432\u0430: \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0438 \u043f\u043e\u043b\u0435. \u0411\u0430\u0440\u044b \u0432 \u0446\u0432\u0435\u0442 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0442\u0435\u043a\u0441\u0442\u044b \u043d\u0430 \u0434\u0432\u0443\u0445 \u044f\u0437\u044b\u043a\u0430\u0445, \u043a\u043d\u043e\u043f\u043a\u0430 \u201c\u041d\u0430\u0437\u0430\u0434\u201d \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043a \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u043c.\u0421\u043b\u0435\u0432\u0430 \u044d\u043a\u0440\u0430\u043d \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a, \u0441\u043f\u0440\u0430\u0432\u0430 \u043f\u043e\u043b\u0435.\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u043e \u0440\u0430\u0443\u043d\u0434\u0430\u043c: \u0441\u0442\u0430\u0440\u044b\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u043f\u0440\u043e\u0442\u0438\u0432 DSL.\u0420\u0430\u0443\u043d\u0434 1. \u0428\u0435\u0439\u0434\u0435\u0440\u041f\u043e \u0441\u0442\u0430\u0440\u0438\u043d\u043a\u0435private const val LIFE_COMPUTE = &#171;&#187;&#187;#version 310 eslayout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in;layout(std430, binding = 0) buffer world { float cells[]; };layout(std140, binding = 0) uniform rules { float birth[27]; float survive[27]; };uniform int u_size;uniform int u_read_offset;uniform int u_write_offset;void main() {    &#8230;}&#187;&#187;&#187;val shader = GLES31.glCreateShader(GLES31.GL_COMPUTE_SHADER)GLES31.glShaderSource(shader, LIFE_COMPUTE)GLES31.glCompileShader(shader)val status = IntArray(1)GLES31.glGetShaderiv(shader, GLES31.GL_COMPILE_STATUS, status, 0)if (status[0] == 0) error(GLES31.glGetShaderInfoLog(shader))val program = GLES31.glCreateProgram()GLES31.glAttachShader(program, shader)GLES31.glLinkProgram(program)GLES31.glGetProgramiv(program, GLES31.GL_LINK_STATUS, status, 0)if (status[0] == 0) error(GLES31.glGetProgramInfoLog(program))val sizeLocation = GLES31.glGetUniformLocation(program, &#171;u_size&#187;)val readLocation = GLES31.glGetUniformLocation(program, &#171;u_read_offset&#187;)val writeLocation = GLES31.glGetUniformLocation(program, &#171;u_write_offset&#187;)\u041c\u043d\u043e\u0433\u043e\u0442\u043e\u0447\u0438\u0435 \u0432 main() &#8212; \u044d\u0442\u043e \u0435\u0449\u0451 40 \u0441\u0442\u0440\u043e\u043a GLSL, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 IDE \u0441\u0447\u0438\u0442\u0430\u0435\u0442 \u043f\u0440\u043e\u0441\u0442\u043e \u0442\u0435\u043a\u0441\u0442\u043e\u043c. \u0420\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u043d\u0433 \u0438\u043c\u0435\u043d\u0438 uniform-\u0430? \u041f\u043e\u0438\u0441\u043a \u043f\u043e \u0441\u0442\u0440\u043e\u043a\u0430\u043c \u0438 \u043c\u043e\u043b\u0438\u0442\u0432\u0430.\u0412 RedByteFXval program = shader(ShaderTarget.Gles31) {    size = uniformInt(&#171;size&#187;, 0)    readOffset = uniformInt(&#171;read_offset&#187;, 0)    writeOffset = uniformInt(&#171;write_offset&#187;, 0)    lateinit var birth: StorageArray&lt;Flt&lt;High&gt;&gt;    lateinit var survive: StorageArray&lt;Flt&lt;High&gt;&gt;    rules = uniformBlock(&#171;rules&#187;) {        birth = floatArray(&#171;birth&#187;, NEIGHBOUR_COUNTS)        survive = floatArray(&#171;survive&#187;, NEIGHBOUR_COUNTS)    }    lateinit var cells: StorageArray&lt;Flt&lt;High&gt;&gt;    world = storageBlock(&#171;world&#187;) {        cells = floatArray(&#171;cells&#187;)    }    compute(WORKGROUP_EDGE, WORKGROUP_EDGE, WORKGROUP_EDGE) {        val n = size.expr        val wrap = fn(0.intLit, 0.intLit, name = &#171;wrap&#187;) { value, edge -&gt;            ifElse(value lt 0.intLit, value + edge, ifElse(value ge edge, value &#8212; edge, value))        }        val block = local(0.intLit, &#171;block&#187;)        repeat(3) { dz -&gt;            repeat(3) { dy -&gt;                repeat(3) { dx -&gt;                    val neighbour = read(x + dx &#8212; 1.intLit, y + dy &#8212; 1.intLit, z + dz &#8212; 1.intLit)                    block.set(block.expr + ifElse(neighbour gt ALIVE, 1.intLit, 0.intLit))                }            }        }        val self = local(read(x, y, z), &#171;self&#187;)        val alive = self.expr gt ALIVE        val neighbours = block.expr &#8212; ifElse(alive, 1.intLit, 0.intLit)        val lives = ifElse(alive, survive[neighbours] gt 0.5f, birth[neighbours] gt 0.5f)        cells[writeOffset.expr + here].store(nextValue)    }}(\u0424\u0440\u0430\u0433\u043c\u0435\u043d\u0442 \u0441\u043e\u043a\u0440\u0430\u0449\u0451\u043d: \u0432 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438 \u0435\u0449\u0451 \u0435\u0441\u0442\u044c \u043e\u0441\u0442\u044b\u0432\u0430\u043d\u0438\u0435 \u043a\u043b\u0435\u0442\u043e\u043a, \u201c\u0432\u0441\u043f\u044b\u0448\u043a\u0430 \u0436\u0438\u0437\u043d\u0438\u201d \u043e\u0442 \u0442\u0430\u043f\u0430 \u0438 \u0440\u0435\u0436\u0438\u043c \u0431\u0435\u0441\u043a\u043e\u043d\u0435\u0447\u043d\u043e\u0433\u043e \u043f\u043e\u043b\u044f.)\u0427\u0442\u043e \u0438\u0437\u043c\u0435\u043d\u0438\u043b\u043e\u0441\u044c \u043f\u043e \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443:\u0422\u0438\u043f\u044b \u0432\u043c\u0435\u0441\u0442\u043e \u0441\u0442\u0440\u043e\u043a. size &#8212; \u044d\u0442\u043e Uniform&lt;IntS&gt;, \u0430 \u043d\u0435 &#171;u_size&#187;. \u0422\u043e\u0442 \u0436\u0435 \u043e\u0431\u044a\u0435\u043a\u0442 \u043f\u043e\u0442\u043e\u043c \u043f\u0435\u0440\u0435\u0434\u0430\u0451\u0442\u0441\u044f \u0432 controller.set(compute.size, n). \u041e\u043f\u0435\u0447\u0430\u0442\u043a\u0443 \u043f\u043e\u0439\u043c\u0430\u0435\u0442 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440 Kotlin, \u0430 \u043f\u0435\u0440\u0435\u0438\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u0435 \u043c\u043e\u0436\u043d\u043e \u043b\u0435\u0433\u043a\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0432 IDE.\u041e\u0448\u0438\u0431\u043a\u0438 \u0434\u043e GPU. \u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c compute { } \u0438\u043b\u0438 \u043e\u0431\u044a\u044f\u0432\u0438\u0442\u044c storage-\u0431\u0443\u0444\u0435\u0440 \u0432 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0435 \u043f\u043e\u0434 ShaderTarget.Gles30: DSL \u043e\u0442\u043a\u0430\u0436\u0435\u0442 \u0435\u0449\u0451 \u043f\u0440\u0438 \u0441\u0431\u043e\u0440\u043a\u0435 \u0448\u0435\u0439\u0434\u0435\u0440\u0430 \u0432 Kotlin, \u0430 \u043d\u0435 \u0432 \u043b\u043e\u0433\u0435 \u0434\u0440\u0430\u0439\u0432\u0435\u0440\u0430 \u043d\u0430 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f.\u041d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u044b\u0435 \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0446\u0438\u0438. fn \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e GLSL-\u0444\u0443\u043d\u043a\u0446\u0438\u044e, local &#8212; \u0432 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u0443\u044e \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e, repeat(3) &#8212; \u0432 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0438\u0439 for. \u041f\u043e\u0447\u0435\u043c\u0443 \u0432 \u0448\u0435\u0439\u0434\u0435\u0440\u0435 \u0441\u0432\u043e\u0439 wrap, \u0430 \u043d\u0435 %? \u041f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0432 GLSL -1 % n \u043d\u0435 \u0434\u0430\u0451\u0442 n &#8212; 1, \u0438 \u0442\u043e\u0440 \u0440\u0432\u0451\u0442\u0441\u044f \u043f\u043e \u0448\u0432\u0430\u043c.\u041f\u0440\u043e\u0437\u0440\u0430\u0447\u043d\u043e\u0441\u0442\u044c. program.computeSource() \u043e\u0442\u0434\u0430\u0451\u0442 \u0438\u0442\u043e\u0433\u043e\u0432\u044b\u0439 GLSL. \u041d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u0441\u043f\u0440\u044f\u0442\u0430\u043d\u043e:#version 310 esprecision highp float;uniform int u_size;uniform int u_read_offset;uniform int u_write_offset;layout(std140, binding = 0) uniform rules {  highp float birth[27];  highp float survive[27];} b_rules;layout(std430, binding = 0) buffer world {  highp float cells[];} b_world;layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in;int wrap(int p0, int p1) {  return ((p0 &lt; 0) ? (p0 + p1) : ((p0 &gt;= p1) ? (p0 &#8212; p1) : p0));}void main() {  int block;  highp float self;  block = 0;  for (int i = 0; i &lt; 3; ++i) {\u0411\u0438\u043d\u0434\u0438\u043d\u0433\u0438 \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u044b, std140\/std430 \u0440\u0430\u0441\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u044b, \u0430 \u043f\u043e\u0432\u0442\u043e\u0440\u044f\u044e\u0449\u0438\u0435\u0441\u044f \u043f\u043e\u0434\u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0441\u0430\u043c\u0430 \u0432\u044b\u043d\u043e\u0441\u0438\u0442 \u0432 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435.\u0420\u0430\u0443\u043d\u0434 2. \u0411\u0443\u0444\u0435\u0440\u044b \u0438 std140\u041f\u043e\u043b\u0435 N\u00b3 \u043b\u0435\u0436\u0438\u0442 \u0432 \u043e\u0434\u043d\u043e\u043c storage-\u0431\u0443\u0444\u0435\u0440\u0435, \u0433\u0434\u0435 \u0434\u0432\u0435 \u0440\u0435\u0448\u0451\u0442\u043a\u0438 \u043f\u043e\u0434\u0440\u044f\u0434: \u043f\u043e\u043a\u043e\u043b\u0435\u043d\u0438\u0435 \u0447\u0438\u0442\u0430\u0435\u0442 \u043e\u0434\u043d\u0443 \u043f\u043e\u043b\u043e\u0432\u0438\u043d\u0443 \u0438 \u043f\u0438\u0448\u0435\u0442 \u0434\u0440\u0443\u0433\u0443\u044e, \u043f\u043e\u0442\u043e\u043c \u043f\u043e\u043b\u043e\u0432\u0438\u043d\u044b \u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f \u0440\u043e\u043b\u044f\u043c\u0438. \u041f\u043b\u044e\u0441 uniform-\u0431\u043b\u043e\u043a \u0441 \u043f\u0440\u0430\u0432\u0438\u043b\u0430\u043c\u0438: 27 \u0444\u043b\u0430\u0433\u043e\u0432 \u0440\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u0438 27 \u0444\u043b\u0430\u0433\u043e\u0432 \u0432\u044b\u0436\u0438\u0432\u0430\u043d\u0438\u044f.\u041f\u043e \u0441\u0442\u0430\u0440\u0438\u043d\u043a\u0435val buffers = IntArray(2)GLES31.glGenBuffers(2, buffers, 0)val cells = ByteBuffer.allocateDirect(world.size * 4).order(ByteOrder.nativeOrder())cells.asFloatBuffer().put(world)GLES31.glBindBuffer(GLES31.GL_SHADER_STORAGE_BUFFER, buffers[0])GLES31.glBufferData(GLES31.GL_SHADER_STORAGE_BUFFER, cells.capacity(), cells, GLES31.GL_DYNAMIC_COPY)GLES31.glBindBufferBase(GLES31.GL_SHADER_STORAGE_BUFFER, 0, buffers[0])val rules = ByteBuffer.allocateDirect(54 * 16).order(ByteOrder.nativeOrder())for (i in values.indices) rules.putFloat(i * 16, values[i])GLES31.glBindBuffer(GLES31.GL_UNIFORM_BUFFER, buffers[1])GLES31.glBufferData(GLES31.GL_UNIFORM_BUFFER, rules.capacity(), rules, GLES31.GL_STATIC_DRAW)GLES31.glBindBufferBase(GLES31.GL_UNIFORM_BUFFER, 0, buffers[1])\u0412\u0438\u0434\u0438\u0442\u0435 i * 16? \u0412 std140 \u043a\u0430\u0436\u0434\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u043c\u0430\u0441\u0441\u0438\u0432\u0430 float \u0432\u044b\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0434\u043e 16 \u0431\u0430\u0439\u0442. \u0417\u0430\u0431\u0443\u0434\u0435\u0442\u0435 &#8212; \u0438 \u043f\u0440\u0430\u0432\u0438\u043b\u043e \u201c\u0440\u043e\u0436\u0434\u0435\u043d\u0438\u0435 \u043f\u0440\u0438 5 \u0441\u043e\u0441\u0435\u0434\u044f\u0445\u201d \u043f\u0440\u0435\u0432\u0440\u0430\u0442\u0438\u0442\u0441\u044f \u0432 \u201c\u0440\u043e\u0436\u0434\u0435\u043d\u0438\u0435 \u043f\u0440\u0438 1, 5 \u0438 9\u201d. \u041a\u043e\u043b\u043e\u043d\u0438\u044f \u043d\u0430\u0447\u043d\u0451\u0442 \u0436\u0438\u0442\u044c \u043f\u043e \u0437\u0430\u043a\u043e\u043d\u0430\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u044b \u0435\u0439 \u043d\u0435 \u0434\u0430\u0432\u0430\u043b\u0438.\u0412&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-499149","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/499149","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=499149"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/499149\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=499149"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=499149"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=499149"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}