1 //
2 // Copyright 2015 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // DrawElementsTest:
7 // Tests for indexed draws.
8 //
9
10 #include "test_utils/ANGLETest.h"
11 #include "test_utils/gl_raii.h"
12
13 using namespace angle;
14
15 namespace
16 {
17
18 class DrawElementsTest : public ANGLETest
19 {
20 protected:
DrawElementsTest()21 DrawElementsTest() : mProgram(0u)
22 {
23 setWindowWidth(64);
24 setWindowHeight(64);
25 setConfigRedBits(8);
26 setConfigGreenBits(8);
27 setConfigBlueBits(8);
28 setConfigAlphaBits(8);
29 }
30
~DrawElementsTest()31 ~DrawElementsTest()
32 {
33 for (GLuint indexBuffer : mIndexBuffers)
34 {
35 if (indexBuffer != 0)
36 {
37 glDeleteBuffers(1, &indexBuffer);
38 }
39 }
40
41 for (GLuint vertexArray : mVertexArrays)
42 {
43 if (vertexArray != 0)
44 {
45 glDeleteVertexArrays(1, &vertexArray);
46 }
47 }
48
49 for (GLuint vertexBuffer : mVertexBuffers)
50 {
51 if (vertexBuffer != 0)
52 {
53 glDeleteBuffers(1, &vertexBuffer);
54 }
55 }
56
57 if (mProgram != 0u)
58 {
59 glDeleteProgram(mProgram);
60 }
61 }
62
63 std::vector<GLuint> mIndexBuffers;
64 std::vector<GLuint> mVertexArrays;
65 std::vector<GLuint> mVertexBuffers;
66 GLuint mProgram;
67 };
68
69 class WebGLDrawElementsTest : public DrawElementsTest
70 {
71 public:
WebGLDrawElementsTest()72 WebGLDrawElementsTest() { setWebGLCompatibilityEnabled(true); }
73 };
74
75 // Test no error is generated when using client-side arrays, indices = nullptr and count = 0
TEST_P(DrawElementsTest,ClientSideNullptrArrayZeroCount)76 TEST_P(DrawElementsTest, ClientSideNullptrArrayZeroCount)
77 {
78 constexpr char kVS[] =
79 "attribute vec3 a_pos;\n"
80 "void main()\n"
81 "{\n"
82 " gl_Position = vec4(a_pos, 1.0);\n"
83 "}\n";
84
85 ANGLE_GL_PROGRAM(program, kVS, essl1_shaders::fs::Blue());
86
87 GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
88 ASSERT_NE(-1, posLocation);
89 glUseProgram(program.get());
90
91 const auto &vertices = GetQuadVertices();
92
93 GLBuffer vertexBuffer;
94 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.get());
95 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices.size(), vertices.data(),
96 GL_STATIC_DRAW);
97
98 glVertexAttribPointer(posLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
99 glEnableVertexAttribArray(posLocation);
100 ASSERT_GL_NO_ERROR();
101
102 // "If drawElements is called with a count greater than zero, and no WebGLBuffer is bound to the
103 // ELEMENT_ARRAY_BUFFER binding point, an INVALID_OPERATION error is generated."
104 glDrawElements(GL_TRIANGLES, 1, GL_UNSIGNED_BYTE, nullptr);
105 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
106
107 // count == 0 so it's fine to have no element array buffer bound.
108 glDrawElements(GL_TRIANGLES, 0, GL_UNSIGNED_BYTE, nullptr);
109 ASSERT_GL_NO_ERROR();
110 }
111
112 // Test a state desync that can occur when using a streaming index buffer in GL in concert with
113 // deleting the applied index buffer.
TEST_P(DrawElementsTest,DeletingAfterStreamingIndexes)114 TEST_P(DrawElementsTest, DeletingAfterStreamingIndexes)
115 {
116 // Init program
117 constexpr char kVS[] =
118 "attribute vec2 position;\n"
119 "attribute vec2 testFlag;\n"
120 "varying vec2 v_data;\n"
121 "void main() {\n"
122 " gl_Position = vec4(position, 0, 1);\n"
123 " v_data = testFlag;\n"
124 "}";
125
126 constexpr char kFS[] =
127 "varying highp vec2 v_data;\n"
128 "void main() {\n"
129 " gl_FragColor = vec4(v_data, 0, 1);\n"
130 "}";
131
132 mProgram = CompileProgram(kVS, kFS);
133 ASSERT_NE(0u, mProgram);
134 glUseProgram(mProgram);
135
136 GLint positionLocation = glGetAttribLocation(mProgram, "position");
137 ASSERT_NE(-1, positionLocation);
138
139 GLint testFlagLocation = glGetAttribLocation(mProgram, "testFlag");
140 ASSERT_NE(-1, testFlagLocation);
141
142 mIndexBuffers.resize(3u);
143 glGenBuffers(3, &mIndexBuffers[0]);
144
145 mVertexArrays.resize(2);
146 glGenVertexArrays(2, &mVertexArrays[0]);
147
148 mVertexBuffers.resize(2);
149 glGenBuffers(2, &mVertexBuffers[0]);
150
151 std::vector<GLuint> indexData[2];
152 indexData[0].push_back(0);
153 indexData[0].push_back(1);
154 indexData[0].push_back(2);
155 indexData[0].push_back(2);
156 indexData[0].push_back(3);
157 indexData[0].push_back(0);
158
159 indexData[1] = indexData[0];
160 for (GLuint &item : indexData[1])
161 {
162 item += 4u;
163 }
164
165 std::vector<GLfloat> positionData = {// quad verts
166 -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f,
167 // Repeat position data
168 -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f};
169
170 std::vector<GLfloat> testFlagData = {// red
171 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
172 // green
173 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f};
174
175 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffers[0]);
176 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * indexData[0].size(), &indexData[0][0],
177 GL_STATIC_DRAW);
178
179 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffers[2]);
180 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * indexData[0].size(), &indexData[0][0],
181 GL_STATIC_DRAW);
182
183 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffers[1]);
184 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * indexData[1].size(), &indexData[1][0],
185 GL_STATIC_DRAW);
186
187 // Initialize first vertex array with second index buffer
188 glBindVertexArray(mVertexArrays[0]);
189
190 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffers[1]);
191 glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffers[0]);
192 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * positionData.size(), &positionData[0],
193 GL_STATIC_DRAW);
194 glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 2, nullptr);
195 glEnableVertexAttribArray(positionLocation);
196
197 glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffers[1]);
198 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * testFlagData.size(), &testFlagData[0],
199 GL_STATIC_DRAW);
200 glVertexAttribPointer(testFlagLocation, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 2, nullptr);
201 glEnableVertexAttribArray(testFlagLocation);
202
203 // Initialize second vertex array with first index buffer
204 glBindVertexArray(mVertexArrays[1]);
205
206 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffers[0]);
207
208 glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffers[0]);
209 glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 2, nullptr);
210 glEnableVertexAttribArray(positionLocation);
211
212 glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffers[1]);
213 glVertexAttribPointer(testFlagLocation, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 2, nullptr);
214 glEnableVertexAttribArray(testFlagLocation);
215
216 ASSERT_GL_NO_ERROR();
217
218 glBindVertexArray(mVertexArrays[0]);
219 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
220 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
221
222 glBindVertexArray(mVertexArrays[1]);
223 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
224 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
225
226 glBindVertexArray(mVertexArrays[0]);
227 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
228 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
229
230 // Trigger the bug here.
231 glDeleteBuffers(1, &mIndexBuffers[2]);
232
233 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
234 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
235
236 ASSERT_GL_NO_ERROR();
237 }
238
239 // Test drawing to part of the indices in an index buffer, and then all of them.
TEST_P(DrawElementsTest,PartOfIndexBufferThenAll)240 TEST_P(DrawElementsTest, PartOfIndexBufferThenAll)
241 {
242 // Init program
243 constexpr char kVS[] =
244 "attribute vec2 position;\n"
245 "attribute vec2 testFlag;\n"
246 "varying vec2 v_data;\n"
247 "void main() {\n"
248 " gl_Position = vec4(position, 0, 1);\n"
249 " v_data = testFlag;\n"
250 "}";
251
252 constexpr char kFS[] =
253 "varying highp vec2 v_data;\n"
254 "void main() {\n"
255 " gl_FragColor = vec4(v_data, 0, 1);\n"
256 "}";
257
258 mProgram = CompileProgram(kVS, kFS);
259 ASSERT_NE(0u, mProgram);
260 glUseProgram(mProgram);
261
262 GLint positionLocation = glGetAttribLocation(mProgram, "position");
263 ASSERT_NE(-1, positionLocation);
264
265 GLint testFlagLocation = glGetAttribLocation(mProgram, "testFlag");
266 ASSERT_NE(-1, testFlagLocation);
267
268 mIndexBuffers.resize(1);
269 glGenBuffers(1, &mIndexBuffers[0]);
270
271 mVertexArrays.resize(1);
272 glGenVertexArrays(1, &mVertexArrays[0]);
273
274 mVertexBuffers.resize(2);
275 glGenBuffers(2, &mVertexBuffers[0]);
276
277 std::vector<GLubyte> indexData[2];
278 indexData[0].push_back(0);
279 indexData[0].push_back(1);
280 indexData[0].push_back(2);
281 indexData[0].push_back(2);
282 indexData[0].push_back(3);
283 indexData[0].push_back(0);
284 indexData[0].push_back(4);
285 indexData[0].push_back(5);
286 indexData[0].push_back(6);
287 indexData[0].push_back(6);
288 indexData[0].push_back(7);
289 indexData[0].push_back(4);
290
291 // Make a copy:
292 indexData[1] = indexData[0];
293
294 std::vector<GLfloat> positionData = {// quad verts
295 -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f,
296 // Repeat position data
297 -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f};
298
299 std::vector<GLfloat> testFlagData = {// red
300 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
301 // green
302 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f};
303
304 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffers[0]);
305 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLubyte) * indexData[0].size(), &indexData[0][0],
306 GL_STATIC_DRAW);
307
308 glBindVertexArray(mVertexArrays[0]);
309
310 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffers[0]);
311 glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffers[0]);
312 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * positionData.size(), &positionData[0],
313 GL_STATIC_DRAW);
314 glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 2, nullptr);
315 glEnableVertexAttribArray(positionLocation);
316
317 glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffers[1]);
318 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * testFlagData.size(), &testFlagData[0],
319 GL_STATIC_DRAW);
320 glVertexAttribPointer(testFlagLocation, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 2, nullptr);
321 glEnableVertexAttribArray(testFlagLocation);
322
323 ASSERT_GL_NO_ERROR();
324
325 // Draw with just the second set of 6 items, then first 6, and then the entire index buffer
326 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, reinterpret_cast<const void *>(6));
327 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
328
329 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, nullptr);
330 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
331
332 glDrawElements(GL_TRIANGLES, 12, GL_UNSIGNED_BYTE, nullptr);
333 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
334
335 // Reload the buffer again with a copy of the same data
336 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLubyte) * indexData[1].size(), &indexData[1][0],
337 GL_STATIC_DRAW);
338
339 // Draw with just the first 6 indices, and then with the entire index buffer
340 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, nullptr);
341 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
342
343 glDrawElements(GL_TRIANGLES, 12, GL_UNSIGNED_BYTE, nullptr);
344 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
345
346 // Reload the buffer again with a copy of the same data
347 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLubyte) * indexData[0].size(), &indexData[0][0],
348 GL_STATIC_DRAW);
349
350 // This time, do not check color between draws (which causes a flush):
351 // Draw with just the second set of 6 items, then first 6, and then the entire index buffer
352 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, reinterpret_cast<const void *>(6));
353 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, nullptr);
354 glDrawElements(GL_TRIANGLES, 12, GL_UNSIGNED_BYTE, nullptr);
355 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
356
357 ASSERT_GL_NO_ERROR();
358 }
359
360 // Test that the offset in the index buffer is forced to be a multiple of the element size
TEST_P(WebGLDrawElementsTest,DrawElementsTypeAlignment)361 TEST_P(WebGLDrawElementsTest, DrawElementsTypeAlignment)
362 {
363 constexpr char kVS[] =
364 "attribute vec3 a_pos;\n"
365 "void main()\n"
366 "{\n"
367 " gl_Position = vec4(a_pos, 1.0);\n"
368 "}\n";
369
370 ANGLE_GL_PROGRAM(program, kVS, essl1_shaders::fs::Blue());
371
372 GLint posLocation = glGetAttribLocation(program, "a_pos");
373 ASSERT_NE(-1, posLocation);
374 glUseProgram(program);
375
376 const auto &vertices = GetQuadVertices();
377
378 GLBuffer vertexBuffer;
379 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
380 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices.size(), vertices.data(),
381 GL_STATIC_DRAW);
382
383 glVertexAttribPointer(posLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
384 glEnableVertexAttribArray(posLocation);
385
386 GLBuffer indexBuffer;
387 const GLubyte indices1[] = {0, 0, 0, 0, 0, 0};
388 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
389 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices1), indices1, GL_STATIC_DRAW);
390
391 ASSERT_GL_NO_ERROR();
392
393 const char *zeroIndices = nullptr;
394
395 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, zeroIndices);
396 ASSERT_GL_NO_ERROR();
397
398 const GLushort indices2[] = {0, 0, 0, 0, 0, 0};
399 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
400 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices2), indices2, GL_STATIC_DRAW);
401
402 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, zeroIndices + 1);
403 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
404 }
405
406 ANGLE_INSTANTIATE_TEST_ES3(DrawElementsTest);
407 ANGLE_INSTANTIATE_TEST_ES2(WebGLDrawElementsTest);
408 } // namespace
409