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