webgl-stencil-texturing.html (13101B)
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 --> 6 7 <!DOCTYPE html> 8 <html> 9 <head> 10 <meta charset="utf-8"> 11 <title>WebGL WEBGL_stencil_texturing 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 <div id="description"></div> 18 <div id="console"></div> 19 <script> 20 "use strict"; 21 description("This test verifies the functionality of the WEBGL_stencil_texturing extension, if it is available."); 22 23 debug(""); 24 25 var wtu = WebGLTestUtils; 26 var gl = wtu.create3DContext(null, null, 2); 27 var ext; 28 29 function runTestNoExtension() { 30 debug(""); 31 debug("Check the texture parameter without the extension"); 32 33 const tex = gl.createTexture(); 34 gl.bindTexture(gl.TEXTURE_2D, tex); 35 36 shouldBeNull("gl.getTexParameter(gl.TEXTURE_2D, 0x90EA /* DEPTH_STENCIL_TEXTURE_MODE_WEBGL */)"); 37 wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "parameter unknown without enabling the extension"); 38 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no more errors"); 39 40 gl.texParameteri(gl.TEXTURE_2D, 0x90EA /* DEPTH_STENCIL_TEXTURE_MODE_WEBGL */, gl.DEPTH_COMPONENT); 41 wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "parameter unknown for texParameteri without enabling the extension"); 42 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no more errors"); 43 44 gl.texParameterf(gl.TEXTURE_2D, 0x90EA /* DEPTH_STENCIL_TEXTURE_MODE_WEBGL */, gl.DEPTH_COMPONENT); 45 wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "parameter unknown for texParameterf without enabling the extension"); 46 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no more errors"); 47 48 const sampler = gl.createSampler(); 49 gl.samplerParameteri(sampler, 0x90EA /* DEPTH_STENCIL_TEXTURE_MODE_WEBGL */, gl.DEPTH_COMPONENT); 50 wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "parameter unknown for samplerParameteri"); 51 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no more errors"); 52 gl.samplerParameterf(sampler, 0x90EA /* DEPTH_STENCIL_TEXTURE_MODE_WEBGL */, gl.DEPTH_COMPONENT); 53 wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "parameter unknown for samplerParameterf"); 54 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no more errors"); 55 } 56 57 function checkEnums() { 58 debug(""); 59 debug("Check enums"); 60 shouldBe("ext.DEPTH_STENCIL_TEXTURE_MODE_WEBGL", "0x90EA"); 61 shouldBe("ext.STENCIL_INDEX_WEBGL", "0x1901"); 62 } 63 64 function checkQueries() { 65 const tex = gl.createTexture(); 66 gl.bindTexture(gl.TEXTURE_2D, tex); 67 68 debug(""); 69 debug("Check default texture state"); 70 shouldBe('gl.getTexParameter(gl.TEXTURE_2D, ext.DEPTH_STENCIL_TEXTURE_MODE_WEBGL)', 'gl.DEPTH_COMPONENT'); 71 debug(""); 72 debug("Check texture state updates using texParameteri"); 73 gl.texParameteri(gl.TEXTURE_2D, ext.DEPTH_STENCIL_TEXTURE_MODE_WEBGL, ext.STENCIL_INDEX_WEBGL); 74 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); 75 shouldBe('gl.getTexParameter(gl.TEXTURE_2D, ext.DEPTH_STENCIL_TEXTURE_MODE_WEBGL)', 'ext.STENCIL_INDEX_WEBGL'); 76 gl.texParameteri(gl.TEXTURE_2D, ext.DEPTH_STENCIL_TEXTURE_MODE_WEBGL, gl.DEPTH_COMPONENT); 77 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); 78 shouldBe('gl.getTexParameter(gl.TEXTURE_2D, ext.DEPTH_STENCIL_TEXTURE_MODE_WEBGL)', 'gl.DEPTH_COMPONENT'); 79 gl.texParameteri(gl.TEXTURE_2D, ext.DEPTH_STENCIL_TEXTURE_MODE_WEBGL, 0); 80 wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "invalid depth stencil mode value rejected by texParameteri"); 81 shouldBe('gl.getTexParameter(gl.TEXTURE_2D, ext.DEPTH_STENCIL_TEXTURE_MODE_WEBGL)', 'gl.DEPTH_COMPONENT'); 82 debug(""); 83 debug("Check texture state updates using texParameterf"); 84 gl.texParameterf(gl.TEXTURE_2D, ext.DEPTH_STENCIL_TEXTURE_MODE_WEBGL, ext.STENCIL_INDEX_WEBGL); 85 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); 86 shouldBe('gl.getTexParameter(gl.TEXTURE_2D, ext.DEPTH_STENCIL_TEXTURE_MODE_WEBGL)', 'ext.STENCIL_INDEX_WEBGL'); 87 gl.texParameterf(gl.TEXTURE_2D, ext.DEPTH_STENCIL_TEXTURE_MODE_WEBGL, gl.DEPTH_COMPONENT); 88 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); 89 shouldBe('gl.getTexParameter(gl.TEXTURE_2D, ext.DEPTH_STENCIL_TEXTURE_MODE_WEBGL)', 'gl.DEPTH_COMPONENT'); 90 gl.texParameterf(gl.TEXTURE_2D, ext.DEPTH_STENCIL_TEXTURE_MODE_WEBGL, 0); 91 wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "invalid depth stencil mode value rejected by texParameterf"); 92 shouldBe('gl.getTexParameter(gl.TEXTURE_2D, ext.DEPTH_STENCIL_TEXTURE_MODE_WEBGL)', 'gl.DEPTH_COMPONENT'); 93 94 debug(""); 95 debug("Check that depth stencil texture mode is not accepted as a sampler state"); 96 const sampler = gl.createSampler(); 97 gl.samplerParameteri(sampler, ext.DEPTH_STENCIL_TEXTURE_MODE_WEBGL, gl.DEPTH_COMPONENT); 98 wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "parameter unknown for samplerParameteri"); 99 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no more errors"); 100 gl.samplerParameterf(sampler, ext.DEPTH_STENCIL_TEXTURE_MODE_WEBGL, gl.DEPTH_COMPONENT); 101 wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "parameter unknown for samplerParameterf"); 102 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no more errors"); 103 } 104 105 function checkSampling() { 106 const formats = [ 107 {name: "DEPTH_COMPONENT16", internalFormat: gl.DEPTH_COMPONENT16, 108 format: gl.DEPTH_COMPONENT, type: gl.UNSIGNED_SHORT}, 109 {name: "DEPTH_COMPONENT24", internalFormat: gl.DEPTH_COMPONENT24, 110 format: gl.DEPTH_COMPONENT, type: gl.UNSIGNED_INT}, 111 {name: "DEPTH_COMPONENT32F", internalFormat: gl.DEPTH_COMPONENT32F, 112 format: gl.DEPTH_COMPONENT, type: gl.FLOAT}, 113 {name: "DEPTH24_STENCIL8", internalFormat: gl.DEPTH24_STENCIL8, 114 format: gl.DEPTH_STENCIL, type: gl.UNSIGNED_INT_24_8}, 115 {name: "DEPTH32F_STENCIL8", internalFormat: gl.DEPTH32F_STENCIL8, 116 format: gl.DEPTH_STENCIL, type: gl.FLOAT_32_UNSIGNED_INT_24_8_REV} 117 ]; 118 119 gl.enable(gl.DEPTH_TEST); 120 gl.enable(gl.STENCIL_TEST); 121 gl.stencilFunc(gl.ALWAYS, 170, 0xFF); 122 gl.stencilOp(gl.REPLACE, gl.REPLACE, gl.REPLACE); 123 124 wtu.setupUnitQuad(gl); 125 126 const drawProgram = wtu.setupProgram(gl, [wtu.simpleVertexShader, 127 wtu.simpleColorFragmentShader]); 128 129 const readDepthProgram = wtu.setupProgram(gl, [wtu.simpleTextureVertexShaderESSL300, 130 wtu.simpleTextureFragmentShaderESSL300]); 131 132 const readStencilShader = `#version 300 es 133 precision highp float; 134 uniform highp usampler2D tex; 135 in vec2 texCoord; 136 out vec4 out_color; 137 void main() { 138 out_color = vec4(texture(tex, texCoord)) / 255.0; 139 }`; 140 const readStencilProgram = wtu.setupProgram(gl, [wtu.simpleTextureVertexShaderESSL300, 141 readStencilShader]); 142 143 for (const format of formats) { 144 debug(""); 145 debug(`Testing depth stencil texture modes with ${format.name}`); 146 const fbo = gl.createFramebuffer(); 147 gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); 148 149 const rbo = gl.createRenderbuffer(); 150 gl.bindRenderbuffer(gl.RENDERBUFFER, rbo); 151 gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA8, 1, 1); 152 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rbo); 153 154 const tex = gl.createTexture(); 155 gl.bindTexture(gl.TEXTURE_2D, tex); 156 gl.texImage2D(gl.TEXTURE_2D, 0, format.internalFormat, 1, 1, 0, format.format, format.type, null); 157 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "texture created"); 158 159 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_2D, tex, 0); 160 if (format.format == gl.DEPTH_STENCIL) { 161 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.TEXTURE_2D, tex, 0); 162 } 163 wtu.framebufferStatusShouldBe(gl, gl.FRAMEBUFFER, gl.FRAMEBUFFER_COMPLETE); 164 165 gl.clear(gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT); 166 gl.useProgram(drawProgram); 167 wtu.drawUnitQuad(gl); 168 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "no errors after drawing to the depth or depth stencil texture"); 169 170 // Detach the depth or depth stencil texture to avoid feedback loop 171 gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, null); 172 wtu.framebufferStatusShouldBe(gl, gl.FRAMEBUFFER, gl.FRAMEBUFFER_COMPLETE); 173 174 const magFilters = ['NEAREST', 'LINEAR']; 175 176 const minFilters = [ 177 'NEAREST', 178 'LINEAR', 179 'NEAREST_MIPMAP_NEAREST', 180 'LINEAR_MIPMAP_NEAREST', 181 'NEAREST_MIPMAP_LINEAR', 182 'LINEAR_MIPMAP_LINEAR' 183 ]; 184 185 const modes = [ 186 [gl.DEPTH_COMPONENT, 'DEPTH_COMPONENT'], 187 [ext.STENCIL_INDEX_WEBGL, 'STENCIL_INDEX_WEBGL'] 188 ]; 189 190 const programs = [ 191 [readDepthProgram, 'depth'], 192 [readStencilProgram, 'stencil'] 193 ]; 194 195 function validFilters(magFilter, minFilter) { 196 return magFilter == gl.NEAREST && 197 (minFilter == gl.NEAREST || minFilter == gl.NEAREST_MIPMAP_NEAREST); 198 } 199 200 for (const program of programs) { 201 gl.useProgram(program[0]); 202 for (const mode of modes) { 203 gl.texParameteri(gl.TEXTURE_2D, ext.DEPTH_STENCIL_TEXTURE_MODE_WEBGL, mode[0]); 204 for (const magFilter of magFilters) { 205 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl[magFilter]); 206 for (const minFilter of minFilters) { 207 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl[minFilter]); 208 debug(`Program: ${program[1]}, mode: ${mode[1]}, mag: ${magFilter}, min: ${minFilter}`); 209 210 gl.clear(gl.COLOR_BUFFER_BIT); 211 wtu.drawUnitQuad(gl); 212 213 if (format.format == gl.DEPTH_COMPONENT || mode[0] == gl.DEPTH_COMPONENT) { 214 if (program[1] == 'depth') { 215 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); 216 if (validFilters(gl[magFilter], gl[minFilter])) { 217 wtu.checkCanvasRect(gl, 0, 0, 1, 1, [128, 0, 0, 255], "sampling depth from complete texture", 1); 218 } else { 219 wtu.checkCanvasRect(gl, 0, 0, 1, 1, [0, 0, 0, 255], "sampling depth from incomplete texture", 1); 220 } 221 } else { 222 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "sampling depth using incompatible program"); 223 } 224 } else { 225 if (program[1] == 'stencil') { 226 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors"); 227 if (validFilters(gl[magFilter], gl[minFilter])) { 228 wtu.checkCanvasRect(gl, 0, 0, 1, 1, [170, 0, 0, 1], "sampling stencil from complete texture", 1); 229 } else { 230 // Incomplete textures may produce [0, 0, 0, 1] or [0, 0, 0, 255]. 231 const value = new Uint8Array(4); 232 gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, value); 233 wtu.glErrorShouldBe(gl, gl.NO_ERROR); 234 const msg = "sampling stencil from incomplete texture"; 235 if (value[0] == 0 && value[1] == 0 && value[2] == 0 && (value[3] == 1 || value[3] == 255)) { 236 testPassed(msg); 237 } else { 238 testFailed(`${msg}: ${value}`); 239 } 240 } 241 } else { 242 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "sampling stencil using incompatible program"); 243 } 244 } 245 } 246 } 247 } 248 } 249 } 250 } 251 252 function runTest() { 253 if (!gl) { 254 testFailed("context does not exist"); 255 return; 256 } 257 testPassed("context exists"); 258 259 runTestNoExtension(); 260 261 ext = gl.getExtension("WEBGL_stencil_texturing"); 262 wtu.runExtensionSupportedTest(gl, "WEBGL_stencil_texturing", ext !== null); 263 264 if (ext !== null) { 265 checkEnums(); 266 checkQueries(); 267 checkSampling(); 268 } else { 269 testPassed("No WEBGL_stencil_texturing support -- this is legal"); 270 } 271 } 272 273 runTest(); 274 275 var successfullyParsed = true; 276 </script> 277 <script src="../../js/js-test-post.js"></script> 278 </body> 279 </html>