instanced-rendering-bug.html (9067B)
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 Instanced Arrays Conformance Tests</title> 12 <link rel="stylesheet" href="../../resources/js-test-style.css"/> 13 <script src="../../js/desktop-gl-constants.js"></script> 14 <script src="../../js/js-test-pre.js"></script> 15 <script src="../../js/webgl-test-utils.js"></script> 16 </head> 17 <body> 18 <div id="description"></div> 19 <canvas id="canvas" style="width: 128px; height: 128px;"> </canvas> 20 <div id="console"></div> 21 <script id="outputVertexShader" type="x-shader/x-vertex">#version 300 es 22 in highp vec2 aPosition; 23 in highp float aOffset; 24 in highp float aColor; 25 out mediump float vColor; 26 void main() { 27 gl_Position = vec4(aPosition, 0.0, 1.0) + vec4(aOffset, 0.0, 0.0, 0.0); 28 vColor = aColor; 29 } 30 </script> 31 32 <script id="outputFragmentShader" type="x-shader/x-fragment">#version 300 es 33 layout(location = 0) out mediump vec4 oColor; 34 in mediump float vColor; 35 void main() { 36 oColor = vec4(vColor, 0.0, 0.0, 1.0); 37 } 38 </script> 39 40 <script> 41 "use strict"; 42 description("This test verifies a bug related with instanced rendering on Mac AMD."); 43 debug("http://crbug.com/645298"); 44 45 debug(""); 46 47 var wtu = WebGLTestUtils; 48 var canvas = document.getElementById("canvas"); 49 var gl = wtu.create3DContext(canvas, null, 2); 50 51 // The second and fourth test cases fail - it seems if the divisor doesn't change, 52 // the next instanced draw call behaves incorrectly. 53 // Also note that if we don't perform a readPixels (in wtu.checkCanvasRect), the bug 54 // isn't triggered. 55 var testCases = [ 56 { instanceCount: 8, divisor: 4 }, 57 { instanceCount: 6, divisor: 4 }, 58 { instanceCount: 6, divisor: 3 }, 59 { instanceCount: 8, divisor: 3 }, 60 ]; 61 62 if (!gl) { 63 testFailed("WebGL context does not exist"); 64 } else { 65 testPassed("WebGL context exists"); 66 67 for (var ii = 0; ii < testCases.length; ++ii) { 68 runDrawArraysTest(testCases[ii].instanceCount, testCases[ii].divisor); 69 } 70 71 for (var ii = 0; ii < testCases.length; ++ii) { 72 runDrawElementsTest(testCases[ii].instanceCount, testCases[ii].divisor); 73 } 74 } 75 76 function runDrawArraysTest(instanceCount, divisor) { 77 debug(""); 78 debug("Testing drawArraysInstanced: instanceCount = " + instanceCount + ", divisor = " + divisor); 79 80 gl.viewport(0, 0, canvas.width, canvas.height); 81 82 var vao = gl.createVertexArray(); 83 gl.bindVertexArray(vao); 84 85 var program = wtu.setupProgram(gl, ["outputVertexShader", "outputFragmentShader"]); 86 var positionLoc = gl.getAttribLocation(program, "aPosition"); 87 var offsetLoc = gl.getAttribLocation(program, "aOffset"); 88 var colorLoc = gl.getAttribLocation(program, "aColor"); 89 if (!program || positionLoc < 0 || offsetLoc < 0 || colorLoc < 0) { 90 testFailed("Set up program failed"); 91 return; 92 } 93 testPassed("Set up program succeeded"); 94 95 var scale = 1.0 / instanceCount; 96 97 gl.enableVertexAttribArray(positionLoc); 98 gl.vertexAttribDivisor(positionLoc, 0); 99 var positions = new Float32Array([ 100 1.0 * scale, 1.0, 101 -1.0 * scale, 1.0, 102 -1.0 * scale, -1.0, 103 1.0 * scale, 1.0, 104 -1.0 * scale, -1.0, 105 1.0 * scale, -1.0, 106 ]); 107 var positionBuffer = gl.createBuffer(); 108 gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); 109 gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW); 110 gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0); 111 112 gl.enableVertexAttribArray(offsetLoc); 113 gl.vertexAttribDivisor(offsetLoc, 1); 114 var offsets = new Float32Array(instanceCount); 115 for (var ii = 0; ii < instanceCount; ++ii) { 116 offsets[ii] = scale * (1 - instanceCount + ii * 2); 117 } 118 var offsetBuffer = gl.createBuffer(); 119 gl.bindBuffer(gl.ARRAY_BUFFER, offsetBuffer); 120 gl.bufferData(gl.ARRAY_BUFFER, offsets, gl.STATIC_DRAW); 121 gl.vertexAttribPointer(offsetLoc, 1, gl.FLOAT, false, 0, 0); 122 123 gl.enableVertexAttribArray(colorLoc); 124 gl.vertexAttribDivisor(colorLoc, divisor); 125 var colorCount = instanceCount / divisor; 126 if ((instanceCount % divisor) != 0) 127 colorCount++; 128 var colors = new Float32Array(colorCount); 129 for (var ii = 0; ii < colorCount; ++ii) { 130 colors[ii] = 1.0 / colorCount * (ii + 1); 131 } 132 var colorBuffer = gl.createBuffer(); 133 gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer); 134 gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW); 135 gl.vertexAttribPointer(colorLoc, 1, gl.FLOAT, false, 0, 0); 136 137 gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, instanceCount); 138 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawArraysInstanced should succeed"); 139 140 var colorIndex = -1; 141 for (var ii = 0; ii < instanceCount; ++ii) { 142 if ((ii % divisor) == 0) 143 colorIndex++; 144 var refColor = [ Math.floor(colors[colorIndex] * 255), 0, 0, 255 ]; 145 wtu.checkCanvasRect(gl, Math.floor(canvas.width / instanceCount * ii) + 1, 0, 1, canvas.height, refColor, 146 "instance " + ii + " should be " + refColor, 2); 147 } 148 149 gl.deleteBuffer(positionBuffer); 150 gl.deleteBuffer(offsetBuffer); 151 gl.deleteBuffer(colorBuffer); 152 gl.deleteProgram(program); 153 gl.deleteVertexArray(vao); 154 gl.bindBuffer(gl.ARRAY_BUFFER, null); 155 gl.useProgram(null); 156 gl.bindVertexArray(null); 157 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "clean up should succeed"); 158 } 159 160 function runDrawElementsTest(instanceCount, divisor) { 161 debug(""); 162 debug("Testing drawElementsInstanced: instanceCount = " + instanceCount + ", divisor = " + divisor); 163 164 gl.viewport(0, 0, canvas.width, canvas.height); 165 166 var vao = gl.createVertexArray(); 167 gl.bindVertexArray(vao); 168 169 var program = wtu.setupProgram(gl, ["outputVertexShader", "outputFragmentShader"]); 170 var positionLoc = gl.getAttribLocation(program, "aPosition"); 171 var offsetLoc = gl.getAttribLocation(program, "aOffset"); 172 var colorLoc = gl.getAttribLocation(program, "aColor"); 173 if (!program || positionLoc < 0 || offsetLoc < 0 || colorLoc < 0) { 174 testFailed("Set up program failed"); 175 return; 176 } 177 testPassed("Set up program succeeded"); 178 179 var scale = 1.0 / instanceCount; 180 181 gl.enableVertexAttribArray(positionLoc); 182 gl.vertexAttribDivisor(positionLoc, 0); 183 var positions = new Float32Array([ 184 1.0 * scale, 1.0, 185 -1.0 * scale, 1.0, 186 -1.0 * scale, -1.0, 187 1.0 * scale, -1.0, 188 ]); 189 var positionBuffer = gl.createBuffer(); 190 gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); 191 gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW); 192 gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0); 193 194 gl.enableVertexAttribArray(offsetLoc); 195 gl.vertexAttribDivisor(offsetLoc, 1); 196 var offsets = new Float32Array(instanceCount); 197 for (var ii = 0; ii < instanceCount; ++ii) { 198 offsets[ii] = scale * (1 - instanceCount + ii * 2); 199 } 200 var offsetBuffer = gl.createBuffer(); 201 gl.bindBuffer(gl.ARRAY_BUFFER, offsetBuffer); 202 gl.bufferData(gl.ARRAY_BUFFER, offsets, gl.STATIC_DRAW); 203 gl.vertexAttribPointer(offsetLoc, 1, gl.FLOAT, false, 0, 0); 204 205 gl.enableVertexAttribArray(colorLoc); 206 gl.vertexAttribDivisor(colorLoc, divisor); 207 var colorCount = instanceCount / divisor; 208 if ((instanceCount % divisor) != 0) 209 colorCount++; 210 var colors = new Float32Array(colorCount); 211 for (var ii = 0; ii < colorCount; ++ii) { 212 colors[ii] = 1.0 / colorCount * (ii + 1); 213 } 214 var colorBuffer = gl.createBuffer(); 215 gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer); 216 gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW); 217 gl.vertexAttribPointer(colorLoc, 1, gl.FLOAT, false, 0, 0); 218 219 var indexBuffer = gl.createBuffer(); 220 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer); 221 var indices = new Uint16Array([0, 1, 2, 0, 2, 3]); 222 gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW); 223 224 gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0, instanceCount); 225 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawElementsInstanced should succeed"); 226 227 var colorIndex = -1; 228 for (var ii = 0; ii < instanceCount; ++ii) { 229 if ((ii % divisor) == 0) 230 colorIndex++; 231 var refColor = [ Math.floor(colors[colorIndex] * 255), 0, 0, 255 ]; 232 wtu.checkCanvasRect(gl, Math.floor(canvas.width / instanceCount * ii) + 1, 0, 1, canvas.height, refColor, 233 "instance " + ii + " should be " + refColor, 2); 234 } 235 236 gl.deleteBuffer(positionBuffer); 237 gl.deleteBuffer(offsetBuffer); 238 gl.deleteBuffer(colorBuffer); 239 gl.deleteBuffer(indexBuffer); 240 gl.deleteProgram(program); 241 gl.deleteVertexArray(vao); 242 gl.bindBuffer(gl.ARRAY_BUFFER, null); 243 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null); 244 gl.useProgram(null); 245 gl.bindVertexArray(null); 246 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "clean up should succeed"); 247 } 248 249 debug(""); 250 var successfullyParsed = true; 251 </script> 252 <script src="../../js/js-test-post.js"></script> 253 </body> 254 </html>