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