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, "a_pos");
88 ASSERT_NE(-1, posLocation);
89 glUseProgram(program);
90
91 const auto &vertices = GetQuadVertices();
92
93 GLBuffer vertexBuffer;
94 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
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 uploading part of an index buffer after deleting a vertex array
113 // previously used for DrawElements.
TEST_P(DrawElementsTest,DeleteVertexArrayAndUploadIndex)114 TEST_P(DrawElementsTest, DeleteVertexArrayAndUploadIndex)
115 {
116 const auto &vertices = GetIndexedQuadVertices();
117 const auto &indices = GetQuadIndices();
118
119 ANGLE_GL_PROGRAM(programDrawRed, essl3_shaders::vs::Simple(), essl3_shaders::fs::Red());
120 glUseProgram(programDrawRed);
121
122 GLint posLocation = glGetAttribLocation(programDrawRed, essl3_shaders::PositionAttrib());
123 ASSERT_NE(-1, posLocation);
124
125 GLuint vertexArray;
126 glGenVertexArrays(1, &vertexArray);
127 glBindVertexArray(vertexArray);
128
129 GLBuffer vertexBuffer;
130 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
131 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices.size(), vertices.data(),
132 GL_STATIC_DRAW);
133
134 glVertexAttribPointer(posLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
135 glEnableVertexAttribArray(posLocation);
136
137 GLBuffer indexBuffer;
138 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
139 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices[0]) * indices.size(), indices.data(),
140 GL_STATIC_DRAW);
141
142 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, nullptr);
143
144 glDeleteVertexArrays(1, &vertexArray);
145
146 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
147
148 // Could crash here if the observer binding from the vertex array doesn't get
149 // removed on vertex array destruction.
150 glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(indices[0]) * 3, indices.data());
151
152 ASSERT_GL_NO_ERROR();
153 }
154
155 // Test VAO switch is handling cached element array buffer properly along with line loop mode
156 // switch.
TEST_P(DrawElementsTest,LineLoopTriangles)157 TEST_P(DrawElementsTest, LineLoopTriangles)
158 {
159 const auto &vertices = GetIndexedQuadVertices();
160 constexpr std::array<GLuint, 6> indices = {{0, 1, 2, 0, 2, 3}};
161
162 ANGLE_GL_PROGRAM(programDrawRed, essl3_shaders::vs::Simple(), essl3_shaders::fs::Red());
163 ANGLE_GL_PROGRAM(programDrawBlue, essl3_shaders::vs::Simple(), essl3_shaders::fs::Blue());
164
165 glUseProgram(programDrawRed);
166 GLint posLocation = glGetAttribLocation(programDrawRed, essl3_shaders::PositionAttrib());
167 ASSERT_NE(-1, posLocation);
168
169 GLVertexArray vertexArray[2];
170 GLBuffer vertexBuffer[2];
171
172 glBindVertexArray(vertexArray[0]);
173
174 GLBuffer indexBuffer;
175 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
176 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices[0]) * indices.size(), indices.data(),
177 GL_STATIC_DRAW);
178
179 for (int i = 0; i < 2; i++)
180 {
181 glBindVertexArray(vertexArray[i]);
182 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[i]);
183 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices.size(), vertices.data(),
184 GL_STATIC_DRAW);
185 glVertexAttribPointer(posLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
186 glEnableVertexAttribArray(posLocation);
187 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
188 }
189
190 // First draw with VAO0 and line loop mode
191 glBindVertexArray(vertexArray[0]);
192 glDrawArrays(GL_LINE_LOOP, 0, 4);
193
194 // Switch to VAO1 and draw with triangle mode.
195 glBindVertexArray(vertexArray[1]);
196 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
197 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
198
199 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
200 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() - 1, 0, GLColor::red);
201 EXPECT_PIXEL_COLOR_EQ(0, getWindowHeight() - 1, GLColor::red);
202 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() - 1, getWindowHeight() - 1, GLColor::red);
203
204 // Switch back to VAO0 and draw with triangle mode.
205 glUseProgram(programDrawBlue);
206 glBindVertexArray(vertexArray[0]);
207 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
208 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
209
210 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
211 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() - 1, 0, GLColor::blue);
212 EXPECT_PIXEL_COLOR_EQ(0, getWindowHeight() - 1, GLColor::blue);
213 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() - 1, getWindowHeight() - 1, GLColor::blue);
214 ASSERT_GL_NO_ERROR();
215 }
216
217 // Regression test for using two VAOs, one to draw only GL_LINE_LOOPs, and
218 // another to draw indexed triangles.
TEST_P(DrawElementsTest,LineLoopTriangles2)219 TEST_P(DrawElementsTest, LineLoopTriangles2)
220 {
221 const auto &vertices = GetIndexedQuadVertices();
222 constexpr std::array<GLuint, 6> indices = {{0, 1, 2, 0, 2, 3}};
223
224 ANGLE_GL_PROGRAM(programDrawRed, essl3_shaders::vs::Simple(), essl3_shaders::fs::Red());
225
226 glUseProgram(programDrawRed);
227 GLint posLocation = glGetAttribLocation(programDrawRed, essl3_shaders::PositionAttrib());
228 ASSERT_NE(-1, posLocation);
229
230 GLVertexArray vertexArray[2];
231 GLBuffer vertexBuffer[2];
232
233 GLBuffer indexBuffer;
234 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
235 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices[0]) * indices.size(), indices.data(),
236 GL_STATIC_DRAW);
237
238 for (int i = 0; i < 2; i++)
239 {
240 glBindVertexArray(vertexArray[i]);
241 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[i]);
242 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices.size(), vertices.data(),
243 GL_STATIC_DRAW);
244 glVertexAttribPointer(posLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
245 glEnableVertexAttribArray(posLocation);
246 if (i != 0)
247 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
248 }
249
250 // First draw with VAO0 and line loop mode
251 glBindVertexArray(vertexArray[0]);
252 glDrawArrays(GL_LINE_LOOP, 0, 4);
253
254 // Switch to VAO1 and draw some indexed triangles
255 glBindVertexArray(vertexArray[1]);
256 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
257 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
258
259 // Switch back to VAO0 and do another line loop
260 glBindVertexArray(vertexArray[0]);
261
262 // Would crash if the index buffer dirty bit got errantly set on VAO0.
263 glDrawArrays(GL_LINE_LOOP, 0, 4);
264
265 ASSERT_GL_NO_ERROR();
266 }
267
268 // Test a state desync that can occur when using a streaming index buffer in GL in concert with
269 // deleting the applied index buffer.
TEST_P(DrawElementsTest,DeletingAfterStreamingIndexes)270 TEST_P(DrawElementsTest, DeletingAfterStreamingIndexes)
271 {
272 // Init program
273 constexpr char kVS[] =
274 "attribute vec2 position;\n"
275 "attribute vec2 testFlag;\n"
276 "varying vec2 v_data;\n"
277 "void main() {\n"
278 " gl_Position = vec4(position, 0, 1);\n"
279 " v_data = testFlag;\n"
280 "}";
281
282 constexpr char kFS[] =
283 "varying highp vec2 v_data;\n"
284 "void main() {\n"
285 " gl_FragColor = vec4(v_data, 0, 1);\n"
286 "}";
287
288 mProgram = CompileProgram(kVS, kFS);
289 ASSERT_NE(0u, mProgram);
290 glUseProgram(mProgram);
291
292 GLint positionLocation = glGetAttribLocation(mProgram, "position");
293 ASSERT_NE(-1, positionLocation);
294
295 GLint testFlagLocation = glGetAttribLocation(mProgram, "testFlag");
296 ASSERT_NE(-1, testFlagLocation);
297
298 mIndexBuffers.resize(3u);
299 glGenBuffers(3, &mIndexBuffers[0]);
300
301 mVertexArrays.resize(2);
302 glGenVertexArrays(2, &mVertexArrays[0]);
303
304 mVertexBuffers.resize(2);
305 glGenBuffers(2, &mVertexBuffers[0]);
306
307 std::vector<GLuint> indexData[2];
308 indexData[0].push_back(0);
309 indexData[0].push_back(1);
310 indexData[0].push_back(2);
311 indexData[0].push_back(2);
312 indexData[0].push_back(3);
313 indexData[0].push_back(0);
314
315 indexData[1] = indexData[0];
316 for (GLuint &item : indexData[1])
317 {
318 item += 4u;
319 }
320
321 std::vector<GLfloat> positionData = {// quad verts
322 -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f,
323 // Repeat position data
324 -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f};
325
326 std::vector<GLfloat> testFlagData = {// red
327 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
328 // green
329 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f};
330
331 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffers[0]);
332 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * indexData[0].size(), &indexData[0][0],
333 GL_STATIC_DRAW);
334
335 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffers[2]);
336 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * indexData[0].size(), &indexData[0][0],
337 GL_STATIC_DRAW);
338
339 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffers[1]);
340 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * indexData[1].size(), &indexData[1][0],
341 GL_STATIC_DRAW);
342
343 // Initialize first vertex array with second index buffer
344 glBindVertexArray(mVertexArrays[0]);
345
346 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffers[1]);
347 glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffers[0]);
348 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * positionData.size(), &positionData[0],
349 GL_STATIC_DRAW);
350 glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 2, nullptr);
351 glEnableVertexAttribArray(positionLocation);
352
353 glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffers[1]);
354 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * testFlagData.size(), &testFlagData[0],
355 GL_STATIC_DRAW);
356 glVertexAttribPointer(testFlagLocation, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 2, nullptr);
357 glEnableVertexAttribArray(testFlagLocation);
358
359 // Initialize second vertex array with first index buffer
360 glBindVertexArray(mVertexArrays[1]);
361
362 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffers[0]);
363
364 glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffers[0]);
365 glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 2, nullptr);
366 glEnableVertexAttribArray(positionLocation);
367
368 glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffers[1]);
369 glVertexAttribPointer(testFlagLocation, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 2, nullptr);
370 glEnableVertexAttribArray(testFlagLocation);
371
372 ASSERT_GL_NO_ERROR();
373
374 glBindVertexArray(mVertexArrays[0]);
375 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
376 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
377
378 glBindVertexArray(mVertexArrays[1]);
379 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
380 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
381
382 glBindVertexArray(mVertexArrays[0]);
383 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
384 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
385
386 // Trigger the bug here.
387 glDeleteBuffers(1, &mIndexBuffers[2]);
388
389 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
390 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
391
392 ASSERT_GL_NO_ERROR();
393 }
394
395 // Verify that detaching shaders after linking doesn't break draw calls
TEST_P(DrawElementsTest,DrawWithDetachedShaders)396 TEST_P(DrawElementsTest, DrawWithDetachedShaders)
397 {
398 const auto &vertices = GetIndexedQuadVertices();
399
400 GLBuffer vertexBuffer;
401 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
402 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices.size(), vertices.data(),
403 GL_STATIC_DRAW);
404
405 GLBuffer indexBuffer;
406 const auto &indices = GetQuadIndices();
407 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
408 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices[0]) * indices.size(), indices.data(),
409 GL_STATIC_DRAW);
410 ASSERT_GL_NO_ERROR();
411
412 GLuint vertexShader = CompileShader(GL_VERTEX_SHADER, essl3_shaders::vs::Simple());
413 GLuint fragmentShader = CompileShader(GL_FRAGMENT_SHADER, essl3_shaders::fs::Red());
414 ASSERT_NE(0u, vertexShader);
415 ASSERT_NE(0u, fragmentShader);
416
417 GLuint program = glCreateProgram();
418 glAttachShader(program, vertexShader);
419 glAttachShader(program, fragmentShader);
420
421 glLinkProgram(program);
422
423 GLint linkStatus;
424 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
425 EXPECT_EQ(GL_TRUE, linkStatus);
426
427 glDetachShader(program, vertexShader);
428 glDetachShader(program, fragmentShader);
429 glDeleteShader(vertexShader);
430 glDeleteShader(fragmentShader);
431 ASSERT_GL_NO_ERROR();
432
433 glUseProgram(program);
434
435 GLint posLocation = glGetAttribLocation(program, essl3_shaders::PositionAttrib());
436 ASSERT_NE(-1, posLocation);
437
438 GLVertexArray vertexArray;
439 glBindVertexArray(vertexArray);
440 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
441 glVertexAttribPointer(posLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
442 glEnableVertexAttribArray(posLocation);
443
444 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
445 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, nullptr);
446 ASSERT_GL_NO_ERROR();
447
448 glDeleteProgram(program);
449 ASSERT_GL_NO_ERROR();
450 }
451
452 // Test drawing to part of the indices in an index buffer, and then all of them.
TEST_P(DrawElementsTest,PartOfIndexBufferThenAll)453 TEST_P(DrawElementsTest, PartOfIndexBufferThenAll)
454 {
455 // Init program
456 constexpr char kVS[] =
457 "attribute vec2 position;\n"
458 "attribute vec2 testFlag;\n"
459 "varying vec2 v_data;\n"
460 "void main() {\n"
461 " gl_Position = vec4(position, 0, 1);\n"
462 " v_data = testFlag;\n"
463 "}";
464
465 constexpr char kFS[] =
466 "varying highp vec2 v_data;\n"
467 "void main() {\n"
468 " gl_FragColor = vec4(v_data, 0, 1);\n"
469 "}";
470
471 mProgram = CompileProgram(kVS, kFS);
472 ASSERT_NE(0u, mProgram);
473 glUseProgram(mProgram);
474
475 GLint positionLocation = glGetAttribLocation(mProgram, "position");
476 ASSERT_NE(-1, positionLocation);
477
478 GLint testFlagLocation = glGetAttribLocation(mProgram, "testFlag");
479 ASSERT_NE(-1, testFlagLocation);
480
481 mIndexBuffers.resize(1);
482 glGenBuffers(1, &mIndexBuffers[0]);
483
484 mVertexArrays.resize(1);
485 glGenVertexArrays(1, &mVertexArrays[0]);
486
487 mVertexBuffers.resize(2);
488 glGenBuffers(2, &mVertexBuffers[0]);
489
490 std::vector<GLubyte> indexData[2];
491 indexData[0].push_back(0);
492 indexData[0].push_back(1);
493 indexData[0].push_back(2);
494 indexData[0].push_back(2);
495 indexData[0].push_back(3);
496 indexData[0].push_back(0);
497 indexData[0].push_back(4);
498 indexData[0].push_back(5);
499 indexData[0].push_back(6);
500 indexData[0].push_back(6);
501 indexData[0].push_back(7);
502 indexData[0].push_back(4);
503
504 // Make a copy:
505 indexData[1] = indexData[0];
506
507 std::vector<GLfloat> positionData = {// quad verts
508 -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f,
509 // Repeat position data
510 -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f};
511
512 std::vector<GLfloat> testFlagData = {// red
513 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
514 // green
515 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f};
516
517 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffers[0]);
518 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLubyte) * indexData[0].size(), &indexData[0][0],
519 GL_STATIC_DRAW);
520
521 glBindVertexArray(mVertexArrays[0]);
522
523 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffers[0]);
524 glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffers[0]);
525 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * positionData.size(), &positionData[0],
526 GL_STATIC_DRAW);
527 glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 2, nullptr);
528 glEnableVertexAttribArray(positionLocation);
529
530 glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffers[1]);
531 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * testFlagData.size(), &testFlagData[0],
532 GL_STATIC_DRAW);
533 glVertexAttribPointer(testFlagLocation, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 2, nullptr);
534 glEnableVertexAttribArray(testFlagLocation);
535
536 ASSERT_GL_NO_ERROR();
537
538 // Draw with just the second set of 6 items, then first 6, and then the entire index buffer
539 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, reinterpret_cast<const void *>(6));
540 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
541
542 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, nullptr);
543 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
544
545 glDrawElements(GL_TRIANGLES, 12, GL_UNSIGNED_BYTE, nullptr);
546 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
547
548 // Reload the buffer again with a copy of the same data
549 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLubyte) * indexData[1].size(), &indexData[1][0],
550 GL_STATIC_DRAW);
551
552 // Draw with just the first 6 indices, and then with the entire index buffer
553 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, nullptr);
554 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
555
556 glDrawElements(GL_TRIANGLES, 12, GL_UNSIGNED_BYTE, nullptr);
557 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
558
559 // Reload the buffer again with a copy of the same data
560 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLubyte) * indexData[0].size(), &indexData[0][0],
561 GL_STATIC_DRAW);
562
563 // This time, do not check color between draws (which causes a flush):
564 // Draw with just the second set of 6 items, then first 6, and then the entire index buffer
565 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, reinterpret_cast<const void *>(6));
566 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, nullptr);
567 glDrawElements(GL_TRIANGLES, 12, GL_UNSIGNED_BYTE, nullptr);
568 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
569
570 ASSERT_GL_NO_ERROR();
571 }
572
573 // Test that glDrawElements call with different index buffer offsets work as expected
TEST_P(DrawElementsTest,DrawElementsWithDifferentIndexBufferOffsets)574 TEST_P(DrawElementsTest, DrawElementsWithDifferentIndexBufferOffsets)
575 {
576 const std::array<Vector3, 4> &vertices = GetIndexedQuadVertices();
577 const std::array<GLushort, 6> &indices = GetQuadIndices();
578
579 glClearColor(0.f, 0.f, 0.f, 1.f);
580 glClear(GL_COLOR_BUFFER_BIT);
581
582 ANGLE_GL_PROGRAM(programDrawRed, essl3_shaders::vs::Simple(), essl3_shaders::fs::Red());
583 ANGLE_GL_PROGRAM(programDrawGreen, essl3_shaders::vs::Simple(), essl3_shaders::fs::Green());
584 ANGLE_GL_PROGRAM(programDrawBlue, essl3_shaders::vs::Simple(), essl3_shaders::fs::Blue());
585
586 glUseProgram(programDrawRed);
587
588 GLuint vertexArray;
589 glGenVertexArrays(1, &vertexArray);
590 glBindVertexArray(vertexArray);
591 GLBuffer vertexBuffer;
592 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
593 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices.size(), vertices.data(),
594 GL_STATIC_DRAW);
595
596 GLint posLocation = glGetAttribLocation(programDrawRed, essl3_shaders::PositionAttrib());
597 ASSERT_NE(-1, posLocation);
598 glVertexAttribPointer(posLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
599 glEnableVertexAttribArray(posLocation);
600
601 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
602
603 // Draw both triangles of quad
604 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices.data());
605 EXPECT_PIXEL_COLOR_EQ(0, 1, GLColor::red);
606 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() - 1, getWindowHeight() - 2, GLColor::red);
607
608 glUseProgram(programDrawGreen);
609
610 GLuint vertexArray1;
611 glGenVertexArrays(1, &vertexArray1);
612 glBindVertexArray(vertexArray1);
613 GLBuffer vertexBuffer1;
614 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer1);
615 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices.size(), vertices.data(),
616 GL_STATIC_DRAW);
617
618 posLocation = glGetAttribLocation(programDrawGreen, essl3_shaders::PositionAttrib());
619 ASSERT_NE(-1, posLocation);
620 glVertexAttribPointer(posLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
621 glEnableVertexAttribArray(posLocation);
622
623 GLBuffer indexBuffer;
624 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
625 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices[0]) * indices.size(), indices.data(),
626 GL_DYNAMIC_DRAW);
627
628 // Draw right triangle of quad
629 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, reinterpret_cast<const void *>(6));
630 EXPECT_PIXEL_COLOR_EQ(0, 1, GLColor::red);
631 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() - 1, getWindowHeight() - 2, GLColor::green);
632
633 glUseProgram(programDrawBlue);
634
635 glBindVertexArray(vertexArray);
636 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
637
638 posLocation = glGetAttribLocation(programDrawBlue, essl3_shaders::PositionAttrib());
639 ASSERT_NE(-1, posLocation);
640 glVertexAttribPointer(posLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
641 glEnableVertexAttribArray(posLocation);
642
643 // Draw both triangles of quad
644 glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices.data());
645 EXPECT_PIXEL_COLOR_EQ(0, 1, GLColor::blue);
646 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() - 1, getWindowHeight() - 2, GLColor::blue);
647
648 glDeleteVertexArrays(1, &vertexArray);
649 glDeleteVertexArrays(1, &vertexArray1);
650
651 ASSERT_GL_NO_ERROR();
652 }
653
654 // Test that the offset in the index buffer is forced to be a multiple of the element size
TEST_P(WebGLDrawElementsTest,DrawElementsTypeAlignment)655 TEST_P(WebGLDrawElementsTest, DrawElementsTypeAlignment)
656 {
657 constexpr char kVS[] =
658 "attribute vec3 a_pos;\n"
659 "void main()\n"
660 "{\n"
661 " gl_Position = vec4(a_pos, 1.0);\n"
662 "}\n";
663
664 ANGLE_GL_PROGRAM(program, kVS, essl1_shaders::fs::Blue());
665
666 GLint posLocation = glGetAttribLocation(program, "a_pos");
667 ASSERT_NE(-1, posLocation);
668 glUseProgram(program);
669
670 const auto &vertices = GetQuadVertices();
671
672 GLBuffer vertexBuffer;
673 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
674 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices.size(), vertices.data(),
675 GL_STATIC_DRAW);
676
677 glVertexAttribPointer(posLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
678 glEnableVertexAttribArray(posLocation);
679
680 GLBuffer indexBuffer;
681 const GLubyte indices1[] = {0, 0, 0, 0, 0, 0};
682 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
683 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices1), indices1, GL_STATIC_DRAW);
684
685 ASSERT_GL_NO_ERROR();
686
687 const char *zeroIndices = nullptr;
688
689 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, zeroIndices);
690 ASSERT_GL_NO_ERROR();
691
692 const GLushort indices2[] = {0, 0, 0, 0, 0, 0};
693 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
694 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices2), indices2, GL_STATIC_DRAW);
695
696 glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, zeroIndices + 1);
697 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
698 }
699
700 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DrawElementsTest);
701 ANGLE_INSTANTIATE_TEST_ES3(DrawElementsTest);
702
703 ANGLE_INSTANTIATE_TEST_ES2(WebGLDrawElementsTest);
704 } // namespace
705