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     // Disable D3D11 SDK Layers warnings checks, see ANGLE issue 667 for details
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     // Disable D3D11 SDK Layers warnings checks, see ANGLE issue 667 for details
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     // Disable D3D11 SDK Layers warnings checks, see ANGLE issue 667 for details
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     // Disable D3D11 SDK Layers warnings checks, see ANGLE issue 667 for details
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     // Disable D3D11 SDK Layers warnings checks, see ANGLE issue 667 for details
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     // Disable D3D11 SDK Layers warnings checks, see ANGLE issue 667 for details
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 class LineLoopTestES3 : public LineLoopTest
223 {};
224 
225 // Test that uploading data to buffer that's in use then using it for line loop elements works.
TEST_P(LineLoopTestES3,UseAsUBOThenUpdateThenLineLoopUByteIndexBuffer)226 TEST_P(LineLoopTestES3, UseAsUBOThenUpdateThenLineLoopUByteIndexBuffer)
227 {
228     // Disable D3D11 SDK Layers warnings checks, see ANGLE issue 667 for details
229     ignoreD3D11SDKLayersWarnings();
230 
231     static const GLubyte indices[] = {0, 7, 6, 9, 8, 0};
232 
233     GLFramebuffer framebuffer;
234     GLTexture texture;
235 
236     GLBuffer buf;
237 
238     preTestUpdateBuffer(framebuffer, texture, buf, sizeof(indices));
239 
240     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buf);
241     glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(indices), indices);
242 
243     runTest(GL_UNSIGNED_BYTE, buf, reinterpret_cast<const void *>(sizeof(GLubyte)));
244 
245     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
246     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
247 }
248 
249 // Test that uploading data to buffer that's in use then using it for line loop elements works.
TEST_P(LineLoopTestES3,UseAsUBOThenUpdateThenLineLoopUShortIndexBuffer)250 TEST_P(LineLoopTestES3, UseAsUBOThenUpdateThenLineLoopUShortIndexBuffer)
251 {
252     // http://anglebug.com/5833
253     ANGLE_SKIP_TEST_IF(IsVulkan() && IsQualcomm());
254 
255     // Disable D3D11 SDK Layers warnings checks, see ANGLE issue 667 for details
256     ignoreD3D11SDKLayersWarnings();
257 
258     static const GLushort indices[] = {0, 7, 6, 9, 8, 0};
259 
260     GLFramebuffer framebuffer;
261     GLTexture texture;
262 
263     GLBuffer buf;
264 
265     preTestUpdateBuffer(framebuffer, texture, buf, sizeof(indices));
266 
267     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buf);
268     glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(indices), indices);
269 
270     runTest(GL_UNSIGNED_SHORT, buf, reinterpret_cast<const void *>(sizeof(GLushort)));
271 
272     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
273     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
274 }
275 
276 // Test that uploading data to buffer that's in use then using it for line loop elements works.
TEST_P(LineLoopTestES3,UseAsUBOThenUpdateThenLineLoopUIntIndexBuffer)277 TEST_P(LineLoopTestES3, UseAsUBOThenUpdateThenLineLoopUIntIndexBuffer)
278 {
279     if (!IsGLExtensionEnabled("GL_OES_element_index_uint"))
280     {
281         return;
282     }
283 
284     // http://anglebug.com/5833
285     ANGLE_SKIP_TEST_IF(IsVulkan() && IsQualcomm());
286 
287     // Disable D3D11 SDK Layers warnings checks, see ANGLE issue 667 for details
288     ignoreD3D11SDKLayersWarnings();
289 
290     static const GLuint indices[] = {0, 7, 6, 9, 8, 0};
291 
292     GLFramebuffer framebuffer;
293     GLTexture texture;
294 
295     GLBuffer buf;
296 
297     preTestUpdateBuffer(framebuffer, texture, buf, sizeof(indices));
298 
299     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buf);
300     glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(indices), indices);
301 
302     runTest(GL_UNSIGNED_INT, buf, reinterpret_cast<const void *>(sizeof(GLuint)));
303 
304     glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
305     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
306 }
307 
308 // Tests an edge case with a very large line loop element count.
309 // Disabled because it is slow and triggers an internal error.
TEST_P(LineLoopTest,DISABLED_DrawArraysWithLargeCount)310 TEST_P(LineLoopTest, DISABLED_DrawArraysWithLargeCount)
311 {
312     constexpr char kVS[] = "void main() { gl_Position = vec4(0); }";
313     constexpr char kFS[] = "void main() { gl_FragColor = vec4(0, 1, 0, 1); }";
314 
315     ANGLE_GL_PROGRAM(program, kVS, kFS);
316     glUseProgram(program);
317     glDrawArrays(GL_LINE_LOOP, 0, 0x3FFFFFFE);
318     EXPECT_GL_ERROR(GL_OUT_OF_MEMORY);
319 
320     glDrawArrays(GL_LINE_LOOP, 0, 0x1FFFFFFE);
321     EXPECT_GL_NO_ERROR();
322 }
323 
324 class LineLoopPrimitiveRestartTest : public ANGLETest
325 {
326   protected:
LineLoopPrimitiveRestartTest()327     LineLoopPrimitiveRestartTest()
328     {
329         setWindowWidth(64);
330         setWindowHeight(64);
331         setConfigRedBits(8);
332         setConfigGreenBits(8);
333         setConfigBlueBits(8);
334         setConfigAlphaBits(8);
335     }
336 };
337 
TEST_P(LineLoopPrimitiveRestartTest,LineLoopWithPrimitiveRestart)338 TEST_P(LineLoopPrimitiveRestartTest, LineLoopWithPrimitiveRestart)
339 {
340     constexpr char kVS[] = R"(#version 300 es
341 in vec2 a_position;
342 // x,y = offset, z = scale
343 in vec3 a_transform;
344 
345 invariant gl_Position;
346 void main()
347 {
348     vec2 v_position = a_transform.z * a_position + a_transform.xy;
349     gl_Position = vec4(v_position, 0.0, 1.0);
350 })";
351 
352     constexpr char kFS[] = R"(#version 300 es
353 precision highp float;
354 layout (location=0) out vec4 fragColor;
355 void main()
356 {
357     fragColor = vec4(1.0, 0.0, 0.0, 1.0);
358 })";
359 
360     ANGLE_GL_PROGRAM(program, kVS, kFS);
361     glBindAttribLocation(program, 0, "a_position");
362     glBindAttribLocation(program, 1, "a_transform");
363     glLinkProgram(program);
364     glUseProgram(program);
365     ASSERT_GL_NO_ERROR();
366 
367     // clang-format off
368     constexpr GLfloat vertices[] = {
369         0.1, 0.1, -0.1, 0.1, -0.1, -0.1, 0.1, -0.1,
370         0.1, 0.1, -0.1, 0.1, -0.1, -0.1, 0.1, -0.1,
371         0.1, 0.1, -0.1, 0.1, -0.1, -0.1, 0.1, -0.1,
372         0.1, 0.1, -0.1, 0.1, -0.1, -0.1, 0.1, -0.1,
373     };
374 
375     constexpr GLfloat transform[] = {
376         // first loop transform
377         0, 0, 9,
378         0, 0, 9,
379         0, 0, 9,
380         0, 0, 9,
381         // second loop transform
382         0.2, 0.1, 2,
383         0.2, 0.1, 2,
384         0.2, 0.1, 2,
385         0.2, 0.1, 2,
386         // third loop transform
387         0.5, -0.2, 3,
388         0.5, -0.2, 3,
389         0.5, -0.2, 3,
390         0.5, -0.2, 3,
391         // forth loop transform
392         -0.8, -0.5, 1,
393         -0.8, -0.5, 1,
394         -0.8, -0.5, 1,
395         -0.8, -0.5, 1,
396     };
397 
398     constexpr GLushort lineloopAsStripIndices[] = {
399         // first strip
400         0, 1, 2, 3, 0,
401         // second strip
402         4, 5, 6, 7, 4,
403         // third strip
404         8, 9, 10, 11, 8,
405         // forth strip
406         12, 13, 14, 15, 12 };
407 
408     constexpr GLushort lineloopWithRestartIndices[] = {
409         // first loop
410         0, 1, 2, 3, 0xffff,
411         // second loop
412         4, 5, 6, 7, 0xffff,
413         // third loop
414         8, 9, 10, 11, 0xffff,
415         // forth loop
416         12, 13, 14, 15,
417     };
418     // clang-format on
419 
420     std::vector<GLColor> expectedPixels(getWindowWidth() * getWindowHeight());
421     std::vector<GLColor> renderedPixels(getWindowWidth() * getWindowHeight());
422 
423     // Draw in non-primitive restart way
424     glClear(GL_COLOR_BUFFER_BIT);
425 
426     glEnableVertexAttribArray(0);
427     glEnableVertexAttribArray(1);
428 
429     glBindBuffer(GL_ARRAY_BUFFER, 0);
430     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
431 
432     for (int loop = 0; loop < 4; ++loop)
433     {
434         glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, vertices + 8 * loop);
435         glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, transform + 12 * loop);
436 
437         glDrawElements(GL_LINE_STRIP, 5, GL_UNSIGNED_SHORT, lineloopAsStripIndices);
438     }
439 
440     glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
441                  expectedPixels.data());
442     ASSERT_GL_NO_ERROR();
443 
444     // Draw line loop with primitive restart:
445     glClear(GL_COLOR_BUFFER_BIT);
446 
447     GLBuffer vertexBuffer[2];
448     GLBuffer indexBuffer;
449 
450     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
451     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(lineloopWithRestartIndices),
452                  lineloopWithRestartIndices, GL_STATIC_DRAW);
453 
454     glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[0]);
455     glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
456     glEnableVertexAttribArray(0);
457     glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
458 
459     glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[1]);
460     glBufferData(GL_ARRAY_BUFFER, sizeof(transform), transform, GL_STATIC_DRAW);
461     glEnableVertexAttribArray(1);
462     glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
463 
464     glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
465 
466     glClear(GL_COLOR_BUFFER_BIT);
467     glDrawElements(GL_LINE_LOOP, ArraySize(lineloopWithRestartIndices), GL_UNSIGNED_SHORT, 0);
468 
469     glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
470                  renderedPixels.data());
471 
472     for (int y = 0; y < getWindowHeight(); ++y)
473     {
474         for (int x = 0; x < getWindowWidth(); ++x)
475         {
476             int idx = y * getWindowWidth() + x;
477             EXPECT_EQ(expectedPixels[idx], renderedPixels[idx])
478                 << "Expected pixel at " << x << ", " << y << " to be " << expectedPixels[idx]
479                 << std::endl;
480         }
481     }
482 }
483 
484 class LineLoopIndirectTest : public LineLoopTest
485 {
486   protected:
runTest(GLenum indexType,const void * indices,GLuint indicesSize,GLuint firstIndex,bool useBuffersAsUboFirst)487     void runTest(GLenum indexType,
488                  const void *indices,
489                  GLuint indicesSize,
490                  GLuint firstIndex,
491                  bool useBuffersAsUboFirst)
492     {
493         struct DrawCommand
494         {
495             GLuint count;
496             GLuint primCount;
497             GLuint firstIndex;
498             GLint baseVertex;
499             GLuint reservedMustBeZero;
500         };
501 
502         glClear(GL_COLOR_BUFFER_BIT);
503 
504         static const GLfloat loopPositions[] = {0.0f,  0.0f, 0.0f, 0.0f, 0.0f, 0.0f,  0.0f,
505                                                 0.0f,  0.0f, 0.0f, 0.0f, 0.0f, -0.5f, -0.5f,
506                                                 -0.5f, 0.5f, 0.5f, 0.5f, 0.5f, -0.5f};
507 
508         static const GLfloat stripPositions[] = {-0.5f, -0.5f, -0.5f, 0.5f,
509                                                  0.5f,  0.5f,  0.5f,  -0.5f};
510         static const GLubyte stripIndices[]   = {1, 0, 3, 2, 1};
511 
512         glUseProgram(mProgram);
513 
514         GLVertexArray vertexArray;
515 
516         ASSERT_GL_NO_ERROR();
517 
518         GLFramebuffer arrayUpdateFbo, elementUpdateFbo;
519         GLTexture arrayUpdateTex, elementUpdateTex;
520 
521         GLBuffer vertBuffer;
522         GLBuffer buf;
523 
524         if (useBuffersAsUboFirst)
525         {
526             preTestUpdateBuffer(arrayUpdateFbo, arrayUpdateTex, vertBuffer, sizeof(loopPositions));
527             preTestUpdateBuffer(elementUpdateFbo, elementUpdateTex, buf, indicesSize);
528         }
529 
530         glBindVertexArray(vertexArray);
531         glBindBuffer(GL_ARRAY_BUFFER, vertBuffer);
532         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buf);
533 
534         if (useBuffersAsUboFirst)
535         {
536             glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(loopPositions), loopPositions);
537             glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, indicesSize, indices);
538         }
539         else
540         {
541             glBufferData(GL_ARRAY_BUFFER, sizeof(loopPositions), loopPositions, GL_STATIC_DRAW);
542             glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicesSize, indices, GL_STATIC_DRAW);
543         }
544         glEnableVertexAttribArray(mPositionLocation);
545         glVertexAttribPointer(mPositionLocation, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
546         glUniform4f(mColorLocation, 0.0f, 0.0f, 1.0f, 1.0f);
547 
548         ASSERT_GL_NO_ERROR();
549 
550         DrawCommand cmdBuffer = {};
551         cmdBuffer.count       = 4;
552         cmdBuffer.firstIndex  = firstIndex;
553         cmdBuffer.primCount   = 1;
554         GLBuffer indirectBuf;
555         glBindBuffer(GL_DRAW_INDIRECT_BUFFER, indirectBuf);
556         glBufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(DrawCommand), &cmdBuffer, GL_STATIC_DRAW);
557 
558         ASSERT_GL_NO_ERROR();
559 
560         glEnable(GL_BLEND);
561         glDrawElementsIndirect(GL_LINE_LOOP, indexType, nullptr);
562         ASSERT_GL_NO_ERROR();
563 
564         glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0);
565 
566         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
567 
568         glBindVertexArray(0);
569 
570         glBindBuffer(GL_ARRAY_BUFFER, 0);
571 
572         glEnableVertexAttribArray(mPositionLocation);
573         glVertexAttribPointer(mPositionLocation, 2, GL_FLOAT, GL_FALSE, 0, stripPositions);
574         glUniform4f(mColorLocation, 0, 1, 0, 1);
575         glDrawElements(GL_LINE_STRIP, 5, GL_UNSIGNED_BYTE, stripIndices);
576 
577         checkPixels();
578 
579         if (useBuffersAsUboFirst)
580         {
581             glBindFramebuffer(GL_FRAMEBUFFER, arrayUpdateFbo);
582             EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
583 
584             glBindFramebuffer(GL_FRAMEBUFFER, elementUpdateFbo);
585             EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
586         }
587     }
588 };
589 
TEST_P(LineLoopIndirectTest,UByteIndexIndirectBuffer)590 TEST_P(LineLoopIndirectTest, UByteIndexIndirectBuffer)
591 {
592     // Old drivers buggy with optimized ConvertIndexIndirectLineLoop shader.
593     // http://anglebug.com/4720
594     ANGLE_SKIP_TEST_IF(IsAMD() && IsWindows() && IsVulkan());
595 
596     // Disable D3D11 SDK Layers warnings checks, see ANGLE issue 667 for details
597     ignoreD3D11SDKLayersWarnings();
598 
599     static const GLubyte indices[] = {0, 7, 6, 9, 8, 0};
600 
601     // Start at index 1.
602     runTest(GL_UNSIGNED_BYTE, reinterpret_cast<const void *>(indices), sizeof(indices), 1, false);
603 }
604 
TEST_P(LineLoopIndirectTest,UShortIndexIndirectBuffer)605 TEST_P(LineLoopIndirectTest, UShortIndexIndirectBuffer)
606 {
607     // Old drivers buggy with optimized ConvertIndexIndirectLineLoop shader.
608     // http://anglebug.com/4720
609     ANGLE_SKIP_TEST_IF(IsAMD() && IsWindows() && IsVulkan());
610 
611     // Disable D3D11 SDK Layers warnings checks, see ANGLE issue 667 for details
612     ignoreD3D11SDKLayersWarnings();
613 
614     static const GLushort indices[] = {0, 7, 6, 9, 8, 0};
615 
616     // Start at index 1.
617     runTest(GL_UNSIGNED_SHORT, reinterpret_cast<const void *>(indices), sizeof(indices), 1, false);
618 }
619 
620 // Test that uploading data to buffer that's in use then using it for line loop elements works.
TEST_P(LineLoopIndirectTest,UseAsUBOThenUpdateThenUByteIndexIndirectBuffer)621 TEST_P(LineLoopIndirectTest, UseAsUBOThenUpdateThenUByteIndexIndirectBuffer)
622 {
623     // http://anglebug.com/5833
624     ANGLE_SKIP_TEST_IF(IsVulkan() && IsQualcomm());
625 
626     // Old drivers buggy with optimized ConvertIndexIndirectLineLoop shader.
627     // http://anglebug.com/4720
628     ANGLE_SKIP_TEST_IF(IsAMD() && IsWindows() && IsVulkan());
629 
630     // Disable D3D11 SDK Layers warnings checks, see ANGLE issue 667 for details
631     ignoreD3D11SDKLayersWarnings();
632 
633     static const GLubyte indices[] = {0, 7, 6, 9, 8, 0};
634 
635     // Start at index 1.
636     runTest(GL_UNSIGNED_BYTE, reinterpret_cast<const void *>(indices), sizeof(indices), 1, true);
637 }
638 
639 // Test that uploading data to buffer that's in use then using it for line loop elements works.
TEST_P(LineLoopIndirectTest,UseAsUBOThenUpdateThenUShortIndexIndirectBuffer)640 TEST_P(LineLoopIndirectTest, UseAsUBOThenUpdateThenUShortIndexIndirectBuffer)
641 {
642     // http://anglebug.com/5833
643     ANGLE_SKIP_TEST_IF(IsVulkan() && IsQualcomm());
644 
645     // Old drivers buggy with optimized ConvertIndexIndirectLineLoop shader.
646     // http://anglebug.com/4720
647     ANGLE_SKIP_TEST_IF(IsAMD() && IsWindows() && IsVulkan());
648 
649     // Disable D3D11 SDK Layers warnings checks, see ANGLE issue 667 for details
650     ignoreD3D11SDKLayersWarnings();
651 
652     static const GLushort indices[] = {0, 7, 6, 9, 8, 0};
653 
654     // Start at index 1.
655     runTest(GL_UNSIGNED_SHORT, reinterpret_cast<const void *>(indices), sizeof(indices), 1, true);
656 }
657 
658 ANGLE_INSTANTIATE_TEST_ES2(LineLoopTest);
659 ANGLE_INSTANTIATE_TEST_ES3_AND(LineLoopTestES3, WithDirectSPIRVGeneration(ES3_VULKAN()));
660 
661 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(LineLoopPrimitiveRestartTest);
662 ANGLE_INSTANTIATE_TEST_ES3_AND(
663     LineLoopPrimitiveRestartTest,
664     WithMetalForcedBufferGPUStorage(ES3_METAL()),
665     WithMetalMemoryBarrierAndCheapRenderPass(ES3_METAL(),
666                                              /* hasBarrier */ false,
667                                              /* cheapRenderPass */ false));
668 
669 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(LineLoopIndirectTest);
670 ANGLE_INSTANTIATE_TEST_ES31(LineLoopIndirectTest);
671