xref: /aosp_15_r20/external/angle/src/tests/gl_tests/IndexBufferOffsetTest.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 
7 // IndexBufferOffsetTest.cpp: Test glDrawElements with an offset and an index buffer
8 
9 #include "test_utils/ANGLETest.h"
10 #include "test_utils/gl_raii.h"
11 #include "util/test_utils.h"
12 
13 using namespace angle;
14 enum class UpdateType
15 {
16     SmallUpdate,
17     SmallThenBigUpdate,
18     BigThenSmallUpdate,
19     FullUpdate,
20 };
21 
22 class IndexBufferOffsetTest : public ANGLETest<>
23 {
24   protected:
IndexBufferOffsetTest()25     IndexBufferOffsetTest()
26     {
27         setWindowWidth(128);
28         setWindowHeight(128);
29         setConfigRedBits(8);
30         setConfigGreenBits(8);
31         setConfigBlueBits(8);
32         setConfigAlphaBits(8);
33     }
34 
testSetUp()35     void testSetUp() override
36     {
37         constexpr char kVS[] =
38             R"(precision highp float;
39             attribute vec2 position;
40 
41             void main()
42             {
43                 gl_Position = vec4(position, 0.0, 1.0);
44             })";
45 
46         constexpr char kFS[] =
47             R"(precision highp float;
48             uniform vec4 color;
49 
50             void main()
51             {
52                 gl_FragColor = color;
53             })";
54 
55         mProgram = CompileProgram(kVS, kFS);
56         ASSERT_NE(0u, mProgram);
57 
58         mColorUniformLocation      = glGetUniformLocation(mProgram, "color");
59         mPositionAttributeLocation = glGetAttribLocation(mProgram, "position");
60 
61         const GLfloat vertices[] = {-1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f};
62         glGenBuffers(1, &mVertexBuffer);
63         glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
64         glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), &vertices[0], GL_STATIC_DRAW);
65 
66         glGenBuffers(1, &mIndexBuffer);
67         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
68     }
69 
testTearDown()70     void testTearDown() override
71     {
72         glDeleteBuffers(1, &mVertexBuffer);
73         glDeleteBuffers(1, &mIndexBuffer);
74         glDeleteProgram(mProgram);
75     }
76 
preTestUpdateBuffer(GLuint framebuffer,GLuint texture,GLuint buffer,GLsizei size)77     void preTestUpdateBuffer(GLuint framebuffer, GLuint texture, GLuint buffer, GLsizei size)
78     {
79         GLsizei uboSize = std::max(size, 16);
80         const std::vector<uint32_t> initialData((uboSize + 3) / 4, 0x1234567u);
81 
82         glBindTexture(GL_TEXTURE_2D, texture);
83         glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 1, 1);
84 
85         glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
86         glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture,
87                                0);
88 
89         glBindBuffer(GL_UNIFORM_BUFFER, buffer);
90         glBufferData(GL_UNIFORM_BUFFER, uboSize, initialData.data(), GL_DYNAMIC_DRAW);
91         glBindBufferBase(GL_UNIFORM_BUFFER, 0, buffer);
92 
93         constexpr char kVerifyUBO[] = R"(#version 300 es
94 precision mediump float;
95 uniform block {
96     uint data;
97 } ubo;
98 out vec4 colorOut;
99 void main()
100 {
101     if (ubo.data == 0x1234567u)
102         colorOut = vec4(0, 1.0, 0, 1.0);
103     else
104         colorOut = vec4(1.0, 0, 0, 1.0);
105 })";
106 
107         ANGLE_GL_PROGRAM(verifyUbo, essl3_shaders::vs::Simple(), kVerifyUBO);
108 
109         glDisable(GL_BLEND);
110         drawQuad(verifyUbo, essl3_shaders::PositionAttrib(), 0.5);
111 
112         EXPECT_GL_NO_ERROR();
113 
114         glBindFramebuffer(GL_FRAMEBUFFER, 0);
115     }
116 
runTest(GLenum type,int typeWidth,void * indexDataIn,UpdateType updateType,bool useBuffersAsUboFirst)117     void runTest(GLenum type,
118                  int typeWidth,
119                  void *indexDataIn,
120                  UpdateType updateType,
121                  bool useBuffersAsUboFirst)
122     {
123         glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
124         glClear(GL_COLOR_BUFFER_BIT);
125 
126         size_t indexDataWidth = 6 * typeWidth;
127 
128         std::vector<GLubyte> indexData(6 * 3 * sizeof(GLuint), 0);
129         memcpy(indexData.data() + indexDataWidth, indexDataIn, indexDataWidth);
130 
131         GLFramebuffer elementUpdateFbo;
132         GLTexture elementUpdateTex;
133 
134         if (useBuffersAsUboFirst)
135         {
136             preTestUpdateBuffer(elementUpdateFbo, elementUpdateTex, mIndexBuffer,
137                                 3 * indexDataWidth);
138         }
139         else
140         {
141             glBufferData(GL_ELEMENT_ARRAY_BUFFER, 3 * indexDataWidth, nullptr, GL_DYNAMIC_DRAW);
142         }
143 
144         if (updateType == UpdateType::SmallUpdate)
145         {
146             glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, indexDataWidth, indexData.data());
147             glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, indexDataWidth, indexDataWidth,
148                             indexData.data() + indexDataWidth);
149             glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 2 * indexDataWidth, indexDataWidth,
150                             indexData.data() + 2 * indexDataWidth);
151         }
152         else if (updateType == UpdateType::SmallThenBigUpdate)
153         {
154             glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, 4, indexData.data());
155             glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 4, 3 * indexDataWidth - 4,
156                             indexData.data() + 4);
157         }
158         else if (updateType == UpdateType::BigThenSmallUpdate)
159         {
160             glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, 3 * indexDataWidth - 4, indexData.data());
161             glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 3 * indexDataWidth - 4, 4,
162                             indexData.data() + 3 * indexDataWidth - 4);
163         }
164         else
165         {
166             ASSERT_EQ(updateType, UpdateType::FullUpdate);
167             glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, 3 * indexDataWidth, indexData.data());
168         }
169 
170         glUseProgram(mProgram);
171 
172         glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
173         glVertexAttribPointer(mPositionAttributeLocation, 2, GL_FLOAT, GL_FALSE, 0, 0);
174         glEnableVertexAttribArray(mPositionAttributeLocation);
175 
176         glUniform4f(mColorUniformLocation, 1.0f, 0.0f, 0.0f, 1.0f);
177 
178         for (int i = 0; i < 16; i++)
179         {
180             glDrawElements(GL_TRIANGLES, 6, type, reinterpret_cast<void *>(indexDataWidth));
181             EXPECT_PIXEL_COLOR_EQ(64, 64, GLColor::red);
182         }
183 
184         if (updateType == UpdateType::SmallUpdate)
185         {
186             glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, indexDataWidth, indexDataWidth,
187                             indexData.data());
188             glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 2 * indexDataWidth, indexDataWidth,
189                             indexData.data() + indexDataWidth);
190         }
191         else if (updateType == UpdateType::SmallThenBigUpdate)
192         {
193             glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, indexDataWidth, 4, indexData.data());
194             glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, indexDataWidth + 4, 2 * indexDataWidth - 4,
195                             indexData.data() + 4);
196         }
197         else if (updateType == UpdateType::BigThenSmallUpdate)
198         {
199             glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, indexDataWidth, 2 * indexDataWidth - 4,
200                             indexData.data());
201             glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 3 * indexDataWidth - 4, 4,
202                             indexData.data() + 2 * indexDataWidth - 4);
203         }
204         else
205         {
206             glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, indexDataWidth, 2 * indexDataWidth,
207                             indexData.data());
208         }
209 
210         glUniform4f(mColorUniformLocation, 0.0f, 1.0f, 0.0f, 1.0f);
211         glDrawElements(GL_TRIANGLES, 6, type, reinterpret_cast<void *>(indexDataWidth * 2));
212         EXPECT_PIXEL_COLOR_EQ(64, 64, GLColor::green);
213 
214         if (useBuffersAsUboFirst)
215         {
216             glBindFramebuffer(GL_FRAMEBUFFER, elementUpdateFbo);
217             EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
218         }
219 
220         EXPECT_GL_NO_ERROR();
221         swapBuffers();
222     }
223 
224     GLuint mProgram;
225     GLint mColorUniformLocation;
226     GLint mPositionAttributeLocation;
227     GLuint mVertexBuffer;
228     GLuint mIndexBuffer;
229 };
230 
231 class IndexBufferOffsetTestES3 : public IndexBufferOffsetTest
232 {};
233 
234 // Test using an offset for an UInt8 index buffer
TEST_P(IndexBufferOffsetTest,UInt8Index)235 TEST_P(IndexBufferOffsetTest, UInt8Index)
236 {
237     GLubyte indexData[] = {0, 1, 2, 1, 2, 3};
238     runTest(GL_UNSIGNED_BYTE, 1, indexData, UpdateType::FullUpdate, false);
239 }
240 
241 // Test using an offset for an UInt16 index buffer
TEST_P(IndexBufferOffsetTest,UInt16Index)242 TEST_P(IndexBufferOffsetTest, UInt16Index)
243 {
244     GLushort indexData[] = {0, 1, 2, 1, 2, 3};
245     runTest(GL_UNSIGNED_SHORT, 2, indexData, UpdateType::FullUpdate, false);
246 }
247 
248 // Test using an offset for an UInt32 index buffer
TEST_P(IndexBufferOffsetTest,UInt32Index)249 TEST_P(IndexBufferOffsetTest, UInt32Index)
250 {
251     ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 &&
252                        !IsGLExtensionEnabled("GL_OES_element_index_uint"));
253 
254     GLuint indexData[] = {0, 1, 2, 1, 2, 3};
255     runTest(GL_UNSIGNED_INT, 4, indexData, UpdateType::FullUpdate, false);
256 }
257 
258 // Test using an offset for an UInt8 index buffer with small buffer updates
TEST_P(IndexBufferOffsetTest,UInt8IndexSmallUpdates)259 TEST_P(IndexBufferOffsetTest, UInt8IndexSmallUpdates)
260 {
261     GLubyte indexData[] = {0, 1, 2, 1, 2, 3};
262     runTest(GL_UNSIGNED_BYTE, 1, indexData, UpdateType::SmallUpdate, false);
263 }
264 
265 // Test using an offset for an UInt16 index buffer with small buffer updates
TEST_P(IndexBufferOffsetTest,UInt16IndexSmallUpdates)266 TEST_P(IndexBufferOffsetTest, UInt16IndexSmallUpdates)
267 {
268     GLushort indexData[] = {0, 1, 2, 1, 2, 3};
269     runTest(GL_UNSIGNED_SHORT, 2, indexData, UpdateType::SmallUpdate, false);
270 }
271 
272 // Test using an offset for an UInt32 index buffer with small buffer updates
TEST_P(IndexBufferOffsetTest,UInt32IndexSmallUpdates)273 TEST_P(IndexBufferOffsetTest, UInt32IndexSmallUpdates)
274 {
275     ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 &&
276                        !IsGLExtensionEnabled("GL_OES_element_index_uint"));
277 
278     GLuint indexData[] = {0, 1, 2, 1, 2, 3};
279     runTest(GL_UNSIGNED_INT, 4, indexData, UpdateType::SmallUpdate, false);
280 }
281 
282 // Test using an offset for an UInt8 index buffer after uploading data to a buffer that is in use
TEST_P(IndexBufferOffsetTestES3,UseAsUBOThenUpdateThenUInt8Index)283 TEST_P(IndexBufferOffsetTestES3, UseAsUBOThenUpdateThenUInt8Index)
284 {
285     // http://anglebug.com/42264483
286     ANGLE_SKIP_TEST_IF(IsAMD() && IsVulkan() && IsWindows());
287 
288     // http://anglebug.com/42264490
289     ANGLE_SKIP_TEST_IF(IsVulkan() && (IsPixel2() || IsPixel2XL()));
290 
291     GLubyte indexData[] = {0, 1, 2, 1, 2, 3};
292     runTest(GL_UNSIGNED_BYTE, 1, indexData, UpdateType::FullUpdate, true);
293 }
294 
295 // Test using an offset for an UInt16 index buffer after uploading data to a buffer that is in use
TEST_P(IndexBufferOffsetTestES3,UseAsUBOThenUpdateThenUInt16Index)296 TEST_P(IndexBufferOffsetTestES3, UseAsUBOThenUpdateThenUInt16Index)
297 {
298     // http://anglebug.com/42264490
299     ANGLE_SKIP_TEST_IF(IsVulkan() && (IsPixel2() || IsPixel2XL()));
300 
301     GLushort indexData[] = {0, 1, 2, 1, 2, 3};
302     runTest(GL_UNSIGNED_SHORT, 2, indexData, UpdateType::FullUpdate, true);
303 }
304 
305 // Test using an offset for an UInt32 index buffer after uploading data to a buffer that is in use
TEST_P(IndexBufferOffsetTestES3,UseAsUBOThenUpdateThenUInt32Index)306 TEST_P(IndexBufferOffsetTestES3, UseAsUBOThenUpdateThenUInt32Index)
307 {
308     ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 &&
309                        !IsGLExtensionEnabled("GL_OES_element_index_uint"));
310 
311     // http://anglebug.com/42264490
312     ANGLE_SKIP_TEST_IF(IsVulkan() && (IsPixel2() || IsPixel2XL()));
313 
314     GLuint indexData[] = {0, 1, 2, 1, 2, 3};
315     runTest(GL_UNSIGNED_INT, 4, indexData, UpdateType::FullUpdate, true);
316 }
317 
318 // Test using an offset for an UInt8 index buffer after uploading data to a buffer that is in use,
319 // with small buffer updates
TEST_P(IndexBufferOffsetTestES3,UseAsUBOThenUpdateThenUInt8IndexSmallUpdates)320 TEST_P(IndexBufferOffsetTestES3, UseAsUBOThenUpdateThenUInt8IndexSmallUpdates)
321 {
322     // http://anglebug.com/42264483
323     ANGLE_SKIP_TEST_IF(IsAMD() && IsVulkan() && IsWindows());
324 
325     // http://anglebug.com/42264490
326     ANGLE_SKIP_TEST_IF(IsVulkan() && (IsPixel2() || IsPixel2XL()));
327 
328     GLubyte indexData[] = {0, 1, 2, 1, 2, 3};
329     runTest(GL_UNSIGNED_BYTE, 1, indexData, UpdateType::SmallUpdate, true);
330 }
331 
332 // Test using an offset for an UInt16 index buffer after uploading data to a buffer that is in use,
333 // with small buffer updates
TEST_P(IndexBufferOffsetTestES3,UseAsUBOThenUpdateThenUInt16IndexSmallUpdates)334 TEST_P(IndexBufferOffsetTestES3, UseAsUBOThenUpdateThenUInt16IndexSmallUpdates)
335 {
336     // http://anglebug.com/42264490
337     ANGLE_SKIP_TEST_IF(IsVulkan() && (IsPixel2() || IsPixel2XL()));
338 
339     GLushort indexData[] = {0, 1, 2, 1, 2, 3};
340     runTest(GL_UNSIGNED_SHORT, 2, indexData, UpdateType::SmallUpdate, true);
341 }
342 
343 // Test using an offset for an UInt32 index buffer after uploading data to a buffer that is in use,
344 // with small buffer updates
TEST_P(IndexBufferOffsetTestES3,UseAsUBOThenUpdateThenUInt32IndexSmallUpdates)345 TEST_P(IndexBufferOffsetTestES3, UseAsUBOThenUpdateThenUInt32IndexSmallUpdates)
346 {
347     ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 &&
348                        !IsGLExtensionEnabled("GL_OES_element_index_uint"));
349 
350     // http://anglebug.com/42264490
351     ANGLE_SKIP_TEST_IF(IsVulkan() && (IsPixel2() || IsPixel2XL()));
352 
353     GLuint indexData[] = {0, 1, 2, 1, 2, 3};
354     runTest(GL_UNSIGNED_INT, 4, indexData, UpdateType::SmallUpdate, true);
355 
356     // Also test with one subData call with more than half updates
357     runTest(GL_UNSIGNED_INT, 4, indexData, UpdateType::SmallThenBigUpdate, true);
358     runTest(GL_UNSIGNED_INT, 4, indexData, UpdateType::BigThenSmallUpdate, true);
359 }
360 
361 // Uses index buffer offset and 2 drawElement calls one of the other, makes sure the second
362 // drawElement call will use the correct offset.
TEST_P(IndexBufferOffsetTest,DrawAtDifferentOffsets)363 TEST_P(IndexBufferOffsetTest, DrawAtDifferentOffsets)
364 {
365     GLushort indexData[] = {0, 1, 2, 1, 2, 3};
366     glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
367     glClear(GL_COLOR_BUFFER_BIT);
368 
369     size_t indexDataWidth = 6 * sizeof(GLushort);
370 
371     glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexDataWidth, indexData, GL_DYNAMIC_DRAW);
372     glUseProgram(mProgram);
373 
374     glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
375     glVertexAttribPointer(mPositionAttributeLocation, 2, GL_FLOAT, GL_FALSE, 0, 0);
376     glEnableVertexAttribArray(mPositionAttributeLocation);
377 
378     glUniform4f(mColorUniformLocation, 1.0f, 0.0f, 0.0f, 1.0f);
379 
380     glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, 0);
381     glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT,
382                    reinterpret_cast<void *>(indexDataWidth / 2));
383 
384     // Check the upper left triangle
385     EXPECT_PIXEL_COLOR_EQ(0, getWindowHeight() / 4, GLColor::red);
386 
387     // Check the down right triangle
388     EXPECT_PIXEL_COLOR_EQ(getWindowWidth() - 1, getWindowHeight() - 1, GLColor::red);
389 
390     EXPECT_GL_NO_ERROR();
391 }
392 
393 // Uses index buffer offset and 2 drawElement calls one of the other, one has aligned
394 // offset and one doesn't
TEST_P(IndexBufferOffsetTest,DrawAtDifferentOffsetAlignments)395 TEST_P(IndexBufferOffsetTest, DrawAtDifferentOffsetAlignments)
396 {
397     GLubyte indexData8[]   = {0, 1, 0, 1, 2, 3};
398     GLushort indexData16[] = {0, 1, 2, 1, 2, 3};
399     glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
400     glClear(GL_COLOR_BUFFER_BIT);
401 
402     size_t indexDataWidth16 = 6 * sizeof(GLushort);
403 
404     GLuint buffer[2];
405     glGenBuffers(2, buffer);
406 
407     glUseProgram(mProgram);
408     glUniform4f(mColorUniformLocation, 1.0f, 0.0f, 0.0f, 1.0f);
409 
410     glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
411     glVertexAttribPointer(mPositionAttributeLocation, 2, GL_FLOAT, GL_FALSE, 0, 0);
412     glEnableVertexAttribArray(mPositionAttributeLocation);
413 
414     // 8 bit index with aligned offset
415     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer[0]);
416     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indexData8), indexData8, GL_DYNAMIC_DRAW);
417 
418     glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_BYTE, reinterpret_cast<void *>(2));
419 
420     // 16 bits index buffer, which unaligned offset
421     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer[1]);
422     glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexDataWidth16, indexData16, GL_DYNAMIC_DRAW);
423 
424     glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT,
425                    reinterpret_cast<void *>(indexDataWidth16 / 2));
426 
427     // Check the upper left triangle
428     EXPECT_PIXEL_COLOR_EQ(0, getWindowHeight() / 4, GLColor::red);
429 
430     // Check the down right triangle
431     EXPECT_PIXEL_COLOR_EQ(getWindowWidth() - 1, getWindowHeight() - 1, GLColor::red);
432 
433     EXPECT_GL_NO_ERROR();
434 }
435 
436 // Draw with the same element buffer, but with two different types of data.
TEST_P(IndexBufferOffsetTest,DrawWithSameBufferButDifferentTypes)437 TEST_P(IndexBufferOffsetTest, DrawWithSameBufferButDifferentTypes)
438 {
439     GLubyte indexData8[]   = {0, 1, 2};
440     GLushort indexData16[] = {1, 2, 3};
441     glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
442     glClear(GL_COLOR_BUFFER_BIT);
443 
444     glUseProgram(mProgram);
445     glUniform4f(mColorUniformLocation, 1.0f, 0.0f, 0.0f, 1.0f);
446 
447     glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
448     glVertexAttribPointer(mPositionAttributeLocation, 2, GL_FLOAT, GL_FALSE, 0, 0);
449     glEnableVertexAttribArray(mPositionAttributeLocation);
450 
451     // Create element buffer and fill offset 0 with data from indexData8 and offset 512 with data
452     // from indexData16
453     GLBuffer buffer;
454     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
455     glBufferData(GL_ELEMENT_ARRAY_BUFFER, 4096, nullptr, GL_DYNAMIC_DRAW);
456     glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(indexData8), indexData8);
457     glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 512, sizeof(indexData16), indexData16);
458 
459     // Draw with 8 bit index data
460     glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_BYTE, reinterpret_cast<void *>(0));
461     // Draw with 16 bits index buffer
462     glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, reinterpret_cast<void *>(512));
463 
464     // Check the upper left triangle
465     EXPECT_PIXEL_COLOR_EQ(0, getWindowHeight() / 4, GLColor::red);
466     // Check the down right triangle
467     EXPECT_PIXEL_COLOR_EQ(getWindowWidth() - 1, getWindowHeight() - 1, GLColor::red);
468 
469     EXPECT_GL_NO_ERROR();
470 }
471 
472 // Draw with GL_LINE_LOOP and followed by GL_TRIANGLES, all using the same element buffer.
TEST_P(IndexBufferOffsetTest,DrawWithSameBufferButDifferentModes)473 TEST_P(IndexBufferOffsetTest, DrawWithSameBufferButDifferentModes)
474 {
475     GLushort indexDataLineLoop[] = {0, 1, 2};
476     GLushort indexDataTriangle[] = {1, 2, 3};
477     glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
478     glClear(GL_COLOR_BUFFER_BIT);
479 
480     glUseProgram(mProgram);
481     glUniform4f(mColorUniformLocation, 1.0f, 0.0f, 0.0f, 1.0f);
482 
483     glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
484     glVertexAttribPointer(mPositionAttributeLocation, 2, GL_FLOAT, GL_FALSE, 0, 0);
485     glEnableVertexAttribArray(mPositionAttributeLocation);
486 
487     // Create element buffer and fill offset 0 with data from indexData8 and offset 512 with data
488     // from indexData16
489     GLBuffer buffer;
490     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
491     glBufferData(GL_ELEMENT_ARRAY_BUFFER, 4096, nullptr, GL_DYNAMIC_DRAW);
492     glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(indexDataLineLoop), indexDataLineLoop);
493     glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 512, sizeof(indexDataTriangle), indexDataTriangle);
494 
495     // Draw line loop
496     glDrawElements(GL_LINE_LOOP, 3, GL_UNSIGNED_SHORT, 0);
497     // Draw triangle
498     glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, reinterpret_cast<void *>(512));
499 
500     // Check the down right triangle
501     EXPECT_PIXEL_COLOR_EQ(getWindowWidth() - 1, getWindowHeight() - 1, GLColor::red);
502 
503     EXPECT_GL_NO_ERROR();
504 }
505 
506 // Draw with GL_LINE_LOOP and followed by GL_TRIANGLES, all using the same element buffer.
TEST_P(IndexBufferOffsetTest,DrawArraysLineLoopFollowedByDrawElementsTriangle)507 TEST_P(IndexBufferOffsetTest, DrawArraysLineLoopFollowedByDrawElementsTriangle)
508 {
509     GLuint indexDataLineLoop[] = {0, 1, 2};
510     GLuint indexDataTriangle[] = {1, 2, 3};
511     glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
512     glClear(GL_COLOR_BUFFER_BIT);
513 
514     glUseProgram(mProgram);
515     glUniform4f(mColorUniformLocation, 1.0f, 0.0f, 0.0f, 1.0f);
516 
517     glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
518     glVertexAttribPointer(mPositionAttributeLocation, 2, GL_FLOAT, GL_FALSE, 0, 0);
519     glEnableVertexAttribArray(mPositionAttributeLocation);
520 
521     // Create element buffer and fill offset 0 with data from indexDataLineLoop and offset 512 with
522     // data from indexDataTriangle
523     GLBuffer buffer;
524     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer);
525     glBufferData(GL_ELEMENT_ARRAY_BUFFER, 4096, nullptr, GL_DYNAMIC_DRAW);
526     glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(indexDataLineLoop), indexDataLineLoop);
527     glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 512, sizeof(indexDataTriangle), indexDataTriangle);
528 
529     // First call drawElements with the same primitive and type as the final drawElement call.
530     glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, reinterpret_cast<void *>(0));
531     // Then drawArray with line loop to trigger the special handling of line loop.
532     glDrawArrays(GL_LINE_LOOP, 0, 3);
533     // Finally drawElements with triangle and same type to ensure the element buffer state that was
534     // modified by line loop draw call gets restored properly.
535     glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, reinterpret_cast<void *>(512));
536 
537     // Check the down right triangle
538     EXPECT_PIXEL_COLOR_EQ(getWindowWidth() - 1, getWindowHeight() - 1, GLColor::red);
539 
540     EXPECT_GL_NO_ERROR();
541 }
542 
543 // Uses index buffer offset and 2 drawElement calls one of the other with different counts,
544 // makes sure the second drawElement call will have its data available.
TEST_P(IndexBufferOffsetTest,DrawWithDifferentCountsSameOffset)545 TEST_P(IndexBufferOffsetTest, DrawWithDifferentCountsSameOffset)
546 {
547     GLubyte indexData[] = {99, 0, 1, 2, 1, 2, 3};
548     glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
549     glClear(GL_COLOR_BUFFER_BIT);
550 
551     size_t indexDataWidth = 7 * sizeof(GLubyte);
552 
553     glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexDataWidth, indexData, GL_DYNAMIC_DRAW);
554     glUseProgram(mProgram);
555 
556     glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
557     glVertexAttribPointer(mPositionAttributeLocation, 2, GL_FLOAT, GL_FALSE, 0, 0);
558     glEnableVertexAttribArray(mPositionAttributeLocation);
559 
560     glUniform4f(mColorUniformLocation, 1.0f, 0.0f, 0.0f, 1.0f);
561 
562     // The first draw draws the first triangle, and the second draws a quad.
563     glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_BYTE, reinterpret_cast<void *>(1));
564     glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, reinterpret_cast<void *>(1));
565 
566     // Check the upper left triangle
567     EXPECT_PIXEL_COLOR_EQ(0, getWindowHeight() / 4, GLColor::red);
568 
569     // Check the down right triangle
570     EXPECT_PIXEL_COLOR_EQ(getWindowWidth() - 1, getWindowHeight() - 1, GLColor::red);
571 
572     EXPECT_GL_NO_ERROR();
573 }
574 
575 ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(IndexBufferOffsetTest);
576 
577 ANGLE_INSTANTIATE_TEST_ES3(IndexBufferOffsetTestES3);
578