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.
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>
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
26 out_value1 = in_value1 *
2.;
27 out_value2 = in_value2 *
2.;
30 <script id=
"fshader" type=
"x-shader/x-fragment">#version
300 es
31 precision mediump float;
39 description("Transform feedback into buffers that are too small should produce errors.");
41 var wtu
= WebGLTestUtils
;
42 var canvas
= document
.getElementById("canvas");
43 var gl
= wtu
.create3DContext(canvas
, null, 2);
46 testFailed("WebGL context does not exist");
48 testPassed("WebGL context exists");
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");
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);
74 let tfBuffer0
= gl
.createBuffer();
75 let tfBuffer1
= gl
.createBuffer();
77 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
, "setup");
79 const sizeOfFloat
= 4;
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]]},
93 for (let {name
, drawFunction
, result
} of cases
) {
94 debug("<h1>" + name
+ "</h1>")
96 let interleavedResult
= [];
97 for (let i
= 0; i
< result
[0].length
; i
++) {
98 interleavedResult
.push(result
[0][i
], result
[1][i
]);
101 let doTransformFeedback
= (drawFunction
, error
) => {
102 gl
.beginTransformFeedback(gl
.POINTS
);
103 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
, "before draw");
105 wtu
.glErrorShouldBe(gl
, error
, "draw");
106 gl
.endTransformFeedback();
109 gl
.useProgram(progInterleaved
);
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
);
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]);
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
))
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]))
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]);
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]);
149 gl
.useProgram(progSeparate
);
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]);
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]);
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]));
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]));
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]);
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]);
218 debug("<h1>integer overflow</h1>")
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
);
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();