Backed out changeset 7272b7396c78 (bug 1932758) for causing fenix debug failures...
[gecko.git] / dom / canvas / test / webgl-conf / checkout / conformance2 / extensions / oes-sample-variables.html
blob41fc8f824290ecbf848babecee3a84247cc48547
1 <!--
2 Copyright (c) 2023 The Khronos Group Inc.
3 Use of this source code is governed by an MIT-style license that can be
4 found in the LICENSE.txt file.
5 -->
7 <!DOCTYPE html>
8 <html>
9 <head>
10 <meta charset="utf-8">
11 <title>WebGL OES_sample_variables Conformance Tests</title>
12 <link rel="stylesheet" href="../../resources/js-test-style.css"/>
13 <script src="../../js/js-test-pre.js"></script>
14 <script src="../../js/webgl-test-utils.js"></script>
15 </head>
16 <body>
17 <canvas width="32" height="32" id="c"></canvas>
18 <div id="description"></div>
19 <div id="console"></div>
20 <script>
21 "use strict";
22 description("This test verifies the functionality of the OES_sample_variables extension, if it is available.");
24 debug("");
26 var wtu = WebGLTestUtils;
27 var gl = wtu.create3DContext("c", { antialias: false }, 2);
28 var ext;
30 function runShaderTests(extensionEnabled) {
31 debug("");
32 debug("Testing various shader compiles with extension " + (extensionEnabled ? "enabled" : "disabled"));
34 const macro = `#version 300 es
35 precision highp float;
36 out vec4 my_FragColor;
37 void main() {
38 #ifdef GL_OES_sample_variables
39 my_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
40 #else
41 #error no GL_OES_sample_variables;
42 #endif
43 }`;
45 // Expect the macro shader to succeed ONLY if enabled
46 if (wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, macro])) {
47 if (extensionEnabled) {
48 testPassed("Macro defined in shaders when extension is enabled");
49 } else {
50 testFailed("Macro defined in shaders when extension is disabled");
52 } else {
53 if (extensionEnabled) {
54 testFailed("Macro not defined in shaders when extension is enabled");
55 } else {
56 testPassed("Macro not defined in shaders when extension is disabled");
60 const missing = `#version 300 es
61 precision highp float;
62 out vec4 my_FragColor;
63 void main() {
64 gl_SampleMask[0] = gl_SampleMaskIn[0] & 0x55555555;
65 my_FragColor = vec4(gl_SamplePosition.yx, float(gl_SampleID), float(gl_MaxSamples + gl_NumSamples));
66 }`;
68 // Always expect the shader missing the #extension pragma to fail (whether enabled or not)
69 if (wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, missing])) {
70 testFailed("Sample variables allowed without #extension pragma");
71 } else {
72 testPassed("Sample variables disallowed without #extension pragma");
75 const valid = `#version 300 es
76 #extension GL_OES_sample_variables : enable
77 precision highp float;
78 out vec4 my_FragColor;
79 void main() {
80 gl_SampleMask[0] = gl_SampleMaskIn[0] & 0x55555555;
81 my_FragColor = vec4(gl_SamplePosition.yx, float(gl_SampleID), float(gl_MaxSamples + gl_NumSamples));
82 }`;
84 // Try to compile a shader using sample variables that should only succeed if enabled
85 if (wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, valid])) {
86 if (extensionEnabled) {
87 testPassed("Sample variables compiled successfully when extension enabled");
88 } else {
89 testFailed("Sample variables compiled successfully when extension disabled");
91 } else {
92 if (extensionEnabled) {
93 testFailed("Sample variables failed to compile when extension enabled");
94 } else {
95 testPassed("Sample variables failed to compile when extension disabled");
99 debug("");
102 function runMaxSamplesTest() {
103 debug("");
104 debug("Testing gl_MaxSamples");
106 const frag = `#version 300 es
107 #extension GL_OES_sample_variables : require
108 precision highp float;
109 out vec4 color;
110 void main() {
111 color = vec4(float(gl_MaxSamples * 4) / 255.0, 0.0, 0.0, 1.0);
113 gl.useProgram(wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, frag]));
115 wtu.setupUnitQuad(gl);
116 wtu.drawUnitQuad(gl);
118 wtu.checkCanvas(gl, [gl.getParameter(gl.MAX_SAMPLES) * 4, 0, 0, 255], "should match MAX_SAMPLES", 1);
121 function runNumSamplesTest() {
122 debug("");
123 debug("Testing gl_NumSamples");
125 const rbo = gl.createRenderbuffer();
126 gl.bindRenderbuffer(gl.RENDERBUFFER, rbo);
127 gl.renderbufferStorageMultisample(gl.RENDERBUFFER, 4, gl.RGBA8, 32, 32);
129 const fbo = gl.createFramebuffer();
130 gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
131 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rbo);
133 wtu.framebufferStatusShouldBe(gl, gl.FRAMEBUFFER, gl.FRAMEBUFFER_COMPLETE);
135 const frag = `#version 300 es
136 #extension GL_OES_sample_variables : require
137 precision highp float;
138 out vec4 color;
139 void main() {
140 if (gl_NumSamples == 4) {
141 color = vec4(0.0, 1.0, 0.0, 1.0);
142 } else {
143 color = vec4(1.0, 0.0, 0.0, 1.0);
146 gl.useProgram(wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, frag]));
148 wtu.setupUnitQuad(gl);
149 wtu.drawUnitQuad(gl);
151 gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo);
152 gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null);
153 gl.blitFramebuffer(0, 0, 32, 32, 0, 0, 32, 32, gl.COLOR_BUFFER_BIT, gl.NEAREST);
155 gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null);
156 wtu.checkCanvas(gl, [0, 255, 0, 255], "should be green");
159 function runSampleIDTest() {
160 debug("");
161 debug("Testing gl_SampleID");
163 const frag = `#version 300 es
164 #extension GL_OES_sample_variables : require
165 precision highp float;
166 out vec4 color;
167 uniform int id;
168 void main() {
169 // Special value when the selected sample is processed, 0.0 otherwise
170 float r = float(gl_SampleID == id ? (1 << gl_SampleID) : 0) * 32.0 / 255.0;
171 // Must always be 0.0
172 float g = float(gl_SampleID < 0 || gl_SampleID >= gl_NumSamples);
173 color = vec4(r, g, 0.0, 1.0);
175 const program = wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, frag]);
176 gl.useProgram(program);
178 wtu.setupUnitQuad(gl);
180 const rbo = gl.createRenderbuffer();
181 gl.bindRenderbuffer(gl.RENDERBUFFER, rbo);
182 gl.renderbufferStorageMultisample(gl.RENDERBUFFER, 4, gl.RGBA8, 32, 32);
184 const fbo = gl.createFramebuffer();
185 gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
186 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rbo);
188 wtu.framebufferStatusShouldBe(gl, gl.FRAMEBUFFER, gl.FRAMEBUFFER_COMPLETE);
190 for (let sample = 0; sample < 4; sample++) {
191 debug(`Sample ${sample} is selected`);
193 gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fbo);
194 gl.uniform1i(gl.getUniformLocation(program, "id"), sample);
195 wtu.drawUnitQuad(gl);
197 gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo);
198 gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null);
199 gl.blitFramebuffer(0, 0, 32, 32, 0, 0, 32, 32, gl.COLOR_BUFFER_BIT, gl.NEAREST);
201 gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null);
202 wtu.checkCanvas(gl, [(1 << sample) * 8, 0, 0, 255], undefined, 1);
206 function runSampleMaskInTest() {
207 debug("");
208 debug("Testing gl_SampleMaskIn");
210 const frag = `#version 300 es
211 #extension GL_OES_sample_variables : require
212 precision highp float;
213 out vec4 color;
214 uint popcount(uint v) {
215 uint c = 0u;
216 for (; v != 0u; v >>= 1) c += v & 1u;
217 return c;
219 void main() {
220 float r = float(popcount(uint(gl_SampleMaskIn[0])));
221 color = vec4(r * 4.0 / 255.0, 0, 0, 1);
224 const program = wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, frag]);
225 gl.useProgram(program);
227 // Use a triangle instead of the WTU's quad
228 // to avoid artifacts along the diagonal
229 const vertices = gl.createBuffer();
230 gl.bindBuffer(gl.ARRAY_BUFFER, vertices);
231 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
232 -1.0, 1.0,
233 1.0, -1.0,
234 -1.0, -1.0]), gl.STATIC_DRAW);
235 gl.enableVertexAttribArray(0);
236 gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
238 function test(sampleCount, sampleCoverageEnabled, coverage) {
239 if (sampleCoverageEnabled) {
240 gl.enable(gl.SAMPLE_COVERAGE);
241 } else {
242 gl.disable(gl.SAMPLE_COVERAGE);
245 gl.sampleCoverage(coverage, false);
247 const rbo = gl.createRenderbuffer();
248 gl.bindRenderbuffer(gl.RENDERBUFFER, rbo);
249 gl.renderbufferStorageMultisample(gl.RENDERBUFFER, sampleCount, gl.RGBA8, 32, 32);
251 const fbo = gl.createFramebuffer();
252 gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
253 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rbo);
255 wtu.framebufferStatusShouldBe(gl, gl.FRAMEBUFFER, gl.FRAMEBUFFER_COMPLETE);
257 gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fbo);
258 gl.clear(gl.COLOR_BUFFER_BIT);
259 gl.drawArrays(gl.TRIANGLES, 0, 3);
261 gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo);
262 gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null);
263 gl.blitFramebuffer(0, 0, 32, 32, 0, 0, 32, 32, gl.COLOR_BUFFER_BIT, gl.NEAREST);
265 // Shader scales up the number of input samples to increase precision in unorm8 space.
266 let expected = Math.max(sampleCount, 1) * 4;
268 // Sample coverage must not affect single sampled buffers
269 if (sampleCoverageEnabled && sampleCount > 0) {
270 // The number of samples in gl_SampleMaskIn must be affected by the sample
271 // coverage GL state and then the resolved value must be scaled down again.
272 expected *= coverage * coverage;
275 // Check only the red channel
276 gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null);
277 const pixel = new Uint8Array(4);
278 gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel);
279 const message = `Expected: ${expected}, Actual: ${pixel[0]}, ` +
280 `Samples: ${sampleCount}, Sample Coverage: ${sampleCoverageEnabled}, Coverage: ${coverage}`;
281 if (Math.abs(pixel[0] - expected) > 2) {
282 testFailed(message);
283 } else {
284 testPassed(message);
288 // Include all exposed sample counts and additionally test single-sampled rendering
289 const sampleCounts = [...gl.getInternalformatParameter(gl.RENDERBUFFER, gl.RGBA8, gl.SAMPLES), 0];
291 for (const sampleCount of sampleCounts) {
292 if (sampleCount > 32) {
293 // This test will not work with more than 32 samples.
294 continue;
297 for (const sampleCoverageEnabled of [false, true]) {
298 for (const coverage of [0.0, 0.5, 1.0]) {
299 if (sampleCount == 1 && coverage != 0.0 && coverage != 1.0) {
300 continue;
302 test(sampleCount, sampleCoverageEnabled, coverage);
308 function runSampleMaskInPerSampleTest() {
309 debug("");
310 debug("Testing gl_SampleMaskIn with per-sample shading");
312 const frag = `#version 300 es
313 #extension GL_OES_sample_variables : require
314 precision highp float;
315 out vec4 color;
316 void main() {
317 float r = float(gl_SampleMaskIn[0] == (1 << gl_SampleID));
318 color = vec4(r, 0, 0, 1);
320 const program = wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, frag]);
321 gl.useProgram(program);
323 wtu.setupUnitQuad(gl);
325 // Include all exposed sample counts and additionally test single-sampled rendering
326 const sampleCounts = [...gl.getInternalformatParameter(gl.RENDERBUFFER, gl.RGBA8, gl.SAMPLES), 0];
327 for (const sampleCount of sampleCounts) {
328 if (sampleCount > 32) {
329 // This test will not work with more than 32 samples.
330 continue;
333 const rbo = gl.createRenderbuffer();
334 gl.bindRenderbuffer(gl.RENDERBUFFER, rbo);
335 gl.renderbufferStorageMultisample(gl.RENDERBUFFER, sampleCount, gl.RGBA8, 32, 32);
337 const fbo = gl.createFramebuffer();
338 gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
339 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rbo);
341 wtu.framebufferStatusShouldBe(gl, gl.FRAMEBUFFER, gl.FRAMEBUFFER_COMPLETE);
343 gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fbo);
344 wtu.drawUnitQuad(gl);
346 gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo);
347 gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null);
348 gl.blitFramebuffer(0, 0, 32, 32, 0, 0, 32, 32, gl.COLOR_BUFFER_BIT, gl.NEAREST);
350 gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null);
351 wtu.checkCanvas(gl, [255, 0, 0, 255], `Samples: ${sampleCount}`, 1);
355 function runSampleMaskTest() {
356 debug("");
357 debug("Testing gl_SampleMask");
359 const frag = `#version 300 es
360 #extension GL_OES_sample_variables : require
361 precision highp float;
362 uniform highp int sampleMask;
363 out vec4 color;
364 void main() {
365 gl_SampleMask[0] = sampleMask;
366 color = vec4(1, 0, 0, 1);
368 const program = wtu.setupProgram(gl, [wtu.simpleVertexShaderESSL300, frag]);
369 gl.useProgram(program);
371 // Use a triangle instead of the WTU's quad
372 // to avoid artifacts along the diagonal
373 const vertices = gl.createBuffer();
374 gl.bindBuffer(gl.ARRAY_BUFFER, vertices);
375 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
376 -1.0, 1.0,
377 1.0, -1.0,
378 -1.0, -1.0]), gl.STATIC_DRAW);
379 gl.enableVertexAttribArray(0);
380 gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
382 function test(sampleCount, sampleMask) {
383 const rbo = gl.createRenderbuffer();
384 gl.bindRenderbuffer(gl.RENDERBUFFER, rbo);
385 gl.renderbufferStorageMultisample(gl.RENDERBUFFER, sampleCount, gl.RGBA8, 32, 32);
387 const fbo = gl.createFramebuffer();
388 gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
389 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rbo);
391 wtu.framebufferStatusShouldBe(gl, gl.FRAMEBUFFER, gl.FRAMEBUFFER_COMPLETE);
393 gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fbo);
394 gl.clear(gl.COLOR_BUFFER_BIT);
395 gl.uniform1i(gl.getUniformLocation(program, "sampleMask"), sampleMask);
396 gl.drawArrays(gl.TRIANGLES, 0, 3);
398 gl.bindFramebuffer(gl.READ_FRAMEBUFFER, fbo);
399 gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null);
400 gl.blitFramebuffer(0, 0, 32, 32, 0, 0, 32, 32, gl.COLOR_BUFFER_BIT, gl.NEAREST);
402 let expected = 1.0;
403 if (sampleCount > 0) {
404 let mask = sampleMask & ((1 << Math.max(sampleCount, 1)) - 1);
405 let bits = 0;
406 for (; mask != 0; mask >>= 1) bits += mask & 1;
407 expected = bits / Math.max(sampleCount, 1);
409 expected *= 255;
411 // Check only the red channel
412 gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null);
413 const pixel = new Uint8Array(4);
414 gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel);
415 const message = `Samples: ${sampleCount}, `
416 + `gl_SampleMask[0]: 0x${sampleMask.toString(16).padStart(8, "0").toUpperCase()}, `
417 + `Actual: ${pixel[0]}, Expected: ${expected}`;
418 if (Math.abs(pixel[0] - expected) > 2) {
419 testFailed(message);
420 } else {
421 testPassed(message);
425 // Include all exposed sample counts and additionally test single-sampled rendering
426 const sampleCounts = [...gl.getInternalformatParameter(gl.RENDERBUFFER, gl.RGBA8, gl.SAMPLES), 0];
428 for (const sampleCount of sampleCounts) {
429 if (sampleCount > 31) {
430 // This test will not work with more than 31 samples.
431 continue;
434 for (const sampleMask of [0xFFFFFFFF, 0x55555555, 0xAAAAAAAA, 0x00000000]) {
435 test(sampleCount, sampleMask);
440 function runTest() {
441 if (!gl) {
442 testFailed("WebGL context does not exist");
443 return;
445 testPassed("WebGL context exists");
447 runShaderTests(false);
449 ext = gl.getExtension("OES_sample_variables");
450 wtu.runExtensionSupportedTest(gl, "OES_sample_variables", ext !== null);
452 if (!ext) {
453 testPassed("No OES_sample_variables support -- this is legal");
454 } else {
455 testPassed("Successfully enabled OES_sample_variables extension");
456 runShaderTests(true);
458 debug("Testing sample variables");
459 runMaxSamplesTest();
460 runNumSamplesTest();
461 runSampleIDTest();
462 runSampleMaskInTest();
463 runSampleMaskInPerSampleTest();
464 runSampleMaskTest();
468 runTest();
470 var successfullyParsed = true;
471 </script>
472 <script src="../../js/js-test-post.js"></script>
473 </body>
474 </html>