xbintsc 0.5.31 → 0.5.36

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (286) hide show
  1. package/README.md +25 -16
  2. package/README.zh-CN.md +10 -8
  3. package/dist/scripts/check-version.d.ts +27 -0
  4. package/dist/scripts/check-version.js +71 -0
  5. package/dist/scripts/check-version.js.map +1 -0
  6. package/dist/scripts/package-platform.d.ts +58 -0
  7. package/dist/scripts/package-platform.js +142 -0
  8. package/dist/scripts/package-platform.js.map +1 -0
  9. package/dist/scripts/verify-platform-package.d.ts +34 -0
  10. package/dist/scripts/verify-platform-package.js +161 -0
  11. package/dist/scripts/verify-platform-package.js.map +1 -0
  12. package/dist/src/binder/references.js +14 -1
  13. package/dist/src/binder/references.js.map +1 -1
  14. package/dist/src/cli/help.d.ts +1 -1
  15. package/dist/src/cli/main.js +3 -1
  16. package/dist/src/cli/main.js.map +1 -1
  17. package/dist/src/codegen/generator/module.d.ts +1 -0
  18. package/dist/src/codegen/generator/module.js +54 -0
  19. package/dist/src/codegen/generator/module.js.map +1 -1
  20. package/dist/src/codegen/generator/statements/variables.js +6 -4
  21. package/dist/src/codegen/generator/statements/variables.js.map +1 -1
  22. package/dist/src/driver/runtime-lib.d.ts +29 -4
  23. package/dist/src/driver/runtime-lib.js +68 -10
  24. package/dist/src/driver/runtime-lib.js.map +1 -1
  25. package/dist/src/driver/version.d.ts +1 -1
  26. package/dist/src/driver/version.js +1 -1
  27. package/dist/src/extensions/gui/css.d.ts +26 -0
  28. package/dist/src/extensions/gui/css.js +100 -0
  29. package/dist/src/extensions/gui/css.js.map +1 -0
  30. package/dist/src/extensions/gui/html.js +9 -2
  31. package/dist/src/extensions/gui/html.js.map +1 -1
  32. package/dist/src/extensions/gui/index.js +22 -7
  33. package/dist/src/extensions/gui/index.js.map +1 -1
  34. package/dist/src/extensions/gui/three.d.ts +16 -0
  35. package/dist/src/extensions/gui/three.js +22 -0
  36. package/dist/src/extensions/gui/three.js.map +1 -0
  37. package/dist/src/extensions/media/index.d.ts +6 -5
  38. package/dist/src/extensions/media/index.js +15 -16
  39. package/dist/src/extensions/media/index.js.map +1 -1
  40. package/dist/src/parser/context.d.ts +41 -0
  41. package/dist/src/parser/context.js +89 -4
  42. package/dist/src/parser/context.js.map +1 -1
  43. package/dist/src/parser/literals.js +6 -12
  44. package/dist/src/parser/literals.js.map +1 -1
  45. package/dist/tests/driver/platform-package.test.d.ts +1 -0
  46. package/dist/tests/driver/platform-package.test.js +49 -0
  47. package/dist/tests/driver/platform-package.test.js.map +1 -0
  48. package/dist/tests/driver/runtime-lib.test.js +51 -4
  49. package/dist/tests/driver/runtime-lib.test.js.map +1 -1
  50. package/dist/tests/e2e/compile-builtins.test.js +24 -0
  51. package/dist/tests/e2e/compile-builtins.test.js.map +1 -1
  52. package/dist/tests/e2e/compile-objects-classes.test.js +23 -0
  53. package/dist/tests/e2e/compile-objects-classes.test.js.map +1 -1
  54. package/dist/tests/e2e/gui-audio.test.d.ts +14 -0
  55. package/dist/tests/e2e/gui-audio.test.js +287 -0
  56. package/dist/tests/e2e/gui-audio.test.js.map +1 -0
  57. package/dist/tests/e2e/gui-browser.test.js +1 -1
  58. package/dist/tests/e2e/gui-browser.test.js.map +1 -1
  59. package/dist/tests/e2e/gui-effects.test.d.ts +6 -0
  60. package/dist/tests/e2e/gui-effects.test.js +262 -0
  61. package/dist/tests/e2e/gui-effects.test.js.map +1 -0
  62. package/dist/tests/e2e/gui-example-webgl.test.d.ts +10 -0
  63. package/dist/tests/e2e/gui-example-webgl.test.js +75 -0
  64. package/dist/tests/e2e/gui-example-webgl.test.js.map +1 -0
  65. package/dist/tests/e2e/gui-example-webgl2.test.d.ts +8 -0
  66. package/dist/tests/e2e/gui-example-webgl2.test.js +72 -0
  67. package/dist/tests/e2e/gui-example-webgl2.test.js.map +1 -0
  68. package/dist/tests/e2e/gui-helpers.d.ts +7 -0
  69. package/dist/tests/e2e/gui-helpers.js +1 -0
  70. package/dist/tests/e2e/gui-helpers.js.map +1 -1
  71. package/dist/tests/e2e/gui-layout.test.js +48 -0
  72. package/dist/tests/e2e/gui-layout.test.js.map +1 -1
  73. package/dist/tests/e2e/gui-media.test.js +83 -4
  74. package/dist/tests/e2e/gui-media.test.js.map +1 -1
  75. package/dist/tests/e2e/gui-style.test.js +55 -0
  76. package/dist/tests/e2e/gui-style.test.js.map +1 -1
  77. package/dist/tests/e2e/gui-webgl.test.d.ts +11 -0
  78. package/dist/tests/e2e/gui-webgl.test.js +437 -0
  79. package/dist/tests/e2e/gui-webgl.test.js.map +1 -0
  80. package/dist/tests/e2e/gui-webgl2-3d.test.d.ts +4 -0
  81. package/dist/tests/e2e/gui-webgl2-3d.test.js +264 -0
  82. package/dist/tests/e2e/gui-webgl2-3d.test.js.map +1 -0
  83. package/dist/tests/e2e/gui-webgl2-blit.test.d.ts +10 -0
  84. package/dist/tests/e2e/gui-webgl2-blit.test.js +262 -0
  85. package/dist/tests/e2e/gui-webgl2-blit.test.js.map +1 -0
  86. package/dist/tests/e2e/gui-webgl2-formats.test.d.ts +6 -0
  87. package/dist/tests/e2e/gui-webgl2-formats.test.js +395 -0
  88. package/dist/tests/e2e/gui-webgl2-formats.test.js.map +1 -0
  89. package/dist/tests/e2e/gui-webgl2-mrt.test.d.ts +4 -0
  90. package/dist/tests/e2e/gui-webgl2-mrt.test.js +105 -0
  91. package/dist/tests/e2e/gui-webgl2-mrt.test.js.map +1 -0
  92. package/dist/tests/e2e/gui-webgl2-ubo.test.d.ts +8 -0
  93. package/dist/tests/e2e/gui-webgl2-ubo.test.js +112 -0
  94. package/dist/tests/e2e/gui-webgl2-ubo.test.js.map +1 -0
  95. package/dist/tests/e2e/gui-webgl2.test.d.ts +10 -0
  96. package/dist/tests/e2e/gui-webgl2.test.js +282 -0
  97. package/dist/tests/e2e/gui-webgl2.test.js.map +1 -0
  98. package/dist/tests/extensions/gui-index.test.js +1 -0
  99. package/dist/tests/extensions/gui-index.test.js.map +1 -1
  100. package/dist/tests/extensions/gui.test.js +41 -0
  101. package/dist/tests/extensions/gui.test.js.map +1 -1
  102. package/dist/tests/extensions/media.test.js +8 -3
  103. package/dist/tests/extensions/media.test.js.map +1 -1
  104. package/dist/tests/parser/expressions.test.js +30 -0
  105. package/dist/tests/parser/expressions.test.js.map +1 -1
  106. package/dist/tests/platform-tarball.test.d.ts +1 -0
  107. package/dist/tests/platform-tarball.test.js +111 -0
  108. package/dist/tests/platform-tarball.test.js.map +1 -0
  109. package/dist/tests/version.test.js +6 -0
  110. package/dist/tests/version.test.js.map +1 -1
  111. package/doc/ai/contributing.md +11 -0
  112. package/doc/ai/extensions.md +35 -12
  113. package/doc/ai/troubleshooting.md +17 -11
  114. package/doc/ai/zh-CN/contributing.md +9 -0
  115. package/doc/ai/zh-CN/extensions.md +30 -10
  116. package/doc/ai/zh-CN/troubleshooting.md +14 -8
  117. package/doc/gui/api.md +63 -14
  118. package/doc/gui/build.md +79 -16
  119. package/doc/gui/canvas.md +11 -3
  120. package/doc/gui/dom.md +35 -17
  121. package/doc/gui/known-issues.md +57 -24
  122. package/doc/gui/layout.md +18 -0
  123. package/doc/gui/media.md +21 -13
  124. package/doc/gui/rendering.md +50 -3
  125. package/doc/gui/webgl.md +315 -0
  126. package/doc/gui.md +113 -18
  127. package/doc/npm-package.md +59 -29
  128. package/doc/requirements.md +24 -11
  129. package/doc/zh-CN/gui/api.md +53 -11
  130. package/doc/zh-CN/gui/build.md +70 -16
  131. package/doc/zh-CN/gui/canvas.md +9 -2
  132. package/doc/zh-CN/gui/dom.md +22 -7
  133. package/doc/zh-CN/gui/known-issues.md +45 -19
  134. package/doc/zh-CN/gui/layout.md +14 -0
  135. package/doc/zh-CN/gui/media.md +18 -11
  136. package/doc/zh-CN/gui/rendering.md +41 -4
  137. package/doc/zh-CN/gui/webgl.md +121 -0
  138. package/doc/zh-CN/gui.md +91 -15
  139. package/doc/zh-CN/npm-package.md +48 -24
  140. package/doc/zh-CN/requirements.md +16 -7
  141. package/llms.txt +2 -0
  142. package/package.json +17 -1
  143. package/runtime/ext_gui/audio.cpp +365 -153
  144. package/runtime/ext_gui/audio_buffer.cpp +166 -0
  145. package/runtime/ext_gui/audio_buffer.h +37 -0
  146. package/runtime/ext_gui/audio_decode.cpp +219 -0
  147. package/runtime/ext_gui/audio_decode.h +39 -0
  148. package/runtime/ext_gui/audio_device.cpp +87 -0
  149. package/runtime/ext_gui/audio_effects.cpp +163 -0
  150. package/runtime/ext_gui/audio_effects.h +25 -0
  151. package/runtime/ext_gui/audio_internal.h +30 -0
  152. package/runtime/ext_gui/audio_mixer.cpp +494 -0
  153. package/runtime/ext_gui/audio_mixer.h +238 -0
  154. package/runtime/ext_gui/audio_param.cpp +104 -0
  155. package/runtime/ext_gui/audio_param_object.cpp +155 -0
  156. package/runtime/ext_gui/browser.cpp +50 -14
  157. package/runtime/ext_gui/canvas.cpp +3 -18
  158. package/runtime/ext_gui/canvas_internal.h +10 -0
  159. package/runtime/ext_gui/canvas_raster.cpp +60 -0
  160. package/runtime/ext_gui/clip_values.cpp +246 -0
  161. package/runtime/ext_gui/css.cpp +94 -0
  162. package/runtime/ext_gui/css.h +22 -1
  163. package/runtime/ext_gui/css_match.cpp +3 -0
  164. package/runtime/ext_gui/css_selector.cpp +30 -3
  165. package/runtime/ext_gui/css_sheet.cpp +89 -45
  166. package/runtime/ext_gui/document.cpp +4 -1
  167. package/runtime/ext_gui/document.h +2 -0
  168. package/runtime/ext_gui/dom.h +16 -0
  169. package/runtime/ext_gui/dom_api.cpp +1 -0
  170. package/runtime/ext_gui/dom_api_canvas.cpp +17 -80
  171. package/runtime/ext_gui/dom_api_canvas_extra.cpp +130 -1
  172. package/runtime/ext_gui/dom_api_canvas_pending.cpp +41 -0
  173. package/runtime/ext_gui/dom_api_internal.h +275 -0
  174. package/runtime/ext_gui/dom_api_webgl.cpp +383 -0
  175. package/runtime/ext_gui/dom_api_webgl2.cpp +549 -0
  176. package/runtime/ext_gui/dom_api_webgl2_draw.cpp +269 -0
  177. package/runtime/ext_gui/dom_api_webgl_buffer.cpp +216 -0
  178. package/runtime/ext_gui/dom_api_webgl_compressed.cpp +167 -0
  179. package/runtime/ext_gui/dom_api_webgl_framebuffer.cpp +160 -0
  180. package/runtime/ext_gui/dom_api_webgl_rt.h +30 -0
  181. package/runtime/ext_gui/dom_api_webgl_shader.cpp +443 -0
  182. package/runtime/ext_gui/dom_api_webgl_source.cpp +161 -0
  183. package/runtime/ext_gui/dom_api_webgl_state.cpp +590 -0
  184. package/runtime/ext_gui/dom_api_webgl_texture.cpp +485 -0
  185. package/runtime/ext_gui/dom_api_webgl_ubo.cpp +81 -0
  186. package/runtime/ext_gui/effect_values.cpp +312 -0
  187. package/runtime/ext_gui/gradient_values.cpp +476 -0
  188. package/runtime/ext_gui/grid_values.cpp +230 -0
  189. package/runtime/ext_gui/gui.cpp +44 -9
  190. package/runtime/ext_gui/gui_canvas.cpp +50 -2
  191. package/runtime/ext_gui/gui_engine.h +36 -4
  192. package/runtime/ext_gui/gui_events.cpp +4 -1
  193. package/runtime/ext_gui/gui_media.cpp +1 -1
  194. package/runtime/ext_gui/gui_webgl.cpp +83 -0
  195. package/runtime/ext_gui/image_bitmap.cpp +28 -0
  196. package/runtime/ext_gui/image_bitmap.h +26 -0
  197. package/runtime/ext_gui/image_bitmap_browser.cpp +136 -0
  198. package/runtime/ext_gui/layout.cpp +21 -0
  199. package/runtime/ext_gui/layout_flow.cpp +81 -4
  200. package/runtime/ext_gui/layout_flow_internal.h +31 -0
  201. package/runtime/ext_gui/layout_grid.cpp +374 -0
  202. package/runtime/ext_gui/media.cpp +32 -0
  203. package/runtime/ext_gui/media.h +14 -1
  204. package/runtime/ext_gui/media_api.h +25 -2
  205. package/runtime/ext_gui/media_query.cpp +211 -0
  206. package/runtime/ext_gui/paint.cpp +111 -77
  207. package/runtime/ext_gui/paint.h +33 -3
  208. package/runtime/ext_gui/paint_background.cpp +229 -0
  209. package/runtime/ext_gui/paint_clip.cpp +268 -0
  210. package/runtime/ext_gui/paint_effects.cpp +324 -0
  211. package/runtime/ext_gui/paint_internal.h +85 -0
  212. package/runtime/ext_gui/renderer.cpp +8 -31
  213. package/runtime/ext_gui/renderer_clip.cpp +196 -0
  214. package/runtime/ext_gui/renderer_image.cpp +13 -8
  215. package/runtime/ext_gui/renderer_internal.h +15 -8
  216. package/runtime/ext_gui/renderer_text.cpp +6 -31
  217. package/runtime/ext_gui/style.cpp +343 -20
  218. package/runtime/ext_gui/style.h +144 -3
  219. package/runtime/ext_gui/style_print.cpp +134 -1
  220. package/runtime/ext_gui/style_values.cpp +152 -126
  221. package/runtime/ext_gui/style_values_internal.h +35 -0
  222. package/runtime/ext_gui/webgl.h +600 -0
  223. package/runtime/ext_gui/webgl2_constants.h +274 -0
  224. package/runtime/ext_gui/webgl_blit.cpp +95 -0
  225. package/runtime/ext_gui/webgl_buffer.cpp +480 -0
  226. package/runtime/ext_gui/webgl_buffer_objects.cpp +270 -0
  227. package/runtime/ext_gui/webgl_clear.cpp +142 -0
  228. package/runtime/ext_gui/webgl_compressed.cpp +180 -0
  229. package/runtime/ext_gui/webgl_constants.h +317 -0
  230. package/runtime/ext_gui/webgl_context.cpp +551 -0
  231. package/runtime/ext_gui/webgl_draw.cpp +560 -0
  232. package/runtime/ext_gui/webgl_draw_buffers.cpp +75 -0
  233. package/runtime/ext_gui/webgl_glsl.h +165 -0
  234. package/runtime/ext_gui/webgl_glsl_compile.cpp +437 -0
  235. package/runtime/ext_gui/webgl_glsl_rewrite.cpp +367 -0
  236. package/runtime/ext_gui/webgl_glsl_scan.cpp +590 -0
  237. package/runtime/ext_gui/webgl_glsl_scan_block.cpp +126 -0
  238. package/runtime/ext_gui/webgl_glsl_tokens.h +28 -0
  239. package/runtime/ext_gui/webgl_msl.cpp +62 -0
  240. package/runtime/ext_gui/webgl_msl.h +33 -0
  241. package/runtime/ext_gui/webgl_pipeline.cpp +326 -0
  242. package/runtime/ext_gui/webgl_program_blocks.cpp +58 -0
  243. package/runtime/ext_gui/webgl_program_internal.h +24 -0
  244. package/runtime/ext_gui/webgl_shader.cpp +594 -0
  245. package/runtime/ext_gui/webgl_state.cpp +228 -0
  246. package/runtime/ext_gui/webgl_texture.cpp +420 -0
  247. package/runtime/ext_gui/webgl_texture_3d.cpp +215 -0
  248. package/runtime/ext_gui/webgl_uniform.cpp +167 -0
  249. package/runtime/ext_gui/webgl_uniform_block.h +31 -0
  250. package/runtime/ext_gui/webgl_webgl2.cpp +277 -0
  251. package/runtime/ext_media/decode_audio.cpp +308 -0
  252. package/runtime/ext_media/media.cpp +1 -1
  253. package/runtime/ext_media/media_bridge.c +11 -3
  254. package/runtime/rt.h +17 -0
  255. package/runtime/rt_internal.h +1 -0
  256. package/runtime/xt_array_buffer.c +30 -0
  257. package/runtime/xt_containers/access.inc +8 -0
  258. package/runtime/xt_regex/api.inc +2 -0
  259. package/runtime/xt_regex/matcher.inc +16 -3
  260. package/runtime/xt_regex/parser.inc +8 -2
  261. package/runtime/xt_regex/types.inc +3 -0
  262. package/runtime/xt_stdlib2/regexp-match.inc +60 -21
  263. package/runtime/xt_stdlib2/regexp.inc +1 -0
  264. package/runtime/xt_typed_array/elements.inc +13 -0
  265. package/runtime/xt_typed_array.c +1 -1
  266. package/scripts/build-gui.ts +90 -3
  267. package/scripts/build-media.ts +335 -62
  268. package/scripts/build-runtime.ts +21 -16
  269. package/scripts/check-version.ts +39 -9
  270. package/scripts/package-platform.ts +183 -0
  271. package/scripts/set-platform-version.ts +62 -0
  272. package/scripts/setup-vs-toolchain.ps1 +152 -0
  273. package/scripts/verify-platform-package.ts +182 -0
  274. package/src/binder/references.ts +13 -1
  275. package/src/cli/main.ts +5 -1
  276. package/src/codegen/generator/module.ts +50 -0
  277. package/src/codegen/generator/statements/variables.ts +6 -3
  278. package/src/driver/runtime-lib.ts +73 -9
  279. package/src/driver/version.ts +1 -1
  280. package/src/extensions/gui/css.ts +113 -0
  281. package/src/extensions/gui/html.ts +9 -2
  282. package/src/extensions/gui/index.ts +22 -7
  283. package/src/extensions/gui/three.ts +25 -0
  284. package/src/extensions/media/index.ts +16 -18
  285. package/src/parser/context.ts +99 -4
  286. package/src/parser/literals.ts +6 -12
@@ -0,0 +1,264 @@
1
+ /**
2
+ * End-to-end tests for WebGL 2 3D and 2D-array textures.
3
+ */
4
+ import { afterAll, beforeAll, describe, expect, it } from "vitest";
5
+ import { createGuiHarness, guiAvailable } from "./gui-helpers.js";
6
+ const harness = createGuiHarness();
7
+ const PAGE = `
8
+ <html><head><title>webgl2-3d</title></head>
9
+ <body style="margin:0">
10
+ <canvas id="c" width="64" height="64"></canvas>
11
+ </body></html>`;
12
+ describe.skipIf(!guiAvailable)("gui extension — WebGL 2 3D textures", () => {
13
+ beforeAll(() => harness.setup());
14
+ afterAll(() => harness.cleanup());
15
+ it("samples 2D-array and 3D texture layers", () => {
16
+ const { value, stderr } = harness.compileAndRun("webgl2-3d", `
17
+ import { createWindow } from "gui";
18
+ import page from "./page.html";
19
+
20
+ const win = createWindow({ title: "3d", width: 320, height: 240 });
21
+ const label = (name: string, value: any): void => console.log(name + "=" + value);
22
+
23
+ win.on("ready", () => {
24
+ const canvas: any = document.getElementById("c");
25
+ const gl: any = canvas.getContext("webgl2");
26
+ if (gl == null) {
27
+ console.log("webgl2=false");
28
+ win.close();
29
+ return;
30
+ }
31
+ label("max-3d", gl.getParameter(gl.MAX_3D_TEXTURE_SIZE));
32
+ label("max-layers", gl.getParameter(gl.MAX_ARRAY_TEXTURE_LAYERS));
33
+
34
+ const vs: any = gl.createShader(gl.VERTEX_SHADER);
35
+ gl.shaderSource(vs, "#version 300 es\\n" +
36
+ "in vec2 a_pos; out vec2 v_uv;" +
37
+ "void main() { v_uv = a_pos * 0.5 + 0.5;" +
38
+ " gl_Position = vec4(a_pos, 0.0, 1.0); }");
39
+ gl.compileShader(vs);
40
+ const make_program = (fs_source: string): any => {
41
+ const fs: any = gl.createShader(gl.FRAGMENT_SHADER);
42
+ gl.shaderSource(fs, fs_source);
43
+ gl.compileShader(fs);
44
+ const program: any = gl.createProgram();
45
+ gl.attachShader(program, vs);
46
+ gl.attachShader(program, fs);
47
+ gl.linkProgram(program);
48
+ return program;
49
+ };
50
+ const array_program: any = make_program("#version 300 es\\n" +
51
+ "precision highp float; precision highp sampler2DArray;" +
52
+ "in vec2 v_uv; uniform sampler2DArray u_arr; uniform float u_layer;" +
53
+ "out vec4 fragColor;" +
54
+ "void main() { fragColor = texture(u_arr, vec3(v_uv, u_layer)); }");
55
+ const volume_program: any = make_program("#version 300 es\\n" +
56
+ "precision highp float; precision highp sampler3D;" +
57
+ "in vec2 v_uv; uniform sampler3D u_vol; uniform float u_z;" +
58
+ "out vec4 fragColor;" +
59
+ "void main() { fragColor = texture(u_vol, vec3(v_uv, u_z)); }");
60
+ label("programs", gl.getProgramParameter(array_program, gl.LINK_STATUS) === true &&
61
+ gl.getProgramParameter(volume_program, gl.LINK_STATUS) === true);
62
+
63
+ const quad = gl.createBuffer();
64
+ gl.bindBuffer(gl.ARRAY_BUFFER, quad);
65
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
66
+ -1, -1, 3, -1, -1, 3,
67
+ ]), gl.STATIC_DRAW);
68
+ const bind_quad = (program: any): void => {
69
+ gl.useProgram(program);
70
+ const pos: any = gl.getAttribLocation(program, "a_pos");
71
+ gl.enableVertexAttribArray(pos);
72
+ gl.vertexAttribPointer(pos, 2, gl.FLOAT, false, 8, 0);
73
+ };
74
+ const px = new Uint8Array(4);
75
+ const probe = (): string => {
76
+ gl.readPixels(32, 32, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, px);
77
+ return px[0] + "," + px[1] + "," + px[2] + "," + px[3];
78
+ };
79
+ const red = [255, 0, 0, 255];
80
+ const green = [0, 255, 0, 255];
81
+ const layer = (color: number[]): number[] => {
82
+ return color.concat(color).concat(color).concat(color);
83
+ };
84
+ const data = new Uint8Array(layer(red).concat(layer(green)));
85
+
86
+ gl.viewport(0, 0, 64, 64);
87
+
88
+ // --- 2D array -----------------------------------------------------
89
+ const array: any = gl.createTexture();
90
+ gl.bindTexture(gl.TEXTURE_2D_ARRAY, array);
91
+ gl.texImage3D(gl.TEXTURE_2D_ARRAY, 0, gl.RGBA, 2, 2, 2, 0,
92
+ gl.RGBA, gl.UNSIGNED_BYTE, data);
93
+ gl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
94
+ gl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
95
+ bind_quad(array_program);
96
+ gl.uniform1i(gl.getUniformLocation(array_program, "u_arr"), 0);
97
+ const array_layer: any = gl.getUniformLocation(array_program, "u_layer");
98
+ gl.clearColor(0, 0, 0, 1);
99
+ gl.clear(gl.COLOR_BUFFER_BIT);
100
+ gl.uniform1f(array_layer, 0);
101
+ gl.drawArrays(gl.TRIANGLES, 0, 3);
102
+ label("array-0", probe());
103
+ gl.uniform1f(array_layer, 1);
104
+ gl.drawArrays(gl.TRIANGLES, 0, 3);
105
+ label("array-1", probe());
106
+
107
+ // --- 3D -----------------------------------------------------------
108
+ const volume: any = gl.createTexture();
109
+ gl.bindTexture(gl.TEXTURE_3D, volume);
110
+ gl.texImage3D(gl.TEXTURE_3D, 0, gl.RGBA, 2, 2, 2, 0,
111
+ gl.RGBA, gl.UNSIGNED_BYTE, data);
112
+ gl.texParameteri(gl.TEXTURE_3D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
113
+ gl.texParameteri(gl.TEXTURE_3D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
114
+ bind_quad(volume_program);
115
+ gl.uniform1i(gl.getUniformLocation(volume_program, "u_vol"), 0);
116
+ const z: any = gl.getUniformLocation(volume_program, "u_z");
117
+ gl.uniform1f(z, 0.25);
118
+ gl.clear(gl.COLOR_BUFFER_BIT);
119
+ gl.drawArrays(gl.TRIANGLES, 0, 3);
120
+ label("volume-0", probe());
121
+ gl.uniform1f(z, 0.75);
122
+ gl.drawArrays(gl.TRIANGLES, 0, 3);
123
+ label("volume-1", probe());
124
+ label("error", gl.getError());
125
+ win.close();
126
+ });
127
+
128
+ win.loadHTML(page);
129
+ `, { files: { "page.html": PAGE }, autocloseMs: 10000 });
130
+ expect(value("max-3d")).toBe("2048");
131
+ expect(value("max-layers")).toBe("256");
132
+ expect(value("programs")).toBe("true");
133
+ expect(value("array-0")).toBe("255,0,0,255");
134
+ expect(value("array-1")).toBe("0,255,0,255");
135
+ expect(value("volume-0")).toBe("255,0,0,255");
136
+ expect(value("volume-1")).toBe("0,255,0,255");
137
+ expect(value("error")).toBe("0");
138
+ expect(stderr).not.toContain("pipeline creation failed");
139
+ });
140
+ it("updates array layers with texSubImage3D and renders with framebufferTextureLayer", () => {
141
+ const { value, stderr } = harness.compileAndRun("webgl2-3d-layer", `
142
+ import { createWindow } from "gui";
143
+ import page from "./page.html";
144
+
145
+ const win = createWindow({ title: "3d-layer", width: 320, height: 240 });
146
+ const label = (name: string, value: any): void => console.log(name + "=" + value);
147
+
148
+ win.on("ready", () => {
149
+ const canvas: any = document.getElementById("c");
150
+ const gl: any = canvas.getContext("webgl2");
151
+ if (gl == null) {
152
+ console.log("webgl2=false");
153
+ win.close();
154
+ return;
155
+ }
156
+ const vs: any = gl.createShader(gl.VERTEX_SHADER);
157
+ gl.shaderSource(vs, "#version 300 es\\n" +
158
+ "in vec2 a_pos; out vec2 v_uv;" +
159
+ "void main() { v_uv = a_pos * 0.5 + 0.5;" +
160
+ " gl_Position = vec4(a_pos, 0.0, 1.0); }");
161
+ gl.compileShader(vs);
162
+ const flat: any = gl.createProgram();
163
+ {
164
+ const fs: any = gl.createShader(gl.FRAGMENT_SHADER);
165
+ gl.shaderSource(fs, "#version 300 es\\n" +
166
+ "precision highp float; uniform vec4 u_color; out vec4 fragColor;" +
167
+ "void main() { fragColor = u_color; }");
168
+ gl.compileShader(fs);
169
+ gl.attachShader(flat, vs);
170
+ gl.attachShader(flat, fs);
171
+ gl.linkProgram(flat);
172
+ }
173
+ const sampler: any = gl.createProgram();
174
+ {
175
+ const fs: any = gl.createShader(gl.FRAGMENT_SHADER);
176
+ gl.shaderSource(fs, "#version 300 es\\n" +
177
+ "precision highp float; precision highp sampler2DArray;" +
178
+ "in vec2 v_uv; uniform sampler2DArray u_arr; uniform float u_layer;" +
179
+ "out vec4 fragColor;" +
180
+ "void main() { fragColor = texture(u_arr, vec3(v_uv, u_layer)); }");
181
+ gl.compileShader(fs);
182
+ gl.attachShader(sampler, vs);
183
+ gl.attachShader(sampler, fs);
184
+ gl.linkProgram(sampler);
185
+ }
186
+ label("programs", gl.getProgramParameter(flat, gl.LINK_STATUS) === true &&
187
+ gl.getProgramParameter(sampler, gl.LINK_STATUS) === true);
188
+
189
+ const quad = gl.createBuffer();
190
+ gl.bindBuffer(gl.ARRAY_BUFFER, quad);
191
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
192
+ -1, -1, 3, -1, -1, 3,
193
+ ]), gl.STATIC_DRAW);
194
+ const bind = (program: any): void => {
195
+ gl.useProgram(program);
196
+ const pos: any = gl.getAttribLocation(program, "a_pos");
197
+ gl.enableVertexAttribArray(pos);
198
+ gl.vertexAttribPointer(pos, 2, gl.FLOAT, false, 8, 0);
199
+ };
200
+ const px = new Uint8Array(4);
201
+ const probe = (): string => {
202
+ gl.readPixels(32, 32, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, px);
203
+ return px[0] + "," + px[1] + "," + px[2] + "," + px[3];
204
+ };
205
+ const red = new Uint8Array(16);
206
+ const green = new Uint8Array(16);
207
+ for (let i = 0; i < 4; i++) {
208
+ red[i * 4] = 255;
209
+ red[i * 4 + 3] = 255;
210
+ green[i * 4 + 1] = 255;
211
+ green[i * 4 + 3] = 255;
212
+ }
213
+
214
+ const array: any = gl.createTexture();
215
+ gl.bindTexture(gl.TEXTURE_2D_ARRAY, array);
216
+ gl.texStorage3D(gl.TEXTURE_2D_ARRAY, 1, gl.RGBA, 2, 2, 2);
217
+ gl.texSubImage3D(gl.TEXTURE_2D_ARRAY, 0, 0, 0, 0, 2, 2, 1,
218
+ gl.RGBA, gl.UNSIGNED_BYTE, red);
219
+ gl.texSubImage3D(gl.TEXTURE_2D_ARRAY, 0, 0, 0, 1, 2, 2, 1,
220
+ gl.RGBA, gl.UNSIGNED_BYTE, green);
221
+ gl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
222
+ gl.texParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
223
+ const sample_layer = (layer: number): string => {
224
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
225
+ gl.viewport(0, 0, 64, 64);
226
+ gl.clearColor(0, 0, 0, 1);
227
+ gl.clear(gl.COLOR_BUFFER_BIT);
228
+ bind(sampler);
229
+ gl.uniform1i(gl.getUniformLocation(sampler, "u_arr"), 0);
230
+ gl.uniform1f(gl.getUniformLocation(sampler, "u_layer"), layer);
231
+ gl.bindTexture(gl.TEXTURE_2D_ARRAY, array);
232
+ gl.drawArrays(gl.TRIANGLES, 0, 3);
233
+ return probe();
234
+ };
235
+ label("sub-0", sample_layer(0));
236
+ label("sub-1", sample_layer(1));
237
+
238
+ const fbo: any = gl.createFramebuffer();
239
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
240
+ gl.framebufferTextureLayer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, array, 0, 1);
241
+ label("fbo", gl.checkFramebufferStatus(gl.FRAMEBUFFER) === gl.FRAMEBUFFER_COMPLETE);
242
+ gl.viewport(0, 0, 2, 2);
243
+ bind(flat);
244
+ gl.uniform4f(gl.getUniformLocation(flat, "u_color"), 0, 0, 1, 1);
245
+ gl.drawArrays(gl.TRIANGLES, 0, 3);
246
+ label("rendered", sample_layer(1));
247
+ label("untouched", sample_layer(0));
248
+ label("error", gl.getError());
249
+ win.close();
250
+ });
251
+
252
+ win.loadHTML(page);
253
+ `, { files: { "page.html": PAGE }, autocloseMs: 10000 });
254
+ expect(value("programs")).toBe("true");
255
+ expect(value("sub-0")).toBe("255,0,0,255");
256
+ expect(value("sub-1")).toBe("0,255,0,255");
257
+ expect(value("fbo")).toBe("true");
258
+ expect(value("rendered")).toBe("0,0,255,255");
259
+ expect(value("untouched")).toBe("255,0,0,255");
260
+ expect(value("error")).toBe("0");
261
+ expect(stderr).not.toContain("pipeline creation failed");
262
+ });
263
+ });
264
+ //# sourceMappingURL=gui-webgl2-3d.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gui-webgl2-3d.test.js","sourceRoot":"","sources":["../../../tests/e2e/gui-webgl2-3d.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * End-to-end tests for WebGL 2 framebuffer blits and scissored clears.
3
+ *
4
+ * A blit or a scissored clear only writes the region it covers; the pixels
5
+ * around it must keep their previous contents. A destination load-op of
6
+ * DONT_CARE breaks that on a tile-based backend (Metal's
7
+ * MTLLoadActionDontCare discards the whole attachment), so these probes read
8
+ * back both the written region and the untouched one.
9
+ */
10
+ export {};
@@ -0,0 +1,262 @@
1
+ /**
2
+ * End-to-end tests for WebGL 2 framebuffer blits and scissored clears.
3
+ *
4
+ * A blit or a scissored clear only writes the region it covers; the pixels
5
+ * around it must keep their previous contents. A destination load-op of
6
+ * DONT_CARE breaks that on a tile-based backend (Metal's
7
+ * MTLLoadActionDontCare discards the whole attachment), so these probes read
8
+ * back both the written region and the untouched one.
9
+ */
10
+ import { afterAll, beforeAll, describe, expect, it } from "vitest";
11
+ import { createGuiHarness, guiAvailable } from "./gui-helpers.js";
12
+ const harness = createGuiHarness();
13
+ const PAGE = `
14
+ <html><head><title>webgl2-blit</title></head>
15
+ <body style="margin:0">
16
+ <canvas id="c" width="64" height="64"></canvas>
17
+ </body></html>`;
18
+ /**
19
+ * Compare a `readPixels` result with the expected RGBA bytes. Depth sampled
20
+ * back through an RGBA8 target differs by one or two bytes between backends
21
+ * (0.5 arrives as 127 or 128), so those values use a tolerance.
22
+ */
23
+ function near(actual, expected, tolerance) {
24
+ const parts = actual.split(",").map((part) => Number(part));
25
+ expect(parts.length).toBe(expected.length);
26
+ for (let i = 0; i < expected.length; i++) {
27
+ const actual = parts[i] ?? Number.POSITIVE_INFINITY;
28
+ const want = expected[i] ?? Number.POSITIVE_INFINITY;
29
+ expect(Math.abs(actual - want)).toBeLessThanOrEqual(tolerance);
30
+ }
31
+ }
32
+ describe.skipIf(!guiAvailable)("gui extension — WebGL 2 blits", () => {
33
+ beforeAll(() => harness.setup());
34
+ afterAll(() => harness.cleanup());
35
+ it("blits framebuffers and clears a scissor rectangle", () => {
36
+ const { value, stderr } = harness.compileAndRun("webgl2-blit", `
37
+ import { createWindow } from "gui";
38
+ import page from "./page.html";
39
+
40
+ const win = createWindow({ title: "blit", width: 320, height: 240 });
41
+ const label = (name: string, value: any): void => console.log(name + "=" + value);
42
+
43
+ win.on("ready", () => {
44
+ const canvas: any = document.getElementById("c");
45
+ const gl: any = canvas.getContext("webgl2");
46
+ if (gl == null) {
47
+ console.log("webgl2=false");
48
+ win.close();
49
+ return;
50
+ }
51
+ const px = new Uint8Array(4);
52
+ const probe = (x: number, y: number): string => {
53
+ gl.readPixels(x, y, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, px);
54
+ return px[0] + "," + px[1] + "," + px[2] + "," + px[3];
55
+ };
56
+ const red = (x: number, y: number): string => {
57
+ gl.readPixels(x, y, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, px);
58
+ return "" + px[0];
59
+ };
60
+
61
+ const make_program = (vs_source: string, fs_source: string): any => {
62
+ const vs: any = gl.createShader(gl.VERTEX_SHADER);
63
+ gl.shaderSource(vs, vs_source);
64
+ gl.compileShader(vs);
65
+ const fs: any = gl.createShader(gl.FRAGMENT_SHADER);
66
+ gl.shaderSource(fs, fs_source);
67
+ gl.compileShader(fs);
68
+ const program: any = gl.createProgram();
69
+ gl.attachShader(program, vs);
70
+ gl.attachShader(program, fs);
71
+ gl.linkProgram(program);
72
+ return program;
73
+ };
74
+ const flat = make_program(
75
+ "#version 300 es\\nin vec2 a_pos; uniform float u_z;" +
76
+ "void main() { gl_Position = vec4(a_pos, u_z, 1.0); }",
77
+ "#version 300 es\\nprecision highp float; uniform vec4 u_color;" +
78
+ "out vec4 fragColor; void main() { fragColor = u_color; }");
79
+ const sampler = make_program(
80
+ "#version 300 es\\nin vec2 a_pos; out vec2 v_uv;" +
81
+ "void main() { v_uv = a_pos * 0.5 + 0.5;" +
82
+ " gl_Position = vec4(a_pos, 0.0, 1.0); }",
83
+ "#version 300 es\\nprecision highp float; in vec2 v_uv;" +
84
+ "uniform sampler2D u_tex; out vec4 fragColor;" +
85
+ "void main() { fragColor = vec4(vec3(texture(u_tex, v_uv).r), 1.0); }");
86
+ label("programs", gl.getProgramParameter(flat, gl.LINK_STATUS) === true &&
87
+ gl.getProgramParameter(sampler, gl.LINK_STATUS) === true);
88
+
89
+ const quad = gl.createBuffer();
90
+ gl.bindBuffer(gl.ARRAY_BUFFER, quad);
91
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
92
+ -1, -1, 3, -1, -1, 3,
93
+ ]), gl.STATIC_DRAW);
94
+ const draw_flat = (r: number, g: number, b: number, z: number): void => {
95
+ gl.useProgram(flat);
96
+ gl.bindBuffer(gl.ARRAY_BUFFER, quad);
97
+ gl.enableVertexAttribArray(gl.getAttribLocation(flat, "a_pos"));
98
+ gl.vertexAttribPointer(gl.getAttribLocation(flat, "a_pos"), 2, gl.FLOAT, false, 8, 0);
99
+ gl.uniform1f(gl.getUniformLocation(flat, "u_z"), z);
100
+ gl.uniform4f(gl.getUniformLocation(flat, "u_color"), r, g, b, 1);
101
+ gl.drawArrays(gl.TRIANGLES, 0, 3);
102
+ };
103
+ const show_depth = (depth: any): string => {
104
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
105
+ gl.viewport(0, 0, 64, 64);
106
+ gl.useProgram(sampler);
107
+ gl.uniform1i(gl.getUniformLocation(sampler, "u_tex"), 0);
108
+ gl.bindTexture(gl.TEXTURE_2D, depth);
109
+ gl.clearColor(0, 0, 0, 1);
110
+ gl.clear(gl.COLOR_BUFFER_BIT);
111
+ gl.drawArrays(gl.TRIANGLES, 0, 3);
112
+ return red(8, 32) + "," + red(56, 32) + "," + red(32, 8) + "," + red(32, 56);
113
+ };
114
+
115
+ // --- scissored colour clear ---------------------------------------
116
+ gl.viewport(0, 0, 64, 64);
117
+ gl.clearColor(1, 0, 0, 1);
118
+ gl.clear(gl.COLOR_BUFFER_BIT);
119
+ gl.enable(gl.SCISSOR_TEST);
120
+ gl.scissor(8, 8, 16, 16);
121
+ gl.clearColor(0, 0, 1, 1);
122
+ gl.clear(gl.COLOR_BUFFER_BIT);
123
+ gl.disable(gl.SCISSOR_TEST);
124
+ label("scissor-inside", probe(16, 16));
125
+ label("scissor-outside", probe(2, 2));
126
+
127
+ // --- render to a texture and blit it back -------------------------
128
+ const target = gl.createTexture();
129
+ gl.bindTexture(gl.TEXTURE_2D, target);
130
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 32, 32, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
131
+ const fbo = gl.createFramebuffer();
132
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
133
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, target, 0);
134
+ label("fbo", gl.checkFramebufferStatus(gl.FRAMEBUFFER) === gl.FRAMEBUFFER_COMPLETE);
135
+ gl.viewport(0, 0, 32, 32);
136
+ gl.clearColor(0, 1, 0, 1);
137
+ gl.clear(gl.COLOR_BUFFER_BIT);
138
+ draw_flat(0, 0, 1, 0);
139
+ gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo);
140
+ gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null);
141
+ gl.blitFramebuffer(0, 0, 32, 32, 0, 0, 64, 64, gl.COLOR_BUFFER_BIT, gl.NEAREST);
142
+ label("blit", probe(32, 32));
143
+
144
+ // --- scissored depth clear ---------------------------------------
145
+ const depth = gl.createTexture();
146
+ gl.bindTexture(gl.TEXTURE_2D, depth);
147
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.DEPTH_COMPONENT24, 32, 32, 0,
148
+ gl.DEPTH_COMPONENT, gl.UNSIGNED_INT, null);
149
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
150
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
151
+ const depth_color = gl.createTexture();
152
+ gl.bindTexture(gl.TEXTURE_2D, depth_color);
153
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 32, 32, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
154
+ const depth_fbo = gl.createFramebuffer();
155
+ gl.bindFramebuffer(gl.FRAMEBUFFER, depth_fbo);
156
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, depth_color, 0);
157
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_2D, depth, 0);
158
+ gl.viewport(0, 0, 32, 32);
159
+ gl.clearDepth(1);
160
+ gl.clearColor(0, 0, 0, 1);
161
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
162
+ gl.enable(gl.DEPTH_TEST);
163
+ gl.depthFunc(gl.LESS);
164
+ draw_flat(1, 1, 1, 0.5);
165
+ gl.disable(gl.DEPTH_TEST);
166
+ label("depth-initial", show_depth(depth));
167
+
168
+ gl.bindFramebuffer(gl.FRAMEBUFFER, depth_fbo);
169
+ gl.viewport(0, 0, 32, 32);
170
+ gl.enable(gl.SCISSOR_TEST);
171
+ gl.scissor(0, 0, 16, 32);
172
+ gl.clearDepth(0);
173
+ gl.clear(gl.DEPTH_BUFFER_BIT);
174
+ gl.disable(gl.SCISSOR_TEST);
175
+ label("depth-half", show_depth(depth));
176
+
177
+ gl.bindFramebuffer(gl.FRAMEBUFFER, depth_fbo);
178
+ gl.enable(gl.SCISSOR_TEST);
179
+ gl.scissor(0, 0, 32, 32);
180
+ gl.clearDepth(1);
181
+ gl.clear(gl.DEPTH_BUFFER_BIT);
182
+ gl.disable(gl.SCISSOR_TEST);
183
+ label("depth-full", show_depth(depth));
184
+ label("error", gl.getError());
185
+ win.close();
186
+ });
187
+
188
+ win.loadHTML(page);
189
+ `, { files: { "page.html": PAGE }, autocloseMs: 12000 });
190
+ expect(value("programs")).toBe("true");
191
+ expect(value("scissor-inside")).toBe("0,0,255,255");
192
+ expect(value("scissor-outside")).toBe("255,0,0,255");
193
+ expect(value("fbo")).toBe("true");
194
+ expect(value("blit")).toBe("0,0,255,255");
195
+ // Depth is sampled back through an RGBA8 target: 0.5 arrives as 127 or 128
196
+ // depending on the backend's float -> UNORM rounding, so compare with a
197
+ // tolerance rather than an exact byte value.
198
+ near(value("depth-initial"), [128, 128, 128, 128], 2);
199
+ near(value("depth-half"), [0, 128, 128, 128], 2);
200
+ near(value("depth-full"), [255, 255, 255, 255], 2);
201
+ expect(value("error")).toBe("0");
202
+ expect(stderr).not.toContain("pipeline creation failed");
203
+ });
204
+ it("preserves pixels outside a partial framebuffer blit", () => {
205
+ const { value, stderr } = harness.compileAndRun("webgl2-partial-blit", `
206
+ import { createWindow } from "gui";
207
+ import page from "./page.html";
208
+
209
+ const win = createWindow({ title: "partial-blit", width: 320, height: 240 });
210
+ const label = (name: string, value: any): void => console.log(name + "=" + value);
211
+
212
+ win.on("ready", () => {
213
+ const canvas: any = document.getElementById("c");
214
+ const gl: any = canvas.getContext("webgl2");
215
+ if (gl == null) {
216
+ console.log("webgl2=false");
217
+ win.close();
218
+ return;
219
+ }
220
+ const px = new Uint8Array(4);
221
+ const probe = (x: number, y: number): string => {
222
+ gl.readPixels(x, y, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, px);
223
+ return px[0] + "," + px[1] + "," + px[2] + "," + px[3];
224
+ };
225
+
226
+ // The whole canvas is red; the blit source is blue.
227
+ gl.viewport(0, 0, 64, 64);
228
+ gl.clearColor(1, 0, 0, 1);
229
+ gl.clear(gl.COLOR_BUFFER_BIT);
230
+
231
+ const target = gl.createTexture();
232
+ gl.bindTexture(gl.TEXTURE_2D, target);
233
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 32, 32, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
234
+ const fbo = gl.createFramebuffer();
235
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
236
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, target, 0);
237
+ gl.viewport(0, 0, 32, 32);
238
+ gl.clearColor(0, 0, 1, 1);
239
+ gl.clear(gl.COLOR_BUFFER_BIT);
240
+
241
+ // Only the bottom-left quarter of the canvas: everywhere else has to
242
+ // keep the red it had. A blit whose destination load-op discards the
243
+ // attachment (Metal's MTLLoadActionDontCare) leaves those pixels
244
+ // undefined, which is what this probe catches.
245
+ gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo);
246
+ gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null);
247
+ gl.blitFramebuffer(0, 0, 32, 32, 0, 0, 16, 16, gl.COLOR_BUFFER_BIT, gl.NEAREST);
248
+ label("blit-inside", probe(8, 8));
249
+ label("blit-outside", probe(48, 48));
250
+ label("error", gl.getError());
251
+ win.close();
252
+ });
253
+
254
+ win.loadHTML(page);
255
+ `, { files: { "page.html": PAGE }, autocloseMs: 10000 });
256
+ expect(value("blit-inside")).toBe("0,0,255,255");
257
+ expect(value("blit-outside")).toBe("255,0,0,255");
258
+ expect(value("error")).toBe("0");
259
+ expect(stderr).not.toContain("pipeline creation failed");
260
+ });
261
+ });
262
+ //# sourceMappingURL=gui-webgl2-blit.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gui-webgl2-blit.test.js","sourceRoot":"","sources":["../../../tests/e2e/gui-webgl2-blit.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAElE,MAAM,OAAO,GAAG,gBAAgB,EAAE,CAAC;AAEnC,MAAM,IAAI,GAAG;;;;eAIE,CAAC;AAEhB;;;;GAIG;AACH,SAAS,IAAI,CAAC,MAAc,EAAE,QAAkB,EAAE,SAAiB;IACjE,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;IAC5D,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC3C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACzC,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,iBAAiB,CAAC;QACpD,MAAM,IAAI,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,iBAAiB,CAAC;QACrD,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,mBAAmB,CAAC,SAAS,CAAC,CAAC;IACjE,CAAC;AACH,CAAC;AAED,QAAQ,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC,+BAA+B,EAAE,GAAG,EAAE;IACnE,SAAS,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;IACjC,QAAQ,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IAElC,EAAE,CAAC,mDAAmD,EAAE,GAAG,EAAE;QAC3D,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,aAAa,CAC7C,aAAa,EACb;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAyJC,EACD,EAAE,KAAK,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,CACrD,CAAC;QAEF,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACvC,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QACpD,MAAM,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QACrD,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAClC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAC1C,2EAA2E;QAC3E,wEAAwE;QACxE,6CAA6C;QAC7C,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;QACtD,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;QACjD,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;QACnD,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACjC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,0BAA0B,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC7D,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,aAAa,CAC7C,qBAAqB,EACrB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAkDC,EACD,EAAE,KAAK,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,CACrD,CAAC;QAEF,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QACjD,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAClD,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACjC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,0BAA0B,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * End-to-end tests for the WebGL 2 format additions: stencil, float/depth
3
+ * textures, `ImageBitmap` uploads and compressed textures. Framebuffer blits
4
+ * and scissored clears live in `gui-webgl2-blit.test.ts`.
5
+ */
6
+ export {};