diff options
Diffstat (limited to 'dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-depth-texture.html')
-rw-r--r-- | dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-depth-texture.html | 377 |
1 files changed, 377 insertions, 0 deletions
diff --git a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-depth-texture.html b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-depth-texture.html new file mode 100644 index 0000000000..f2318cc1d3 --- /dev/null +++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/webgl-depth-texture.html @@ -0,0 +1,377 @@ +<!-- +Copyright (c) 2019 The Khronos Group Inc. +Use of this source code is governed by an MIT-style license that can be +found in the LICENSE.txt file. +--> +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<link rel="stylesheet" href="../../resources/js-test-style.css"/> +<script src="../../js/js-test-pre.js"></script> +<script src="../../js/webgl-test-utils.js"></script> +<title>WebGL WEBGL_depth_texture Conformance Tests</title> +</head> +<body> +<script id="vshader" type="x-shader/x-vertex"> +attribute vec4 a_position; +void main() +{ + gl_Position = a_position; +} +</script> + +<script id="fshader" type="x-shader/x-fragment"> +precision mediump float; +uniform sampler2D u_texture; +uniform vec2 u_resolution; +void main() +{ + vec2 texcoord = (gl_FragCoord.xy - vec2(0.5)) / (u_resolution - vec2(1.0)); + gl_FragColor = texture2D(u_texture, texcoord); +} +</script> +<div id="description"></div> +<div id="console"></div> +<canvas id="canvas" width="8" height="8" style="width: 8px; height: 8px;"></canvas> +<script> +"use strict"; +description("This test verifies the functionality of the WEBGL_depth_texture extension, if it is available."); + +debug(""); + +var wtu = WebGLTestUtils; +var canvas = document.getElementById("canvas"); +var gl = wtu.create3DContext(canvas, {antialias: false}); +var program = wtu.setupTexturedQuad(gl); +var ext = null; +var vao = null; +var tex; +var name; +var supportedFormats; +var canvas2; + +if (!gl) { + testFailed("WebGL context does not exist"); +} else { + testPassed("WebGL context exists"); + + // Run tests with extension disabled + runTestDisabled(); + + // Query the extension and store globally so shouldBe can access it + ext = wtu.getExtensionWithKnownPrefixes(gl, "WEBGL_depth_texture"); + if (!ext) { + testPassed("No WEBGL_depth_texture support -- this is legal"); + runSupportedTest(false); + } else { + testPassed("Successfully enabled WEBGL_depth_texture extension"); + + runSupportedTest(true); + runTestExtension(true); + runTestExtension(false); + } +} + +function runSupportedTest(extensionEnabled) { + var name = wtu.getSupportedExtensionWithKnownPrefixes(gl, "WEBGL_depth_texture"); + if (name !== undefined) { + if (extensionEnabled) { + testPassed("WEBGL_depth_texture listed as supported and getExtension succeeded"); + } else { + testFailed("WEBGL_depth_texture listed as supported but getExtension failed"); + } + } else { + if (extensionEnabled) { + testFailed("WEBGL_depth_texture not listed as supported but getExtension succeeded"); + } else { + testPassed("WEBGL_depth_texture not listed as supported and getExtension failed -- this is legal"); + } + } +} + + +function runTestDisabled() { + debug("Testing binding enum with extension disabled"); + + var tex = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, tex); + wtu.shouldGenerateGLError(gl, [gl.INVALID_ENUM, gl.INVALID_VALUE], + 'gl.texImage2D(gl.TEXTURE_2D, 0, gl.DEPTH_COMPONENT, 1, 1, 0, gl.DEPTH_COMPONENT, gl.UNSIGNED_SHORT, null)'); + wtu.shouldGenerateGLError(gl, [gl.INVALID_ENUM, gl.INVALID_VALUE], + 'gl.texImage2D(gl.TEXTURE_2D, 0, gl.DEPTH_COMPONENT, 1, 1, 0, gl.DEPTH_COMPONENT, gl.UNSIGNED_INT, null)'); +} + + +function dumpIt(gl, res, msg) { + return; // comment out to debug + debug(msg); + var actualPixels = new Uint8Array(res * res * 4); + gl.readPixels(0, 0, res, res, gl.RGBA, gl.UNSIGNED_BYTE, actualPixels); + + for (var yy = 0; yy < res; ++yy) { + var strs = []; + for (var xx = 0; xx < res; ++xx) { + var actual = (yy * res + xx) * 4; + strs.push("(" + actualPixels[actual] + "," + actualPixels[actual+1] + "," + actualPixels[actual + 2] + "," + actualPixels[actual + 3] + ")"); + } + debug(strs.join(" ")); + } +} +function runTestExtension(unpackFlipY) { + debug("Testing WEBGL_depth_texture. UNPACK_FLIP_Y_WEBGL: " + unpackFlipY); + + const res = 2; + const destRes = 4; + + // make canvas for testing. + canvas2 = document.createElement("canvas"); + canvas2.width = res; + canvas2.height = res; + var ctx = canvas2.getContext("2d"); + ctx.fillStyle = "blue"; + ctx.fillRect(0, 0, canvas2.width, canvas2.height); + + var program = wtu.setupProgram(gl, ['vshader', 'fshader'], ['a_position']); + gl.useProgram(program); + gl.uniform2f(gl.getUniformLocation(program, "u_resolution"), destRes, destRes); + + var buffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, buffer); + gl.bufferData( + gl.ARRAY_BUFFER, + new Float32Array( + [ 1, 1, 1, + -1, 1, 0, + -1, -1, -1, + 1, 1, 1, + -1, -1, -1, + 1, -1, 0, + ]), + gl.STATIC_DRAW); + gl.enableVertexAttribArray(0); + gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0); + + gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, unpackFlipY); + + var types = [ + {obj: 'gl', attachment: 'DEPTH_ATTACHMENT', format: 'DEPTH_COMPONENT', type: 'UNSIGNED_SHORT', data: 'new Uint16Array(1)', depthBits: "16"}, + {obj: 'gl', attachment: 'DEPTH_ATTACHMENT', format: 'DEPTH_COMPONENT', type: 'UNSIGNED_INT', data: 'new Uint32Array(1)', depthBits: "16"}, + {obj: 'ext', attachment: 'DEPTH_STENCIL_ATTACHMENT', format: 'DEPTH_STENCIL', type: 'UNSIGNED_INT_24_8_WEBGL', data: 'new Uint32Array(1)', depthBits: "24", stencilBits: "8"} + ]; + + for (var ii = 0; ii < types.length; ++ii) { + var typeInfo = types[ii]; + var type = typeInfo.type; + var typeStr = typeInfo.obj + '.' + type; + + debug(""); + debug("testing: " + type); + + // check that cubemaps are not allowed. + var cubeTex = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_CUBE_MAP, cubeTex); + var targets = [ + 'TEXTURE_CUBE_MAP_POSITIVE_X', + 'TEXTURE_CUBE_MAP_NEGATIVE_X', + 'TEXTURE_CUBE_MAP_POSITIVE_Y', + 'TEXTURE_CUBE_MAP_NEGATIVE_Y', + 'TEXTURE_CUBE_MAP_POSITIVE_Z', + 'TEXTURE_CUBE_MAP_NEGATIVE_Z' + ]; + for (var tt = 0; tt < targets.length; ++tt) { + wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, 'gl.texImage2D(gl.' + targets[ii] + ', 0, gl.' + typeInfo.format + ', 1, 1, 0, gl.' + typeInfo.format + ', ' + typeStr + ', null)'); + } + + // The WebGL_depth_texture extension supports both NEAREST and + // LINEAR filtering for depth textures, even though LINEAR + // doesn't have much meaning, and isn't supported in WebGL + // 2.0. Still, test both. + var filterModes = [ + 'LINEAR', + 'NEAREST' + ]; + + for (var jj = 0; jj < filterModes.length; ++jj) { + debug(''); + debug('testing ' + filterModes[jj] + ' filtering'); + var filterMode = gl[filterModes[jj]]; + + // check 2d textures. + tex = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, tex); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, filterMode); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, filterMode); + + // test level > 0 + wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, 'gl.texImage2D(gl.TEXTURE_2D, 1, gl.' + typeInfo.format + ', 1, 1, 0, gl.' + typeInfo.format + ', ' + typeStr + ', null)'); + + // test with data + wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, 'gl.texImage2D(gl.TEXTURE_2D, 0, gl.' + typeInfo.format + ', 1, 1, 0, gl.' + typeInfo.format + ', ' + typeStr + ', ' + typeInfo.data + ')'); + + // test with canvas + 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)'); + + // test copyTexImage2D + wtu.shouldGenerateGLError(gl, [gl.INVALID_ENUM, gl.INVALID_OPERATION], 'gl.copyTexImage2D(gl.TEXTURE_2D, 0, gl.' + typeInfo.format + ', 0, 0, 1, 1, 0)'); + + // test real thing + wtu.shouldGenerateGLError(gl, gl.NO_ERROR, 'gl.texImage2D(gl.TEXTURE_2D, 0, gl.' + typeInfo.format + ', ' + res + ', ' + res + ', 0, gl.' + typeInfo.format + ', ' + typeStr + ', null)'); + + // test texSubImage2D + wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, 'gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 1, 1, gl.' + typeInfo.format + ', ' + typeStr + ', ' + typeInfo.data + ')'); + + // test copyTexSubImage2D + wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, 'gl.copyTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1)'); + + // test generateMipmap + wtu.shouldGenerateGLError(gl, gl.INVALID_OPERATION, 'gl.generateMipmap(gl.TEXTURE_2D)'); + + var fbo = gl.createFramebuffer(); + gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl[typeInfo.attachment], gl.TEXTURE_2D, tex, 0); + + // Ensure DEPTH_BITS returns >= 16 bits for UNSIGNED_SHORT and UNSIGNED_INT, >= 24 UNSIGNED_INT_24_8_WEBGL. + // If there is stencil, ensure STENCIL_BITS reports >= 8 for UNSIGNED_INT_24_8_WEBGL. + shouldBeGreaterThanOrEqual('gl.getParameter(gl.DEPTH_BITS)', typeInfo.depthBits); + if (typeInfo.stencilBits === undefined) { + shouldBe('gl.getParameter(gl.STENCIL_BITS)', '0'); + } else { + shouldBeGreaterThanOrEqual('gl.getParameter(gl.STENCIL_BITS)', typeInfo.stencilBits); + } + + // TODO: remove this check if the spec is updated to require these combinations to work. + if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) + { + // try adding a color buffer. + var colorTex = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, colorTex); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, res, res, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, colorTex, 0); + } + + shouldBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE'); + + // use the default texture to render with while we return to the depth texture. + gl.bindTexture(gl.TEXTURE_2D, null); + + /* Setup 2x2 depth texture: + * 1 0.6 0.8 + * | + * 0 0.2 0.4 + * 0---1 + */ + const d00 = 0.2; + const d01 = 0.4; + const d10 = 0.6; + const d11 = 0.8; + + gl.enable(gl.SCISSOR_TEST); + + gl.scissor(0, 0, 1, 1); + gl.clearDepth(d00); + gl.clear(gl.DEPTH_BUFFER_BIT); + + gl.scissor(1, 0, 1, 1); + gl.clearDepth(d10); + gl.clear(gl.DEPTH_BUFFER_BIT); + + gl.scissor(0, 1, 1, 1); + gl.clearDepth(d01); + gl.clear(gl.DEPTH_BUFFER_BIT); + + gl.scissor(1, 1, 1, 1); + gl.clearDepth(d11); + gl.clear(gl.DEPTH_BUFFER_BIT); + + gl.disable(gl.SCISSOR_TEST); + + // render the depth texture. + gl.bindFramebuffer(gl.FRAMEBUFFER, null); + gl.canvas.width = destRes; + gl.canvas.height = destRes; + gl.viewport(0, 0, destRes, destRes); + gl.bindTexture(gl.TEXTURE_2D, tex); + + gl.disable(gl.DITHER); + gl.enable(gl.DEPTH_TEST); + gl.clearColor(1, 0, 0, 1); + gl.clearDepth(1.0); + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); + gl.drawArrays(gl.TRIANGLES, 0, 6); + + dumpIt(gl, res, "--depth--"); + + var actualPixels = new Uint8Array(destRes * destRes * 4); + gl.readPixels(0, 0, destRes, destRes, gl.RGBA, gl.UNSIGNED_BYTE, actualPixels); + + const eps = 0.002; + + let expectedMin; + let expectedMax; + if (filterMode == gl.NEAREST) { + expectedMin = [ + d00, d00, d10, d10, + d00, d00, d10, d10, + d01, d01, d11, d11, + d01, d01, d11, d11 + ]; + expectedMax = expectedMin.slice(); + + expectedMin = expectedMin.map(x => x - eps); + expectedMax = expectedMax.map(x => x + eps); + } else { + expectedMin = [ + d00-eps, d00, d00, d10-eps, + d00, d00, d00, d10, + d00, d00, d00, d10, + d01-eps, d01, d01, d11-eps, + ]; + expectedMax = [ + d00+eps, d10, d10, d10+eps, + d01, d11, d11, d11, + d01, d11, d11, d11, + d01+eps, d11, d11, d11+eps, + ]; + } + + for (var yy = 0; yy < destRes; ++yy) { + for (var xx = 0; xx < destRes; ++xx) { + const t = xx + destRes*yy; + const was = actualPixels[4*t] / 255.0; // 4bpp + const eMin = expectedMin[t]; + const eMax = expectedMax[t]; + let func = testPassed; + const text = `At ${xx},${yy}, expected within [${eMin},${eMax}], was ${was.toFixed(3)}` + if (was <= eMin || was >= eMax) { + func = testFailed; + } + func(text); + } + } + + // check limitations + gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); + gl.framebufferTexture2D(gl.FRAMEBUFFER, gl[typeInfo.attachment], gl.TEXTURE_2D, null, 0); + var badAttachment = typeInfo.attachment == 'DEPTH_ATTACHMENT' ? 'DEPTH_STENCIL_ATTACHMENT' : 'DEPTH_ATTACHMENT'; + wtu.shouldGenerateGLError(gl, gl.NO_ERROR, 'gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.' + badAttachment + ', gl.TEXTURE_2D, tex, 0)'); + shouldNotBe('gl.checkFramebufferStatus(gl.FRAMEBUFFER)', 'gl.FRAMEBUFFER_COMPLETE'); + wtu.shouldGenerateGLError(gl, gl.INVALID_FRAMEBUFFER_OPERATION, 'gl.clear(gl.DEPTH_BUFFER_BIT)'); + gl.bindFramebuffer(gl.FRAMEBUFFER, null); + shouldBe('gl.getError()', 'gl.NO_ERROR'); + } + } +} + +debug(""); +var successfullyParsed = true; +</script> +<script src="../../js/js-test-post.js"></script> +</body> +</html> |