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