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 
runTest(GLenum indexType,GLuint indexBuffer,const void * indexPtr)67     void runTest(GLenum indexType, GLuint indexBuffer, const void *indexPtr)
68     {
69         glClear(GL_COLOR_BUFFER_BIT);
70 
71         static const GLfloat loopPositions[] = {0.0f,  0.0f, 0.0f, 0.0f, 0.0f, 0.0f,  0.0f,
72                                                 0.0f,  0.0f, 0.0f, 0.0f, 0.0f, -0.5f, -0.5f,
73                                                 -0.5f, 0.5f, 0.5f, 0.5f, 0.5f, -0.5f};
74 
75         static const GLfloat stripPositions[] = {-0.5f, -0.5f, -0.5f, 0.5f,
76                                                  0.5f,  0.5f,  0.5f,  -0.5f};
77         static const GLubyte stripIndices[]   = {1, 0, 3, 2, 1};
78 
79         glUseProgram(mProgram);
80         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
81         glEnableVertexAttribArray(mPositionLocation);
82         glVertexAttribPointer(mPositionLocation, 2, GL_FLOAT, GL_FALSE, 0, loopPositions);
83         glUniform4f(mColorLocation, 0.0f, 0.0f, 1.0f, 1.0f);
84         glDrawElements(GL_LINE_LOOP, 4, indexType, indexPtr);
85 
86         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
87         glVertexAttribPointer(mPositionLocation, 2, GL_FLOAT, GL_FALSE, 0, stripPositions);
88         glUniform4f(mColorLocation, 0, 1, 0, 1);
89         glDrawElements(GL_LINE_STRIP, 5, GL_UNSIGNED_BYTE, stripIndices);
90 
91         checkPixels();
92     }
93 
94     GLuint mProgram;
95     GLint mPositionLocation;
96     GLint mColorLocation;
97 };
98 
TEST_P(LineLoopTest,LineLoopUByteIndices)99 TEST_P(LineLoopTest, LineLoopUByteIndices)
100 {
101     // Disable D3D11 SDK Layers warnings checks, see ANGLE issue 667 for details
102     // On Win7, the D3D SDK Layers emits a false warning for these tests.
103     // This doesn't occur on Windows 10 (Version 1511) though.
104     ignoreD3D11SDKLayersWarnings();
105 
106     static const GLubyte indices[] = {0, 7, 6, 9, 8, 0};
107     runTest(GL_UNSIGNED_BYTE, 0, indices + 1);
108 }
109 
TEST_P(LineLoopTest,LineLoopUShortIndices)110 TEST_P(LineLoopTest, LineLoopUShortIndices)
111 {
112     // Disable D3D11 SDK Layers warnings checks, see ANGLE issue 667 for details
113     ignoreD3D11SDKLayersWarnings();
114 
115     static const GLushort indices[] = {0, 7, 6, 9, 8, 0};
116     runTest(GL_UNSIGNED_SHORT, 0, indices + 1);
117 }
118 
TEST_P(LineLoopTest,LineLoopUIntIndices)119 TEST_P(LineLoopTest, LineLoopUIntIndices)
120 {
121     if (!IsGLExtensionEnabled("GL_OES_element_index_uint"))
122     {
123         return;
124     }
125 
126     // Disable D3D11 SDK Layers warnings checks, see ANGLE issue 667 for details
127     ignoreD3D11SDKLayersWarnings();
128 
129     static const GLuint indices[] = {0, 7, 6, 9, 8, 0};
130     runTest(GL_UNSIGNED_INT, 0, indices + 1);
131 }
132 
TEST_P(LineLoopTest,LineLoopUByteIndexBuffer)133 TEST_P(LineLoopTest, LineLoopUByteIndexBuffer)
134 {
135     // Disable D3D11 SDK Layers warnings checks, see ANGLE issue 667 for details
136     ignoreD3D11SDKLayersWarnings();
137 
138     static const GLubyte indices[] = {0, 7, 6, 9, 8, 0};
139 
140     GLuint buf;
141     glGenBuffers(1, &buf);
142     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buf);
143     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
144 
145     runTest(GL_UNSIGNED_BYTE, buf, reinterpret_cast<const void *>(sizeof(GLubyte)));
146 
147     glDeleteBuffers(1, &buf);
148 }
149 
TEST_P(LineLoopTest,LineLoopUShortIndexBuffer)150 TEST_P(LineLoopTest, LineLoopUShortIndexBuffer)
151 {
152     // Disable D3D11 SDK Layers warnings checks, see ANGLE issue 667 for details
153     ignoreD3D11SDKLayersWarnings();
154 
155     static const GLushort indices[] = {0, 7, 6, 9, 8, 0};
156 
157     GLuint buf;
158     glGenBuffers(1, &buf);
159     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buf);
160     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
161 
162     runTest(GL_UNSIGNED_SHORT, buf, reinterpret_cast<const void *>(sizeof(GLushort)));
163 
164     glDeleteBuffers(1, &buf);
165 }
166 
TEST_P(LineLoopTest,LineLoopUIntIndexBuffer)167 TEST_P(LineLoopTest, LineLoopUIntIndexBuffer)
168 {
169     if (!IsGLExtensionEnabled("GL_OES_element_index_uint"))
170     {
171         return;
172     }
173 
174     // Disable D3D11 SDK Layers warnings checks, see ANGLE issue 667 for details
175     ignoreD3D11SDKLayersWarnings();
176 
177     static const GLuint indices[] = {0, 7, 6, 9, 8, 0};
178 
179     GLuint buf;
180     glGenBuffers(1, &buf);
181     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buf);
182     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
183 
184     runTest(GL_UNSIGNED_INT, buf, reinterpret_cast<const void *>(sizeof(GLuint)));
185 
186     glDeleteBuffers(1, &buf);
187 }
188 
189 // Tests an edge case with a very large line loop element count.
190 // Disabled because it is slow and triggers an internal error.
TEST_P(LineLoopTest,DISABLED_DrawArraysWithLargeCount)191 TEST_P(LineLoopTest, DISABLED_DrawArraysWithLargeCount)
192 {
193     constexpr char kVS[] = "void main() { gl_Position = vec4(0); }";
194     constexpr char kFS[] = "void main() { gl_FragColor = vec4(0, 1, 0, 1); }";
195 
196     ANGLE_GL_PROGRAM(program, kVS, kFS);
197     glUseProgram(program);
198     glDrawArrays(GL_LINE_LOOP, 0, 0x3FFFFFFE);
199     EXPECT_GL_ERROR(GL_OUT_OF_MEMORY);
200 
201     glDrawArrays(GL_LINE_LOOP, 0, 0x1FFFFFFE);
202     EXPECT_GL_NO_ERROR();
203 }
204 
205 class LineLoopPrimitiveRestartTest : public ANGLETest
206 {
207   protected:
LineLoopPrimitiveRestartTest()208     LineLoopPrimitiveRestartTest()
209     {
210         setWindowWidth(64);
211         setWindowHeight(64);
212         setConfigRedBits(8);
213         setConfigGreenBits(8);
214         setConfigBlueBits(8);
215         setConfigAlphaBits(8);
216     }
217 };
218 
TEST_P(LineLoopPrimitiveRestartTest,LineLoopWithPrimitiveRestart)219 TEST_P(LineLoopPrimitiveRestartTest, LineLoopWithPrimitiveRestart)
220 {
221     constexpr char kVS[] = R"(#version 300 es
222 in vec2 a_position;
223 // x,y = offset, z = scale
224 in vec3 a_transform;
225 
226 invariant gl_Position;
227 void main()
228 {
229     vec2 v_position = a_transform.z * a_position + a_transform.xy;
230     gl_Position = vec4(v_position, 0.0, 1.0);
231 })";
232 
233     constexpr char kFS[] = R"(#version 300 es
234 precision highp float;
235 layout (location=0) out vec4 fragColor;
236 void main()
237 {
238     fragColor = vec4(1.0, 0.0, 0.0, 1.0);
239 })";
240 
241     ANGLE_GL_PROGRAM(program, kVS, kFS);
242     glBindAttribLocation(program, 0, "a_position");
243     glBindAttribLocation(program, 1, "a_transform");
244     glLinkProgram(program);
245     glUseProgram(program);
246     ASSERT_GL_NO_ERROR();
247 
248     // clang-format off
249     constexpr GLfloat vertices[] = {
250         0.1, 0.1, -0.1, 0.1, -0.1, -0.1, 0.1, -0.1,
251         0.1, 0.1, -0.1, 0.1, -0.1, -0.1, 0.1, -0.1,
252         0.1, 0.1, -0.1, 0.1, -0.1, -0.1, 0.1, -0.1,
253         0.1, 0.1, -0.1, 0.1, -0.1, -0.1, 0.1, -0.1,
254     };
255 
256     constexpr GLfloat transform[] = {
257         // first loop transform
258         0, 0, 9,
259         0, 0, 9,
260         0, 0, 9,
261         0, 0, 9,
262         // second loop transform
263         0.2, 0.1, 2,
264         0.2, 0.1, 2,
265         0.2, 0.1, 2,
266         0.2, 0.1, 2,
267         // third loop transform
268         0.5, -0.2, 3,
269         0.5, -0.2, 3,
270         0.5, -0.2, 3,
271         0.5, -0.2, 3,
272         // forth loop transform
273         -0.8, -0.5, 1,
274         -0.8, -0.5, 1,
275         -0.8, -0.5, 1,
276         -0.8, -0.5, 1,
277     };
278 
279     constexpr GLushort lineloopAsStripIndices[] = {
280         // first strip
281         0, 1, 2, 3, 0,
282         // second strip
283         4, 5, 6, 7, 4,
284         // third strip
285         8, 9, 10, 11, 8,
286         // forth strip
287         12, 13, 14, 15, 12 };
288 
289     constexpr GLushort lineloopWithRestartIndices[] = {
290         // first loop
291         0, 1, 2, 3, 0xffff,
292         // second loop
293         4, 5, 6, 7, 0xffff,
294         // third loop
295         8, 9, 10, 11, 0xffff,
296         // forth loop
297         12, 13, 14, 15,
298     };
299     // clang-format on
300 
301     std::vector<GLColor> expectedPixels(getWindowWidth() * getWindowHeight());
302     std::vector<GLColor> renderedPixels(getWindowWidth() * getWindowHeight());
303 
304     // Draw in non-primitive restart way
305     glClear(GL_COLOR_BUFFER_BIT);
306 
307     glEnableVertexAttribArray(0);
308     glEnableVertexAttribArray(1);
309 
310     glBindBuffer(GL_ARRAY_BUFFER, 0);
311     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
312 
313     for (int loop = 0; loop < 4; ++loop)
314     {
315         glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, vertices + 8 * loop);
316         glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, transform + 12 * loop);
317 
318         glDrawElements(GL_LINE_STRIP, 5, GL_UNSIGNED_SHORT, lineloopAsStripIndices);
319     }
320 
321     glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
322                  expectedPixels.data());
323     ASSERT_GL_NO_ERROR();
324 
325     // Draw line loop with primitive restart:
326     glClear(GL_COLOR_BUFFER_BIT);
327 
328     GLBuffer vertexBuffer[2];
329     GLBuffer indexBuffer;
330 
331     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
332     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(lineloopWithRestartIndices),
333                  lineloopWithRestartIndices, GL_STATIC_DRAW);
334 
335     glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[0]);
336     glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
337     glEnableVertexAttribArray(0);
338     glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
339 
340     glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer[1]);
341     glBufferData(GL_ARRAY_BUFFER, sizeof(transform), transform, GL_STATIC_DRAW);
342     glEnableVertexAttribArray(1);
343     glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
344 
345     glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
346 
347     glClear(GL_COLOR_BUFFER_BIT);
348     glDrawElements(GL_LINE_LOOP, ArraySize(lineloopWithRestartIndices), GL_UNSIGNED_SHORT, 0);
349 
350     glReadPixels(0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA, GL_UNSIGNED_BYTE,
351                  renderedPixels.data());
352 
353     for (int y = 0; y < getWindowHeight(); ++y)
354     {
355         for (int x = 0; x < getWindowWidth(); ++x)
356         {
357             int idx = y * getWindowWidth() + x;
358             EXPECT_EQ(expectedPixels[idx], renderedPixels[idx])
359                 << "Expected pixel at " << x << ", " << y << " to be " << expectedPixels[idx]
360                 << std::endl;
361         }
362     }
363 }
364 
365 class LineLoopIndirectTest : public LineLoopTest
366 {
367   protected:
runTest(GLenum indexType,const void * indices,GLuint indicesSize,GLuint firstIndex)368     void runTest(GLenum indexType, const void *indices, GLuint indicesSize, GLuint firstIndex)
369     {
370         struct DrawCommand
371         {
372             GLuint count;
373             GLuint primCount;
374             GLuint firstIndex;
375             GLint baseVertex;
376             GLuint reservedMustBeZero;
377         };
378 
379         glClear(GL_COLOR_BUFFER_BIT);
380 
381         static const GLfloat loopPositions[] = {0.0f,  0.0f, 0.0f, 0.0f, 0.0f, 0.0f,  0.0f,
382                                                 0.0f,  0.0f, 0.0f, 0.0f, 0.0f, -0.5f, -0.5f,
383                                                 -0.5f, 0.5f, 0.5f, 0.5f, 0.5f, -0.5f};
384 
385         static const GLfloat stripPositions[] = {-0.5f, -0.5f, -0.5f, 0.5f,
386                                                  0.5f,  0.5f,  0.5f,  -0.5f};
387         static const GLubyte stripIndices[]   = {1, 0, 3, 2, 1};
388 
389         glUseProgram(mProgram);
390 
391         GLuint vertexArray = 0;
392         glGenVertexArrays(1, &vertexArray);
393         glBindVertexArray(vertexArray);
394 
395         ASSERT_GL_NO_ERROR();
396 
397         GLuint vertBuffer = 0;
398         glGenBuffers(1, &vertBuffer);
399         glBindBuffer(GL_ARRAY_BUFFER, vertBuffer);
400         glBufferData(GL_ARRAY_BUFFER, sizeof(loopPositions), loopPositions, GL_STATIC_DRAW);
401         glEnableVertexAttribArray(mPositionLocation);
402         glVertexAttribPointer(mPositionLocation, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
403         glUniform4f(mColorLocation, 0.0f, 0.0f, 1.0f, 1.0f);
404 
405         ASSERT_GL_NO_ERROR();
406 
407         GLuint buf;
408         glGenBuffers(1, &buf);
409         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buf);
410         glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicesSize, indices, GL_STATIC_DRAW);
411 
412         DrawCommand cmdBuffer = {};
413         cmdBuffer.count       = 4;
414         cmdBuffer.firstIndex  = firstIndex;
415         cmdBuffer.primCount   = 1;
416         GLuint indirectBuf    = 0;
417         glGenBuffers(1, &indirectBuf);
418         glBindBuffer(GL_DRAW_INDIRECT_BUFFER, indirectBuf);
419         glBufferData(GL_DRAW_INDIRECT_BUFFER, sizeof(DrawCommand), &cmdBuffer, GL_STATIC_DRAW);
420 
421         ASSERT_GL_NO_ERROR();
422 
423         glDrawElementsIndirect(GL_LINE_LOOP, indexType, nullptr);
424         ASSERT_GL_NO_ERROR();
425 
426         glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0);
427         glDeleteBuffers(1, &indirectBuf);
428 
429         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
430         glDeleteBuffers(1, &buf);
431 
432         glBindVertexArray(0);
433         glDeleteVertexArrays(1, &vertexArray);
434 
435         glBindBuffer(GL_ARRAY_BUFFER, 0);
436         glDeleteBuffers(1, &vertBuffer);
437 
438         glEnableVertexAttribArray(mPositionLocation);
439         glVertexAttribPointer(mPositionLocation, 2, GL_FLOAT, GL_FALSE, 0, stripPositions);
440         glUniform4f(mColorLocation, 0, 1, 0, 1);
441         glDrawElements(GL_LINE_STRIP, 5, GL_UNSIGNED_BYTE, stripIndices);
442 
443         checkPixels();
444     }
445 };
446 
TEST_P(LineLoopIndirectTest,UByteIndexIndirectBuffer)447 TEST_P(LineLoopIndirectTest, UByteIndexIndirectBuffer)
448 {
449     // Old drivers buggy with optimized ConvertIndexIndirectLineLoop shader.
450     // http://anglebug.com/4720
451     ANGLE_SKIP_TEST_IF(IsAMD() && IsWindows() && IsVulkan());
452 
453     // Disable D3D11 SDK Layers warnings checks, see ANGLE issue 667 for details
454     ignoreD3D11SDKLayersWarnings();
455 
456     static const GLubyte indices[] = {0, 7, 6, 9, 8, 0};
457 
458     // Start at index 1.
459     runTest(GL_UNSIGNED_BYTE, reinterpret_cast<const void *>(indices), sizeof(indices), 1);
460 }
461 
TEST_P(LineLoopIndirectTest,UShortIndexIndirectBuffer)462 TEST_P(LineLoopIndirectTest, UShortIndexIndirectBuffer)
463 {
464     // Old drivers buggy with optimized ConvertIndexIndirectLineLoop shader.
465     // http://anglebug.com/4720
466     ANGLE_SKIP_TEST_IF(IsAMD() && IsWindows() && IsVulkan());
467 
468     // Disable D3D11 SDK Layers warnings checks, see ANGLE issue 667 for details
469     ignoreD3D11SDKLayersWarnings();
470 
471     static const GLushort indices[] = {0, 7, 6, 9, 8, 0};
472 
473     // Start at index 1.
474     runTest(GL_UNSIGNED_SHORT, reinterpret_cast<const void *>(indices), sizeof(indices), 1);
475 }
476 
477 // Use this to select which configurations (e.g. which renderer, which GLES major version) these
478 // tests should be run against.
479 ANGLE_INSTANTIATE_TEST_ES2(LineLoopTest);
480 
481 ANGLE_INSTANTIATE_TEST_ES3_AND(
482     LineLoopPrimitiveRestartTest,
483     WithMetalForcedBufferGPUStorage(ES3_METAL()),
484     WithMetalMemoryBarrierAndCheapRenderPass(ES3_METAL(),
485                                              /* hasBarrier */ false,
486                                              /* cheapRenderPass */ false));
487 
488 ANGLE_INSTANTIATE_TEST_ES31(LineLoopIndirectTest);
489