tex-storage-2d.html (12119B)
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 7 <!DOCTYPE html> 8 <html> 9 <head> 10 <meta charset="utf-8"> 11 <title>texStorage2D conformance test</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 <canvas id="canvas" width="64" height="64"> </canvas> 19 <div id="console"></div> 20 21 22 <script> 23 "use strict"; 24 description("This test verifies the functionality of texStorage2D."); 25 26 debug(""); 27 28 var wtu = WebGLTestUtils; 29 var canvas = document.getElementById("canvas"); 30 var gl = wtu.create3DContext(canvas, null, 2); 31 var vao = null; 32 33 if (!gl) { 34 testFailed("WebGL context does not exist"); 35 } else { 36 testPassed("WebGL context exists"); 37 38 runTexStorage2DTest(); 39 40 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "there should be no errors"); 41 } 42 43 function enumToString(value) { 44 return wtu.glEnumToString(gl, value); 45 } 46 47 function runTexStorage2DTest() 48 { 49 var texStorage2DTestCases = [ 50 { 51 target: gl.TEXTURE_2D, 52 mipmap: false, 53 sizedformat: gl.RGBA8, 54 unsizedformat: gl.RGBA, 55 type: gl.UNSIGNED_BYTE, 56 alpha: true, 57 redpixel: new Uint8Array([0xff, 0x00, 0x00, 0x00]), 58 }, 59 { 60 target: gl.TEXTURE_2D, 61 mipmap: true, 62 sizedformat: gl.R11F_G11F_B10F, 63 unsizedformat: gl.RGB, 64 type: gl.UNSIGNED_INT_10F_11F_11F_REV, 65 alpha: false, 66 // Red is unsigned floating point with 5 exponent bits followed by 6 mantissa bits. 67 // The effective value is 2^(exponent - 15) * (1 + mantissa / 64) 68 // See OpenGL ES 3.0.3 spec, section 2.1.3 69 // Here we want to encode the value 1.0, which we achieve with a zero mantissa 70 // and an exponent of 15. 71 redpixel: new Uint32Array([15<<6]), 72 }, 73 { 74 target: gl.TEXTURE_2D, 75 mipmap: true, 76 sizedformat: gl.RGBA32F, 77 unsizedformat: gl.RGBA, 78 type: gl.FLOAT, 79 alpha: true, 80 redpixel: new Float32Array([1, 0, 0, 0]), 81 }, 82 { 83 target: gl.TEXTURE_CUBE_MAP, 84 mipmap: true, 85 sizedformat: gl.RGBA8, 86 unsizedformat: gl.RGBA, 87 type: gl.UNSIGNED_BYTE, 88 alpha: true, 89 redpixel: new Uint8Array([0xff, 0x00, 0x00, 0x00]), 90 }, 91 { 92 target: gl.TEXTURE_CUBE_MAP, 93 mipmap: false, 94 sizedformat: gl.RGB8, 95 unsizedformat: gl.RGB, 96 type: gl.UNSIGNED_BYTE, 97 alpha: false, 98 redpixel: new Uint8Array([0xff, 0x00, 0x00]), 99 }, 100 { 101 target: gl.TEXTURE_CUBE_MAP, 102 mipmap: true, 103 sizedformat: gl.RGB10_A2UI, 104 unsizedformat: gl.UNSIGNED_INT_2_10_10_10_REV, // type enum, bad as format 105 }, 106 { 107 target: gl.TEXTURE_CUBE_MAP, 108 mipmap: false, 109 sizedformat: gl.R11F_G11F_B10F, 110 unsizedformat: gl.RGB, 111 } 112 ]; 113 114 texStorage2DTestCases.forEach(function(testcase){ 115 var target = testcase.target; 116 var imageTargets; 117 118 if (target == gl.TEXTURE_2D) { 119 imageTargets = [ gl.TEXTURE_2D ]; 120 } else { 121 imageTargets = [ gl.TEXTURE_CUBE_MAP_POSITIVE_X, 122 gl.TEXTURE_CUBE_MAP_NEGATIVE_X, 123 gl.TEXTURE_CUBE_MAP_POSITIVE_Y, 124 gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, 125 gl.TEXTURE_CUBE_MAP_POSITIVE_Z, 126 gl.TEXTURE_CUBE_MAP_NEGATIVE_Z ]; 127 } 128 129 var tex = gl.createTexture(); 130 gl.bindTexture(target, tex); 131 var texsize = 4; 132 var levels = testcase.mipmap 133 ? Math.floor(Math.log(texsize) / Math.log(2)) + 1 134 : 1; 135 136 debug(""); 137 debug("Testing texStorage2D with target " + enumToString(target) + ", " + 138 (testcase.mipmap ? "mipmap" : "no mipmap") + ", " + 139 "internalformat: " + enumToString(testcase.sizedformat)); 140 141 gl.texStorage2D(target, levels, testcase.sizedformat, 142 0, texsize); 143 wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "texStorage2D should fail for zero width"); 144 gl.texStorage2D(target, levels, testcase.sizedformat, 145 texsize, 0); 146 wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "texStorage2D should fail for zero height"); 147 gl.texStorage2D(target, levels, testcase.sizedformat, 148 texsize, -texsize); 149 wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "texStorage2D should fail for negative height"); 150 gl.texStorage2D(target, 0, testcase.sizedformat, 151 texsize, texsize); 152 wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "texStorage2D should fail for zero levels"); 153 gl.texStorage2D(target, 154 Math.ceil(Math.log(texsize) / Math.log(2)) + 2, 155 testcase.sizedformat, 156 texsize, texsize); 157 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "texStorage2D should fail for too many levels"); 158 gl.texStorage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_X, levels, testcase.sizedformat, 159 texsize, texsize); 160 wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "texStorage2D should fail for bad target TEXTURE_CUBE_MAP_NEGATIVE_X"); 161 162 gl.bindTexture(target, null); 163 gl.texStorage2D(target, levels, testcase.sizedformat, 164 texsize, texsize); 165 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "texStorage2D should fail when no texture is bound"); 166 gl.bindTexture(target, tex); 167 168 // texStorage2D should only accept sized internalformats 169 gl.texStorage2D(target, levels, testcase.unsizedformat, 170 texsize, texsize); 171 wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "texStorage2D should fail for bad internalformat " + enumToString(testcase.unsizedformat)); 172 173 // OK, now let's finally do the successfull texStorage2D call 174 gl.texStorage2D(target, levels, testcase.sizedformat, 175 texsize, texsize); 176 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "texStorage2D should succeed with a good sized internalformat"); 177 178 // check TEXTURE_IMMUTABLE_FORMAT 179 var immutable = gl.getTexParameter(target, gl.TEXTURE_IMMUTABLE_FORMAT); 180 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "getTexParameter should succeed with TEXTURE_IMMUTABLE_FORMAT"); 181 assertMsg(immutable != 0, "getTexParameter with TEXTURE_IMMUTABLE_FORMAT should not return 0"); 182 183 // check operations disallowed on immutable texture 184 gl.texImage2D(imageTargets[0], 0, gl.RGBA, texsize, texsize, 0, 185 gl.RGBA, gl.UNSIGNED_BYTE, null); 186 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "texImage2D should fail on immutable texture"); 187 var s3tc = gl.getExtension("WEBGL_compressed_texture_s3tc"); 188 // FIXME - should eventually use a compressed format that's core in WebGL2, but 189 // I wanted something that I can run in Firefox today, which doesn't support the new formats yet. 190 if (s3tc) { 191 gl.compressedTexImage2D(imageTargets[0], 0, s3tc.COMPRESSED_RGBA_S3TC_DXT3_EXT, 192 texsize, texsize, 0, 193 new Uint8Array(texsize * texsize)); 194 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "compressedTexImage2D should fail on immutable texture"); 195 } 196 gl.copyTexImage2D(imageTargets[0], 0, gl.RGBA, 0, 0, texsize, texsize, 0); 197 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "copyTexImage2D should fail on immutable texture"); 198 199 if ('redpixel' in testcase) { 200 // At this point, the texture images have only been defined by 201 // texStorage2D, which per spec should be equivalent to having 202 // defined texture images with null data, which should sample as RGBA 0,0,0,0. 203 gl.texParameteri(target, gl.TEXTURE_MIN_FILTER, 204 testcase.mipmap ? gl.NEAREST_MIPMAP_NEAREST : gl.NEAREST); 205 if (testcase.type == gl.FLOAT) { 206 gl.texParameteri(target, gl.TEXTURE_MAG_FILTER, gl.NEAREST); 207 } 208 209 // Now upload some red texture data 210 var s = texsize; 211 var pixels; 212 if (testcase.redpixel instanceof Uint8Array) { 213 pixels = new Uint8Array(texsize * texsize * testcase.redpixel.length); 214 } else if (testcase.redpixel instanceof Uint16Array) { 215 pixels = new Uint16Array(texsize * texsize * testcase.redpixel.length); 216 } else if (testcase.redpixel instanceof Uint32Array) { 217 pixels = new Uint32Array(texsize * texsize * testcase.redpixel.length); 218 } else if (testcase.redpixel instanceof Float32Array) { 219 pixels = new Float32Array(texsize * texsize * testcase.redpixel.length); 220 } 221 for (var i = 0; i < texsize * texsize; i++) { 222 for (var j = 0; j < testcase.redpixel.length; j++) { 223 pixels[i * testcase.redpixel.length + j] = testcase.redpixel[j]; 224 } 225 } 226 227 if (target == gl.TEXTURE_2D) { 228 wtu.setupTexturedQuad(gl); 229 } else if (target == gl.TEXTURE_CUBE_MAP) { 230 wtu.setupTexturedQuadWithCubeMap(gl); 231 } 232 233 wtu.clearAndDrawUnitQuad(gl); 234 var alpha = testcase.alpha ? 0 : 255; 235 wtu.checkCanvas(gl, [0, 0, 0, alpha], "texture should sample as uninitialized texture after texStorage2D"); 236 237 if (target == gl.TEXTURE_2D) { 238 for (var l = 0; l < levels; l++) { 239 gl.texSubImage2D(gl.TEXTURE_2D, 240 l, 0, 0, 241 s, s, 242 testcase.unsizedformat, testcase.type, 243 pixels); 244 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "texSubImage2D should succeed on immutable texture as long as the format is compatible"); 245 s /= 2; 246 } 247 } else if (target == gl.TEXTURE_CUBE_MAP) { 248 for (var l = 0; l < levels; l++) { 249 for (var f = 0; f < 6; f++) { 250 gl.texSubImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X + f, 251 l, 0, 0, 252 s, s, 253 testcase.unsizedformat, testcase.type, 254 pixels); 255 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "texSubImage2D should succeed on immutable texture as long as the format is compatible"); 256 } 257 s /= 2; 258 } 259 } 260 261 wtu.clearAndDrawUnitQuad(gl); 262 wtu.checkCanvas(gl, [255, 0, 0, alpha], "texture should sample as red after uploading red pixels with texSubImage2D"); 263 } 264 }); 265 266 debug(""); 267 debug("Test non-square images:"); 268 const levels = 4; 269 const maxSize = 1 << (levels-1); 270 271 function expectOk(x,y) { 272 const tex = gl.createTexture(); 273 gl.bindTexture(gl.TEXTURE_2D, tex); 274 gl.texStorage2D(gl.TEXTURE_2D, levels, gl.RGBA8, x, y); 275 wtu.glErrorShouldBe(gl, gl.NO_ERROR, 276 "texStorage2D should succeed with size [" + ([x,y].join(', ')) + "]."); 277 gl.deleteTexture(tex); 278 } 279 expectOk(maxSize, maxSize); 280 expectOk(maxSize, 1); 281 expectOk( 1, maxSize); 282 } 283 284 debug(""); 285 var successfullyParsed = true; 286 </script> 287 <script src="../../../js/js-test-post.js"></script> 288 289 </body> 290 </html>