xbintsc 0.5.32 → 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.
- package/README.md +10 -7
- package/README.zh-CN.md +10 -8
- package/dist/scripts/check-version.d.ts +27 -0
- package/dist/scripts/check-version.js +71 -0
- package/dist/scripts/check-version.js.map +1 -0
- package/dist/scripts/package-platform.d.ts +58 -0
- package/dist/scripts/package-platform.js +142 -0
- package/dist/scripts/package-platform.js.map +1 -0
- package/dist/scripts/verify-platform-package.d.ts +34 -0
- package/dist/scripts/verify-platform-package.js +161 -0
- package/dist/scripts/verify-platform-package.js.map +1 -0
- package/dist/src/cli/help.d.ts +1 -1
- package/dist/src/cli/main.js +3 -1
- package/dist/src/cli/main.js.map +1 -1
- package/dist/src/driver/runtime-lib.d.ts +29 -4
- package/dist/src/driver/runtime-lib.js +68 -10
- package/dist/src/driver/runtime-lib.js.map +1 -1
- package/dist/src/driver/version.d.ts +1 -1
- package/dist/src/driver/version.js +1 -1
- package/dist/src/extensions/gui/index.js +6 -5
- package/dist/src/extensions/gui/index.js.map +1 -1
- package/dist/src/extensions/media/index.js +4 -3
- package/dist/src/extensions/media/index.js.map +1 -1
- package/dist/src/parser/context.d.ts +41 -0
- package/dist/src/parser/context.js +89 -4
- package/dist/src/parser/context.js.map +1 -1
- package/dist/src/parser/literals.js +6 -12
- package/dist/src/parser/literals.js.map +1 -1
- package/dist/tests/driver/platform-package.test.d.ts +1 -0
- package/dist/tests/driver/platform-package.test.js +49 -0
- package/dist/tests/driver/platform-package.test.js.map +1 -0
- package/dist/tests/driver/runtime-lib.test.js +51 -4
- package/dist/tests/driver/runtime-lib.test.js.map +1 -1
- package/dist/tests/e2e/gui-audio.test.d.ts +14 -0
- package/dist/tests/e2e/gui-audio.test.js +287 -0
- package/dist/tests/e2e/gui-audio.test.js.map +1 -0
- package/dist/tests/e2e/gui-helpers.d.ts +7 -0
- package/dist/tests/e2e/gui-helpers.js +1 -0
- package/dist/tests/e2e/gui-helpers.js.map +1 -1
- package/dist/tests/e2e/gui-media.test.js +78 -0
- package/dist/tests/e2e/gui-media.test.js.map +1 -1
- package/dist/tests/e2e/gui-style.test.js +55 -0
- package/dist/tests/e2e/gui-style.test.js.map +1 -1
- package/dist/tests/e2e/gui-webgl.test.js +258 -0
- package/dist/tests/e2e/gui-webgl.test.js.map +1 -1
- package/dist/tests/e2e/gui-webgl2-3d.test.d.ts +4 -0
- package/dist/tests/e2e/gui-webgl2-3d.test.js +264 -0
- package/dist/tests/e2e/gui-webgl2-3d.test.js.map +1 -0
- package/dist/tests/e2e/gui-webgl2-blit.test.d.ts +10 -0
- package/dist/tests/e2e/gui-webgl2-blit.test.js +262 -0
- package/dist/tests/e2e/gui-webgl2-blit.test.js.map +1 -0
- package/dist/tests/e2e/gui-webgl2-formats.test.d.ts +6 -0
- package/dist/tests/e2e/gui-webgl2-formats.test.js +395 -0
- package/dist/tests/e2e/gui-webgl2-formats.test.js.map +1 -0
- package/dist/tests/e2e/gui-webgl2-mrt.test.d.ts +4 -0
- package/dist/tests/e2e/gui-webgl2-mrt.test.js +105 -0
- package/dist/tests/e2e/gui-webgl2-mrt.test.js.map +1 -0
- package/dist/tests/e2e/gui-webgl2-ubo.test.d.ts +8 -0
- package/dist/tests/e2e/gui-webgl2-ubo.test.js +112 -0
- package/dist/tests/e2e/gui-webgl2-ubo.test.js.map +1 -0
- package/dist/tests/e2e/gui-webgl2.test.js +45 -1
- package/dist/tests/e2e/gui-webgl2.test.js.map +1 -1
- package/dist/tests/extensions/gui-index.test.js +1 -0
- package/dist/tests/extensions/gui-index.test.js.map +1 -1
- package/dist/tests/extensions/media.test.js +1 -0
- package/dist/tests/extensions/media.test.js.map +1 -1
- package/dist/tests/parser/expressions.test.js +30 -0
- package/dist/tests/parser/expressions.test.js.map +1 -1
- package/dist/tests/platform-tarball.test.d.ts +1 -0
- package/dist/tests/platform-tarball.test.js +111 -0
- package/dist/tests/platform-tarball.test.js.map +1 -0
- package/dist/tests/version.test.js +6 -0
- package/dist/tests/version.test.js.map +1 -1
- package/doc/ai/contributing.md +11 -0
- package/doc/ai/extensions.md +7 -4
- package/doc/ai/troubleshooting.md +7 -5
- package/doc/ai/zh-CN/contributing.md +9 -0
- package/doc/ai/zh-CN/extensions.md +4 -2
- package/doc/ai/zh-CN/troubleshooting.md +5 -3
- package/doc/gui/api.md +61 -13
- package/doc/gui/build.md +11 -4
- package/doc/gui/dom.md +6 -3
- package/doc/gui/media.md +4 -0
- package/doc/gui/webgl.md +105 -46
- package/doc/gui.md +7 -3
- package/doc/npm-package.md +55 -27
- package/doc/requirements.md +6 -2
- package/doc/zh-CN/gui/api.md +51 -10
- package/doc/zh-CN/gui/build.md +7 -2
- package/doc/zh-CN/gui/dom.md +3 -1
- package/doc/zh-CN/gui/media.md +3 -0
- package/doc/zh-CN/gui/webgl.md +22 -16
- package/doc/zh-CN/gui.md +3 -2
- package/doc/zh-CN/npm-package.md +44 -23
- package/doc/zh-CN/requirements.md +4 -1
- package/package.json +17 -1
- package/runtime/ext_gui/audio.cpp +365 -153
- package/runtime/ext_gui/audio_buffer.cpp +166 -0
- package/runtime/ext_gui/audio_buffer.h +37 -0
- package/runtime/ext_gui/audio_decode.cpp +219 -0
- package/runtime/ext_gui/audio_decode.h +39 -0
- package/runtime/ext_gui/audio_device.cpp +87 -0
- package/runtime/ext_gui/audio_effects.cpp +163 -0
- package/runtime/ext_gui/audio_effects.h +25 -0
- package/runtime/ext_gui/audio_internal.h +30 -0
- package/runtime/ext_gui/audio_mixer.cpp +494 -0
- package/runtime/ext_gui/audio_mixer.h +238 -0
- package/runtime/ext_gui/audio_param.cpp +104 -0
- package/runtime/ext_gui/audio_param_object.cpp +155 -0
- package/runtime/ext_gui/browser.cpp +11 -1
- package/runtime/ext_gui/css_selector.cpp +21 -3
- package/runtime/ext_gui/dom_api_internal.h +16 -0
- package/runtime/ext_gui/dom_api_webgl.cpp +7 -0
- package/runtime/ext_gui/dom_api_webgl2.cpp +151 -36
- package/runtime/ext_gui/dom_api_webgl2_draw.cpp +3 -3
- package/runtime/ext_gui/dom_api_webgl_buffer.cpp +6 -2
- package/runtime/ext_gui/dom_api_webgl_compressed.cpp +167 -0
- package/runtime/ext_gui/dom_api_webgl_framebuffer.cpp +160 -0
- package/runtime/ext_gui/dom_api_webgl_shader.cpp +4 -4
- package/runtime/ext_gui/dom_api_webgl_source.cpp +161 -0
- package/runtime/ext_gui/dom_api_webgl_state.cpp +169 -23
- package/runtime/ext_gui/dom_api_webgl_texture.cpp +276 -236
- package/runtime/ext_gui/dom_api_webgl_ubo.cpp +81 -0
- package/runtime/ext_gui/gui.cpp +44 -9
- package/runtime/ext_gui/gui_engine.h +9 -4
- package/runtime/ext_gui/image_bitmap.cpp +28 -0
- package/runtime/ext_gui/image_bitmap.h +26 -0
- package/runtime/ext_gui/image_bitmap_browser.cpp +136 -0
- package/runtime/ext_gui/media.cpp +32 -0
- package/runtime/ext_gui/media.h +13 -0
- package/runtime/ext_gui/media_api.h +23 -0
- package/runtime/ext_gui/webgl.h +152 -18
- package/runtime/ext_gui/webgl_blit.cpp +95 -0
- package/runtime/ext_gui/webgl_buffer.cpp +178 -263
- package/runtime/ext_gui/webgl_buffer_objects.cpp +270 -0
- package/runtime/ext_gui/webgl_clear.cpp +142 -0
- package/runtime/ext_gui/webgl_compressed.cpp +180 -0
- package/runtime/ext_gui/webgl_context.cpp +241 -156
- package/runtime/ext_gui/webgl_draw.cpp +68 -3
- package/runtime/ext_gui/webgl_draw_buffers.cpp +75 -0
- package/runtime/ext_gui/webgl_glsl.h +40 -0
- package/runtime/ext_gui/webgl_glsl_compile.cpp +6 -0
- package/runtime/ext_gui/webgl_glsl_rewrite.cpp +18 -0
- package/runtime/ext_gui/webgl_glsl_scan.cpp +20 -11
- package/runtime/ext_gui/webgl_glsl_scan_block.cpp +126 -0
- package/runtime/ext_gui/webgl_glsl_tokens.h +28 -0
- package/runtime/ext_gui/webgl_pipeline.cpp +71 -19
- package/runtime/ext_gui/webgl_program_blocks.cpp +58 -0
- package/runtime/ext_gui/webgl_program_internal.h +6 -0
- package/runtime/ext_gui/webgl_shader.cpp +13 -1
- package/runtime/ext_gui/webgl_state.cpp +228 -0
- package/runtime/ext_gui/webgl_texture.cpp +144 -17
- package/runtime/ext_gui/webgl_texture_3d.cpp +215 -0
- package/runtime/ext_gui/webgl_uniform_block.h +31 -0
- package/runtime/ext_gui/webgl_webgl2.cpp +58 -5
- package/runtime/ext_media/decode_audio.cpp +308 -0
- package/runtime/ext_media/media_bridge.c +2 -0
- package/runtime/rt.h +17 -0
- package/runtime/xt_array_buffer.c +30 -0
- package/runtime/xt_typed_array/elements.inc +13 -0
- package/scripts/build-media.ts +14 -6
- package/scripts/build-runtime.ts +21 -16
- package/scripts/check-version.ts +39 -9
- package/scripts/package-platform.ts +183 -0
- package/scripts/set-platform-version.ts +62 -0
- package/scripts/verify-platform-package.ts +182 -0
- package/src/cli/main.ts +5 -1
- package/src/driver/runtime-lib.ts +73 -9
- package/src/driver/version.ts +1 -1
- package/src/extensions/gui/index.ts +6 -5
- package/src/extensions/media/index.ts +4 -3
- package/src/parser/context.ts +99 -4
- 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":"AAAA;;GAEG;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,QAAQ,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC,qCAAqC,EAAE,GAAG,EAAE;IACzE,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,wCAAwC,EAAE,GAAG,EAAE;QAChD,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,aAAa,CAC7C,WAAW,EACX;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAiHC,EACD,EAAE,KAAK,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,CACrD,CAAC;QAEF,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACrC,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACvC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAC7C,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAC7C,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAC9C,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAC9C,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,kFAAkF,EAAE,GAAG,EAAE;QAC1F,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,aAAa,CAC7C,iBAAiB,EACjB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAgHC,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,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAC3C,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAC3C,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAClC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAC9C,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAC/C,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,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":"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"}
|