texture-bias.html (4790B)
1 <!-- 2 Copyright (c) 2022 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>GLSL texture bias 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 <script src="../../js/glsl-conformance-test.js"></script> 16 </head> 17 <body> 18 <div id="description"></div> 19 <div id="console"></div> 20 <script> 21 "use strict"; 22 description("Texture bias should both function and respect limits."); 23 24 function runTest(gl) { 25 // no if idea any drivers have a giant limit like 2^32 so just in case. 26 const kMaxMaxTextureSize = 256 * 1024 * 1024; 27 const maxTextureSize = Math.min(kMaxMaxTextureSize, gl.getParameter(gl.MAX_TEXTURE_SIZE)); 28 const maxLODs = (Math.log2(maxTextureSize) | 0) + 1; 29 const maxTextureLODBias = gl.getParameter(gl.MAX_TEXTURE_LOD_BIAS); 30 31 debug(`maxTextureSize: ${maxTextureSize}`); 32 debug(`maxLODs: ${maxLODs}`); 33 debug(`maxTextureLODBias: ${maxTextureLODBias}`); 34 35 const vs = `#version 300 es 36 uniform float uvMult; 37 out vec2 v_uv; 38 void main() { 39 vec2 xy = vec2( 40 gl_VertexID % 2, 41 (gl_VertexID / 2 + gl_VertexID / 3) % 2); 42 43 gl_Position = vec4(xy * 2. - 1.0, 0, 1); 44 v_uv = xy * uvMult; 45 } 46 `; 47 const fs = `#version 300 es 48 precision highp float; 49 uniform sampler2D tex; 50 uniform float biasMult; 51 in vec2 v_uv; 52 out vec4 fragColor; 53 void main() { 54 vec4 texColor = texture(tex, v_uv, (gl_FragCoord.x - 0.5) * biasMult); // the color we care about 55 vec4 texelColor = texelFetch(tex, ivec2(0), int(gl_FragCoord)); // just a sanity check 56 vec4 coordColor = vec4((100.0 + gl_FragCoord.x - 0.5) / 255.0); // another sanity check 57 fragColor = mix(texColor, coordColor, step(1.0, gl_FragCoord.y)); // line < 1 = texColor, line >= 1 = coordColor 58 fragColor = mix(fragColor, texelColor, step(2.0, gl_FragCoord.y)); // line < 2 = fragColor, line >= 2 = texelColor 59 } 60 `; 61 const program = wtu.setupProgram(gl, [vs, fs]); 62 const uvMultLoc = gl.getUniformLocation(program, 'uvMult'); 63 const biasLoc = gl.getUniformLocation(program, 'biasMult'); 64 65 gl.canvas.width = maxLODs; 66 gl.canvas.height = 3; 67 gl.viewport(0, 0, maxLODs, 3); 68 69 // create a texture where each mip is a different color (1, 2, 3, ...) 70 const tex = gl.createTexture(); 71 gl.bindTexture(gl.TEXTURE_2D, tex); 72 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); 73 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST_MIPMAP_NEAREST); 74 gl.texStorage2D(gl.TEXTURE_2D, maxLODs, gl.RGBA8, maxTextureSize, 1); 75 { 76 let level = 0; 77 for (let width = maxTextureSize; width > 0; width = width / 2 | 0) { 78 const pixels = new Uint8Array(width * 1 * 4); 79 pixels.fill(level + 1); 80 debug(`fill mip level: ${level}, width: ${width}`); 81 gl.texSubImage2D(gl.TEXTURE_2D, level, 0, 0, width, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixels); 82 wtu.glErrorShouldBe(gl, gl.NO_ERROR); 83 ++level; 84 } 85 } 86 87 // Draw each mip. Result should be [mip0, mip1, mip2, ...] 88 debug(""); 89 debug("check positive bias"); 90 // set the UVs so we'd get mip level 0 for every pixel 91 gl.uniform1f(uvMultLoc, maxLODs / maxTextureSize); 92 gl.uniform1f(biasLoc, 1); 93 gl.drawArrays(gl.TRIANGLES, 0, 6); 94 95 wtu.glErrorShouldBe(gl, gl.NO_ERROR); 96 97 const clampPlusMinus = (v, limit) => Math.min(limit, Math.max(-limit, v)); 98 99 const checkResults = (gl, biasMult) => { 100 const base = biasMult > 0 ? 1 : maxLODs; 101 for (let i = 0; i < maxLODs; ++i) { 102 { 103 const expected = new Array(4).fill(clampPlusMinus(i * biasMult, maxTextureLODBias) + base); 104 wtu.checkCanvasRect(gl, i, 0, 1, 1, expected, `should be: ${expected}`); 105 } 106 { 107 const expected = new Array(4).fill(100 + i); 108 wtu.checkCanvasRect(gl, i, 1, 1, 1, expected, `should be: ${expected}`); 109 } 110 { 111 const expected = new Array(4).fill(i + 1); 112 wtu.checkCanvasRect(gl, i, 2, 1, 1, expected, `should be: ${expected}`); 113 } 114 } 115 } 116 117 checkResults(gl, 1); 118 119 // Draw each mip. Result should be [mipMax, mipMax - 1, mipMax - 2, ...] 120 debug(""); 121 debug("check negative bias"); 122 // set the UVs so we'd get highest mip level (the 1x1 level mip) for every pixel 123 gl.uniform1f(uvMultLoc, maxLODs); 124 gl.uniform1f(biasLoc, -1); 125 gl.drawArrays(gl.TRIANGLES, 0, 6); 126 127 checkResults(gl, -1); 128 129 finishTest(); 130 } 131 132 const wtu = WebGLTestUtils; 133 134 const gl = wtu.create3DContext(undefined, undefined, 2); 135 136 var successfullyParsed = true; 137 138 if (!gl) { 139 testFailed("Unable to initialize WebGL 2.0 context."); 140 } else { 141 runTest(gl); 142 } 143 144 </script> 145 </body> 146 </html>