Backed out changeset b462e7b742d8 (bug 1908261) for causing multiple reftest failures...
[gecko.git] / dom / canvas / test / webgl-conf / checkout / conformance / extensions / webgl-depth-texture.html
blobf2318cc1d35c7e1764c6de159a93987453955fe8
1 <!--
2 Copyright (c) 2019 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 -->
6 <!DOCTYPE html>
7 <html>
8 <head>
9 <meta charset="utf-8">
10 <link rel="stylesheet" href="../../resources/js-test-style.css"/>
11 <script src="../../js/js-test-pre.js"></script>
12 <script src="../../js/webgl-test-utils.js"></script>
13 <title>WebGL WEBGL_depth_texture Conformance Tests</title>
14 </head>
15 <body>
16 <script id="vshader" type="x-shader/x-vertex">
17 attribute vec4 a_position;
18 void main()
20 gl_Position = a_position;
22 </script>
24 <script id="fshader" type="x-shader/x-fragment">
25 precision mediump float;
26 uniform sampler2D u_texture;
27 uniform vec2 u_resolution;
28 void main()
30 vec2 texcoord = (gl_FragCoord.xy - vec2(0.5)) / (u_resolution - vec2(1.0));
31 gl_FragColor = texture2D(u_texture, texcoord);
33 </script>
34 <div id="description"></div>
35 <div id="console"></div>
36 <canvas id="canvas" width="8" height="8" style="width: 8px; height: 8px;"></canvas>
37 <script>
38 "use strict";
39 description("This test verifies the functionality of the WEBGL_depth_texture extension, if it is available.");
41 debug("");
43 var wtu = WebGLTestUtils;
44 var canvas = document.getElementById("canvas");
45 var gl = wtu.create3DContext(canvas, {antialias: false});
46 var program = wtu.setupTexturedQuad(gl);
47 var ext = null;
48 var vao = null;
49 var tex;
50 var name;
51 var supportedFormats;
52 var canvas2;
54 if (!gl) {
55 testFailed("WebGL context does not exist");
56 } else {
57 testPassed("WebGL context exists");
59 // Run tests with extension disabled
60 runTestDisabled();
62 // Query the extension and store globally so shouldBe can access it
63 ext = wtu.getExtensionWithKnownPrefixes(gl, "WEBGL_depth_texture");
64 if (!ext) {
65 testPassed("No WEBGL_depth_texture support -- this is legal");
66 runSupportedTest(false);
67 } else {
68 testPassed("Successfully enabled WEBGL_depth_texture extension");
70 runSupportedTest(true);
71 runTestExtension(true);
72 runTestExtension(false);
76 function runSupportedTest(extensionEnabled) {
77 var name = wtu.getSupportedExtensionWithKnownPrefixes(gl, "WEBGL_depth_texture");
78 if (name !== undefined) {
79 if (extensionEnabled) {
80 testPassed("WEBGL_depth_texture listed as supported and getExtension succeeded");
81 } else {
82 testFailed("WEBGL_depth_texture listed as supported but getExtension failed");
84 } else {
85 if (extensionEnabled) {
86 testFailed("WEBGL_depth_texture not listed as supported but getExtension succeeded");
87 } else {
88 testPassed("WEBGL_depth_texture not listed as supported and getExtension failed -- this is legal");
94 function runTestDisabled() {
95 debug("Testing binding enum with extension disabled");
97 var tex = gl.createTexture();
98 gl.bindTexture(gl.TEXTURE_2D, tex);
99 wtu.shouldGenerateGLError(gl, [gl.INVALID_ENUM, gl.INVALID_VALUE],
100 'gl.texImage2D(gl.TEXTURE_2D, 0, gl.DEPTH_COMPONENT, 1, 1, 0, gl.DEPTH_COMPONENT, gl.UNSIGNED_SHORT, null)');
101 wtu.shouldGenerateGLError(gl, [gl.INVALID_ENUM, gl.INVALID_VALUE],
102 'gl.texImage2D(gl.TEXTURE_2D, 0, gl.DEPTH_COMPONENT, 1, 1, 0, gl.DEPTH_COMPONENT, gl.UNSIGNED_INT, null)');
106 function dumpIt(gl, res, msg) {
107 return; // comment out to debug
108 debug(msg);
109 var actualPixels = new Uint8Array(res * res * 4);
110 gl.readPixels(0, 0, res, res, gl.RGBA, gl.UNSIGNED_BYTE, actualPixels);
112 for (var yy = 0; yy < res; ++yy) {
113 var strs = [];
114 for (var xx = 0; xx < res; ++xx) {
115 var actual = (yy * res + xx) * 4;
116 strs.push("(" + actualPixels[actual] + "," + actualPixels[actual+1] + "," + actualPixels[actual + 2] + "," + actualPixels[actual + 3] + ")");
118 debug(strs.join(" "));
121 function runTestExtension(unpackFlipY) {
122 debug("Testing WEBGL_depth_texture. UNPACK_FLIP_Y_WEBGL: " + unpackFlipY);
124 const res = 2;
125 const destRes = 4;
127 // make canvas for testing.
128 canvas2 = document.createElement("canvas");
129 canvas2.width = res;
130 canvas2.height = res;
131 var ctx = canvas2.getContext("2d");
132 ctx.fillStyle = "blue";
133 ctx.fillRect(0, 0, canvas2.width, canvas2.height);
135 var program = wtu.setupProgram(gl, ['vshader', 'fshader'], ['a_position']);
136 gl.useProgram(program);
137 gl.uniform2f(gl.getUniformLocation(program, "u_resolution"), destRes, destRes);
139 var buffer = gl.createBuffer();
140 gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
141 gl.bufferData(
142 gl.ARRAY_BUFFER,
143 new Float32Array(
144 [ 1, 1, 1,
145 -1, 1, 0,
146 -1, -1, -1,
147 1, 1, 1,
148 -1, -1, -1,
149 1, -1, 0,
151 gl.STATIC_DRAW);
152 gl.enableVertexAttribArray(0);
153 gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
155 gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, unpackFlipY);
157 var types = [
158 {obj: 'gl', attachment: 'DEPTH_ATTACHMENT', format: 'DEPTH_COMPONENT', type: 'UNSIGNED_SHORT', data: 'new Uint16Array(1)', depthBits: "16"},
159 {obj: 'gl', attachment: 'DEPTH_ATTACHMENT', format: 'DEPTH_COMPONENT', type: 'UNSIGNED_INT', data: 'new Uint32Array(1)', depthBits: "16"},
160 {obj: 'ext', attachment: 'DEPTH_STENCIL_ATTACHMENT', format: 'DEPTH_STENCIL', type: 'UNSIGNED_INT_24_8_WEBGL', data: 'new Uint32Array(1)', depthBits: "24", stencilBits: "8"}
163 for (var ii = 0; ii < types.length; ++ii) {
164 var typeInfo = types[ii];
165 var type = typeInfo.type;
166 var typeStr = typeInfo.obj + '.' + type;
168 debug("");
169 debug("testing: " + type);
171 // check that cubemaps are not allowed.
172 var cubeTex = gl.createTexture();
173 gl.bindTexture(gl.TEXTURE_CUBE_MAP, cubeTex);
174 var targets = [
175 'TEXTURE_CUBE_MAP_POSITIVE_X',
176 'TEXTURE_CUBE_MAP_NEGATIVE_X',
177 'TEXTURE_CUBE_MAP_POSITIVE_Y',
178 'TEXTURE_CUBE_MAP_NEGATIVE_Y',
179 'TEXTURE_CUBE_MAP_POSITIVE_Z',
180 'TEXTURE_CUBE_MAP_NEGATIVE_Z'
182 for (var tt = 0; tt < targets.length; ++tt) {
183 wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, 'gl.texImage2D(gl.' + targets[ii] + ', 0, gl.' + typeInfo.format + ', 1, 1, 0, gl.' + typeInfo.format + ', ' + typeStr + ', null)');
186 // The WebGL_depth_texture extension supports both NEAREST and
187 // LINEAR filtering for depth textures, even though LINEAR
188 // doesn't have much meaning, and isn't supported in WebGL
189 // 2.0. Still, test both.
190 var filterModes = [
191 'LINEAR',
192 'NEAREST'
195 for (var jj = 0; jj < filterModes.length; ++jj) {
196 debug('');
197 debug('testing ' + filterModes[jj] + ' filtering');
198 var filterMode = gl[filterModes[jj]];
200 // check 2d textures.
201 tex = gl.createTexture();
202 gl.bindTexture(gl.TEXTURE_2D, tex);
203 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
204 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
205 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, filterMode);
206 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, filterMode);
208 // test level > 0
209 wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, 'gl.texImage2D(gl.TEXTURE_2D, 1, gl.' + typeInfo.format + ', 1, 1, 0, gl.' + typeInfo.format + ', ' + typeStr + ', null)');
211 // test with data
212 wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, 'gl.texImage2D(gl.TEXTURE_2D, 0, gl.' + typeInfo.format + ', 1, 1, 0, gl.' + typeInfo.format + ', ' + typeStr + ', ' + typeInfo.data + ')');
214 // test with canvas
215 wtu.shouldGenerateGLError(gl, [gl.INVALID_VALUE, gl.INVALID_ENUM, gl.INVALID_OPERATION], 'gl.texImage2D(gl.TEXTURE_2D, 0, gl.' + typeInfo.format + ', gl.' + typeInfo.format + ', ' + typeStr + ', canvas2)');
217 // test copyTexImage2D
218 wtu.shouldGenerateGLError(gl, [gl.INVALID_ENUM, gl.INVALID_OPERATION], 'gl.copyTexImage2D(gl.TEXTURE_2D, 0, gl.' + typeInfo.format + ', 0, 0, 1, 1, 0)');
220 // test real thing
221 wtu.shouldGenerateGLError(gl, gl.NO_ERROR, 'gl.texImage2D(gl.TEXTURE_2D, 0, gl.' + typeInfo.format + ', ' + res + ', ' + res + ', 0, gl.' + typeInfo.format + ', ' + typeStr + ', null)');
223 // test texSubImage2D
224 wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, 'gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 1, 1, gl.' + typeInfo.format + ', ' + typeStr + ', ' + typeInfo.data + ')');
226 // test copyTexSubImage2D
227 wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, 'gl.copyTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1)');
229 // test generateMipmap
230 wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, 'gl.generateMipmap(gl.TEXTURE_2D)');
232 var fbo = gl.createFramebuffer();
233 gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
234 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl[typeInfo.attachment], gl.TEXTURE_2D, tex, 0);
236 // Ensure DEPTH_BITS returns >= 16 bits for UNSIGNED_SHORT and UNSIGNED_INT, >= 24 UNSIGNED_INT_24_8_WEBGL.
237 // If there is stencil, ensure STENCIL_BITS reports >= 8 for UNSIGNED_INT_24_8_WEBGL.
238 shouldBeGreaterThanOrEqual('gl.getParameter(gl.DEPTH_BITS)', typeInfo.depthBits);
239 if (typeInfo.stencilBits === undefined) {
240 shouldBe('gl.getParameter(gl.STENCIL_BITS)', '0');
241 } else {
242 shouldBeGreaterThanOrEqual('gl.getParameter(gl.STENCIL_BITS)', typeInfo.stencilBits);
245 // TODO: remove this check if the spec is updated to require these combinations to work.
246 if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE)
248 // try adding a color buffer.
249 var colorTex = gl.createTexture();
250 gl.bindTexture(gl.TEXTURE_2D, colorTex);
251 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
252 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
253 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
254 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
255 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, res, res, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
256 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, colorTex, 0);
259 shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
261 // use the default texture to render with while we return to the depth texture.
262 gl.bindTexture(gl.TEXTURE_2D, null);
264 /* Setup 2x2 depth texture:
265 * 1 0.6 0.8
267 * 0 0.2 0.4
268 * 0---1
270 const d00 = 0.2;
271 const d01 = 0.4;
272 const d10 = 0.6;
273 const d11 = 0.8;
275 gl.enable(gl.SCISSOR_TEST);
277 gl.scissor(0, 0, 1, 1);
278 gl.clearDepth(d00);
279 gl.clear(gl.DEPTH_BUFFER_BIT);
281 gl.scissor(1, 0, 1, 1);
282 gl.clearDepth(d10);
283 gl.clear(gl.DEPTH_BUFFER_BIT);
285 gl.scissor(0, 1, 1, 1);
286 gl.clearDepth(d01);
287 gl.clear(gl.DEPTH_BUFFER_BIT);
289 gl.scissor(1, 1, 1, 1);
290 gl.clearDepth(d11);
291 gl.clear(gl.DEPTH_BUFFER_BIT);
293 gl.disable(gl.SCISSOR_TEST);
295 // render the depth texture.
296 gl.bindFramebuffer(gl.FRAMEBUFFER, null);
297 gl.canvas.width = destRes;
298 gl.canvas.height = destRes;
299 gl.viewport(0, 0, destRes, destRes);
300 gl.bindTexture(gl.TEXTURE_2D, tex);
302 gl.disable(gl.DITHER);
303 gl.enable(gl.DEPTH_TEST);
304 gl.clearColor(1, 0, 0, 1);
305 gl.clearDepth(1.0);
306 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
307 gl.drawArrays(gl.TRIANGLES, 0, 6);
309 dumpIt(gl, res, "--depth--");
311 var actualPixels = new Uint8Array(destRes * destRes * 4);
312 gl.readPixels(0, 0, destRes, destRes, gl.RGBA, gl.UNSIGNED_BYTE, actualPixels);
314 const eps = 0.002;
316 let expectedMin;
317 let expectedMax;
318 if (filterMode == gl.NEAREST) {
319 expectedMin = [
320 d00, d00, d10, d10,
321 d00, d00, d10, d10,
322 d01, d01, d11, d11,
323 d01, d01, d11, d11
325 expectedMax = expectedMin.slice();
327 expectedMin = expectedMin.map(x => x - eps);
328 expectedMax = expectedMax.map(x => x + eps);
329 } else {
330 expectedMin = [
331 d00-eps, d00, d00, d10-eps,
332 d00, d00, d00, d10,
333 d00, d00, d00, d10,
334 d01-eps, d01, d01, d11-eps,
336 expectedMax = [
337 d00+eps, d10, d10, d10+eps,
338 d01, d11, d11, d11,
339 d01, d11, d11, d11,
340 d01+eps, d11, d11, d11+eps,
344 for (var yy = 0; yy < destRes; ++yy) {
345 for (var xx = 0; xx < destRes; ++xx) {
346 const t = xx + destRes*yy;
347 const was = actualPixels[4*t] / 255.0; // 4bpp
348 const eMin = expectedMin[t];
349 const eMax = expectedMax[t];
350 let func = testPassed;
351 const text = `At ${xx},${yy}, expected within [${eMin},${eMax}], was ${was.toFixed(3)}`
352 if (was <= eMin || was >= eMax) {
353 func = testFailed;
355 func(text);
359 // check limitations
360 gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
361 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl[typeInfo.attachment], gl.TEXTURE_2D, null, 0);
362 var badAttachment = typeInfo.attachment == 'DEPTH_ATTACHMENT' ? 'DEPTH_STENCIL_ATTACHMENT' : 'DEPTH_ATTACHMENT';
363 wtu.shouldGenerateGLError(gl, gl.NO_ERROR, 'gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.' + badAttachment + ', gl.TEXTURE_2D, tex, 0)');
364 shouldNotBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE');
365 wtu.shouldGenerateGLError(gl, gl.INVALID_FRAMEBUFFER_OPERATION, 'gl.clear(gl.DEPTH_BUFFER_BIT)');
366 gl.bindFramebuffer(gl.FRAMEBUFFER, null);
367 shouldBe('gl.getError()', 'gl.NO_ERROR');
372 debug("");
373 var successfullyParsed = true;
374 </script>
375 <script src="../../js/js-test-post.js"></script>
376 </body>
377 </html>