xref: /aosp_15_r20/external/angle/src/tests/gl_tests/DrawElementsTest.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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