out-of-bounds-uniform-array-access.html (5095B)
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 out of bounds uniform array access.</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="example" width="128" height="128" style="background: black;"> 19 </canvas> 20 <div id="console"></div> 21 <script id="vshader" type="x-shader/x-vertex"> 22 attribute vec4 vPosition; 23 varying vec4 v_color; 24 uniform float lineWidth; 25 uniform int elemMult; 26 uniform vec4 colorArray[6]; 27 void main() 28 { 29 vec2 texcoord = vec2(vPosition.xy * 0.5 + vec2(0.5, 0.5)); 30 int index = int(texcoord.x + texcoord.y * lineWidth) * elemMult; 31 v_color = colorArray[index]; 32 gl_Position = vPosition; 33 gl_PointSize = 1.0; 34 } 35 </script> 36 37 <script id="fshader" type="x-shader/x-fragment"> 38 precision mediump float; 39 varying vec4 v_color; 40 void main() 41 { 42 gl_FragColor = v_color; 43 } 44 </script> 45 <script> 46 "use strict"; 47 debug("Tests a WebGL program that accesses out of bounds uniform array elements"); 48 49 var gl; 50 var gridRes = 127; 51 var lineWidthLoc; 52 var elemMultLoc; 53 var width = 128; 54 var height = 128; 55 var pixels = new Uint8Array(width * height * 4); 56 57 var lineWidth = 0; 58 var elemMult = 0; 59 60 var knownColors = [ 61 1.0, 0.0, 0.0, 1.0, // Red 62 0.0, 1.0, 0.0, 1.0, // Green 63 0.0, 0.0, 1.0, 1.0, // Blue 64 0.0, 1.0, 1.0, 1.0, // Cyan 65 1.0, 0.0, 1.0, 1.0, // Magenta 66 1.0, 1.0, 0.0, 1.0 // Yellow 67 ]; 68 69 function main() { 70 var wtu = WebGLTestUtils; 71 gl = wtu.create3DContext("example"); 72 var program = wtu.setupProgram( 73 gl, 74 ['vshader', 'fshader'], 75 ['vPosition'], [0]); 76 77 // setupQuad produces the geometry we want for a gridRes x gridRes grid 78 // of points. No interpolation will be performed across the points, so 79 // according to the WebGL specification for out-of-bounds array accesses, 80 // we will get exactly the input colors from the uniform colorArray, or 81 // zero, for each pixel on the canvas. 82 wtu.setupIndexedQuad(gl, gridRes, 0); 83 var colorArrayLoc = gl.getUniformLocation(program, "colorArray[0]"); 84 assertMsg(colorArrayLoc != null, "color array uniform should be found"); 85 var colors = new Float32Array(knownColors); 86 gl.uniform4fv(colorArrayLoc, colors); 87 lineWidthLoc = gl.getUniformLocation(program, "lineWidth"); 88 elemMultLoc = gl.getUniformLocation(program, "elemMult"); 89 assertMsg(gl.getError() == gl.NO_ERROR, "Should be no errors from setup."); 90 runOneIteration(); 91 } 92 93 function withinEpsilon(val1, val2) { 94 return Math.abs(val1 - val2) < 0.0001; 95 } 96 97 function isKnownColor(r, g, b) { 98 if (r == 0 && g == 0 && b == 0) 99 return true; 100 for (var ii = 0; ii < knownColors.length; ii += 4) { 101 if (withinEpsilon(r / 255.0, knownColors[ii + 0]) && 102 withinEpsilon(g / 255.0, knownColors[ii + 1]) && 103 withinEpsilon(b / 255.0, knownColors[ii + 2])) 104 return true; 105 } 106 return false; 107 } 108 109 function runOneIteration() { 110 if (elemMult < 2048) { 111 var ok = true; 112 var startingLineWidth = lineWidth; 113 var firstFailingPixel = null; 114 var firstFailingValue = null; 115 for (; lineWidth < 2540; lineWidth += 31) { 116 // Draw 117 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); 118 gl.uniform1f(lineWidthLoc, lineWidth); 119 gl.uniform1i(elemMultLoc, elemMult); 120 gl.drawArrays(gl.POINTS, 0, gridRes * gridRes); 121 122 // Read back 123 gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels); 124 125 // Verify 126 for (var y = 0; y < height; ++y) { 127 for (var x = 0; x < width; ++x) { 128 if (!isKnownColor(pixels[4 * (width * y + x) + 0], 129 pixels[4 * (width * y + x) + 1], 130 pixels[4 * (width * y + x) + 2])) { 131 ok = false; 132 if (firstFailingPixel == null) { 133 firstFailingPixel = [x, y]; 134 firstFailingValue = [pixels[4 * (width * y + x) + 0], 135 pixels[4 * (width * y + x) + 1], 136 pixels[4 * (width * y + x) + 2]]; 137 } 138 } 139 } 140 } 141 } 142 var endingLineWidth = lineWidth - 31; 143 lineWidth -= 2540; 144 if (ok) { 145 testPassed("Good rendering results for lineWidths " + 146 startingLineWidth + "..." + endingLineWidth + 147 " at elemMult=" + elemMult); 148 } else { 149 testFailed("for lineWidth=" + lineWidth + ", elemMult=" + elemMult + 150 ": first failing pixel (" + firstFailingPixel[0] + ", " + firstFailingPixel[1] + ") was (" + 151 firstFailingValue[0] + ", " + 152 firstFailingValue[1] + ", " + 153 firstFailingValue[2] + "), should be (0, 0, 0) or one of known colors"); 154 } 155 elemMult += 73; 156 setTimeout(runOneIteration, 0); 157 } else { 158 finishTest(); 159 } 160 } 161 162 main(); 163 164 var successfullyParsed = true; 165 166 </script> 167 </body> 168 </html>