texture-mips.html (8828B)
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>WebGL texture mips 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 <canvas id="example" width="2" height="2" style="width: 40px; height: 40px;"></canvas> 18 <div id="description"></div> 19 <div id="console"></div> 20 <script id="vshader" type="x-shader/x-vertex"> 21 uniform vec4 uMult; 22 attribute vec4 vPosition; 23 attribute vec2 texCoord0; 24 varying vec2 texCoord; 25 void main() 26 { 27 gl_Position = vPosition * uMult; 28 texCoord = texCoord0; 29 } 30 </script> 31 32 <script id="fshader" type="x-shader/x-fragment"> 33 precision mediump float; 34 uniform sampler2D tex; 35 varying vec2 texCoord; 36 void main() 37 { 38 gl_FragColor = texture2D(tex, texCoord); 39 } 40 </script> 41 <script> 42 "use strict"; 43 var canvas; 44 var wtu = WebGLTestUtils; 45 function init() 46 { 47 description("Checks mip issues"); 48 49 canvas = document.getElementById("example"); 50 shouldBe("canvas.width", "2"); 51 shouldBe("canvas.height", "2"); 52 53 var gl = wtu.create3DContext(canvas); 54 55 var tex = gl.createTexture(); 56 gl.bindTexture(gl.TEXTURE_2D, tex); 57 gl.generateMipmap(gl.TEXTURE_2D); 58 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "for generateMipmap with mip 0 is 0x0"); 59 gl.texImage2D( 60 gl.TEXTURE_2D, 1, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, 61 new Uint8Array(4)); 62 gl.generateMipmap(gl.TEXTURE_2D); 63 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "for generateMipmap with mip 0 is 0x0"); 64 65 tex = gl.createTexture(); 66 gl.bindTexture(gl.TEXTURE_CUBE_MAP, tex); 67 gl.generateMipmap(gl.TEXTURE_CUBE_MAP); 68 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "for generateMipmap with mip 0 is 0x0"); 69 70 var faces = [ 71 gl.TEXTURE_CUBE_MAP_POSITIVE_X, 72 gl.TEXTURE_CUBE_MAP_NEGATIVE_X, 73 gl.TEXTURE_CUBE_MAP_POSITIVE_Y, 74 gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, 75 gl.TEXTURE_CUBE_MAP_POSITIVE_Z, 76 gl.TEXTURE_CUBE_MAP_NEGATIVE_Z 77 ]; 78 for (var ii = 0; ii < faces.length; ++ii) { 79 gl.texImage2D( 80 faces[ii], 0, gl.RGBA, 2, 2, 0, gl.RGBA, gl.UNSIGNED_BYTE, 81 new Uint8Array(4 * 2 * 2)); 82 gl.generateMipmap(gl.TEXTURE_CUBE_MAP); 83 wtu.glErrorShouldBe(gl, ii == 5 ? gl.NO_ERROR : gl.INVALID_OPERATION, "for generateMipmap with " + (ii + 1) + " faces"); 84 } 85 86 wtu.setupUnitQuad(gl, 0, 1); 87 var program = wtu.setupProgram( 88 gl, ['vshader', 'fshader'], ['vPosition', 'texCoord0'], [0, 1]); 89 90 gl.disable(gl.DEPTH_TEST); 91 gl.disable(gl.BLEND); 92 93 var colors = { 94 blue: [0, 0, 255, 255], 95 red: [255, 0, 0, 255], 96 green: [0, 255, 0, 255], 97 cyan: [128, 255, 255, 255], 98 black: [0, 0, 0, 255], 99 blank: [0, 0, 0, 0] 100 }; 101 102 var mips = [ 103 ]; 104 105 var texLoc = gl.getUniformLocation(program, "tex"); 106 gl.uniform1i(texLoc, 0); 107 var multLoc = gl.getUniformLocation(program, "uMult"); 108 109 // ---------------------------------------------------- 110 var clearTex = createTexture(); 111 gl.uniform4f(multLoc, 1, 1, 1, 1); 112 gl.bindTexture(gl.TEXTURE_2D, clearTex); 113 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 16, 16, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); 114 debug('gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 16, 16, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);'); 115 setMipData(0, 16, 'blank'); 116 makeDivMipChain(); 117 generateMipmap(); 118 check('blank', "texture created with null that has all mips"); 119 120 // ---------------------------------------------------- 121 var tex = createTexture(); 122 gl.uniform4f(multLoc, 1, 1, 1, 1); 123 124 gl.bindTexture(gl.TEXTURE_2D, tex); 125 // 16x16 texture no mips 126 fillLevel(tex, 0, 16, 'cyan'); 127 128 check('black', 129 "texture that is missing mips when TEXTURE_MIN_FILTER not NEAREST or LINEAR"); 130 131 generateMipmap(); 132 133 check('cyan', "texture that has all mips"); 134 135 // Fill in the bottom 2 mips with a different color. 136 fillLevel(tex, 4, 1, 'green'); 137 fillLevel(tex, 3, 2, 'green'); 138 139 // Choose the nearest mip 140 texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST); 141 142 check('green', "texture that is only using the smallest 2 mips"); 143 144 gl.uniform4f(multLoc, 16, 16, 1, 1); 145 146 check('cyan', "texture that is using only the largest 2 mips"); 147 148 // Set the top level 149 fillLevel(tex, 0, 1, 'red'); 150 check('red', 151 "texture that is only using the top level even though other levels are defined"); 152 153 // Set the top 2 levels using generateMipmap 154 fillLevel(tex, 0, 2, 'blue'); 155 generateMipmap(); 156 157 check('blue', 158 "texture that is only using the top 2 levels even though other levels are defined"); 159 160 // Set the top 2 levels back to sizes that end up using levels 2, 3, and 4 again. 161 fillLevel(tex, 0, 16, 'blue'); 162 fillLevel(tex, 1, 8, 'blue'); 163 check('blue', "texture that is only using the largest 2 mips"); 164 gl.uniform4f(multLoc, 1, 1, 1, 1); 165 check('green', "texture that is only using the smallest 2 mips"); 166 167 // ---------------------------------------------------- 168 var tex = createTexture(); 169 gl.uniform4f(multLoc, 1, 1, 1, 1); 170 fillLevel(tex, 0, 8, 'cyan'); 171 generateMipmap(); 172 check('cyan', "texture that has 3 mips"); 173 174 fillLevel(tex, 0, 16, 'blue'); 175 texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); 176 check('blue', "texture that is only using top mips"); 177 178 fillLevel(tex, 0, 8, 'red'); 179 texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST); 180 check('cyan', "texture that is only using smallest mips"); 181 182 gl.uniform4f(multLoc, 16, 16, 1, 1); 183 check('red', "texture that is using only the largest mip"); 184 185 // ---------------------------------------------------- 186 var tex = createTexture(); 187 gl.uniform4f(multLoc, 1, 1, 1, 1); 188 fillLevel(tex, 2, 1, 'green'); 189 fillLevel(tex, 1, 2, 'green'); 190 fillLevel(tex, 0, 4, 'green'); 191 check('green', "texture that was built smallest mip first"); 192 193 // ---------------------------------------------------- 194 var tex = createTexture(); 195 gl.uniform4f(multLoc, 1, 1, 1, 1); 196 fillLevel(tex, 0, 16, 'red'); 197 generateMipmap(); 198 check('red', "texture with 1 genmipmaps"); 199 fillLevel(tex, 0, 16, 'blue'); 200 generateMipmap(); 201 fillLevel(tex, 0, 16, 'green'); 202 generateMipmap(); 203 check('green', "texture with 2 genmipmaps"); 204 205 // ---------------------------------------------------- 206 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors."); 207 208 function createTexture() { 209 debug("<hr/>gl.createTexture()"); 210 mips = []; 211 makeDivMipChain(); 212 return gl.createTexture(); 213 } 214 215 function texParameteri(target, pname, value) { 216 debug("gl.texParameteri(" + 217 wtu.glEnumToString(gl, target) + ", " + 218 wtu.glEnumToString(gl, pname) + ", " + 219 wtu.glEnumToString(gl, value) + ")") 220 gl.texParameteri(target, pname, value); 221 } 222 223 function generateMipmap() { 224 debug("gl.generateMipmap(gl.TEXTURE_2D)"); 225 gl.generateMipmap(gl.TEXTURE_2D); 226 var mip0 = mips[0]; 227 var size = mip0.size; 228 var level = 1; 229 for(;;) { 230 size = Math.floor(size / 2); 231 if (!size) { 232 break; 233 } 234 setMipData(level, size, mip0.color); 235 ++level; 236 } 237 makeDivMipChain(); 238 } 239 240 function check(color, msg) { 241 wtu.clearAndDrawUnitQuad(gl); 242 wtu.checkCanvas(gl, colors[color], msg + " should draw with " + color); 243 } 244 245 function fillLevel(tex, level, size, color) { 246 setMipData(level, size, color); 247 debug("gl.texImage2D(gl.TEXTURE_2D, " + level + ", gl.RGBA, " + size + ", " + size + 248 ", 0, gl.RGBA, gl.UNSIGNED_BYTE, " + color + ");"); 249 wtu.fillTexture(gl, tex, size, size, colors[color], level); 250 makeDivMipChain(); 251 } 252 253 function setMipData(level, size, color) { 254 mips[level] = { 255 size: size, 256 color: color 257 }; 258 } 259 260 function makeDivMipChain(color) { 261 var html = [ 262 '<div style="height: 68px; margin-top: 5px">', 263 '<div style="float:left;">mips: </div>']; 264 for (var ii = 0; ii < 5; ++ii) { 265 var mip = mips[ii]; 266 if (mip) { 267 html.push(makeDivSquare(mip.size, mip.color)); 268 } else { 269 html.push(makeDivSquare(16, undefined)); 270 } 271 } 272 html.push("</div>"); 273 debug(html.join("")); 274 } 275 276 function makeDivSquare(size, color) { 277 size *= 4; 278 var c = color ? colors[color] : [255,255,255]; 279 var border = color ? 'solid' : 'dashed'; 280 return '<div style="float:left; width: ' + size + 'px; height: ' + size + 281 'px; background-color: ' + rgb(c) + 282 '; border: 1px ' + border + ' black; margin-right: 3px;"></div>'; 283 } 284 285 function rgb(c) { 286 return 'rgb(' + c[0] + ',' + c[1] + ',' + c[2] +')'; 287 } 288 } 289 290 init(); 291 var successfullyParsed = true; 292 </script> 293 <script src="../../../js/js-test-post.js"></script> 294 295 </body> 296 </html>