xref: /aosp_15_r20/external/angle/src/tests/gl_tests/LineLoopTest.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 #include "test_utils/ANGLETest.h"
8 
9 #include "test_utils/gl_raii.h"
10 
11 using namespace angle;
12 
13 class LineLoopTest : public ANGLETest<>
14 {
15   protected:
LineLoopTest()16     LineLoopTest()
17     {
18         setWindowWidth(256);
19         setWindowHeight(256);
20         setConfigRedBits(8);
21         setConfigGreenBits(8);
22         setConfigBlueBits(8);
23         setConfigAlphaBits(8);
24     }
25 
testSetUp()26     void testSetUp() override
27     {
28         mProgram = CompileProgram(essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor());
29         if (mProgram == 0)
30         {
31             FAIL() << "shader compilation failed.";
32         }
33 
34         mPositionLocation = glGetAttribLocation(mProgram, essl1_shaders::PositionAttrib());
35         mColorLocation    = glGetUniformLocation(mProgram, essl1_shaders::ColorUniform());
36 
37         glBlendFunc(GL_ONE, GL_ONE);
38         glEnable(GL_BLEND);
39         glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
40 
41         ASSERT_GL_NO_ERROR();
42     }
43 
testTearDown()44     void testTearDown() override { glDeleteProgram(mProgram); }
45 
checkPixels()46     void checkPixels()
47     {
48         std::vector<GLubyte> pixels(getWindowWidth() * getWindowHeight() * 4);
49         glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
50                      &pixels[0]);
51 
52         ASSERT_GL_NO_ERROR();
53 
54         for (int y = 0; y < getWindowHeight(); y++)
55         {
56             for (int x = 0; x < getWindowWidth(); x++)
57             {
58                 const GLubyte *pixel = &pixels[0] + ((y * getWindowWidth() + x) * 4);
59 
60                 EXPECT_EQ(pixel[0], 0) << "Failed at " << x << ", " << y << std::endl;
61                 EXPECT_EQ(pixel[1], pixel[2]) << "Failed at " << x << ", " << y << std::endl;
62                 ASSERT_EQ(pixel[3], 255) << "Failed at " << x << ", " << y << std::endl;
63             }
64         }
65     }
66 
preTestUpdateBuffer(GLuint framebuffer,GLuint texture,GLuint buffer,GLsizei size)67     void preTestUpdateBuffer(GLuint framebuffer, GLuint texture, GLuint buffer, GLsizei size)
68     {
69         GLsizei uboSize = std::max(size, 16);
70         const std::vector<uint32_t> initialData((uboSize + 3) / 4, 0x1234567u);
71 
72         glBindTexture(GL_TEXTURE_2D, texture);
73         glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 1, 1);
74 
75         glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
76         glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture,
77                                0);
78 
79         glBindBuffer(GL_UNIFORM_BUFFER, buffer);
80         glBufferData(GL_UNIFORM_BUFFER, uboSize, initialData.data(), GL_DYNAMIC_DRAW);
81         glBindBufferBase(GL_UNIFORM_BUFFER, 0, buffer);
82 
83         constexpr char kVerifyUBO[] = R"(#version 300 es
84 precision mediump float;
85 uniform block {
86     uint data;
87 } ubo;
88 out vec4 colorOut;
89 void main()
90 {
91     if (ubo.data == 0x1234567u)
92         colorOut = vec4(0, 1.0, 0, 1.0);
93     else
94         colorOut = vec4(1.0, 0, 0, 1.0);
95 })";
96 
97         ANGLE_GL_PROGRAM(verifyUbo, essl3_shaders::vs::Simple(), kVerifyUBO);
98 
99         glDisable(GL_BLEND);
100         drawQuad(verifyUbo, essl3_shaders::PositionAttrib(), 0.5);
101 
102         EXPECT_GL_NO_ERROR();
103 
104         glBindFramebuffer(GL_FRAMEBUFFER, 0);
105     }
106 
runTest(GLenum indexType,GLuint indexBuffer,const void * indexPtr)107     void runTest(GLenum indexType, GLuint indexBuffer, const void *indexPtr)
108     {
109         glClear(GL_COLOR_BUFFER_BIT);
110 
111         static const GLfloat loopPositions[] = {0.0f,  0.0f, 0.0f, 0.0f, 0.0f, 0.0f,  0.0f,
112                                                 0.0f,  0.0f, 0.0f, 0.0f, 0.0f, -0.5f, -0.5f,
113                                                 -0.5f, 0.5f, 0.5f, 0.5f, 0.5f, -0.5f};
114 
115         static const GLfloat stripPositions[] = {-0.5f, -0.5f, -0.5f, 0.5f,
116                                                  0.5f,  0.5f,  0.5f,  -0.5f};
117         static const GLubyte stripIndices[]   = {1, 0, 3, 2, 1};
118 
119         glEnable(GL_BLEND);
120 
121         glUseProgram(mProgram);
122         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
123         glEnableVertexAttribArray(mPositionLocation);
124         glVertexAttribPointer(mPositionLocation, 2, GL_FLOAT, GL_FALSE, 0, loopPositions);
125         glUniform4f(mColorLocation, 0.0f, 0.0f, 1.0f, 1.0f);
126         glDrawElements(GL_LINE_LOOP, 4, indexType, indexPtr);
127 
128         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
129         glVertexAttribPointer(mPositionLocation, 2, GL_FLOAT, GL_FALSE, 0, stripPositions);
130         glUniform4f(mColorLocation, 0, 1, 0, 1);
131         glDrawElements(GL_LINE_STRIP, 5, GL_UNSIGNED_BYTE, stripIndices);
132 
133         checkPixels();
134     }
135 
136     GLuint mProgram;
137     GLint mPositionLocation;
138     GLint mColorLocation;
139 };
140 
TEST_P(LineLoopTest,LineLoopUByteIndices)141 TEST_P(LineLoopTest, LineLoopUByteIndices)
142 {
143     // http://anglebug.com/42265165: Disable D3D11 SDK Layers warnings checks.
144     // On Win7, the D3D SDK Layers emits a false warning for these tests.
145     // This doesn't occur on Windows 10 (Version 1511) though.
146     ignoreD3D11SDKLayersWarnings();
147 
148     static const GLubyte indices[] = {0, 7, 6, 9, 8, 0};
149     runTest(GL_UNSIGNED_BYTE, 0, indices + 1);
150 }
151 
TEST_P(LineLoopTest,LineLoopUShortIndices)152 TEST_P(LineLoopTest, LineLoopUShortIndices)
153 {
154     // http://anglebug.com/42265165: Disable D3D11 SDK Layers warnings checks.
155     ignoreD3D11SDKLayersWarnings();
156 
157     static const GLushort indices[] = {0, 7, 6, 9, 8, 0};
158     runTest(GL_UNSIGNED_SHORT, 0, indices + 1);
159 }
160 
TEST_P(LineLoopTest,LineLoopUIntIndices)161 TEST_P(LineLoopTest, LineLoopUIntIndices)
162 {
163     if (!IsGLExtensionEnabled("GL_OES_element_index_uint"))
164     {
165         return;
166     }
167 
168     // http://anglebug.com/42265165: Disable D3D11 SDK Layers warnings checks.
169     ignoreD3D11SDKLayersWarnings();
170 
171     static const GLuint indices[] = {0, 7, 6, 9, 8, 0};
172     runTest(GL_UNSIGNED_INT, 0, indices + 1);
173 }
174 
TEST_P(LineLoopTest,LineLoopUByteIndexBuffer)175 TEST_P(LineLoopTest, LineLoopUByteIndexBuffer)
176 {
177     // http://anglebug.com/42265165: Disable D3D11 SDK Layers warnings checks.
178     ignoreD3D11SDKLayersWarnings();
179 
180     static const GLubyte indices[] = {0, 7, 6, 9, 8, 0};
181 
182     GLBuffer buf;
183     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buf);
184     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
185 
186     runTest(GL_UNSIGNED_BYTE, buf, reinterpret_cast<const void *>(sizeof(GLubyte)));
187 }
188 
TEST_P(LineLoopTest,LineLoopUShortIndexBuffer)189 TEST_P(LineLoopTest, LineLoopUShortIndexBuffer)
190 {
191     // http://anglebug.com/42265165: Disable D3D11 SDK Layers warnings checks.
192     ignoreD3D11SDKLayersWarnings();
193 
194     static const GLushort indices[] = {0, 7, 6, 9, 8, 0};
195 
196     GLBuffer buf;
197     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buf);
198     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
199 
200     runTest(GL_UNSIGNED_SHORT, buf, reinterpret_cast<const void *>(sizeof(GLushort)));
201 }
202 
TEST_P(LineLoopTest,LineLoopUIntIndexBuffer)203 TEST_P(LineLoopTest, LineLoopUIntIndexBuffer)
204 {
205     if (!IsGLExtensionEnabled("GL_OES_element_index_uint"))
206     {
207         return;
208     }
209 
210     // http://anglebug.com/42265165: Disable D3D11 SDK Layers warnings checks.
211     ignoreD3D11SDKLayersWarnings();
212 
213     static const GLuint indices[] = {0, 7, 6, 9, 8, 0};
214 
215     GLBuffer buf;
216     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buf);
217     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
218 
219     runTest(GL_UNSIGNED_INT, buf, reinterpret_cast<const void *>(sizeof(GLuint)));
220 }
221 
222 // Test that drawing elements between line loop arrays using the same array buffer does not result
223 // in incorrect rendering.
TEST_P(LineLoopTest,DrawTriangleElementsBetweenArrays)224 TEST_P(LineLoopTest, DrawTriangleElementsBetweenArrays)
225 {
226     // http://anglebug.com/42265165: Disable D3D11 SDK Layers warnings checks.
227     ignoreD3D11SDKLayersWarnings();
228 
229     static const GLfloat positions[] = {-0.5f, -0.5f, -0.5f, 0.5f,  0.5f,  0.5f,
230                                         0.5f,  -0.5f, -0.5f, -0.5f, -0.1f, 0.1f,
231                                         -0.1f, -0.1f, 0.1f,  -0.1f, 0.1f,  0.1f};
232     static const GLubyte indices[]   = {5, 6, 7, 5, 7, 8};
233 
234     GLBuffer arrayBuffer;
235     glBindBuffer(GL_ARRAY_BUFFER, arrayBuffer);
236     glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, GL_STATIC_DRAW);
237 
238     GLBuffer indexBuffer;
239     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
240     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
241 
242     glClear(GL_COLOR_BUFFER_BIT);
243     glUseProgram(mProgram);
244     glEnableVertexAttribArray(mPositionLocation);
245     glVertexAttribPointer(mPositionLocation, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
246     glEnable(GL_BLEND);
247 
248     glUniform4f(mColorLocation, 0.0f, 0.0f, 1.0f, 1.0f);
249     glDrawArrays(GL_LINE_LOOP, 0, 4);
250 
251     glUniform4f(mColorLocation, 0.0f, 0.0f, 0.0f, 1.0f);
252     glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, nullptr);
253 
254     glUniform4f(mColorLocation, 0.0f, 1.0f, 0.0f, 1.0f);
255     glDrawArrays(GL_LINE_LOOP, 0, 4);
256 
257     checkPixels();
258 }
259 
260 class LineLoopTestES3 : public LineLoopTest
261 {};
262 
263 // Test that uploading data to buffer that's in use then using it for line loop elements works.
TEST_P(LineLoopTestES3,UseAsUBOThenUpdateThenLineLoopUByteIndexBuffer)264 TEST_P(LineLoopTestES3, UseAsUBOThenUpdateThenLineLoopUByteIndexBuffer)
265 {
266     // http://anglebug.com/42265165: Disable D3D11 SDK Layers warnings checks.
267     ignoreD3D11SDKLayersWarnings();
268 
269     static const GLubyte indices[] = {0, 7, 6, 9, 8, 0};
270 
271     GLFramebuffer framebuffer;
272     GLTexture texture;
273 
274     GLBuffer buf;
275 
276     preTestUpdateBuffer(framebuffer, texture, buf, sizeof(indices));
277 
278     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buf);
279     glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(indices), indices);
280 
281     runTest(GL_UNSIGNED_BYTE, buf, reinterpret_cast<const void *>(sizeof(GLubyte)));
282 
283     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
284     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
285 }
286 
287 // Test that uploading data to buffer that's in use then using it for line loop elements works.
TEST_P(LineLoopTestES3,UseAsUBOThenUpdateThenLineLoopUShortIndexBuffer)288 TEST_P(LineLoopTestES3, UseAsUBOThenUpdateThenLineLoopUShortIndexBuffer)
289 {
290     // http://anglebug.com/42264370
291     ANGLE_SKIP_TEST_IF(IsVulkan() && IsQualcomm());
292 
293     // http://anglebug.com/42265165: Disable D3D11 SDK Layers warnings checks.
294     ignoreD3D11SDKLayersWarnings();
295 
296     static const GLushort indices[] = {0, 7, 6, 9, 8, 0};
297 
298     GLFramebuffer framebuffer;
299     GLTexture texture;
300 
301     GLBuffer buf;
302 
303     preTestUpdateBuffer(framebuffer, texture, buf, sizeof(indices));
304 
305     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buf);
306     glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(indices), indices);
307 
308     runTest(GL_UNSIGNED_SHORT, buf, reinterpret_cast<const void *>(sizeof(GLushort)));
309 
310     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
311     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
312 }
313 
314 // Test that uploading data to buffer that's in use then using it for line loop elements works.
TEST_P(LineLoopTestES3,UseAsUBOThenUpdateThenLineLoopUIntIndexBuffer)315 TEST_P(LineLoopTestES3, UseAsUBOThenUpdateThenLineLoopUIntIndexBuffer)
316 {
317     if (!IsGLExtensionEnabled("GL_OES_element_index_uint"))
318     {
319         return;
320     }
321 
322     // http://anglebug.com/42264370
323     ANGLE_SKIP_TEST_IF(IsVulkan() && IsQualcomm());
324 
325     // http://anglebug.com/42265165: Disable D3D11 SDK Layers warnings checks.
326     ignoreD3D11SDKLayersWarnings();
327 
328     static const GLuint indices[] = {0, 7, 6, 9, 8, 0};
329 
330     GLFramebuffer framebuffer;
331     GLTexture texture;
332 
333     GLBuffer buf;
334 
335     preTestUpdateBuffer(framebuffer, texture, buf, sizeof(indices));
336 
337     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buf);
338     glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(indices), indices);
339 
340     runTest(GL_UNSIGNED_INT, buf, reinterpret_cast<const void *>(sizeof(GLuint)));
341 
342     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
343     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
344 }
345 
346 // Tests an edge case with a very large line loop element count.
347 // Disabled because it is slow and triggers an internal error.
TEST_P(LineLoopTest,DISABLED_DrawArraysWithLargeCount)348 TEST_P(LineLoopTest, DISABLED_DrawArraysWithLargeCount)
349 {
350     constexpr char kVS[] = "void main() { gl_Position = vec4(0); }";
351     constexpr char kFS[] = "void main() { gl_FragColor = vec4(0, 1, 0, 1); }";
352 
353     ANGLE_GL_PROGRAM(program, kVS, kFS);
354     glUseProgram(program);
355     glDrawArrays(GL_LINE_LOOP, 0, 0x3FFFFFFE);
356     EXPECT_GL_ERROR(GL_OUT_OF_MEMORY);
357 
358     glDrawArrays(GL_LINE_LOOP, 0, 0x1FFFFFFE);
359     EXPECT_GL_NO_ERROR();
360 }
361 
362 class LineLoopPrimitiveRestartTest : public ANGLETest<>
363 {
364   protected:
LineLoopPrimitiveRestartTest()365     LineLoopPrimitiveRestartTest()
366     {
367         setWindowWidth(64);
368         setWindowHeight(64);
369         setConfigRedBits(8);
370         setConfigGreenBits(8);
371         setConfigBlueBits(8);
372         setConfigAlphaBits(8);
373     }
374 };
375 
TEST_P(LineLoopPrimitiveRestartTest,LineLoopWithPrimitiveRestart)376 TEST_P(LineLoopPrimitiveRestartTest, LineLoopWithPrimitiveRestart)
377 {
378     constexpr char kVS[] = R"(#version 300 es
379 in vec2 a_position;
380 // x,y = offset, z = scale
381 in vec3 a_transform;
382 
383 invariant gl_Position;
384 void main()
385 {
386     vec2 v_position = a_transform.z * a_position + a_transform.xy;
387     gl_Position = vec4(v_position, 0.0, 1.0);
388 })";
389 
390     constexpr char kFS[] = R"(#version 300 es
391 precision highp float;
392 layout (location=0) out vec4 fragColor;
393 void main()
394 {
395     fragColor = vec4(1.0, 0.0, 0.0, 1.0);
396 })";
397 
398     ANGLE_GL_PROGRAM(program, kVS, kFS);
399     glBindAttribLocation(program, 0, "a_position");
400     glBindAttribLocation(program, 1, "a_transform");
401     glLinkProgram(program);
402     glUseProgram(program);
403     ASSERT_GL_NO_ERROR();
404 
405     // clang-format off
406     constexpr GLfloat vertices[] = {
407         0.1, 0.1, -0.1, 0.1, -0.1, -0.1, 0.1, -0.1,
408         0.1, 0.1, -0.1, 0.1, -0.1, -0.1, 0.1, -0.1,
409         0.1, 0.1, -0.1, 0.1, -0.1, -0.1, 0.1, -0.1,
410         0.1, 0.1, -0.1, 0.1, -0.1, -0.1, 0.1, -0.1,
411     };
412 
413     constexpr GLfloat transform[] = {
414         // first loop transform
415         0, 0, 9,
416         0, 0, 9,
417         0, 0, 9,
418         0, 0, 9,
419         // second loop transform
420         0.2, 0.1, 2,
421         0.2, 0.1, 2,
422         0.2, 0.1, 2,
423         0.2, 0.1, 2,
424         // third loop transform
425         0.5, -0.2, 3,
426         0.5, -0.2, 3,
427         0.5, -0.2, 3,
428         0.5, -0.2, 3,
429         // forth loop transform
430         -0.8, -0.5, 1,
431         -0.8, -0.5, 1,
432         -0.8, -0.5, 1,
433         -0.8, -0.5, 1,
434     };
435 
436     constexpr GLushort lineloopAsStripIndices[] = {
437         // first strip
438         0, 1, 2, 3, 0,
439         // second strip
440         4, 5, 6, 7, 4,
441         // third strip
442         8, 9, 10, 11, 8,
443         // forth strip
444         12, 13, 14, 15, 12 };
445 
446     constexpr GLushort lineloopWithRestartIndices[] = {
447         // first loop
448         0, 1, 2, 3, 0xffff,
449         // second loop
450         4, 5, 6, 7, 0xffff,
451         // third loop
452         8, 9, 10, 11, 0xffff,
453         // forth loop
454         12, 13, 14, 15,
455     };
456     // clang-format on
457 
458     std::vector<GLColor> expectedPixels(getWindowWidth() * getWindowHeight());
459     std::vector<GLColor> renderedPixels(getWindowWidth() * getWindowHeight());
460 
461     // Draw in non-primitive restart way
462     glClear(GL_COLOR_BUFFER_BIT);
463 
464     glEnableVertexAttribArray(0);
465     glEnableVertexAttribArray(1);
466 
467     glBindBuffer(GL_ARRAY_BUFFER, 0);
468     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
469 
470     for (int loop = 0; loop < 4; ++loop)
471     {
472         glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, vertices + 8 * loop);
473         glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, transform + 12 * loop);
474 
475         glDrawElements(GL_LINE_STRIP, 5, GL_UNSIGNED_SHORT, lineloopAsStripIndices);
476     }
477 
478     glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
479                  expectedPixels.data());
480     ASSERT_GL_NO_ERROR();
481 
482     // Draw line loop with primitive restart:
483     glClear(GL_COLOR_BUFFER_BIT);
484 
485     GLBuffer vertexBuffer[2];
486     GLBuffer indexBuffer;
487 
488     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
489     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(lineloopWithRestartIndices),
490                  lineloopWithRestartIndices, GL_STATIC_DRAW);
491 
492     glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[0]);
493     glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
494     glEnableVertexAttribArray(0);
495     glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
496 
497     glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[1]);
498     glBufferData(GL_ARRAY_BUFFER, sizeof(transform), transform, GL_STATIC_DRAW);
499     glEnableVertexAttribArray(1);
500     glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
501 
502     glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
503 
504     glClear(GL_COLOR_BUFFER_BIT);
505     glDrawElements(GL_LINE_LOOP, ArraySize(lineloopWithRestartIndices), GL_UNSIGNED_SHORT, 0);
506 
507     glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
508                  renderedPixels.data());
509 
510     for (int y = 0; y < getWindowHeight(); ++y)
511     {
512         for (int x = 0; x < getWindowWidth(); ++x)
513         {
514             int idx = y * getWindowWidth() + x;
515             EXPECT_EQ(expectedPixels[idx], renderedPixels[idx])
516                 << "Expected pixel at " << x << ", " << y << " to be " << expectedPixels[idx]
517                 << std::endl;
518         }
519     }
520 }
521 
522 class LineLoopIndirectTest : public LineLoopTest
523 {
524   protected:
525     struct DrawCommand
526     {
527         GLuint count;
528         GLuint primCount;
529         GLuint firstIndex;
530         GLint baseVertex;
531         GLuint reservedMustBeZero;
532     };
533 
initUpdateBuffers(GLuint vertexArray,GLuint vertexBuffer,GLuint indexBuffer,const void * positions,uint32_t positionsSize,const void * indices,uint32_t indicesSize)534     void initUpdateBuffers(GLuint vertexArray,
535                            GLuint vertexBuffer,
536                            GLuint indexBuffer,
537                            const void *positions,
538                            uint32_t positionsSize,
539                            const void *indices,
540                            uint32_t indicesSize)
541     {
542         glBindVertexArray(vertexArray);
543         glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
544         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
545 
546         glBufferData(GL_ARRAY_BUFFER, positionsSize, positions, GL_STATIC_DRAW);
547         glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicesSize, indices, GL_STATIC_DRAW);
548     }
549 
preTestUBOAndInitUpdateBuffers(GLuint vertexArray,GLuint vertexBuffer,GLuint indexBuffer,const void * positions,GLsizei positionsSize,const void * indices,GLsizei indicesSize,GLuint arrayUpdateFbo,GLuint arrayUpdateTexture,GLuint elementUpdateFbo,GLuint elementUpdateTexture)550     void preTestUBOAndInitUpdateBuffers(GLuint vertexArray,
551                                         GLuint vertexBuffer,
552                                         GLuint indexBuffer,
553                                         const void *positions,
554                                         GLsizei positionsSize,
555                                         const void *indices,
556                                         GLsizei indicesSize,
557                                         GLuint arrayUpdateFbo,
558                                         GLuint arrayUpdateTexture,
559                                         GLuint elementUpdateFbo,
560                                         GLuint elementUpdateTexture)
561     {
562         preTestUpdateBuffer(arrayUpdateFbo, arrayUpdateTexture, vertexBuffer, positionsSize);
563         preTestUpdateBuffer(elementUpdateFbo, elementUpdateTexture, indexBuffer, indicesSize);
564 
565         glBindVertexArray(vertexArray);
566         glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
567         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
568 
569         glBufferSubData(GL_ARRAY_BUFFER, 0, positionsSize, positions);
570         glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, indicesSize, indices);
571     }
572 
initIndirectBuffer(GLuint indirectBuffer,GLuint firstIndex)573     void initIndirectBuffer(GLuint indirectBuffer, GLuint firstIndex)
574     {
575         DrawCommand indirectData = {};
576         indirectData.count       = 4;
577         indirectData.firstIndex  = firstIndex;
578         indirectData.primCount   = 1;
579 
580         glBindBuffer(GL_DRAW_INDIRECT_BUFFER, indirectBuffer);
581         glBufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(DrawCommand), &indirectData, GL_STATIC_DRAW);
582         ASSERT_GL_NO_ERROR();
583     }
584 
setVertexAttribs(const void * positions)585     void setVertexAttribs(const void *positions)
586     {
587         glEnableVertexAttribArray(mPositionLocation);
588         glVertexAttribPointer(mPositionLocation, 2, GL_FLOAT, GL_FALSE, 0, positions);
589         ASSERT_GL_NO_ERROR();
590     }
591 
592     static constexpr GLfloat kLoopPositions[]  = {0.0f,  0.0f, 0.0f, 0.0f, 0.0f, 0.0f,  0.0f,
593                                                   0.0f,  0.0f, 0.0f, 0.0f, 0.0f, -0.5f, -0.5f,
594                                                   -0.5f, 0.5f, 0.5f, 0.5f, 0.5f, -0.5f};
595     static constexpr GLfloat kStripPositions[] = {-0.5f, -0.5f, -0.5f, 0.5f,
596                                                   0.5f,  0.5f,  0.5f,  -0.5f};
597     static constexpr GLubyte kStripIndices[]   = {1, 0, 3, 2, 1};
598 };
599 
600 // Test that drawing a line loop using an index buffer of unsigned bytes works.
TEST_P(LineLoopIndirectTest,UByteIndexIndirectBuffer)601 TEST_P(LineLoopIndirectTest, UByteIndexIndirectBuffer)
602 {
603     // Old drivers buggy with optimized ConvertIndexIndirectLineLoop shader.
604     // http://anglebug.com/40096699
605     ANGLE_SKIP_TEST_IF(IsAMD() && IsWindows() && IsVulkan());
606 
607     // http://anglebug.com/42265165: Disable D3D11 SDK Layers warnings checks.
608     ignoreD3D11SDKLayersWarnings();
609 
610     // Start at index 1.
611     GLuint firstIndex       = 1;
612     const GLubyte indices[] = {0, 7, 6, 9, 8, 0};
613 
614     glClear(GL_COLOR_BUFFER_BIT);
615     glUseProgram(mProgram);
616     ASSERT_GL_NO_ERROR();
617 
618     GLVertexArray vertexArray;
619     GLBuffer vertexBuffer;
620     GLBuffer indexBuffer;
621 
622     initUpdateBuffers(vertexArray, vertexBuffer, indexBuffer, kLoopPositions,
623                       sizeof(kLoopPositions), indices, sizeof(indices));
624 
625     GLBuffer indirectBuffer;
626     initIndirectBuffer(indirectBuffer, firstIndex);
627 
628     glEnable(GL_BLEND);
629     setVertexAttribs(nullptr);
630     glUniform4f(mColorLocation, 0.0f, 0.0f, 1.0f, 1.0f);
631     glDrawElementsIndirect(GL_LINE_LOOP, GL_UNSIGNED_BYTE, nullptr);
632     ASSERT_GL_NO_ERROR();
633 
634     glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0);
635     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
636     glBindBuffer(GL_ARRAY_BUFFER, 0);
637     glBindVertexArray(0);
638 
639     setVertexAttribs(kStripPositions);
640     glUniform4f(mColorLocation, 0.0f, 1.0f, 0.0f, 1.0f);
641     glDrawElements(GL_LINE_STRIP, 5, GL_UNSIGNED_BYTE, kStripIndices);
642     ASSERT_GL_NO_ERROR();
643 
644     checkPixels();
645 }
646 
647 // Test that drawing a line loop using an index buffer of unsigned short values works.
TEST_P(LineLoopIndirectTest,UShortIndexIndirectBuffer)648 TEST_P(LineLoopIndirectTest, UShortIndexIndirectBuffer)
649 {
650     // Old drivers buggy with optimized ConvertIndexIndirectLineLoop shader.
651     // http://anglebug.com/40096699
652     ANGLE_SKIP_TEST_IF(IsAMD() && IsWindows() && IsVulkan());
653 
654     // http://anglebug.com/42265165: Disable D3D11 SDK Layers warnings checks.
655     ignoreD3D11SDKLayersWarnings();
656 
657     // Start at index 1.
658     GLuint firstIndex        = 1;
659     const GLushort indices[] = {0, 7, 6, 9, 8, 0};
660 
661     glClear(GL_COLOR_BUFFER_BIT);
662     glUseProgram(mProgram);
663     ASSERT_GL_NO_ERROR();
664 
665     GLVertexArray vertexArray;
666     GLBuffer vertexBuffer;
667     GLBuffer indexBuffer;
668 
669     initUpdateBuffers(vertexArray, vertexBuffer, indexBuffer, kLoopPositions,
670                       sizeof(kLoopPositions), indices, sizeof(indices));
671 
672     GLBuffer indirectBuffer;
673     initIndirectBuffer(indirectBuffer, firstIndex);
674 
675     glEnable(GL_BLEND);
676     setVertexAttribs(nullptr);
677     glUniform4f(mColorLocation, 0.0f, 0.0f, 1.0f, 1.0f);
678     glDrawElementsIndirect(GL_LINE_LOOP, GL_UNSIGNED_SHORT, nullptr);
679     ASSERT_GL_NO_ERROR();
680 
681     glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0);
682     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
683     glBindBuffer(GL_ARRAY_BUFFER, 0);
684     glBindVertexArray(0);
685 
686     setVertexAttribs(kStripPositions);
687     glUniform4f(mColorLocation, 0.0f, 1.0f, 0.0f, 1.0f);
688     glDrawElements(GL_LINE_STRIP, 5, GL_UNSIGNED_BYTE, kStripIndices);
689     ASSERT_GL_NO_ERROR();
690 
691     checkPixels();
692 }
693 
694 // Test that uploading data to buffer that's in use then using it for line loop elements works.
TEST_P(LineLoopIndirectTest,UseAsUBOThenUpdateThenUByteIndexIndirectBuffer)695 TEST_P(LineLoopIndirectTest, UseAsUBOThenUpdateThenUByteIndexIndirectBuffer)
696 {
697     // http://anglebug.com/42264370
698     ANGLE_SKIP_TEST_IF(IsVulkan() && IsQualcomm());
699 
700     // Old drivers buggy with optimized ConvertIndexIndirectLineLoop shader.
701     // http://anglebug.com/40096699
702     ANGLE_SKIP_TEST_IF(IsAMD() && IsWindows() && IsVulkan());
703 
704     // http://anglebug.com/42265165: Disable D3D11 SDK Layers warnings checks.
705     ignoreD3D11SDKLayersWarnings();
706 
707     // Start at index 1.
708     GLuint firstIndex       = 1;
709     const GLubyte indices[] = {0, 7, 6, 9, 8, 0};
710 
711     glClear(GL_COLOR_BUFFER_BIT);
712     glUseProgram(mProgram);
713     ASSERT_GL_NO_ERROR();
714 
715     GLVertexArray vertexArray;
716     GLFramebuffer arrayUpdateFbo, elementUpdateFbo;
717     GLTexture arrayUpdateTex, elementUpdateTex;
718     GLBuffer vertexBuffer;
719     GLBuffer indexBuffer;
720 
721     preTestUBOAndInitUpdateBuffers(vertexArray, vertexBuffer, indexBuffer, kLoopPositions,
722                                    sizeof(kLoopPositions), indices, sizeof(indices), arrayUpdateFbo,
723                                    arrayUpdateTex, elementUpdateFbo, elementUpdateTex);
724 
725     GLBuffer indirectBuffer;
726     initIndirectBuffer(indirectBuffer, firstIndex);
727 
728     glEnable(GL_BLEND);
729     setVertexAttribs(nullptr);
730     glUniform4f(mColorLocation, 0.0f, 0.0f, 1.0f, 1.0f);
731     glDrawElementsIndirect(GL_LINE_LOOP, GL_UNSIGNED_BYTE, nullptr);
732     ASSERT_GL_NO_ERROR();
733 
734     glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0);
735     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
736     glBindBuffer(GL_ARRAY_BUFFER, 0);
737     glBindVertexArray(0);
738 
739     setVertexAttribs(kStripPositions);
740     glUniform4f(mColorLocation, 0.0f, 1.0f, 0.0f, 1.0f);
741     glDrawElements(GL_LINE_STRIP, 5, GL_UNSIGNED_BYTE, kStripIndices);
742     ASSERT_GL_NO_ERROR();
743 
744     checkPixels();
745 
746     glBindFramebuffer(GL_FRAMEBUFFER, arrayUpdateFbo);
747     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
748 
749     glBindFramebuffer(GL_FRAMEBUFFER, elementUpdateFbo);
750     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
751 }
752 
753 // Test that uploading data to buffer that's in use then using it for line loop elements works.
TEST_P(LineLoopIndirectTest,UseAsUBOThenUpdateThenUShortIndexIndirectBuffer)754 TEST_P(LineLoopIndirectTest, UseAsUBOThenUpdateThenUShortIndexIndirectBuffer)
755 {
756     // http://anglebug.com/42264370
757     ANGLE_SKIP_TEST_IF(IsVulkan() && IsQualcomm());
758 
759     // Old drivers buggy with optimized ConvertIndexIndirectLineLoop shader.
760     // http://anglebug.com/40096699
761     ANGLE_SKIP_TEST_IF(IsAMD() && IsWindows() && IsVulkan());
762 
763     // http://anglebug.com/42265165: Disable D3D11 SDK Layers warnings checks.
764     ignoreD3D11SDKLayersWarnings();
765 
766     // Start at index 1.
767     GLuint firstIndex       = 1;
768     const GLshort indices[] = {0, 7, 6, 9, 8, 0};
769 
770     glClear(GL_COLOR_BUFFER_BIT);
771     glUseProgram(mProgram);
772     ASSERT_GL_NO_ERROR();
773 
774     GLVertexArray vertexArray;
775     GLFramebuffer arrayUpdateFbo, elementUpdateFbo;
776     GLTexture arrayUpdateTex, elementUpdateTex;
777     GLBuffer vertexBuffer;
778     GLBuffer indexBuffer;
779 
780     preTestUBOAndInitUpdateBuffers(vertexArray, vertexBuffer, indexBuffer, kLoopPositions,
781                                    sizeof(kLoopPositions), indices, sizeof(indices), arrayUpdateFbo,
782                                    arrayUpdateTex, elementUpdateFbo, elementUpdateTex);
783 
784     GLBuffer indirectBuffer;
785     initIndirectBuffer(indirectBuffer, firstIndex);
786 
787     glEnable(GL_BLEND);
788     setVertexAttribs(nullptr);
789     glUniform4f(mColorLocation, 0.0f, 0.0f, 1.0f, 1.0f);
790     glDrawElementsIndirect(GL_LINE_LOOP, GL_UNSIGNED_SHORT, nullptr);
791     ASSERT_GL_NO_ERROR();
792 
793     glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0);
794     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
795     glBindBuffer(GL_ARRAY_BUFFER, 0);
796     glBindVertexArray(0);
797 
798     setVertexAttribs(kStripPositions);
799     glUniform4f(mColorLocation, 0.0f, 1.0f, 0.0f, 1.0f);
800     glDrawElements(GL_LINE_STRIP, 5, GL_UNSIGNED_BYTE, kStripIndices);
801     ASSERT_GL_NO_ERROR();
802 
803     checkPixels();
804 
805     glBindFramebuffer(GL_FRAMEBUFFER, arrayUpdateFbo);
806     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
807 
808     glBindFramebuffer(GL_FRAMEBUFFER, elementUpdateFbo);
809     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
810 }
811 
812 // Test that two indirect draws drawing lineloop and sharing same index buffer works.
TEST_P(LineLoopIndirectTest,TwoIndirectDrawsShareIndexBuffer)813 TEST_P(LineLoopIndirectTest, TwoIndirectDrawsShareIndexBuffer)
814 {
815     // http://anglebug.com/42264370
816     ANGLE_SKIP_TEST_IF(IsVulkan() && IsQualcomm());
817 
818     // Old drivers buggy with optimized ConvertIndexIndirectLineLoop shader.
819     // http://anglebug.com/40096699
820     ANGLE_SKIP_TEST_IF(IsAMD() && IsWindows() && IsVulkan());
821 
822     // http://anglebug.com/42265165: Disable D3D11 SDK Layers warnings checks.
823     ignoreD3D11SDKLayersWarnings();
824 
825     // Start at index 1.
826     GLuint firstIndex        = 1;
827     const GLushort indices[] = {0, 7, 6, 9, 8, 0};
828 
829     glClear(GL_COLOR_BUFFER_BIT);
830     glUseProgram(mProgram);
831     ASSERT_GL_NO_ERROR();
832 
833     GLVertexArray vertexArray;
834     GLBuffer vertexBuffer;
835     GLBuffer indexBuffer;
836 
837     initUpdateBuffers(vertexArray, vertexBuffer, indexBuffer, kLoopPositions,
838                       sizeof(kLoopPositions), indices, sizeof(indices));
839 
840     GLBuffer indirectBuffer;
841     initIndirectBuffer(indirectBuffer, firstIndex);
842 
843     glEnable(GL_BLEND);
844     setVertexAttribs(nullptr);
845     glUniform4f(mColorLocation, 0.0f, 0.0f, 1.0f, 1.0f);
846     glDrawElementsIndirect(GL_LINE_LOOP, GL_UNSIGNED_SHORT, nullptr);
847     ASSERT_GL_NO_ERROR();
848     glDrawElementsIndirect(GL_LINE_LOOP, GL_UNSIGNED_SHORT, nullptr);
849     ASSERT_GL_NO_ERROR();
850 
851     glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0);
852     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
853     glBindBuffer(GL_ARRAY_BUFFER, 0);
854     glBindVertexArray(0);
855 
856     setVertexAttribs(kStripPositions);
857     glUniform4f(mColorLocation, 0.0f, 1.0f, 0.0f, 1.0f);
858     glDrawElements(GL_LINE_STRIP, 5, GL_UNSIGNED_BYTE, kStripIndices);
859     ASSERT_GL_NO_ERROR();
860 
861     checkPixels();
862 }
863 
864 // Test that one indirect line-loop followed by one non-line-loop draw that share the same index
865 // buffer works.
TEST_P(LineLoopIndirectTest,IndirectAndElementDrawsShareIndexBuffer)866 TEST_P(LineLoopIndirectTest, IndirectAndElementDrawsShareIndexBuffer)
867 {
868     // http://anglebug.com/42264370
869     ANGLE_SKIP_TEST_IF(IsVulkan() && IsQualcomm());
870 
871     // Old drivers buggy with optimized ConvertIndexIndirectLineLoop shader.
872     // http://anglebug.com/40096699
873     ANGLE_SKIP_TEST_IF(IsAMD() && IsWindows() && IsVulkan());
874 
875     // http://anglebug.com/42265165: Disable D3D11 SDK Layers warnings checks.
876     ignoreD3D11SDKLayersWarnings();
877 
878     GLuint firstIndex                    = 10;
879     static const GLubyte indices[]       = {0, 6, 9, 8, 7, 6, 0, 0, 9, 1, 2, 3, 4, 1, 0};
880     static const GLfloat loopPositions[] = {0.0f,  0.0f, 0.5f,  0.0f, 0.0f, 0.5f,  -0.5f,
881                                             0.0f,  0.0f, -0.5f, 0.0f, 0.0f, -0.5f, -0.5f,
882                                             -0.5f, 0.5f, 0.5f,  0.5f, 0.5f, -0.5f};
883 
884     glClear(GL_COLOR_BUFFER_BIT);
885     glUseProgram(mProgram);
886     ASSERT_GL_NO_ERROR();
887 
888     GLVertexArray vertexArray;
889     GLBuffer vertexBuffer;
890     GLBuffer indexBuffer;
891 
892     initUpdateBuffers(vertexArray, vertexBuffer, indexBuffer, loopPositions, sizeof(loopPositions),
893                       indices, sizeof(indices));
894 
895     GLBuffer indirectBuffer;
896     initIndirectBuffer(indirectBuffer, firstIndex);
897 
898     glEnable(GL_BLEND);
899     setVertexAttribs(nullptr);
900     glUniform4f(mColorLocation, 1.0f, 0.0f, 1.0f, 1.0f);
901 
902     glViewport(0, 0, getWindowWidth() / 2, getWindowHeight());
903     glDrawElementsIndirect(GL_LINE_LOOP, GL_UNSIGNED_BYTE, nullptr);
904     ASSERT_GL_NO_ERROR();
905 
906     glViewport(getWindowWidth() / 2, 0, getWindowWidth() / 2, getWindowHeight());
907     glUniform4f(mColorLocation, 0.0, 1.0, 1.0, 1.0);
908     glDrawElements(GL_LINE_STRIP, 5, GL_UNSIGNED_BYTE, reinterpret_cast<const void *>(1));
909     ASSERT_GL_NO_ERROR();
910 
911     glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0);
912     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
913     glBindBuffer(GL_ARRAY_BUFFER, 0);
914     glBindVertexArray(0);
915 
916     // Check pixels.
917     std::vector<GLubyte> pixels(getWindowWidth() * getWindowHeight() * 4);
918     glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE, &pixels[0]);
919     ASSERT_GL_NO_ERROR();
920 
921     for (int y = 0; y < getWindowHeight(); y++)
922     {
923         for (int x = 0; x < getWindowWidth() / 2; x++)
924         {
925             const GLubyte *pixel = &pixels[0] + ((y * getWindowWidth() + x) * 4);
926 
927             EXPECT_TRUE(pixel[0] == pixel[2]) << "Failed at " << x << ", " << y << std::endl;
928             EXPECT_TRUE(pixel[1] == 0) << "Failed at " << x << ", " << y << std::endl;
929             ASSERT_EQ(pixel[3], 255) << "Failed at " << x << ", " << y << std::endl;
930         }
931         for (int x = getWindowWidth() / 2; x < getWindowWidth(); x++)
932         {
933             const GLubyte *pixel = &pixels[0] + ((y * getWindowWidth() + x) * 4);
934 
935             EXPECT_TRUE(pixel[0] == 0) << "Failed at " << x << ", " << y << std::endl;
936             EXPECT_TRUE(pixel[1] == pixel[2]) << "Failed at " << x << ", " << y << std::endl;
937             ASSERT_EQ(pixel[3], 255) << "Failed at " << x << ", " << y << std::endl;
938         }
939     }
940 }
941 
942 ANGLE_INSTANTIATE_TEST_ES2(LineLoopTest);
943 ANGLE_INSTANTIATE_TEST_ES3(LineLoopTestES3);
944 
945 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(LineLoopPrimitiveRestartTest);
946 ANGLE_INSTANTIATE_TEST_ES3_AND(
947     LineLoopPrimitiveRestartTest,
948     ES3_METAL().enable(Feature::ForceBufferGPUStorage),
949     ES3_METAL().disable(Feature::HasExplicitMemBarrier).disable(Feature::HasCheapRenderPass));
950 
951 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(LineLoopIndirectTest);
952 ANGLE_INSTANTIATE_TEST_ES31(LineLoopIndirectTest);
953