too-small-buffers.html (10734B)
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>TF too small buffers</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" style="width: 50px; height: 50px;"> </canvas> 19 <div id="console"></div> 20 <script id="vshader" type="x-shader/x-vertex">#version 300 es 21 in float in_value1; 22 in float in_value2; 23 out float out_value1; 24 out float out_value2; 25 void main() { 26 out_value1 = in_value1 * 2.; 27 out_value2 = in_value2 * 2.; 28 } 29 </script> 30 <script id="fshader" type="x-shader/x-fragment">#version 300 es 31 precision mediump float; 32 out vec4 dummy; 33 void main() { 34 dummy = vec4(0.); 35 } 36 </script> 37 <script> 38 "use strict"; 39 description("Transform feedback into buffers that are too small should produce errors."); 40 41 var wtu = WebGLTestUtils; 42 var canvas = document.getElementById("canvas"); 43 var gl = wtu.create3DContext(canvas, null, 2); 44 45 if (!gl) { 46 testFailed("WebGL context does not exist"); 47 } else { 48 testPassed("WebGL context exists"); 49 } 50 51 const progInterleaved = wtu.setupTransformFeedbackProgram(gl, ["vshader", "fshader"], 52 ["out_value1", "out_value2"], gl.INTERLEAVED_ATTRIBS, 53 ["in_value1", "in_value2"]); 54 const progSeparate = wtu.setupTransformFeedbackProgram(gl, ["vshader", "fshader"], 55 ["out_value1", "out_value2"], gl.SEPARATE_ATTRIBS, 56 ["in_value1", "in_value2"]); 57 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "program compilation"); 58 59 // Attrib 1 contains 4 vertices. Attrib 2 contains 4 instance indices. 60 const vertexBuffer0 = gl.createBuffer(); 61 gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer0); 62 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([1, 2, 3, 4]), gl.STATIC_DRAW); 63 const vertexBuffer1 = gl.createBuffer(); 64 gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer1); 65 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([1, 2, 3, 4]), gl.STATIC_DRAW); 66 gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer0); 67 gl.enableVertexAttribArray(0); 68 gl.vertexAttribPointer(0, 1, gl.FLOAT, false, 0, 0); 69 gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer1); 70 gl.enableVertexAttribArray(1); 71 gl.vertexAttribPointer(1, 1, gl.FLOAT, false, 0, 0); 72 gl.vertexAttribDivisor(1, 1); 73 74 let tfBuffer0 = gl.createBuffer(); 75 let tfBuffer1 = gl.createBuffer(); 76 77 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "setup"); 78 79 const sizeOfFloat = 4; 80 81 let cases = [ 82 { name: "drawArrays", 83 drawFunction: ()=>gl.drawArrays(gl.POINTS, 0, 4), 84 result: [[2, 4, 6, 8], [2, 2, 2, 2]]}, 85 { name: "drawArraysInstanced one instance", 86 drawFunction: ()=>gl.drawArraysInstanced(gl.POINTS, 0, 4, 1), 87 result: [[2, 4, 6, 8], [2, 2, 2, 2]]}, 88 { name: "drawArraysInstanced four instances", 89 drawFunction: ()=>gl.drawArraysInstanced(gl.POINTS, 0, 1, 4), 90 result: [[2, 2, 2, 2], [2, 4, 6, 8]]}, 91 ]; 92 93 for (let {name, drawFunction, result} of cases) { 94 debug("<h1>" + name + "</h1>") 95 96 let interleavedResult = []; 97 for (let i = 0; i < result[0].length; i++) { 98 interleavedResult.push(result[0][i], result[1][i]); 99 } 100 101 let doTransformFeedback = (drawFunction, error) => { 102 gl.beginTransformFeedback(gl.POINTS); 103 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "before draw"); 104 drawFunction(); 105 wtu.glErrorShouldBe(gl, error, "draw"); 106 gl.endTransformFeedback(); 107 } 108 109 gl.useProgram(progInterleaved); 110 111 debug("<h3>interleaved - Baseline success case</h3>") 112 gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, tfBuffer0); 113 gl.bufferData(gl.TRANSFORM_FEEDBACK_BUFFER, 8*sizeOfFloat, gl.STREAM_READ); 114 doTransformFeedback(drawFunction, gl.NO_ERROR); 115 wtu.checkFloatBuffer(gl, gl.TRANSFORM_FEEDBACK_BUFFER, interleavedResult); 116 117 debug("<h3>interleaved - Buffer too small</h3>") 118 gl.bufferData(gl.TRANSFORM_FEEDBACK_BUFFER, 8*sizeOfFloat-1, gl.STREAM_READ); 119 doTransformFeedback(drawFunction, gl.INVALID_OPERATION); 120 wtu.checkFloatBuffer(gl, gl.TRANSFORM_FEEDBACK_BUFFER, 121 [0, 0, 0, 0, 0, 0, 0]); 122 123 debug("<h3>interleaved - Multiple draws success case</h3>") 124 gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, tfBuffer0); 125 gl.bufferData(gl.TRANSFORM_FEEDBACK_BUFFER, 8*sizeOfFloat*2, gl.STREAM_READ); 126 doTransformFeedback(()=>{drawFunction(); drawFunction()}, gl.NO_ERROR); 127 wtu.checkFloatBuffer(gl, gl.TRANSFORM_FEEDBACK_BUFFER, interleavedResult.concat(interleavedResult)) 128 129 debug("<h3>interleaved - Too small for multiple draws</h3>") 130 gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, tfBuffer0); 131 gl.bufferData(gl.TRANSFORM_FEEDBACK_BUFFER, 8*sizeOfFloat*2-1, gl.STREAM_READ); 132 doTransformFeedback(()=>{drawFunction(); drawFunction()}, gl.INVALID_OPERATION); 133 wtu.checkFloatBuffer(gl, gl.TRANSFORM_FEEDBACK_BUFFER, interleavedResult.concat([0, 0, 0, 0, 0, 0, 0])) 134 135 debug("<h3>interleaved - bindBufferRange too small</h3>") 136 gl.bufferData(gl.TRANSFORM_FEEDBACK_BUFFER, 8*sizeOfFloat, gl.STREAM_READ); 137 gl.bindBufferRange(gl.TRANSFORM_FEEDBACK_BUFFER, 0, tfBuffer0, 0, 7*sizeOfFloat); 138 doTransformFeedback(drawFunction, gl.INVALID_OPERATION); 139 wtu.checkFloatBuffer(gl, gl.TRANSFORM_FEEDBACK_BUFFER, 140 [0, 0, 0, 0, 0, 0, 0, 0]); 141 142 debug("<h3>interleaved - bindBufferRange larger than buffer</h3>") 143 gl.bufferData(gl.TRANSFORM_FEEDBACK_BUFFER, 8*sizeOfFloat-1, gl.STREAM_READ); 144 gl.bindBufferRange(gl.TRANSFORM_FEEDBACK_BUFFER, 0, tfBuffer0, 0, 8*sizeOfFloat); 145 doTransformFeedback(drawFunction, gl.INVALID_OPERATION); 146 wtu.checkFloatBuffer(gl, gl.TRANSFORM_FEEDBACK_BUFFER, 147 [0, 0, 0, 0, 0, 0, 0]); 148 149 gl.useProgram(progSeparate); 150 151 debug("<h3>separate - Baseline success case</h3>") 152 gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, tfBuffer0); 153 gl.bufferData(gl.TRANSFORM_FEEDBACK_BUFFER, 4*sizeOfFloat, gl.STREAM_READ); 154 gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 1, tfBuffer1); 155 gl.bufferData(gl.TRANSFORM_FEEDBACK_BUFFER, 4*sizeOfFloat, gl.STREAM_READ); 156 doTransformFeedback(drawFunction, gl.NO_ERROR); 157 gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, tfBuffer0); 158 wtu.checkFloatBuffer(gl, gl.TRANSFORM_FEEDBACK_BUFFER, result[0]); 159 gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, tfBuffer1); 160 wtu.checkFloatBuffer(gl, gl.TRANSFORM_FEEDBACK_BUFFER, result[1]); 161 162 debug("<h3>separate - Buffer too small</h3>") 163 gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, tfBuffer0); 164 gl.bufferData(gl.TRANSFORM_FEEDBACK_BUFFER, 4*sizeOfFloat, gl.STREAM_READ); 165 gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 1, tfBuffer1); 166 gl.bufferData(gl.TRANSFORM_FEEDBACK_BUFFER, 4*sizeOfFloat-1, gl.STREAM_READ); 167 doTransformFeedback(drawFunction, gl.INVALID_OPERATION); 168 gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, tfBuffer0); 169 wtu.checkFloatBuffer(gl, gl.TRANSFORM_FEEDBACK_BUFFER, [0, 0, 0, 0]); 170 gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, tfBuffer1); 171 wtu.checkFloatBuffer(gl, gl.TRANSFORM_FEEDBACK_BUFFER, [0, 0, 0]); 172 173 debug("<h3>separate - multiple draws success case</h3>") 174 gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, tfBuffer0); 175 gl.bufferData(gl.TRANSFORM_FEEDBACK_BUFFER, 4*sizeOfFloat*2, gl.STREAM_READ); 176 gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 1, tfBuffer1); 177 gl.bufferData(gl.TRANSFORM_FEEDBACK_BUFFER, 4*sizeOfFloat*2, gl.STREAM_READ); 178 doTransformFeedback(()=>{drawFunction(); drawFunction();}, gl.NO_ERROR); 179 gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, tfBuffer0); 180 wtu.checkFloatBuffer(gl, gl.TRANSFORM_FEEDBACK_BUFFER, result[0].concat(result[0])); 181 gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, tfBuffer1); 182 wtu.checkFloatBuffer(gl, gl.TRANSFORM_FEEDBACK_BUFFER, result[1].concat(result[1])); 183 184 debug("<h3>separate - Too small for multiple draws</h3>") 185 gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, tfBuffer0); 186 gl.bufferData(gl.TRANSFORM_FEEDBACK_BUFFER, 4*sizeOfFloat*2, gl.STREAM_READ); 187 gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 1, tfBuffer1); 188 gl.bufferData(gl.TRANSFORM_FEEDBACK_BUFFER, 4*sizeOfFloat*2-1, gl.STREAM_READ); 189 doTransformFeedback(()=>{drawFunction(); drawFunction();}, gl.INVALID_OPERATION); 190 gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, tfBuffer0); 191 wtu.checkFloatBuffer(gl, gl.TRANSFORM_FEEDBACK_BUFFER, result[0].concat([0, 0, 0, 0])); 192 gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, tfBuffer1); 193 wtu.checkFloatBuffer(gl, gl.TRANSFORM_FEEDBACK_BUFFER, result[1].concat([0, 0, 0])); 194 195 debug("<h3>separate - bindBufferRange too small</h3>") 196 gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, tfBuffer0); 197 gl.bufferData(gl.TRANSFORM_FEEDBACK_BUFFER, 4*sizeOfFloat, gl.STREAM_READ); 198 gl.bindBufferRange(gl.TRANSFORM_FEEDBACK_BUFFER, 1, tfBuffer1, 0, 3*sizeOfFloat); 199 gl.bufferData(gl.TRANSFORM_FEEDBACK_BUFFER, 4*sizeOfFloat, gl.STREAM_READ); 200 doTransformFeedback(drawFunction, gl.INVALID_OPERATION); 201 gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, tfBuffer0); 202 wtu.checkFloatBuffer(gl, gl.TRANSFORM_FEEDBACK_BUFFER, [0, 0, 0, 0]); 203 gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, tfBuffer1); 204 wtu.checkFloatBuffer(gl, gl.TRANSFORM_FEEDBACK_BUFFER, [0, 0, 0]); 205 206 debug("<h3>separate - bindBufferRange larger than buffer</h3>") 207 gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, tfBuffer0); 208 gl.bufferData(gl.TRANSFORM_FEEDBACK_BUFFER, 4*sizeOfFloat, gl.STREAM_READ); 209 gl.bindBufferRange(gl.TRANSFORM_FEEDBACK_BUFFER, 1, tfBuffer1, 0, 4*sizeOfFloat); 210 gl.bufferData(gl.TRANSFORM_FEEDBACK_BUFFER, 4*sizeOfFloat-1, gl.STREAM_READ); 211 doTransformFeedback(drawFunction, gl.INVALID_OPERATION); 212 gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, tfBuffer0); 213 wtu.checkFloatBuffer(gl, gl.TRANSFORM_FEEDBACK_BUFFER, [0, 0, 0, 0]); 214 gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, tfBuffer1); 215 wtu.checkFloatBuffer(gl, gl.TRANSFORM_FEEDBACK_BUFFER, [0, 0, 0]); 216 } 217 218 debug("<h1>integer overflow</h1>") 219 220 gl.useProgram(progInterleaved); 221 gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer0); 222 gl.bufferData(gl.ARRAY_BUFFER, (1<<16)*sizeOfFloat, gl.STREAM_READ); 223 gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer1); 224 gl.bufferData(gl.ARRAY_BUFFER, (1<<16)*sizeOfFloat, gl.STREAM_READ); 225 gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0, tfBuffer0); 226 gl.bufferData(gl.TRANSFORM_FEEDBACK_BUFFER, (1<<16)*sizeOfFloat*2, gl.STREAM_READ); 227 228 gl.beginTransformFeedback(gl.POINTS); 229 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "before draw"); 230 // If count and primcount are stored in 32-bit signed integers and then 231 // multiplied to calculate the number of transform feedback vertices, the 232 // calculation will overflow to 0. 233 gl.drawArraysInstanced(gl.POINTS, 0, 1<<16, 1<<16); 234 wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "integer overflow and/or buffer too small"); 235 gl.endTransformFeedback(); 236 237 finishTest(); 238 239 </script> 240 241 </body> 242 </html>