xref: /aosp_15_r20/external/angle/src/tests/gl_tests/ProvokingVertexTest.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 // ProvkingVertexTest:
7 //   Tests on the conformance of the provoking vertex, which applies to flat
8 //   shading and compatibility with D3D. See the section on 'flatshading'
9 //   in the ES 3 specs.
10 //
11 
12 #include "GLES2/gl2.h"
13 #include "test_utils/ANGLETest.h"
14 #include "test_utils/gl_raii.h"
15 #include "util/gles_loader_autogen.h"
16 
17 using namespace angle;
18 
19 namespace
20 {
21 
22 template <typename T>
sizeOfVectorContents(const T & vector)23 size_t sizeOfVectorContents(const T &vector)
24 {
25     return vector.size() * sizeof(typename T::value_type);
26 }
27 
checkFlatQuadColors(size_t width,size_t height,const GLColor & bottomLeftColor,const GLColor & topRightColor)28 void checkFlatQuadColors(size_t width,
29                          size_t height,
30                          const GLColor &bottomLeftColor,
31                          const GLColor &topRightColor)
32 {
33     for (size_t x = 0; x < width; x += 2)
34     {
35         EXPECT_PIXEL_COLOR_EQ(x, 0, bottomLeftColor);
36         EXPECT_PIXEL_COLOR_EQ(x + 1, height - 1, topRightColor);
37     }
38 }
39 
40 class ProvokingVertexTest : public ANGLETest<>
41 {
42   protected:
ProvokingVertexTest()43     ProvokingVertexTest()
44         : mProgram(0),
45           mFramebuffer(0),
46           mTexture(0),
47           mTransformFeedback(0),
48           mBuffer(0),
49           mIntAttribLocation(-1)
50     {
51         setWindowWidth(64);
52         setWindowHeight(64);
53         setConfigRedBits(8);
54         setConfigGreenBits(8);
55         setConfigBlueBits(8);
56         setConfigAlphaBits(8);
57         setConfigDepthBits(24);
58     }
59 
testSetUp()60     void testSetUp() override
61     {
62         constexpr char kVS[] =
63             "#version 300 es\n"
64             "in int intAttrib;\n"
65             "in vec2 position;\n"
66             "flat out int attrib;\n"
67             "void main() {\n"
68             "  gl_Position = vec4(position, 0, 1);\n"
69             "  attrib = intAttrib;\n"
70             "}";
71 
72         constexpr char kFS[] =
73             "#version 300 es\n"
74             "flat in int attrib;\n"
75             "out int fragColor;\n"
76             "void main() {\n"
77             "  fragColor = attrib;\n"
78             "}";
79 
80         std::vector<std::string> tfVaryings;
81         tfVaryings.push_back("attrib");
82         mProgram = CompileProgramWithTransformFeedback(kVS, kFS, tfVaryings, GL_SEPARATE_ATTRIBS);
83         ASSERT_NE(0u, mProgram);
84 
85         glGenTextures(1, &mTexture);
86         glBindTexture(GL_TEXTURE_2D, mTexture);
87         glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32I, getWindowWidth(), getWindowHeight());
88 
89         glGenFramebuffers(1, &mFramebuffer);
90         glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
91         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTexture, 0);
92 
93         mIntAttribLocation = glGetAttribLocation(mProgram, "intAttrib");
94         ASSERT_NE(-1, mIntAttribLocation);
95         glEnableVertexAttribArray(mIntAttribLocation);
96 
97         ASSERT_GL_NO_ERROR();
98     }
99 
testTearDown()100     void testTearDown() override
101     {
102         if (mProgram != 0)
103         {
104             glDeleteProgram(mProgram);
105             mProgram = 0;
106         }
107 
108         if (mFramebuffer != 0)
109         {
110             glDeleteFramebuffers(1, &mFramebuffer);
111             mFramebuffer = 0;
112         }
113 
114         if (mTexture != 0)
115         {
116             glDeleteTextures(1, &mTexture);
117             mTexture = 0;
118         }
119 
120         if (mTransformFeedback != 0)
121         {
122             glDeleteTransformFeedbacks(1, &mTransformFeedback);
123             mTransformFeedback = 0;
124         }
125 
126         if (mBuffer != 0)
127         {
128             glDeleteBuffers(1, &mBuffer);
129             mBuffer = 0;
130         }
131     }
132 
133     GLuint mProgram;
134     GLuint mFramebuffer;
135     GLuint mTexture;
136     GLuint mTransformFeedback;
137     GLuint mBuffer;
138     GLint mIntAttribLocation;
139 };
140 
141 // Test drawing a simple triangle with flat shading, and different valued vertices.
TEST_P(ProvokingVertexTest,FlatTriangle)142 TEST_P(ProvokingVertexTest, FlatTriangle)
143 {
144     GLint vertexData[] = {1, 2, 3, 1, 2, 3};
145     glVertexAttribIPointer(mIntAttribLocation, 1, GL_INT, 0, vertexData);
146 
147     drawQuad(mProgram, "position", 0.5f);
148 
149     GLint pixelValue[4] = {0};
150     glReadPixels(0, 0, 1, 1, GL_RGBA_INTEGER, GL_INT, &pixelValue);
151 
152     ASSERT_GL_NO_ERROR();
153     EXPECT_EQ(vertexData[2], pixelValue[0]);
154 }
155 
156 // Ensure that any provoking vertex shenanigans still gives correct vertex streams.
TEST_P(ProvokingVertexTest,FlatTriWithTransformFeedback)157 TEST_P(ProvokingVertexTest, FlatTriWithTransformFeedback)
158 {
159     glGenTransformFeedbacks(1, &mTransformFeedback);
160     glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, mTransformFeedback);
161 
162     glGenBuffers(1, &mBuffer);
163     glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, mBuffer);
164     glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 128, nullptr, GL_STREAM_DRAW);
165 
166     glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mBuffer);
167 
168     GLint vertexData[] = {1, 2, 3, 1, 2, 3};
169     glVertexAttribIPointer(mIntAttribLocation, 1, GL_INT, 0, vertexData);
170 
171     glUseProgram(mProgram);
172     glBeginTransformFeedback(GL_TRIANGLES);
173     drawQuad(mProgram, "position", 0.5f);
174     glEndTransformFeedback();
175     glUseProgram(0);
176 
177     GLint pixelValue[4] = {0};
178     glReadPixels(0, 0, 1, 1, GL_RGBA_INTEGER, GL_INT, &pixelValue);
179 
180     ASSERT_GL_NO_ERROR();
181     EXPECT_EQ(vertexData[2], pixelValue[0]);
182 
183     void *mapPointer =
184         glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sizeof(int) * 6, GL_MAP_READ_BIT);
185     ASSERT_NE(nullptr, mapPointer);
186 
187     int *mappedInts = static_cast<int *>(mapPointer);
188     for (unsigned int cnt = 0; cnt < 6; ++cnt)
189     {
190         EXPECT_EQ(vertexData[cnt], mappedInts[cnt]);
191     }
192 }
193 
194 // Test drawing a simple line with flat shading, and different valued vertices.
TEST_P(ProvokingVertexTest,FlatLine)195 TEST_P(ProvokingVertexTest, FlatLine)
196 {
197     GLfloat halfPixel = 1.0f / static_cast<GLfloat>(getWindowWidth());
198 
199     GLint vertexData[]     = {1, 2};
200     GLfloat positionData[] = {-1.0f + halfPixel, -1.0f, -1.0f + halfPixel, 1.0f};
201 
202     glVertexAttribIPointer(mIntAttribLocation, 1, GL_INT, 0, vertexData);
203 
204     GLint positionLocation = glGetAttribLocation(mProgram, "position");
205     glEnableVertexAttribArray(positionLocation);
206     glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, 0, positionData);
207 
208     glUseProgram(mProgram);
209     glDrawArrays(GL_LINES, 0, 2);
210 
211     GLint pixelValue[4] = {0};
212     glReadPixels(0, 0, 1, 1, GL_RGBA_INTEGER, GL_INT, &pixelValue);
213 
214     ASSERT_GL_NO_ERROR();
215     EXPECT_EQ(vertexData[1], pixelValue[0]);
216 }
217 
218 // Test drawing a simple line with flat shading, and different valued vertices.
TEST_P(ProvokingVertexTest,FlatLineWithFirstIndex)219 TEST_P(ProvokingVertexTest, FlatLineWithFirstIndex)
220 {
221     GLfloat halfPixel = 1.0f / static_cast<GLfloat>(getWindowWidth());
222 
223     GLint vertexData[]     = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2};
224     GLfloat positionData[] = {0,
225                               0,
226                               0,
227                               0,
228                               0,
229                               0,
230                               0,
231                               0,
232                               0,
233                               0,
234                               0,
235                               0,
236                               0,
237                               0,
238                               0,
239                               0,
240                               0,
241                               0,
242                               0,
243                               0,
244                               -1.0f + halfPixel,
245                               -1.0f,
246                               -1.0f + halfPixel,
247                               1.0f};
248 
249     glVertexAttribIPointer(mIntAttribLocation, 1, GL_INT, 0, vertexData);
250 
251     GLint positionLocation = glGetAttribLocation(mProgram, "position");
252     glEnableVertexAttribArray(positionLocation);
253     glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, 0, positionData);
254 
255     glUseProgram(mProgram);
256     glDrawArrays(GL_LINES, 10, 2);
257 
258     GLint pixelValue[4] = {0};
259     glReadPixels(0, 0, 1, 1, GL_RGBA_INTEGER, GL_INT, &pixelValue);
260 
261     ASSERT_GL_NO_ERROR();
262     EXPECT_EQ(vertexData[11], pixelValue[0]);
263 }
264 
265 // Test drawing a simple triangle strip with flat shading, and different valued vertices.
TEST_P(ProvokingVertexTest,FlatTriStrip)266 TEST_P(ProvokingVertexTest, FlatTriStrip)
267 {
268     GLint vertexData[]     = {1, 2, 3, 4, 5, 6};
269     GLfloat positionData[] = {-1.0f, -1.0f, -1.0f, 1.0f,  0.0f, -1.0f,
270                               0.0f,  1.0f,  1.0f,  -1.0f, 1.0f, 1.0f};
271 
272     glVertexAttribIPointer(mIntAttribLocation, 1, GL_INT, 0, vertexData);
273 
274     GLint positionLocation = glGetAttribLocation(mProgram, "position");
275     glEnableVertexAttribArray(positionLocation);
276     glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, 0, positionData);
277 
278     glUseProgram(mProgram);
279     glDrawArrays(GL_TRIANGLE_STRIP, 0, 6);
280 
281     std::vector<GLint> pixelBuffer(getWindowWidth() * getWindowHeight() * 4, 0);
282     glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA_INTEGER, GL_INT,
283                  &pixelBuffer[0]);
284 
285     ASSERT_GL_NO_ERROR();
286 
287     for (unsigned int triIndex = 0; triIndex < 4; ++triIndex)
288     {
289         GLfloat sumX = positionData[triIndex * 2 + 0] + positionData[triIndex * 2 + 2] +
290                        positionData[triIndex * 2 + 4];
291         GLfloat sumY = positionData[triIndex * 2 + 1] + positionData[triIndex * 2 + 3] +
292                        positionData[triIndex * 2 + 5];
293 
294         float centerX = sumX / 3.0f * 0.5f + 0.5f;
295         float centerY = sumY / 3.0f * 0.5f + 0.5f;
296         unsigned int pixelX =
297             static_cast<unsigned int>(centerX * static_cast<GLfloat>(getWindowWidth()));
298         unsigned int pixelY =
299             static_cast<unsigned int>(centerY * static_cast<GLfloat>(getWindowHeight()));
300         unsigned int pixelIndex = pixelY * getWindowWidth() + pixelX;
301 
302         unsigned int provokingVertexIndex = triIndex + 2;
303 
304         EXPECT_EQ(vertexData[provokingVertexIndex], pixelBuffer[pixelIndex * 4]);
305     }
306 }
307 
308 // Test drawing an indexed triangle strip with flat shading and primitive restart.
TEST_P(ProvokingVertexTest,FlatTriStripPrimitiveRestart)309 TEST_P(ProvokingVertexTest, FlatTriStripPrimitiveRestart)
310 {
311     // TODO(jmadill): Implement on the D3D back-end.
312     ANGLE_SKIP_TEST_IF(IsD3D11());
313 
314     GLint indexData[]      = {0, 1, 2, -1, 1, 2, 3, 4, -1, 3, 4, 5};
315     GLint vertexData[]     = {1, 2, 3, 4, 5, 6};
316     GLfloat positionData[] = {-1.0f, -1.0f, -1.0f, 1.0f,  0.0f, -1.0f,
317                               0.0f,  1.0f,  1.0f,  -1.0f, 1.0f, 1.0f};
318 
319     glVertexAttribIPointer(mIntAttribLocation, 1, GL_INT, 0, vertexData);
320 
321     GLint positionLocation = glGetAttribLocation(mProgram, "position");
322     glEnableVertexAttribArray(positionLocation);
323     glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, 0, positionData);
324 
325     glDisable(GL_CULL_FACE);
326     glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
327     glUseProgram(mProgram);
328     glDrawElements(GL_TRIANGLE_STRIP, 12, GL_UNSIGNED_INT, indexData);
329 
330     std::vector<GLint> pixelBuffer(getWindowWidth() * getWindowHeight() * 4, 0);
331     glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA_INTEGER, GL_INT,
332                  &pixelBuffer[0]);
333 
334     ASSERT_GL_NO_ERROR();
335 
336     // Account for primitive restart when checking the tris.
337     GLint triOffsets[] = {0, 4, 5, 9};
338 
339     for (unsigned int triIndex = 0; triIndex < 4; ++triIndex)
340     {
341         GLint vertexA = indexData[triOffsets[triIndex] + 0];
342         GLint vertexB = indexData[triOffsets[triIndex] + 1];
343         GLint vertexC = indexData[triOffsets[triIndex] + 2];
344 
345         GLfloat sumX =
346             positionData[vertexA * 2] + positionData[vertexB * 2] + positionData[vertexC * 2];
347         GLfloat sumY = positionData[vertexA * 2 + 1] + positionData[vertexB * 2 + 1] +
348                        positionData[vertexC * 2 + 1];
349 
350         float centerX = sumX / 3.0f * 0.5f + 0.5f;
351         float centerY = sumY / 3.0f * 0.5f + 0.5f;
352         unsigned int pixelX =
353             static_cast<unsigned int>(centerX * static_cast<GLfloat>(getWindowWidth()));
354         unsigned int pixelY =
355             static_cast<unsigned int>(centerY * static_cast<GLfloat>(getWindowHeight()));
356         unsigned int pixelIndex = pixelY * getWindowWidth() + pixelX;
357 
358         unsigned int provokingVertexIndex = triIndex + 2;
359 
360         EXPECT_EQ(vertexData[provokingVertexIndex], pixelBuffer[pixelIndex * 4]);
361     }
362 }
363 
364 // Test with FRONT_CONVENTION if we have ANGLE_provoking_vertex.
TEST_P(ProvokingVertexTest,ANGLEProvokingVertex)365 TEST_P(ProvokingVertexTest, ANGLEProvokingVertex)
366 {
367     int32_t vertexData[] = {1, 2, 3};
368     float positionData[] = {-1.0f, -1.0f, 3.0f, -1.0f, -1.0f, 3.0f};
369 
370     glEnableVertexAttribArray(mIntAttribLocation);
371     glVertexAttribIPointer(mIntAttribLocation, 1, GL_INT, 0, vertexData);
372 
373     GLint positionLocation = glGetAttribLocation(mProgram, "position");
374     glEnableVertexAttribArray(positionLocation);
375     glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, 0, positionData);
376 
377     glUseProgram(mProgram);
378     ASSERT_GL_NO_ERROR();
379 
380     const auto &fnExpectId = [&](int id) {
381         const int32_t zero[4] = {};
382         glClearBufferiv(GL_COLOR, 0, zero);
383         glDrawArrays(GL_TRIANGLES, 0, 3);
384 
385         int32_t pixelValue[4] = {0};
386         glReadPixels(0, 0, 1, 1, GL_RGBA_INTEGER, GL_INT, &pixelValue);
387 
388         ASSERT_GL_NO_ERROR();
389         EXPECT_EQ(vertexData[id], pixelValue[0]);
390     };
391 
392     fnExpectId(2);
393 
394     const bool hasExt = IsGLExtensionEnabled("GL_ANGLE_provoking_vertex");
395     if (IsD3D11())
396     {
397         EXPECT_TRUE(hasExt);
398     }
399     if (hasExt)
400     {
401         GLint mode;
402         glGetIntegerv(GL_PROVOKING_VERTEX_ANGLE, &mode);
403         EXPECT_EQ(mode, GL_LAST_VERTEX_CONVENTION_ANGLE);
404 
405         glProvokingVertexANGLE(GL_FIRST_VERTEX_CONVENTION_ANGLE);
406         glGetIntegerv(GL_PROVOKING_VERTEX_ANGLE, &mode);
407         EXPECT_EQ(mode, GL_FIRST_VERTEX_CONVENTION_ANGLE);
408 
409         fnExpectId(0);
410     }
411 }
412 
413 // Tests that alternating between drawing with flat and interpolated varyings works.
TEST_P(ProvokingVertexTest,DrawWithBothFlatAndInterpolatedVarying)414 TEST_P(ProvokingVertexTest, DrawWithBothFlatAndInterpolatedVarying)
415 {
416     constexpr char kFlatVS[] = R"(#version 300 es
417       layout(location = 0) in vec4 position;
418       layout(location = 1) in vec4 color;
419       flat out highp vec4 v_color;
420       void main() {
421         gl_Position = position;
422         v_color = color;
423       }
424     )";
425 
426     constexpr char kFlatFS[] = R"(#version 300 es
427         precision highp float;
428         flat in highp vec4 v_color;
429         out vec4 fragColor;
430         void main() {
431           fragColor = v_color;
432         }
433     )";
434 
435     constexpr char kVS[] = R"(#version 300 es
436       layout(location = 0) in vec4 position;
437       layout(location = 1) in vec4 color;
438       out vec4 v_color;
439       void main() {
440         gl_Position = position;
441         v_color = color;
442       }
443     )";
444 
445     constexpr char kFS[] = R"(#version 300 es
446         precision highp float;
447         in vec4 v_color;
448         out vec4 fragColor;
449         void main() {
450           fragColor = v_color;
451         }
452     )";
453 
454     GLProgram varyingProgram;
455     varyingProgram.makeRaster(kVS, kFS);
456     GLProgram mProgram;
457     mProgram.makeRaster(kFlatVS, kFlatFS);
458 
459     constexpr GLuint posNdx   = 0;
460     constexpr GLuint colorNdx = 1;
461 
462     static float positions[] = {
463         -1, -1, 1, -1, -1, 1,
464     };
465 
466     static GLColor colors[] = {
467         GLColor::red,
468         GLColor::green,
469         GLColor::blue,
470     };
471 
472     glBindFramebuffer(GL_FRAMEBUFFER, 0);
473     glClearColor(0, 0, 0, 0);
474     glClear(GL_COLOR_BUFFER_BIT);
475 
476     GLBuffer mPositionBuffer;
477     glBindBuffer(GL_ARRAY_BUFFER, mPositionBuffer);
478     glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, GL_STATIC_DRAW);
479     glEnableVertexAttribArray(posNdx);
480     glVertexAttribPointer(posNdx, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
481 
482     GLBuffer mColorBuffer;
483     glBindBuffer(GL_ARRAY_BUFFER, mColorBuffer);
484     glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW);
485     glEnableVertexAttribArray(colorNdx);
486     glVertexAttribPointer(colorNdx, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, nullptr);
487 
488     glUseProgram(varyingProgram);
489     glDrawArrays(GL_TRIANGLES, 0, 3);
490     glUseProgram(mProgram);
491     glDrawArrays(GL_TRIANGLES, 0, 3);
492     glUseProgram(varyingProgram);
493     glDrawArrays(GL_TRIANGLES, 0, 3);
494     glUseProgram(mProgram);
495     glDrawArrays(GL_TRIANGLES, 0, 3);
496 
497     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
498     ASSERT_GL_NO_ERROR();
499 }
500 
501 class ProvokingVertexBufferUpdateTest : public ANGLETest<>
502 {
503   protected:
504     static constexpr size_t kWidth  = 64;
505     static constexpr size_t kHeight = 64;
ProvokingVertexBufferUpdateTest()506     ProvokingVertexBufferUpdateTest()
507     {
508         setWindowWidth(64);
509         setWindowHeight(64);
510         setConfigRedBits(8);
511         setConfigGreenBits(8);
512         setConfigBlueBits(8);
513         setConfigAlphaBits(8);
514         setConfigDepthBits(24);
515     }
516 
testSetUp()517     void testSetUp() override
518     {
519         constexpr char kFlatVS[] = R"(#version 300 es
520           layout(location = 0) in vec4 position;
521           layout(location = 1) in vec4 color;
522           flat out highp vec4 v_color;
523           void main() {
524             gl_Position = position;
525             v_color = color;
526           }
527         )";
528 
529         constexpr char kFlatFS[] = R"(#version 300 es
530             precision highp float;
531             flat in highp vec4 v_color;
532             out vec4 fragColor;
533             void main() {
534               fragColor = v_color;
535             }
536         )";
537 
538         mProgram.makeRaster(kFlatVS, kFlatFS);
539         glUseProgram(mProgram);
540 
541         ASSERT(kWidth % 2 == 0);
542         ASSERT(kHeight > 1);
543 
544         constexpr GLuint posNdx   = 0;
545         constexpr GLuint colorNdx = 1;
546 
547         const size_t numQuads        = kWidth / 2;
548         const size_t numVertsPerQuad = 4;
549         std::vector<Vector2> positions;
550         std::vector<GLColor> colors;
551 
552         const size_t mNumVertsToDrawPerQuad = 6;
553         mNumVertsToDraw                     = mNumVertsToDrawPerQuad * numQuads;
554 
555         for (size_t i = 0; i < numQuads; ++i)
556         {
557             float x0 = float(i + 0) / float(numQuads) * 2.0f - 1.0f;
558             float x1 = float(i + 1) / float(numQuads) * 2.0f - 1.0f;
559 
560             positions.push_back(Vector2(x0, -1));  // 2--3
561             positions.push_back(Vector2(x1, -1));  // |  |
562             positions.push_back(Vector2(x0, 1));   // 0--1
563             positions.push_back(Vector2(x1, 1));
564 
565             colors.push_back(GLColor::red);
566             colors.push_back(GLColor::green);
567             colors.push_back(GLColor::blue);
568             colors.push_back(GLColor::yellow);
569 
570             size_t offset = i * numVertsPerQuad;
571 
572             mIndicesBlueYellow.push_back(offset + 0);
573             mIndicesBlueYellow.push_back(offset + 1);
574             mIndicesBlueYellow.push_back(offset + 2);  // blue
575             mIndicesBlueYellow.push_back(offset + 2);
576             mIndicesBlueYellow.push_back(offset + 1);
577             mIndicesBlueYellow.push_back(offset + 3);  // yellow
578 
579             mIndicesRedGreen.push_back(offset + 1);
580             mIndicesRedGreen.push_back(offset + 2);
581             mIndicesRedGreen.push_back(offset + 0);  // red
582             mIndicesRedGreen.push_back(offset + 3);
583             mIndicesRedGreen.push_back(offset + 2);
584             mIndicesRedGreen.push_back(offset + 1);  // green
585 
586             mIndicesGreenBlue.push_back(offset + 2);
587             mIndicesGreenBlue.push_back(offset + 0);
588             mIndicesGreenBlue.push_back(offset + 1);  // green
589             mIndicesGreenBlue.push_back(offset + 1);
590             mIndicesGreenBlue.push_back(offset + 3);
591             mIndicesGreenBlue.push_back(offset + 2);  // blue
592         }
593 
594         glBindFramebuffer(GL_FRAMEBUFFER, 0);
595         glClearColor(0, 0, 0, 0);
596         glClear(GL_COLOR_BUFFER_BIT);
597 
598         glBindBuffer(GL_ARRAY_BUFFER, mPositionBuffer);
599         glBufferData(GL_ARRAY_BUFFER, sizeOfVectorContents(positions), positions.data(),
600                      GL_STATIC_DRAW);
601         glEnableVertexAttribArray(posNdx);
602         glVertexAttribPointer(posNdx, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
603 
604         glBindBuffer(GL_ARRAY_BUFFER, mColorBuffer);
605         glBufferData(GL_ARRAY_BUFFER, sizeOfVectorContents(colors), colors.data(), GL_STATIC_DRAW);
606         glEnableVertexAttribArray(colorNdx);
607         glVertexAttribPointer(colorNdx, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, nullptr);
608 
609         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
610         ASSERT_GL_NO_ERROR();
611     }
612 
testTearDown()613     void testTearDown() override {}
614 
615     size_t mNumVertsToDraw;
616     GLProgram mProgram;
617     GLBuffer mPositionBuffer;
618     GLBuffer mColorBuffer;
619     GLBuffer mIndexBuffer;
620     std::vector<GLushort> mIndicesBlueYellow;
621     std::vector<GLushort> mIndicesRedGreen;
622     std::vector<GLushort> mIndicesGreenBlue;
623 };
624 
625 // Tests that updating the index buffer via BufferData more than once works with flat interpolation
626 // The backend may queue the updates so the test tests that we draw after the buffer has been
627 // updated.
TEST_P(ProvokingVertexBufferUpdateTest,DrawFlatWith2BufferUpdates)628 TEST_P(ProvokingVertexBufferUpdateTest, DrawFlatWith2BufferUpdates)
629 {
630     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeOfVectorContents(mIndicesBlueYellow),
631                  mIndicesBlueYellow.data(), GL_STREAM_DRAW);
632     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeOfVectorContents(mIndicesRedGreen),
633                  mIndicesRedGreen.data(), GL_STREAM_DRAW);
634     glDrawElements(GL_TRIANGLES, mNumVertsToDraw, GL_UNSIGNED_SHORT, nullptr);
635     checkFlatQuadColors(kWidth, kHeight, GLColor::red, GLColor::green);
636 }
637 
638 // Tests that updating the index buffer more than once with a draw in between updates works with
639 // flat interpolation The backend may queue the updates so the test tests that we draw after the
640 // buffer has been updated.
TEST_P(ProvokingVertexBufferUpdateTest,DrawFlatWithBufferUpdateBetweenDraws)641 TEST_P(ProvokingVertexBufferUpdateTest, DrawFlatWithBufferUpdateBetweenDraws)
642 {
643     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeOfVectorContents(mIndicesBlueYellow),
644                  mIndicesBlueYellow.data(), GL_STREAM_DRAW);
645     glDrawElements(GL_TRIANGLES, mNumVertsToDraw, GL_UNSIGNED_SHORT, nullptr);
646     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeOfVectorContents(mIndicesRedGreen),
647                  mIndicesRedGreen.data(), GL_STREAM_DRAW);
648     glDrawElements(GL_TRIANGLES, mNumVertsToDraw, GL_UNSIGNED_SHORT, nullptr);
649     checkFlatQuadColors(kWidth, kHeight, GLColor::red, GLColor::green);
650 }
651 
652 // Tests that updating the index buffer with BufferSubData works with flat interpolation
653 // The backend may queue the updates so the test tests that we draw after the buffer has been
654 // updated.
TEST_P(ProvokingVertexBufferUpdateTest,DrawFlatWithBufferSubUpdate)655 TEST_P(ProvokingVertexBufferUpdateTest, DrawFlatWithBufferSubUpdate)
656 {
657     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeOfVectorContents(mIndicesBlueYellow),
658                  mIndicesBlueYellow.data(), GL_STREAM_DRAW);
659     glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeOfVectorContents(mIndicesRedGreen),
660                     mIndicesRedGreen.data());
661     glDrawElements(GL_TRIANGLES, mNumVertsToDraw, GL_UNSIGNED_SHORT, nullptr);
662     checkFlatQuadColors(kWidth, kHeight, GLColor::red, GLColor::green);
663 }
664 
665 // Tests that updating the index buffer with BufferSubData after drawing works with flat
666 // interpolation The backend may queue the updates so the test tests that we draw after the buffer
667 // has been updated.
TEST_P(ProvokingVertexBufferUpdateTest,DrawFlatWithBufferSubUpdateBetweenDraws)668 TEST_P(ProvokingVertexBufferUpdateTest, DrawFlatWithBufferSubUpdateBetweenDraws)
669 {
670     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeOfVectorContents(mIndicesBlueYellow),
671                  mIndicesBlueYellow.data(), GL_STREAM_DRAW);
672     glDrawElements(GL_TRIANGLES, mNumVertsToDraw, GL_UNSIGNED_SHORT, nullptr);
673     glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeOfVectorContents(mIndicesRedGreen),
674                     mIndicesRedGreen.data());
675     glDrawElements(GL_TRIANGLES, mNumVertsToDraw, GL_UNSIGNED_SHORT, nullptr);
676     checkFlatQuadColors(kWidth, kHeight, GLColor::red, GLColor::green);
677 }
678 
679 // Tests that updating the index buffer twice with BufferSubData works with flat interpolation
680 // The backend may queue the updates so the test tests that we draw after the buffer has been
681 // updated.
TEST_P(ProvokingVertexBufferUpdateTest,DrawFlatWith2BufferSubUpdates)682 TEST_P(ProvokingVertexBufferUpdateTest, DrawFlatWith2BufferSubUpdates)
683 {
684     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeOfVectorContents(mIndicesBlueYellow),
685                  mIndicesBlueYellow.data(), GL_STREAM_DRAW);
686     glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeOfVectorContents(mIndicesRedGreen),
687                     mIndicesRedGreen.data());
688     glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeOfVectorContents(mIndicesGreenBlue),
689                     mIndicesGreenBlue.data());
690     glDrawElements(GL_TRIANGLES, mNumVertsToDraw, GL_UNSIGNED_SHORT, nullptr);
691     checkFlatQuadColors(kWidth, kHeight, GLColor::green, GLColor::blue);
692 }
693 
694 // Tests that updating the index buffer with BufferSubData works after drawing with flat
695 // interpolation The backend may queue the updates so the test tests that we draw after the buffer
696 // has been updated.
TEST_P(ProvokingVertexBufferUpdateTest,DrawFlatWith2BufferSubUpdatesBetweenDraws)697 TEST_P(ProvokingVertexBufferUpdateTest, DrawFlatWith2BufferSubUpdatesBetweenDraws)
698 {
699     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeOfVectorContents(mIndicesBlueYellow),
700                  mIndicesBlueYellow.data(), GL_STREAM_DRAW);
701     glDrawElements(GL_TRIANGLES, mNumVertsToDraw, GL_UNSIGNED_SHORT, nullptr);
702     glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeOfVectorContents(mIndicesRedGreen),
703                     mIndicesRedGreen.data());
704     glDrawElements(GL_TRIANGLES, mNumVertsToDraw, GL_UNSIGNED_SHORT, nullptr);
705     glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeOfVectorContents(mIndicesGreenBlue),
706                     mIndicesGreenBlue.data());
707     glDrawElements(GL_TRIANGLES, mNumVertsToDraw, GL_UNSIGNED_SHORT, nullptr);
708     checkFlatQuadColors(kWidth, kHeight, GLColor::green, GLColor::blue);
709 }
710 
711 // Tests that updating the index buffer via multiple calls to BufferSubData works with flat
712 // interpolation The backend may queue the updates so the test tests that we draw after the buffer
713 // has been updated.
TEST_P(ProvokingVertexBufferUpdateTest,DrawFlatWithPartialBufferSubUpdates)714 TEST_P(ProvokingVertexBufferUpdateTest, DrawFlatWithPartialBufferSubUpdates)
715 {
716     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeOfVectorContents(mIndicesBlueYellow),
717                  mIndicesBlueYellow.data(), GL_STREAM_DRAW);
718     glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeOfVectorContents(mIndicesRedGreen) / 2,
719                     mIndicesRedGreen.data());
720     glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, sizeOfVectorContents(mIndicesRedGreen) / 2,
721                     sizeOfVectorContents(mIndicesRedGreen) / 2,
722                     &mIndicesRedGreen[mIndicesRedGreen.size() / 2]);
723     glDrawElements(GL_TRIANGLES, mNumVertsToDraw, GL_UNSIGNED_SHORT, nullptr);
724     checkFlatQuadColors(kWidth, kHeight, GLColor::red, GLColor::green);
725 }
726 
727 // Tests that updating the index buffer via multiple calls to BufferSubData and drawing before the
728 // update works with flat interpolation The backend may queue the updates so the test tests that we
729 // draw after the buffer has been updated.
TEST_P(ProvokingVertexBufferUpdateTest,DrawFlatWithPartialBufferSubUpdatesBetweenDraws)730 TEST_P(ProvokingVertexBufferUpdateTest, DrawFlatWithPartialBufferSubUpdatesBetweenDraws)
731 {
732     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeOfVectorContents(mIndicesBlueYellow),
733                  mIndicesBlueYellow.data(), GL_STREAM_DRAW);
734     glDrawElements(GL_TRIANGLES, mNumVertsToDraw, GL_UNSIGNED_SHORT, nullptr);
735     glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeOfVectorContents(mIndicesRedGreen) / 2,
736                     mIndicesRedGreen.data());
737     glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, sizeOfVectorContents(mIndicesRedGreen) / 2,
738                     sizeOfVectorContents(mIndicesRedGreen) / 2,
739                     &mIndicesRedGreen[mIndicesRedGreen.size() / 2]);
740     glDrawElements(GL_TRIANGLES, mNumVertsToDraw, GL_UNSIGNED_SHORT, nullptr);
741     checkFlatQuadColors(kWidth, kHeight, GLColor::red, GLColor::green);
742 }
743 
744 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ProvokingVertexTest);
745 ANGLE_INSTANTIATE_TEST(ProvokingVertexTest, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES(), ES3_METAL());
746 
747 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ProvokingVertexBufferUpdateTest);
748 ANGLE_INSTANTIATE_TEST(ProvokingVertexBufferUpdateTest,
749                        ES3_D3D11(),
750                        ES3_OPENGL(),
751                        ES3_OPENGLES(),
752                        ES3_METAL());
753 
754 }  // anonymous namespace
755