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.
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>
16 <script id=
"vshader" type=
"x-shader/x-vertex">
17 attribute vec4 a_position;
20 gl_Position = a_position;
24 <script id=
"fshader" type=
"x-shader/x-fragment">
25 precision mediump float;
26 uniform sampler2D u_texture;
27 uniform vec2 u_resolution;
30 vec2 texcoord = (gl_FragCoord.xy - vec2(
0.5)) / (u_resolution - vec2(
1.0));
31 gl_FragColor = texture2D(u_texture, texcoord);
34 <div id=
"description"></div>
35 <div id=
"console"></div>
36 <canvas id=
"canvas" width=
"8" height=
"8" style=
"width: 8px; height: 8px;"></canvas>
39 description("This test verifies the functionality of the WEBGL_depth_texture extension, if it is available.");
43 var wtu
= WebGLTestUtils
;
44 var canvas
= document
.getElementById("canvas");
45 var gl
= wtu
.create3DContext(canvas
, {antialias
: false});
46 var program
= wtu
.setupTexturedQuad(gl
);
55 testFailed("WebGL context does not exist");
57 testPassed("WebGL context exists");
59 // Run tests with extension disabled
62 // Query the extension and store globally so shouldBe can access it
63 ext
= wtu
.getExtensionWithKnownPrefixes(gl
, "WEBGL_depth_texture");
65 testPassed("No WEBGL_depth_texture support -- this is legal");
66 runSupportedTest(false);
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");
82 testFailed("WEBGL_depth_texture listed as supported but getExtension failed");
85 if (extensionEnabled
) {
86 testFailed("WEBGL_depth_texture not listed as supported but getExtension succeeded");
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
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
) {
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
);
127 // make canvas for testing.
128 canvas2
= document
.createElement("canvas");
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
);
152 gl
.enableVertexAttribArray(0);
153 gl
.vertexAttribPointer(0, 3, gl
.FLOAT
, false, 0, 0);
155 gl
.pixelStorei(gl
.UNPACK_FLIP_Y_WEBGL
, unpackFlipY
);
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
;
169 debug("testing: " + type
);
171 // check that cubemaps are not allowed.
172 var cubeTex
= gl
.createTexture();
173 gl
.bindTexture(gl
.TEXTURE_CUBE_MAP
, cubeTex
);
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.
195 for (var jj
= 0; jj
< filterModes
.length
; ++jj
) {
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
);
209 wtu
.shouldGenerateGLError(gl
, gl
.INVALID_OPERATION
, 'gl.texImage2D(gl.TEXTURE_2D, 1, gl.' + typeInfo
.format
+ ', 1, 1, 0, gl.' + typeInfo
.format
+ ', ' + typeStr
+ ', null)');
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
+ ')');
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)');
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');
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:
275 gl
.enable(gl
.SCISSOR_TEST
);
277 gl
.scissor(0, 0, 1, 1);
279 gl
.clear(gl
.DEPTH_BUFFER_BIT
);
281 gl
.scissor(1, 0, 1, 1);
283 gl
.clear(gl
.DEPTH_BUFFER_BIT
);
285 gl
.scissor(0, 1, 1, 1);
287 gl
.clear(gl
.DEPTH_BUFFER_BIT
);
289 gl
.scissor(1, 1, 1, 1);
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);
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
);
318 if (filterMode
== gl
.NEAREST
) {
325 expectedMax
= expectedMin
.slice();
327 expectedMin
= expectedMin
.map(x
=> x
- eps
);
328 expectedMax
= expectedMax
.map(x
=> x
+ eps
);
331 d00
-eps
, d00
, d00
, d10
-eps
,
334 d01
-eps
, d01
, d01
, d11
-eps
,
337 d00
+eps
, d10
, d10
, d10
+eps
,
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
) {
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');
373 var successfullyParsed
= true;
375 <script src=
"../../js/js-test-post.js"></script>