@gjsify/webgl 0.3.12 → 0.3.14

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 (55) hide show
  1. package/lib/esm/conformance/attribs.spec.js +312 -293
  2. package/lib/esm/conformance/buffers.spec.js +217 -200
  3. package/lib/esm/conformance/context.spec.js +295 -295
  4. package/lib/esm/conformance/programs.spec.js +458 -445
  5. package/lib/esm/conformance/rendering-basic.spec.js +134 -128
  6. package/lib/esm/conformance/rendering.spec.js +502 -400
  7. package/lib/esm/conformance/setup.js +42 -31
  8. package/lib/esm/conformance/state.spec.js +360 -343
  9. package/lib/esm/conformance/textures.spec.js +330 -338
  10. package/lib/esm/conformance/uniforms.spec.js +465 -309
  11. package/lib/esm/conformance-test.js +24 -22
  12. package/lib/esm/extensions/ext-blend-minmax.js +16 -16
  13. package/lib/esm/extensions/ext-color-buffer-float.js +10 -11
  14. package/lib/esm/extensions/ext-color-buffer-half-float.js +10 -11
  15. package/lib/esm/extensions/ext-texture-filter-anisotropic.js +16 -16
  16. package/lib/esm/extensions/oes-element-index-unit.js +11 -12
  17. package/lib/esm/extensions/oes-standard-derivatives.js +15 -15
  18. package/lib/esm/extensions/oes-texture-float-linear.js +11 -12
  19. package/lib/esm/extensions/oes-texture-float.js +11 -12
  20. package/lib/esm/extensions/oes-texture-half-float.js +17 -17
  21. package/lib/esm/extensions/stackgl-destroy-context.js +10 -10
  22. package/lib/esm/extensions/stackgl-resize-drawing-buffer.js +10 -10
  23. package/lib/esm/html-canvas-element.js +64 -64
  24. package/lib/esm/index.js +29 -26
  25. package/lib/esm/linkable.js +49 -49
  26. package/lib/esm/test-utils.js +158 -107
  27. package/lib/esm/test.js +8 -4
  28. package/lib/esm/types/index.js +5 -5
  29. package/lib/esm/utils.js +164 -187
  30. package/lib/esm/webgl-active-info.js +10 -9
  31. package/lib/esm/webgl-bridge.js +162 -147
  32. package/lib/esm/webgl-buffer.js +17 -15
  33. package/lib/esm/webgl-context-attributes.js +23 -22
  34. package/lib/esm/webgl-context-base.js +3039 -3351
  35. package/lib/esm/webgl-drawing-buffer-wrapper.js +10 -9
  36. package/lib/esm/webgl-framebuffer.js +108 -106
  37. package/lib/esm/webgl-program.js +25 -23
  38. package/lib/esm/webgl-query.js +15 -13
  39. package/lib/esm/webgl-renderbuffer.js +23 -21
  40. package/lib/esm/webgl-rendering-context.js +173 -187
  41. package/lib/esm/webgl-sampler.js +15 -13
  42. package/lib/esm/webgl-shader-precision-format.js +10 -9
  43. package/lib/esm/webgl-shader.js +23 -21
  44. package/lib/esm/webgl-sync.js +15 -13
  45. package/lib/esm/webgl-texture-unit.js +12 -11
  46. package/lib/esm/webgl-texture.js +21 -19
  47. package/lib/esm/webgl-transform-feedback.js +15 -13
  48. package/lib/esm/webgl-uniform-location.js +14 -13
  49. package/lib/esm/webgl-vertex-array-object.js +20 -18
  50. package/lib/esm/webgl-vertex-attribute.js +149 -145
  51. package/lib/esm/webgl1.spec.js +1039 -650
  52. package/lib/esm/webgl2-rendering-context.js +1210 -1273
  53. package/lib/esm/webgl2.spec.js +1284 -1252
  54. package/package.json +9 -9
  55. package/lib/esm/@types/glsl-tokenizer/index.d.js +0 -0
@@ -1,6 +1,8 @@
1
- import { describe, it, expect, beforeEach, on } from "@gjsify/unit";
2
- import { makeTestFBO, destroyTestFBO, readPixel, pixelClose } from "../test-utils.js";
1
+ import { destroyTestFBO, makeTestFBO, pixelClose, readPixel } from "../test-utils.js";
3
2
  import { createGLSetup } from "./setup.js";
3
+ import { beforeEach, describe, expect, it, on } from "@gjsify/unit";
4
+
5
+ //#region src/ts/conformance/programs.spec.ts
4
6
  const VS_POSITION = `attribute vec4 a_position; void main() { gl_Position = a_position; }`;
5
7
  const VS_COLOR_ATTRIB = `attribute vec4 aVertex; attribute vec4 aColor; varying vec4 vColor; void main() { vColor = aColor; gl_Position = aVertex; }`;
6
8
  const FS_VARYING_COLOR = `precision mediump float; varying vec4 vColor; void main() { gl_FragColor = vColor; }`;
@@ -16,453 +18,464 @@ const FS_STANDARD = `
16
18
  precision mediump float;
17
19
  void main() { gl_FragColor = vec4(1.0); }`;
18
20
  function compileShader(gl, type, src) {
19
- const s = gl.createShader(type);
20
- gl.shaderSource(s, src);
21
- gl.compileShader(s);
22
- return s;
21
+ const s = gl.createShader(type);
22
+ gl.shaderSource(s, src);
23
+ gl.compileShader(s);
24
+ return s;
23
25
  }
24
26
  function linkProgram(gl, vsSrc, fsSrc, attribBindings) {
25
- const vs = compileShader(gl, gl.VERTEX_SHADER, vsSrc);
26
- const fs = compileShader(gl, gl.FRAGMENT_SHADER, fsSrc);
27
- const prog = gl.createProgram();
28
- gl.attachShader(prog, vs);
29
- gl.attachShader(prog, fs);
30
- if (attribBindings) {
31
- for (const [name, loc] of attribBindings) gl.bindAttribLocation(prog, loc, name);
32
- }
33
- gl.linkProgram(prog);
34
- return prog;
27
+ const vs = compileShader(gl, gl.VERTEX_SHADER, vsSrc);
28
+ const fs = compileShader(gl, gl.FRAGMENT_SHADER, fsSrc);
29
+ const prog = gl.createProgram();
30
+ gl.attachShader(prog, vs);
31
+ gl.attachShader(prog, fs);
32
+ if (attribBindings) {
33
+ for (const [name, loc] of attribBindings) gl.bindAttribLocation(prog, loc, name);
34
+ }
35
+ gl.linkProgram(prog);
36
+ return prog;
35
37
  }
38
+ /** Fill the current FBO with a fullscreen triangle and return the center pixel. */
36
39
  function drawFullscreenAndRead(gl, prog, posAttrib = "a_position") {
37
- const loc = typeof posAttrib === "string" ? gl.getAttribLocation(prog, posAttrib) : posAttrib;
38
- const buf = gl.createBuffer();
39
- gl.bindBuffer(gl.ARRAY_BUFFER, buf);
40
- gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-4, -4, 4, -4, 0, 4]), gl.STREAM_DRAW);
41
- gl.enableVertexAttribArray(loc);
42
- gl.vertexAttribPointer(loc, 2, gl.FLOAT, false, 0, 0);
43
- gl.drawArrays(gl.TRIANGLES, 0, 3);
44
- gl.disableVertexAttribArray(loc);
45
- gl.deleteBuffer(buf);
46
- return readPixel(gl, 0, 0);
40
+ const loc = typeof posAttrib === "string" ? gl.getAttribLocation(prog, posAttrib) : posAttrib;
41
+ const buf = gl.createBuffer();
42
+ gl.bindBuffer(gl.ARRAY_BUFFER, buf);
43
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
44
+ -4,
45
+ -4,
46
+ 4,
47
+ -4,
48
+ 0,
49
+ 4
50
+ ]), gl.STREAM_DRAW);
51
+ gl.enableVertexAttribArray(loc);
52
+ gl.vertexAttribPointer(loc, 2, gl.FLOAT, false, 0, 0);
53
+ gl.drawArrays(gl.TRIANGLES, 0, 3);
54
+ gl.disableVertexAttribArray(loc);
55
+ gl.deleteBuffer(buf);
56
+ return readPixel(gl, 0, 0);
47
57
  }
48
58
  var programs_spec_default = async () => {
49
- await on("Display", async () => {
50
- const setup = createGLSetup();
51
- if (!setup) {
52
- console.warn("WebGL context not available \u2014 skipping conformance/programs tests");
53
- return;
54
- }
55
- const { gl, glArea, win } = setup;
56
- glArea.make_current();
57
- await describe("conformance/programs/program-test: compileShader", async () => {
58
- beforeEach(async () => {
59
- glArea.make_current();
60
- });
61
- await it("good vertex shader should compile", async () => {
62
- const vs = compileShader(
63
- gl,
64
- gl.VERTEX_SHADER,
65
- "attribute vec4 aVertex; void main() { gl_Position = aVertex; }"
66
- );
67
- expect(gl.getShaderParameter(vs, gl.COMPILE_STATUS)).toBeTruthy();
68
- gl.deleteShader(vs);
69
- });
70
- await it("good fragment shader should compile", async () => {
71
- const fs = compileShader(
72
- gl,
73
- gl.FRAGMENT_SHADER,
74
- "precision mediump float; void main() { gl_FragColor = vec4(1.0); }"
75
- );
76
- expect(gl.getShaderParameter(fs, gl.COMPILE_STATUS)).toBeTruthy();
77
- gl.deleteShader(fs);
78
- });
79
- await it("getShaderParameter with desktop-only INFO_LOG_LENGTH returns null and INVALID_ENUM", async () => {
80
- const vs = compileShader(
81
- gl,
82
- gl.VERTEX_SHADER,
83
- "attribute vec4 v; void main() { gl_Position = v; }"
84
- );
85
- const INFO_LOG_LENGTH = 35716;
86
- const result = gl.getShaderParameter(vs, INFO_LOG_LENGTH);
87
- expect(result).toBeNull();
88
- expect(gl.getError()).toBe(gl.INVALID_ENUM);
89
- gl.deleteShader(vs);
90
- });
91
- });
92
- await describe("conformance/programs/program-test: attachShader / detachShader", async () => {
93
- beforeEach(async () => {
94
- glArea.make_current();
95
- });
96
- await it("attaching a vertex shader succeeds", async () => {
97
- const vs = compileShader(gl, gl.VERTEX_SHADER, VS_COLOR_ATTRIB);
98
- const prog = gl.createProgram();
99
- gl.attachShader(prog, vs);
100
- expect(gl.getError()).toBe(gl.NO_ERROR);
101
- gl.deleteProgram(prog);
102
- gl.deleteShader(vs);
103
- });
104
- await it("attaching the same shader twice generates INVALID_OPERATION", async () => {
105
- const vs = compileShader(gl, gl.VERTEX_SHADER, VS_COLOR_ATTRIB);
106
- const prog = gl.createProgram();
107
- gl.attachShader(prog, vs);
108
- gl.getError();
109
- gl.attachShader(prog, vs);
110
- expect(gl.getError()).toBe(gl.INVALID_OPERATION);
111
- gl.deleteProgram(prog);
112
- gl.deleteShader(vs);
113
- });
114
- await it("attaching two vertex shaders to same program generates INVALID_OPERATION", async () => {
115
- const vs1 = compileShader(gl, gl.VERTEX_SHADER, VS_COLOR_ATTRIB);
116
- const vs2 = compileShader(
117
- gl,
118
- gl.VERTEX_SHADER,
119
- "attribute vec4 v; void main() { gl_Position = v * 0.5; }"
120
- );
121
- const prog = gl.createProgram();
122
- gl.attachShader(prog, vs1);
123
- gl.getError();
124
- gl.attachShader(prog, vs2);
125
- expect(gl.getError()).toBe(gl.INVALID_OPERATION);
126
- gl.deleteProgram(prog);
127
- gl.deleteShader(vs1);
128
- gl.deleteShader(vs2);
129
- });
130
- await it("detaching an attached shader succeeds", async () => {
131
- const vs = compileShader(gl, gl.VERTEX_SHADER, VS_COLOR_ATTRIB);
132
- const prog = gl.createProgram();
133
- gl.attachShader(prog, vs);
134
- gl.detachShader(prog, vs);
135
- expect(gl.getError()).toBe(gl.NO_ERROR);
136
- gl.deleteProgram(prog);
137
- gl.deleteShader(vs);
138
- });
139
- await it("detaching a non-attached shader generates INVALID_OPERATION", async () => {
140
- const vs = compileShader(gl, gl.VERTEX_SHADER, VS_COLOR_ATTRIB);
141
- const fs = compileShader(gl, gl.FRAGMENT_SHADER, FS_VARYING_COLOR);
142
- const prog = gl.createProgram();
143
- gl.attachShader(prog, fs);
144
- gl.getError();
145
- gl.detachShader(prog, vs);
146
- expect(gl.getError()).toBe(gl.INVALID_OPERATION);
147
- gl.deleteProgram(prog);
148
- gl.deleteShader(vs);
149
- gl.deleteShader(fs);
150
- });
151
- });
152
- await describe("conformance/programs/program-test: getAttachedShaders", async () => {
153
- beforeEach(async () => {
154
- glArea.make_current();
155
- });
156
- await it("empty program returns empty list", async () => {
157
- const prog = gl.createProgram();
158
- const shaders = gl.getAttachedShaders(prog);
159
- expect(shaders?.length).toBe(0);
160
- gl.deleteProgram(prog);
161
- });
162
- await it("attached shaders appear in getAttachedShaders", async () => {
163
- const vs = compileShader(gl, gl.VERTEX_SHADER, VS_COLOR_ATTRIB);
164
- const fs = compileShader(gl, gl.FRAGMENT_SHADER, FS_VARYING_COLOR);
165
- const prog = gl.createProgram();
166
- gl.attachShader(prog, vs);
167
- gl.attachShader(prog, fs);
168
- const shaders = gl.getAttachedShaders(prog);
169
- expect(shaders.length).toBe(2);
170
- expect(shaders.includes(vs)).toBeTruthy();
171
- expect(shaders.includes(fs)).toBeTruthy();
172
- gl.deleteProgram(prog);
173
- gl.deleteShader(vs);
174
- gl.deleteShader(fs);
175
- });
176
- await it("detached shaders are removed from getAttachedShaders", async () => {
177
- const vs = compileShader(gl, gl.VERTEX_SHADER, VS_COLOR_ATTRIB);
178
- const fs = compileShader(gl, gl.FRAGMENT_SHADER, FS_VARYING_COLOR);
179
- const prog = gl.createProgram();
180
- gl.attachShader(prog, vs);
181
- gl.attachShader(prog, fs);
182
- gl.detachShader(prog, vs);
183
- const shaders = gl.getAttachedShaders(prog);
184
- expect(shaders.length).toBe(1);
185
- expect(shaders.includes(fs)).toBeTruthy();
186
- gl.deleteProgram(prog);
187
- gl.deleteShader(vs);
188
- gl.deleteShader(fs);
189
- });
190
- });
191
- await describe("conformance/programs/program-test: linkProgram / useProgram", async () => {
192
- beforeEach(async () => {
193
- glArea.make_current();
194
- });
195
- await it("valid program should link", async () => {
196
- const prog = linkProgram(
197
- gl,
198
- VS_COLOR_ATTRIB,
199
- FS_VARYING_COLOR,
200
- [["aVertex", 0], ["aColor", 1]]
201
- );
202
- expect(gl.getProgramParameter(prog, gl.LINK_STATUS)).toBeTruthy();
203
- expect(typeof gl.getProgramInfoLog(prog)).toBe("string");
204
- gl.deleteProgram(prog);
205
- });
206
- await it("program with no fragment shader should fail to link", async () => {
207
- const vs = compileShader(gl, gl.VERTEX_SHADER, VS_COLOR_ATTRIB);
208
- const prog = gl.createProgram();
209
- gl.attachShader(prog, vs);
210
- gl.linkProgram(prog);
211
- expect(gl.getProgramParameter(prog, gl.LINK_STATUS)).toBeFalsy();
212
- gl.deleteProgram(prog);
213
- gl.deleteShader(vs);
214
- });
215
- await it("program with no vertex shader should fail to link", async () => {
216
- const fs = compileShader(gl, gl.FRAGMENT_SHADER, FS_VARYING_COLOR);
217
- const prog = gl.createProgram();
218
- gl.attachShader(prog, fs);
219
- gl.linkProgram(prog);
220
- expect(gl.getProgramParameter(prog, gl.LINK_STATUS)).toBeFalsy();
221
- gl.deleteProgram(prog);
222
- gl.deleteShader(fs);
223
- });
224
- await it("using a valid program should succeed", async () => {
225
- const prog = linkProgram(
226
- gl,
227
- VS_COLOR_ATTRIB,
228
- FS_VARYING_COLOR,
229
- [["aVertex", 0], ["aColor", 1]]
230
- );
231
- gl.useProgram(prog);
232
- expect(gl.getError()).toBe(gl.NO_ERROR);
233
- gl.useProgram(null);
234
- gl.deleteProgram(prog);
235
- });
236
- await it("using an invalid (unlinked) program should generate INVALID_OPERATION", async () => {
237
- const vs = compileShader(gl, gl.VERTEX_SHADER, VS_COLOR_ATTRIB);
238
- const prog = gl.createProgram();
239
- gl.attachShader(prog, vs);
240
- gl.linkProgram(prog);
241
- gl.useProgram(prog);
242
- expect(gl.getError()).toBe(gl.INVALID_OPERATION);
243
- gl.deleteProgram(prog);
244
- gl.deleteShader(vs);
245
- });
246
- await it("drawing with null program generates INVALID_OPERATION", async () => {
247
- const prog = linkProgram(gl, VS_POSITION, FS_RED, [["a_position", 0]]);
248
- const fbo = makeTestFBO(gl, 2, 2);
249
- const buf = gl.createBuffer();
250
- gl.bindBuffer(gl.ARRAY_BUFFER, buf);
251
- gl.bufferData(
252
- gl.ARRAY_BUFFER,
253
- new Float32Array([0, 0, 1, 0, 0, 1]),
254
- gl.STATIC_DRAW
255
- );
256
- gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
257
- gl.enableVertexAttribArray(0);
258
- gl.useProgram(null);
259
- gl.drawArrays(gl.TRIANGLES, 0, 3);
260
- expect(gl.getError()).toBe(gl.INVALID_OPERATION);
261
- gl.disableVertexAttribArray(0);
262
- gl.deleteBuffer(buf);
263
- destroyTestFBO(gl, fbo);
264
- gl.deleteProgram(prog);
265
- });
266
- });
267
- await describe("conformance/programs/program-test: deleteProgram / deleteShader", async () => {
268
- beforeEach(async () => {
269
- glArea.make_current();
270
- });
271
- await it("deleting the current program does not affect the current rendering state", async () => {
272
- const prog = linkProgram(gl, VS_POSITION, FS_RED, [["a_position", 0]]);
273
- gl.useProgram(prog);
274
- gl.deleteProgram(prog);
275
- const fbo = makeTestFBO(gl, 2, 2);
276
- const pixel = drawFullscreenAndRead(gl, prog, 0);
277
- expect(gl.getError()).toBe(gl.NO_ERROR);
278
- expect(pixelClose(pixel, [255, 0, 0, 255])).toBeTruthy();
279
- destroyTestFBO(gl, fbo);
280
- gl.useProgram(null);
281
- });
282
- await it("unattached deleted shader is invalid immediately", async () => {
283
- const fs = compileShader(gl, gl.FRAGMENT_SHADER, FS_RED);
284
- gl.deleteShader(fs);
285
- gl.compileShader(fs);
286
- expect(gl.getError()).toBe(gl.INVALID_VALUE);
287
- });
288
- await it("attached deleted shader is still valid while attached", async () => {
289
- const vs = compileShader(gl, gl.VERTEX_SHADER, VS_POSITION);
290
- const fs = compileShader(gl, gl.FRAGMENT_SHADER, FS_RED);
291
- const prog = linkProgram(gl, VS_POSITION, FS_RED, [["a_position", 0]]);
292
- gl.attachShader(prog, vs);
293
- gl.getError();
294
- const fs3 = compileShader(gl, gl.FRAGMENT_SHADER, FS_GREEN);
295
- const prog2 = gl.createProgram();
296
- gl.attachShader(prog2, vs);
297
- gl.attachShader(prog2, fs3);
298
- gl.deleteShader(fs3);
299
- gl.compileShader(fs3);
300
- expect(gl.getShaderParameter(fs3, gl.COMPILE_STATUS)).toBeTruthy();
301
- gl.deleteProgram(prog);
302
- gl.deleteProgram(prog2);
303
- gl.deleteShader(vs);
304
- gl.deleteShader(fs);
305
- });
306
- });
307
- await describe("conformance/programs/program-test: relink updates rendering", async () => {
308
- beforeEach(async () => {
309
- glArea.make_current();
310
- });
311
- await it("relinking with a new fragment shader updates the program output", async () => {
312
- const fbo = makeTestFBO(gl, 2, 2);
313
- const vs = compileShader(gl, gl.VERTEX_SHADER, VS_POSITION);
314
- const fs = compileShader(gl, gl.FRAGMENT_SHADER, FS_RED);
315
- const prog = gl.createProgram();
316
- gl.attachShader(prog, vs);
317
- gl.attachShader(prog, fs);
318
- gl.bindAttribLocation(prog, 0, "a_position");
319
- gl.linkProgram(prog);
320
- gl.useProgram(prog);
321
- expect(gl.getProgramParameter(prog, gl.LINK_STATUS)).toBeTruthy();
322
- gl.clear(gl.COLOR_BUFFER_BIT);
323
- let pixel = drawFullscreenAndRead(gl, prog, 0);
324
- expect(pixelClose(pixel, [255, 0, 0, 255])).toBeTruthy();
325
- gl.shaderSource(fs, FS_GREEN);
326
- gl.compileShader(fs);
327
- gl.linkProgram(prog);
328
- expect(gl.getProgramParameter(prog, gl.LINK_STATUS)).toBeTruthy();
329
- gl.clear(gl.COLOR_BUFFER_BIT);
330
- pixel = drawFullscreenAndRead(gl, prog, 0);
331
- expect(pixelClose(pixel, [0, 255, 0, 255])).toBeTruthy();
332
- destroyTestFBO(gl, fbo);
333
- gl.deleteProgram(prog);
334
- gl.deleteShader(vs);
335
- gl.deleteShader(fs);
336
- });
337
- await it("relinking clears uniforms \u2014 output should be transparent black", async () => {
338
- const fbo = makeTestFBO(gl, 2, 2);
339
- const vs = compileShader(gl, gl.VERTEX_SHADER, VS_POSITION);
340
- const fs = compileShader(gl, gl.FRAGMENT_SHADER, FS_SETTABLE);
341
- const prog = gl.createProgram();
342
- gl.attachShader(prog, vs);
343
- gl.attachShader(prog, fs);
344
- gl.bindAttribLocation(prog, 0, "a_position");
345
- gl.linkProgram(prog);
346
- gl.useProgram(prog);
347
- const colorLoc = gl.getUniformLocation(prog, "u_color");
348
- gl.uniform4f(colorLoc, 1, 0, 0, 1);
349
- gl.clear(gl.COLOR_BUFFER_BIT);
350
- let pixel = drawFullscreenAndRead(gl, prog, 0);
351
- expect(pixelClose(pixel, [255, 0, 0, 255])).toBeTruthy();
352
- gl.linkProgram(prog);
353
- gl.clear(gl.COLOR_BUFFER_BIT);
354
- pixel = drawFullscreenAndRead(gl, prog, 0);
355
- expect(pixelClose(pixel, [0, 0, 0, 0])).toBeTruthy();
356
- destroyTestFBO(gl, fbo);
357
- gl.deleteProgram(prog);
358
- gl.deleteShader(vs);
359
- gl.deleteShader(fs);
360
- });
361
- });
362
- await describe("conformance/programs/gl-shader-test", async () => {
363
- beforeEach(async () => {
364
- glArea.make_current();
365
- });
366
- await it("creating a GEOMETRY shader should return null", async () => {
367
- const GEOMETRY_SHADER_ARB = 36313;
368
- const shader = gl.createShader(GEOMETRY_SHADER_ARB);
369
- expect(shader).toBeNull();
370
- });
371
- await it("deferred compilation: shader linked with source set after first compile", async () => {
372
- const fbo = makeTestFBO(gl, 2, 2);
373
- const vs = compileShader(
374
- gl,
375
- gl.VERTEX_SHADER,
376
- "attribute vec4 vPosition; void main() { gl_Position = vPosition; }"
377
- );
378
- const fs = compileShader(gl, gl.FRAGMENT_SHADER, FS_GREEN);
379
- gl.shaderSource(fs, FS_RED);
380
- const prog = gl.createProgram();
381
- gl.attachShader(prog, vs);
382
- gl.attachShader(prog, fs);
383
- gl.bindAttribLocation(prog, 0, "vPosition");
384
- gl.linkProgram(prog);
385
- gl.useProgram(prog);
386
- gl.clear(gl.COLOR_BUFFER_BIT);
387
- const pixel = drawFullscreenAndRead(gl, prog, 0);
388
- expect(pixelClose(pixel, [255, 0, 0, 255])).toBeTruthy();
389
- destroyTestFBO(gl, fbo);
390
- gl.deleteProgram(prog);
391
- gl.deleteShader(vs);
392
- gl.deleteShader(fs);
393
- });
394
- });
395
- await describe("conformance/programs/get-active-test: getActiveAttrib", async () => {
396
- beforeEach(async () => {
397
- glArea.make_current();
398
- });
399
- await it("getActiveAttrib returns correct info for standard attribs", async () => {
400
- const prog = linkProgram(gl, VS_STANDARD, FS_STANDARD);
401
- expect(gl.getProgramParameter(prog, gl.LINK_STATUS)).toBeTruthy();
402
- const count = gl.getProgramParameter(prog, gl.ACTIVE_ATTRIBUTES);
403
- expect(count).toBe(2);
404
- const infos = [];
405
- for (let i = 0; i < count; i++) {
406
- const info = gl.getActiveAttrib(prog, i);
407
- expect(info).not.toBeNull();
408
- infos.push(info);
409
- }
410
- const names = infos.map((i) => i.name).sort();
411
- expect(names).toContain("a_vertex");
412
- expect(names).toContain("a_normal");
413
- const vertexInfo = infos.find((i) => i.name === "a_vertex");
414
- expect(vertexInfo.type).toBe(gl.FLOAT_VEC4);
415
- expect(vertexInfo.size).toBe(1);
416
- const normalInfo = infos.find((i) => i.name === "a_normal");
417
- expect(normalInfo.type).toBe(gl.FLOAT_VEC3);
418
- expect(normalInfo.size).toBe(1);
419
- gl.deleteProgram(prog);
420
- });
421
- await it("getActiveAttrib with out-of-range index returns null and INVALID_VALUE", async () => {
422
- const prog = linkProgram(gl, VS_STANDARD, FS_STANDARD);
423
- const count = gl.getProgramParameter(prog, gl.ACTIVE_ATTRIBUTES);
424
- const result = gl.getActiveAttrib(prog, count);
425
- expect(result).toBeNull();
426
- expect(gl.getError()).toBe(gl.INVALID_VALUE);
427
- gl.deleteProgram(prog);
428
- });
429
- await it("getActiveAttrib with null program throws", async () => {
430
- expect(() => gl.getActiveAttrib(null, 0)).toThrow();
431
- });
432
- });
433
- await describe("conformance/programs/get-active-test: getActiveUniform", async () => {
434
- beforeEach(async () => {
435
- glArea.make_current();
436
- });
437
- await it("getActiveUniform returns correct info for u_modelViewProjMatrix", async () => {
438
- const prog = linkProgram(gl, VS_STANDARD, FS_STANDARD);
439
- const count = gl.getProgramParameter(prog, gl.ACTIVE_UNIFORMS);
440
- expect(count).toBeGreaterThan(0);
441
- let found = null;
442
- for (let i = 0; i < count; i++) {
443
- const info = gl.getActiveUniform(prog, i);
444
- if (info?.name === "u_modelViewProjMatrix") found = info;
445
- }
446
- expect(found).not.toBeNull();
447
- expect(found.type).toBe(gl.FLOAT_MAT4);
448
- expect(found.size).toBe(1);
449
- gl.deleteProgram(prog);
450
- });
451
- await it("getActiveUniform with out-of-range index returns null and INVALID_VALUE", async () => {
452
- const prog = linkProgram(gl, VS_STANDARD, FS_STANDARD);
453
- const count = gl.getProgramParameter(prog, gl.ACTIVE_UNIFORMS);
454
- const result = gl.getActiveUniform(prog, count);
455
- expect(result).toBeNull();
456
- expect(gl.getError()).toBe(gl.INVALID_VALUE);
457
- gl.deleteProgram(prog);
458
- });
459
- await it("getActiveUniform with null program throws", async () => {
460
- expect(() => gl.getActiveUniform(null, 0)).toThrow();
461
- });
462
- });
463
- win.destroy();
464
- });
465
- };
466
- export {
467
- programs_spec_default as default
59
+ await on("Display", async () => {
60
+ const setup = createGLSetup();
61
+ if (!setup) {
62
+ console.warn("WebGL context not available skipping conformance/programs tests");
63
+ return;
64
+ }
65
+ const { gl, glArea, win } = setup;
66
+ glArea.make_current();
67
+ await describe("conformance/programs/program-test: compileShader", async () => {
68
+ beforeEach(async () => {
69
+ glArea.make_current();
70
+ });
71
+ await it("good vertex shader should compile", async () => {
72
+ const vs = compileShader(gl, gl.VERTEX_SHADER, "attribute vec4 aVertex; void main() { gl_Position = aVertex; }");
73
+ expect(gl.getShaderParameter(vs, gl.COMPILE_STATUS)).toBeTruthy();
74
+ gl.deleteShader(vs);
75
+ });
76
+ await it("good fragment shader should compile", async () => {
77
+ const fs = compileShader(gl, gl.FRAGMENT_SHADER, "precision mediump float; void main() { gl_FragColor = vec4(1.0); }");
78
+ expect(gl.getShaderParameter(fs, gl.COMPILE_STATUS)).toBeTruthy();
79
+ gl.deleteShader(fs);
80
+ });
81
+ await it("getShaderParameter with desktop-only INFO_LOG_LENGTH returns null and INVALID_ENUM", async () => {
82
+ const vs = compileShader(gl, gl.VERTEX_SHADER, "attribute vec4 v; void main() { gl_Position = v; }");
83
+ const INFO_LOG_LENGTH = 35716;
84
+ const result = gl.getShaderParameter(vs, INFO_LOG_LENGTH);
85
+ expect(result).toBeNull();
86
+ expect(gl.getError()).toBe(gl.INVALID_ENUM);
87
+ gl.deleteShader(vs);
88
+ });
89
+ });
90
+ await describe("conformance/programs/program-test: attachShader / detachShader", async () => {
91
+ beforeEach(async () => {
92
+ glArea.make_current();
93
+ });
94
+ await it("attaching a vertex shader succeeds", async () => {
95
+ const vs = compileShader(gl, gl.VERTEX_SHADER, VS_COLOR_ATTRIB);
96
+ const prog = gl.createProgram();
97
+ gl.attachShader(prog, vs);
98
+ expect(gl.getError()).toBe(gl.NO_ERROR);
99
+ gl.deleteProgram(prog);
100
+ gl.deleteShader(vs);
101
+ });
102
+ await it("attaching the same shader twice generates INVALID_OPERATION", async () => {
103
+ const vs = compileShader(gl, gl.VERTEX_SHADER, VS_COLOR_ATTRIB);
104
+ const prog = gl.createProgram();
105
+ gl.attachShader(prog, vs);
106
+ gl.getError();
107
+ gl.attachShader(prog, vs);
108
+ expect(gl.getError()).toBe(gl.INVALID_OPERATION);
109
+ gl.deleteProgram(prog);
110
+ gl.deleteShader(vs);
111
+ });
112
+ await it("attaching two vertex shaders to same program generates INVALID_OPERATION", async () => {
113
+ const vs1 = compileShader(gl, gl.VERTEX_SHADER, VS_COLOR_ATTRIB);
114
+ const vs2 = compileShader(gl, gl.VERTEX_SHADER, "attribute vec4 v; void main() { gl_Position = v * 0.5; }");
115
+ const prog = gl.createProgram();
116
+ gl.attachShader(prog, vs1);
117
+ gl.getError();
118
+ gl.attachShader(prog, vs2);
119
+ expect(gl.getError()).toBe(gl.INVALID_OPERATION);
120
+ gl.deleteProgram(prog);
121
+ gl.deleteShader(vs1);
122
+ gl.deleteShader(vs2);
123
+ });
124
+ await it("detaching an attached shader succeeds", async () => {
125
+ const vs = compileShader(gl, gl.VERTEX_SHADER, VS_COLOR_ATTRIB);
126
+ const prog = gl.createProgram();
127
+ gl.attachShader(prog, vs);
128
+ gl.detachShader(prog, vs);
129
+ expect(gl.getError()).toBe(gl.NO_ERROR);
130
+ gl.deleteProgram(prog);
131
+ gl.deleteShader(vs);
132
+ });
133
+ await it("detaching a non-attached shader generates INVALID_OPERATION", async () => {
134
+ const vs = compileShader(gl, gl.VERTEX_SHADER, VS_COLOR_ATTRIB);
135
+ const fs = compileShader(gl, gl.FRAGMENT_SHADER, FS_VARYING_COLOR);
136
+ const prog = gl.createProgram();
137
+ gl.attachShader(prog, fs);
138
+ gl.getError();
139
+ gl.detachShader(prog, vs);
140
+ expect(gl.getError()).toBe(gl.INVALID_OPERATION);
141
+ gl.deleteProgram(prog);
142
+ gl.deleteShader(vs);
143
+ gl.deleteShader(fs);
144
+ });
145
+ });
146
+ await describe("conformance/programs/program-test: getAttachedShaders", async () => {
147
+ beforeEach(async () => {
148
+ glArea.make_current();
149
+ });
150
+ await it("empty program returns empty list", async () => {
151
+ const prog = gl.createProgram();
152
+ const shaders = gl.getAttachedShaders(prog);
153
+ expect(shaders?.length).toBe(0);
154
+ gl.deleteProgram(prog);
155
+ });
156
+ await it("attached shaders appear in getAttachedShaders", async () => {
157
+ const vs = compileShader(gl, gl.VERTEX_SHADER, VS_COLOR_ATTRIB);
158
+ const fs = compileShader(gl, gl.FRAGMENT_SHADER, FS_VARYING_COLOR);
159
+ const prog = gl.createProgram();
160
+ gl.attachShader(prog, vs);
161
+ gl.attachShader(prog, fs);
162
+ const shaders = gl.getAttachedShaders(prog);
163
+ expect(shaders.length).toBe(2);
164
+ expect(shaders.includes(vs)).toBeTruthy();
165
+ expect(shaders.includes(fs)).toBeTruthy();
166
+ gl.deleteProgram(prog);
167
+ gl.deleteShader(vs);
168
+ gl.deleteShader(fs);
169
+ });
170
+ await it("detached shaders are removed from getAttachedShaders", async () => {
171
+ const vs = compileShader(gl, gl.VERTEX_SHADER, VS_COLOR_ATTRIB);
172
+ const fs = compileShader(gl, gl.FRAGMENT_SHADER, FS_VARYING_COLOR);
173
+ const prog = gl.createProgram();
174
+ gl.attachShader(prog, vs);
175
+ gl.attachShader(prog, fs);
176
+ gl.detachShader(prog, vs);
177
+ const shaders = gl.getAttachedShaders(prog);
178
+ expect(shaders.length).toBe(1);
179
+ expect(shaders.includes(fs)).toBeTruthy();
180
+ gl.deleteProgram(prog);
181
+ gl.deleteShader(vs);
182
+ gl.deleteShader(fs);
183
+ });
184
+ });
185
+ await describe("conformance/programs/program-test: linkProgram / useProgram", async () => {
186
+ beforeEach(async () => {
187
+ glArea.make_current();
188
+ });
189
+ await it("valid program should link", async () => {
190
+ const prog = linkProgram(gl, VS_COLOR_ATTRIB, FS_VARYING_COLOR, [["aVertex", 0], ["aColor", 1]]);
191
+ expect(gl.getProgramParameter(prog, gl.LINK_STATUS)).toBeTruthy();
192
+ expect(typeof gl.getProgramInfoLog(prog)).toBe("string");
193
+ gl.deleteProgram(prog);
194
+ });
195
+ await it("program with no fragment shader should fail to link", async () => {
196
+ const vs = compileShader(gl, gl.VERTEX_SHADER, VS_COLOR_ATTRIB);
197
+ const prog = gl.createProgram();
198
+ gl.attachShader(prog, vs);
199
+ gl.linkProgram(prog);
200
+ expect(gl.getProgramParameter(prog, gl.LINK_STATUS)).toBeFalsy();
201
+ gl.deleteProgram(prog);
202
+ gl.deleteShader(vs);
203
+ });
204
+ await it("program with no vertex shader should fail to link", async () => {
205
+ const fs = compileShader(gl, gl.FRAGMENT_SHADER, FS_VARYING_COLOR);
206
+ const prog = gl.createProgram();
207
+ gl.attachShader(prog, fs);
208
+ gl.linkProgram(prog);
209
+ expect(gl.getProgramParameter(prog, gl.LINK_STATUS)).toBeFalsy();
210
+ gl.deleteProgram(prog);
211
+ gl.deleteShader(fs);
212
+ });
213
+ await it("using a valid program should succeed", async () => {
214
+ const prog = linkProgram(gl, VS_COLOR_ATTRIB, FS_VARYING_COLOR, [["aVertex", 0], ["aColor", 1]]);
215
+ gl.useProgram(prog);
216
+ expect(gl.getError()).toBe(gl.NO_ERROR);
217
+ gl.useProgram(null);
218
+ gl.deleteProgram(prog);
219
+ });
220
+ await it("using an invalid (unlinked) program should generate INVALID_OPERATION", async () => {
221
+ const vs = compileShader(gl, gl.VERTEX_SHADER, VS_COLOR_ATTRIB);
222
+ const prog = gl.createProgram();
223
+ gl.attachShader(prog, vs);
224
+ gl.linkProgram(prog);
225
+ gl.useProgram(prog);
226
+ expect(gl.getError()).toBe(gl.INVALID_OPERATION);
227
+ gl.deleteProgram(prog);
228
+ gl.deleteShader(vs);
229
+ });
230
+ await it("drawing with null program generates INVALID_OPERATION", async () => {
231
+ const prog = linkProgram(gl, VS_POSITION, FS_RED, [["a_position", 0]]);
232
+ const fbo = makeTestFBO(gl, 2, 2);
233
+ const buf = gl.createBuffer();
234
+ gl.bindBuffer(gl.ARRAY_BUFFER, buf);
235
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
236
+ 0,
237
+ 0,
238
+ 1,
239
+ 0,
240
+ 0,
241
+ 1
242
+ ]), gl.STATIC_DRAW);
243
+ gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
244
+ gl.enableVertexAttribArray(0);
245
+ gl.useProgram(null);
246
+ gl.drawArrays(gl.TRIANGLES, 0, 3);
247
+ expect(gl.getError()).toBe(gl.INVALID_OPERATION);
248
+ gl.disableVertexAttribArray(0);
249
+ gl.deleteBuffer(buf);
250
+ destroyTestFBO(gl, fbo);
251
+ gl.deleteProgram(prog);
252
+ });
253
+ });
254
+ await describe("conformance/programs/program-test: deleteProgram / deleteShader", async () => {
255
+ beforeEach(async () => {
256
+ glArea.make_current();
257
+ });
258
+ await it("deleting the current program does not affect the current rendering state", async () => {
259
+ const prog = linkProgram(gl, VS_POSITION, FS_RED, [["a_position", 0]]);
260
+ gl.useProgram(prog);
261
+ gl.deleteProgram(prog);
262
+ const fbo = makeTestFBO(gl, 2, 2);
263
+ const pixel = drawFullscreenAndRead(gl, prog, 0);
264
+ expect(gl.getError()).toBe(gl.NO_ERROR);
265
+ expect(pixelClose(pixel, [
266
+ 255,
267
+ 0,
268
+ 0,
269
+ 255
270
+ ])).toBeTruthy();
271
+ destroyTestFBO(gl, fbo);
272
+ gl.useProgram(null);
273
+ });
274
+ await it("unattached deleted shader is invalid immediately", async () => {
275
+ const fs = compileShader(gl, gl.FRAGMENT_SHADER, FS_RED);
276
+ gl.deleteShader(fs);
277
+ gl.compileShader(fs);
278
+ expect(gl.getError()).toBe(gl.INVALID_VALUE);
279
+ });
280
+ await it("attached deleted shader is still valid while attached", async () => {
281
+ const vs = compileShader(gl, gl.VERTEX_SHADER, VS_POSITION);
282
+ const fs = compileShader(gl, gl.FRAGMENT_SHADER, FS_RED);
283
+ const prog = linkProgram(gl, VS_POSITION, FS_RED, [["a_position", 0]]);
284
+ gl.attachShader(prog, vs);
285
+ gl.getError();
286
+ const fs3 = compileShader(gl, gl.FRAGMENT_SHADER, FS_GREEN);
287
+ const prog2 = gl.createProgram();
288
+ gl.attachShader(prog2, vs);
289
+ gl.attachShader(prog2, fs3);
290
+ gl.deleteShader(fs3);
291
+ gl.compileShader(fs3);
292
+ expect(gl.getShaderParameter(fs3, gl.COMPILE_STATUS)).toBeTruthy();
293
+ gl.deleteProgram(prog);
294
+ gl.deleteProgram(prog2);
295
+ gl.deleteShader(vs);
296
+ gl.deleteShader(fs);
297
+ });
298
+ });
299
+ await describe("conformance/programs/program-test: relink updates rendering", async () => {
300
+ beforeEach(async () => {
301
+ glArea.make_current();
302
+ });
303
+ await it("relinking with a new fragment shader updates the program output", async () => {
304
+ const fbo = makeTestFBO(gl, 2, 2);
305
+ const vs = compileShader(gl, gl.VERTEX_SHADER, VS_POSITION);
306
+ const fs = compileShader(gl, gl.FRAGMENT_SHADER, FS_RED);
307
+ const prog = gl.createProgram();
308
+ gl.attachShader(prog, vs);
309
+ gl.attachShader(prog, fs);
310
+ gl.bindAttribLocation(prog, 0, "a_position");
311
+ gl.linkProgram(prog);
312
+ gl.useProgram(prog);
313
+ expect(gl.getProgramParameter(prog, gl.LINK_STATUS)).toBeTruthy();
314
+ gl.clear(gl.COLOR_BUFFER_BIT);
315
+ let pixel = drawFullscreenAndRead(gl, prog, 0);
316
+ expect(pixelClose(pixel, [
317
+ 255,
318
+ 0,
319
+ 0,
320
+ 255
321
+ ])).toBeTruthy();
322
+ gl.shaderSource(fs, FS_GREEN);
323
+ gl.compileShader(fs);
324
+ gl.linkProgram(prog);
325
+ expect(gl.getProgramParameter(prog, gl.LINK_STATUS)).toBeTruthy();
326
+ gl.clear(gl.COLOR_BUFFER_BIT);
327
+ pixel = drawFullscreenAndRead(gl, prog, 0);
328
+ expect(pixelClose(pixel, [
329
+ 0,
330
+ 255,
331
+ 0,
332
+ 255
333
+ ])).toBeTruthy();
334
+ destroyTestFBO(gl, fbo);
335
+ gl.deleteProgram(prog);
336
+ gl.deleteShader(vs);
337
+ gl.deleteShader(fs);
338
+ });
339
+ await it("relinking clears uniforms — output should be transparent black", async () => {
340
+ const fbo = makeTestFBO(gl, 2, 2);
341
+ const vs = compileShader(gl, gl.VERTEX_SHADER, VS_POSITION);
342
+ const fs = compileShader(gl, gl.FRAGMENT_SHADER, FS_SETTABLE);
343
+ const prog = gl.createProgram();
344
+ gl.attachShader(prog, vs);
345
+ gl.attachShader(prog, fs);
346
+ gl.bindAttribLocation(prog, 0, "a_position");
347
+ gl.linkProgram(prog);
348
+ gl.useProgram(prog);
349
+ const colorLoc = gl.getUniformLocation(prog, "u_color");
350
+ gl.uniform4f(colorLoc, 1, 0, 0, 1);
351
+ gl.clear(gl.COLOR_BUFFER_BIT);
352
+ let pixel = drawFullscreenAndRead(gl, prog, 0);
353
+ expect(pixelClose(pixel, [
354
+ 255,
355
+ 0,
356
+ 0,
357
+ 255
358
+ ])).toBeTruthy();
359
+ gl.linkProgram(prog);
360
+ gl.clear(gl.COLOR_BUFFER_BIT);
361
+ pixel = drawFullscreenAndRead(gl, prog, 0);
362
+ expect(pixelClose(pixel, [
363
+ 0,
364
+ 0,
365
+ 0,
366
+ 0
367
+ ])).toBeTruthy();
368
+ destroyTestFBO(gl, fbo);
369
+ gl.deleteProgram(prog);
370
+ gl.deleteShader(vs);
371
+ gl.deleteShader(fs);
372
+ });
373
+ });
374
+ await describe("conformance/programs/gl-shader-test", async () => {
375
+ beforeEach(async () => {
376
+ glArea.make_current();
377
+ });
378
+ await it("creating a GEOMETRY shader should return null", async () => {
379
+ const GEOMETRY_SHADER_ARB = 36313;
380
+ const shader = gl.createShader(GEOMETRY_SHADER_ARB);
381
+ expect(shader).toBeNull();
382
+ });
383
+ await it("deferred compilation: shader linked with source set after first compile", async () => {
384
+ const fbo = makeTestFBO(gl, 2, 2);
385
+ const vs = compileShader(gl, gl.VERTEX_SHADER, "attribute vec4 vPosition; void main() { gl_Position = vPosition; }");
386
+ const fs = compileShader(gl, gl.FRAGMENT_SHADER, FS_GREEN);
387
+ gl.shaderSource(fs, FS_RED);
388
+ const prog = gl.createProgram();
389
+ gl.attachShader(prog, vs);
390
+ gl.attachShader(prog, fs);
391
+ gl.bindAttribLocation(prog, 0, "vPosition");
392
+ gl.linkProgram(prog);
393
+ gl.useProgram(prog);
394
+ gl.clear(gl.COLOR_BUFFER_BIT);
395
+ const pixel = drawFullscreenAndRead(gl, prog, 0);
396
+ expect(pixelClose(pixel, [
397
+ 255,
398
+ 0,
399
+ 0,
400
+ 255
401
+ ])).toBeTruthy();
402
+ destroyTestFBO(gl, fbo);
403
+ gl.deleteProgram(prog);
404
+ gl.deleteShader(vs);
405
+ gl.deleteShader(fs);
406
+ });
407
+ });
408
+ await describe("conformance/programs/get-active-test: getActiveAttrib", async () => {
409
+ beforeEach(async () => {
410
+ glArea.make_current();
411
+ });
412
+ await it("getActiveAttrib returns correct info for standard attribs", async () => {
413
+ const prog = linkProgram(gl, VS_STANDARD, FS_STANDARD);
414
+ expect(gl.getProgramParameter(prog, gl.LINK_STATUS)).toBeTruthy();
415
+ const count = gl.getProgramParameter(prog, gl.ACTIVE_ATTRIBUTES);
416
+ expect(count).toBe(2);
417
+ const infos = [];
418
+ for (let i = 0; i < count; i++) {
419
+ const info = gl.getActiveAttrib(prog, i);
420
+ expect(info).not.toBeNull();
421
+ infos.push(info);
422
+ }
423
+ const names = infos.map((i) => i.name).sort();
424
+ expect(names).toContain("a_vertex");
425
+ expect(names).toContain("a_normal");
426
+ const vertexInfo = infos.find((i) => i.name === "a_vertex");
427
+ expect(vertexInfo.type).toBe(gl.FLOAT_VEC4);
428
+ expect(vertexInfo.size).toBe(1);
429
+ const normalInfo = infos.find((i) => i.name === "a_normal");
430
+ expect(normalInfo.type).toBe(gl.FLOAT_VEC3);
431
+ expect(normalInfo.size).toBe(1);
432
+ gl.deleteProgram(prog);
433
+ });
434
+ await it("getActiveAttrib with out-of-range index returns null and INVALID_VALUE", async () => {
435
+ const prog = linkProgram(gl, VS_STANDARD, FS_STANDARD);
436
+ const count = gl.getProgramParameter(prog, gl.ACTIVE_ATTRIBUTES);
437
+ const result = gl.getActiveAttrib(prog, count);
438
+ expect(result).toBeNull();
439
+ expect(gl.getError()).toBe(gl.INVALID_VALUE);
440
+ gl.deleteProgram(prog);
441
+ });
442
+ await it("getActiveAttrib with null program throws", async () => {
443
+ expect(() => gl.getActiveAttrib(null, 0)).toThrow();
444
+ });
445
+ });
446
+ await describe("conformance/programs/get-active-test: getActiveUniform", async () => {
447
+ beforeEach(async () => {
448
+ glArea.make_current();
449
+ });
450
+ await it("getActiveUniform returns correct info for u_modelViewProjMatrix", async () => {
451
+ const prog = linkProgram(gl, VS_STANDARD, FS_STANDARD);
452
+ const count = gl.getProgramParameter(prog, gl.ACTIVE_UNIFORMS);
453
+ expect(count).toBeGreaterThan(0);
454
+ let found = null;
455
+ for (let i = 0; i < count; i++) {
456
+ const info = gl.getActiveUniform(prog, i);
457
+ if (info?.name === "u_modelViewProjMatrix") found = info;
458
+ }
459
+ expect(found).not.toBeNull();
460
+ expect(found.type).toBe(gl.FLOAT_MAT4);
461
+ expect(found.size).toBe(1);
462
+ gl.deleteProgram(prog);
463
+ });
464
+ await it("getActiveUniform with out-of-range index returns null and INVALID_VALUE", async () => {
465
+ const prog = linkProgram(gl, VS_STANDARD, FS_STANDARD);
466
+ const count = gl.getProgramParameter(prog, gl.ACTIVE_UNIFORMS);
467
+ const result = gl.getActiveUniform(prog, count);
468
+ expect(result).toBeNull();
469
+ expect(gl.getError()).toBe(gl.INVALID_VALUE);
470
+ gl.deleteProgram(prog);
471
+ });
472
+ await it("getActiveUniform with null program throws", async () => {
473
+ expect(() => gl.getActiveUniform(null, 0)).toThrow();
474
+ });
475
+ });
476
+ win.destroy();
477
+ });
468
478
  };
479
+
480
+ //#endregion
481
+ export { programs_spec_default as default };