1 //
2 // Copyright 2018 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 // MultiDrawTest: Tests of GL_ANGLE_multi_draw
8 // MultiDrawIndirectTest: Tests of GL_EXT_multi_draw_indirect
9
10 #include "test_utils/ANGLETest.h"
11 #include "test_utils/gl_raii.h"
12
13 using namespace angle;
14
15 namespace
16 {
17
18 // Create a kWidth * kHeight canvas equally split into kCountX * kCountY tiles
19 // each containing a quad partially covering each tile
20 constexpr uint32_t kWidth = 256;
21 constexpr uint32_t kHeight = 256;
22 constexpr uint32_t kCountX = 8;
23 constexpr uint32_t kCountY = 8;
24 constexpr uint32_t kQuadCount = kCountX * kCountY;
25 constexpr uint32_t kTriCount = kQuadCount * 2;
26 constexpr std::array<GLfloat, 2> kTileSize = {
27 1.f / static_cast<GLfloat>(kCountX),
28 1.f / static_cast<GLfloat>(kCountY),
29 };
30 constexpr std::array<uint32_t, 2> kTilePixelSize = {kWidth / kCountX, kHeight / kCountY};
31 constexpr std::array<GLfloat, 2> kQuadRadius = {0.25f * kTileSize[0], 0.25f * kTileSize[1]};
32 constexpr std::array<uint32_t, 2> kPixelCheckSize = {
33 static_cast<uint32_t>(kQuadRadius[0] * kWidth),
34 static_cast<uint32_t>(kQuadRadius[1] * kHeight)};
35
getTileCenter(uint32_t x,uint32_t y)36 constexpr std::array<GLfloat, 2> getTileCenter(uint32_t x, uint32_t y)
37 {
38 return {
39 kTileSize[0] * (0.5f + static_cast<GLfloat>(x)),
40 kTileSize[1] * (0.5f + static_cast<GLfloat>(y)),
41 };
42 }
getQuadVertices(uint32_t x,uint32_t y)43 constexpr std::array<std::array<GLfloat, 3>, 4> getQuadVertices(uint32_t x, uint32_t y)
44 {
45 const auto center = getTileCenter(x, y);
46 return {
47 std::array<GLfloat, 3>{center[0] - kQuadRadius[0], center[1] - kQuadRadius[1], 0.0f},
48 std::array<GLfloat, 3>{center[0] + kQuadRadius[0], center[1] - kQuadRadius[1], 0.0f},
49 std::array<GLfloat, 3>{center[0] + kQuadRadius[0], center[1] + kQuadRadius[1], 0.0f},
50 std::array<GLfloat, 3>{center[0] - kQuadRadius[0], center[1] + kQuadRadius[1], 0.0f},
51 };
52 }
53
54 enum class DrawIDOption
55 {
56 NoDrawID,
57 UseDrawID,
58 };
59
60 enum class InstancingOption
61 {
62 NoInstancing,
63 UseInstancing,
64 };
65
66 enum class BufferDataUsageOption
67 {
68 StaticDraw,
69 DynamicDraw
70 };
71
72 using MultiDrawTestParams =
73 std::tuple<angle::PlatformParameters, DrawIDOption, InstancingOption, BufferDataUsageOption>;
74
75 using MultiDrawIndirectTestParams = angle::PlatformParameters;
76
77 struct PrintToStringParamName
78 {
operator ()__anon0e40ab140111::PrintToStringParamName79 std::string operator()(const ::testing::TestParamInfo<MultiDrawTestParams> &info) const
80 {
81 ::std::stringstream ss;
82 ss << std::get<0>(info.param)
83 << (std::get<3>(info.param) == BufferDataUsageOption::StaticDraw ? "__StaticDraw"
84 : "__DynamicDraw")
85 << (std::get<2>(info.param) == InstancingOption::UseInstancing ? "__Instanced" : "")
86 << (std::get<1>(info.param) == DrawIDOption::UseDrawID ? "__DrawID" : "");
87 return ss.str();
88 }
89 };
90
91 struct DrawArraysIndirectCommand
92 {
DrawArraysIndirectCommand__anon0e40ab140111::DrawArraysIndirectCommand93 DrawArraysIndirectCommand() : count(0u), instanceCount(0u), first(0u), baseInstance(0u) {}
DrawArraysIndirectCommand__anon0e40ab140111::DrawArraysIndirectCommand94 DrawArraysIndirectCommand(GLuint count, GLuint instanceCount, GLuint first, GLuint baseInstance)
95 : count(count), instanceCount(instanceCount), first(first), baseInstance(baseInstance)
96 {}
97 GLuint count;
98 GLuint instanceCount;
99 GLuint first;
100 GLuint baseInstance;
101 };
102
103 struct DrawElementsIndirectCommand
104 {
DrawElementsIndirectCommand__anon0e40ab140111::DrawElementsIndirectCommand105 DrawElementsIndirectCommand()
106 : count(0), primCount(0), firstIndex(0), baseVertex(0), baseInstance(0)
107 {}
DrawElementsIndirectCommand__anon0e40ab140111::DrawElementsIndirectCommand108 DrawElementsIndirectCommand(GLuint count,
109 GLuint primCount,
110 GLuint firstIndex,
111 GLint baseVertex,
112 GLuint baseInstance)
113 : count(count),
114 primCount(primCount),
115 firstIndex(firstIndex),
116 baseVertex(baseVertex),
117 baseInstance(baseInstance)
118 {}
119 GLuint count;
120 GLuint primCount;
121 GLuint firstIndex;
122 GLint baseVertex;
123 GLuint baseInstance;
124 };
125
126 // The tests in MultiDrawTest and MultiDrawNoInstancingSupportTest check the correctness
127 // of the ANGLE_multi_draw extension.
128 // An array of quads is drawn across the screen.
129 // gl_DrawID is checked by using it to select the color of the draw.
130 // MultiDraw*Instanced entrypoints use the existing instancing APIs which are
131 // more fully tested in InstancingTest.cpp.
132 // Correct interaction with the instancing APIs is tested here by using scaling
133 // and then instancing the array of quads over four quadrants on the screen.
134 class MultiDrawTest : public ANGLETestBase, public ::testing::TestWithParam<MultiDrawTestParams>
135 {
136 protected:
MultiDrawTest()137 MultiDrawTest()
138 : ANGLETestBase(std::get<0>(GetParam())),
139 mNonIndexedVertexBuffer(0u),
140 mVertexBuffer(0u),
141 mIndexBuffer(0u),
142 mInstanceBuffer(0u),
143 mProgram(0u),
144 mPositionLoc(0u),
145 mInstanceLoc(0u)
146 {
147 setWindowWidth(kWidth);
148 setWindowHeight(kHeight);
149 setConfigRedBits(8);
150 setConfigGreenBits(8);
151 setConfigBlueBits(8);
152 setConfigAlphaBits(8);
153 }
154
SetUp()155 void SetUp() override { ANGLETestBase::ANGLETestSetUp(); }
156
IsDrawIDTest() const157 bool IsDrawIDTest() const { return std::get<1>(GetParam()) == DrawIDOption::UseDrawID; }
158
IsInstancedTest() const159 bool IsInstancedTest() const
160 {
161 return std::get<2>(GetParam()) == InstancingOption::UseInstancing;
162 }
163
getBufferDataUsage() const164 GLenum getBufferDataUsage() const
165 {
166 return std::get<3>(GetParam()) == BufferDataUsageOption::StaticDraw ? GL_STATIC_DRAW
167 : GL_DYNAMIC_DRAW;
168 }
169
VertexShaderSource()170 std::string VertexShaderSource()
171 {
172
173 std::stringstream shader;
174 shader << (IsDrawIDTest() ? "#extension GL_ANGLE_multi_draw : require\n" : "")
175 << (IsInstancedTest() ? "attribute float vInstance;" : "") << R"(
176 attribute vec2 vPosition;
177 varying vec4 color;
178 void main()
179 {
180 int id = )" << (IsDrawIDTest() ? "gl_DrawID" : "0")
181 << ";" << R"(
182 float quad_id = float(id / 2);
183 float color_id = quad_id - (3.0 * floor(quad_id / 3.0));
184 if (color_id == 0.0) {
185 color = vec4(1, 0, 0, 1);
186 } else if (color_id == 1.0) {
187 color = vec4(0, 1, 0, 1);
188 } else {
189 color = vec4(0, 0, 1, 1);
190 }
191
192 mat3 transform = mat3(1.0);
193 )"
194 << (IsInstancedTest() ? R"(
195 transform[0][0] = 0.5;
196 transform[1][1] = 0.5;
197 if (vInstance == 0.0) {
198
199 } else if (vInstance == 1.0) {
200 transform[2][0] = 0.5;
201 } else if (vInstance == 2.0) {
202 transform[2][1] = 0.5;
203 } else if (vInstance == 3.0) {
204 transform[2][0] = 0.5;
205 transform[2][1] = 0.5;
206 }
207 )"
208 : "")
209 << R"(
210 gl_Position = vec4(transform * vec3(vPosition, 1.0) * 2.0 - 1.0, 1);
211 })";
212
213 return shader.str();
214 }
215
FragmentShaderSource()216 std::string FragmentShaderSource()
217 {
218 return
219 R"(precision mediump float;
220 varying vec4 color;
221 void main()
222 {
223 gl_FragColor = color;
224 })";
225 }
226
SetupProgram()227 void SetupProgram()
228 {
229 mProgram = CompileProgram(VertexShaderSource().c_str(), FragmentShaderSource().c_str());
230 EXPECT_GL_NO_ERROR();
231 ASSERT_GE(mProgram, 1u);
232 glUseProgram(mProgram);
233 mPositionLoc = glGetAttribLocation(mProgram, "vPosition");
234 mInstanceLoc = glGetAttribLocation(mProgram, "vInstance");
235 }
236
SetupBuffers()237 void SetupBuffers()
238 {
239 for (uint32_t y = 0; y < kCountY; ++y)
240 {
241 for (uint32_t x = 0; x < kCountX; ++x)
242 {
243 // v3 ---- v2
244 // | |
245 // | |
246 // v0 ---- v1
247 uint32_t quadIndex = y * kCountX + x;
248 GLushort starting_index = static_cast<GLushort>(4 * quadIndex);
249 std::array<GLushort, 6> is = {0, 1, 2, 0, 2, 3};
250 const auto vs = getQuadVertices(x, y);
251 for (GLushort i : is)
252 {
253 mIndices.push_back(starting_index + i);
254 }
255
256 for (const auto &v : vs)
257 {
258 mVertices.insert(mVertices.end(), v.begin(), v.end());
259 }
260
261 for (GLushort i : is)
262 {
263 mNonIndexedVertices.insert(mNonIndexedVertices.end(), vs[i].begin(),
264 vs[i].end());
265 }
266 }
267 }
268
269 std::array<GLfloat, 4> instances{0, 1, 2, 3};
270
271 glGenBuffers(1, &mNonIndexedVertexBuffer);
272 glBindBuffer(GL_ARRAY_BUFFER, mNonIndexedVertexBuffer);
273 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * mNonIndexedVertices.size(),
274 mNonIndexedVertices.data(), getBufferDataUsage());
275
276 glGenBuffers(1, &mVertexBuffer);
277 glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
278 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * mVertices.size(), mVertices.data(),
279 getBufferDataUsage());
280
281 glGenBuffers(1, &mIndexBuffer);
282 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
283 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort) * mIndices.size(), mIndices.data(),
284 getBufferDataUsage());
285
286 glGenBuffers(1, &mInstanceBuffer);
287 glBindBuffer(GL_ARRAY_BUFFER, mInstanceBuffer);
288 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * instances.size(), instances.data(),
289 getBufferDataUsage());
290
291 ASSERT_GL_NO_ERROR();
292 }
293
DoVertexAttribDivisor(GLint location,GLuint divisor)294 void DoVertexAttribDivisor(GLint location, GLuint divisor)
295 {
296 if (getClientMajorVersion() <= 2)
297 {
298 ASSERT_TRUE(IsGLExtensionEnabled("GL_ANGLE_instanced_arrays"));
299 glVertexAttribDivisorANGLE(location, divisor);
300 }
301 else
302 {
303 glVertexAttribDivisor(location, divisor);
304 }
305 }
306
DoDrawArrays()307 void DoDrawArrays()
308 {
309 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
310 glBindBuffer(GL_ARRAY_BUFFER, mNonIndexedVertexBuffer);
311 glEnableVertexAttribArray(mPositionLoc);
312 glVertexAttribPointer(mPositionLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
313
314 std::vector<GLint> firsts(kTriCount);
315 std::vector<GLsizei> counts(kTriCount, 3);
316 for (uint32_t i = 0; i < kTriCount; ++i)
317 {
318 firsts[i] = i * 3;
319 }
320
321 if (IsInstancedTest())
322 {
323 glBindBuffer(GL_ARRAY_BUFFER, mInstanceBuffer);
324 glEnableVertexAttribArray(mInstanceLoc);
325 glVertexAttribPointer(mInstanceLoc, 1, GL_FLOAT, GL_FALSE, 0, nullptr);
326 DoVertexAttribDivisor(mInstanceLoc, 1);
327 std::vector<GLsizei> instanceCounts(kTriCount, 4);
328 glMultiDrawArraysInstancedANGLE(GL_TRIANGLES, firsts.data(), counts.data(),
329 instanceCounts.data(), kTriCount);
330 }
331 else
332 {
333 glMultiDrawArraysANGLE(GL_TRIANGLES, firsts.data(), counts.data(), kTriCount);
334 }
335 }
336
DoDrawElements()337 void DoDrawElements()
338 {
339 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
340 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
341 glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
342 glEnableVertexAttribArray(mPositionLoc);
343 glVertexAttribPointer(mPositionLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
344
345 std::vector<GLsizei> counts(kTriCount, 3);
346 std::vector<const GLvoid *> indices(kTriCount);
347 for (uint32_t i = 0; i < kTriCount; ++i)
348 {
349 indices[i] = reinterpret_cast<GLvoid *>(static_cast<uintptr_t>(i * 3 * 2));
350 }
351
352 if (IsInstancedTest())
353 {
354 glBindBuffer(GL_ARRAY_BUFFER, mInstanceBuffer);
355 glEnableVertexAttribArray(mInstanceLoc);
356 glVertexAttribPointer(mInstanceLoc, 1, GL_FLOAT, GL_FALSE, 0, nullptr);
357 DoVertexAttribDivisor(mInstanceLoc, 1);
358 std::vector<GLsizei> instanceCounts(kTriCount, 4);
359 glMultiDrawElementsInstancedANGLE(GL_TRIANGLES, counts.data(), GL_UNSIGNED_SHORT,
360 indices.data(), instanceCounts.data(), kTriCount);
361 }
362 else
363 {
364 glMultiDrawElementsANGLE(GL_TRIANGLES, counts.data(), GL_UNSIGNED_SHORT, indices.data(),
365 kTriCount);
366 }
367 }
368
369 enum class DrawIDOptionOverride
370 {
371 Default,
372 NoDrawID,
373 UseDrawID,
374 };
375
CheckDrawResult(DrawIDOptionOverride overrideDrawID)376 void CheckDrawResult(DrawIDOptionOverride overrideDrawID)
377 {
378 for (uint32_t y = 0; y < kCountY; ++y)
379 {
380 for (uint32_t x = 0; x < kCountX; ++x)
381 {
382 uint32_t center_x = x * kTilePixelSize[0] + kTilePixelSize[0] / 2;
383 uint32_t center_y = y * kTilePixelSize[1] + kTilePixelSize[1] / 2;
384 uint32_t quadID = IsDrawIDTest() && overrideDrawID != DrawIDOptionOverride::NoDrawID
385 ? y * kCountX + x
386 : 0;
387 uint32_t colorID = quadID % 3u;
388 std::array<GLColor, 3> colors = {GLColor(255, 0, 0, 255), GLColor(0, 255, 0, 255),
389 GLColor(0, 0, 255, 255)};
390 GLColor expected = colors[colorID];
391
392 if (IsInstancedTest())
393 {
394 EXPECT_PIXEL_RECT_EQ(center_x / 2 - kPixelCheckSize[0] / 4,
395 center_y / 2 - kPixelCheckSize[1] / 4,
396 kPixelCheckSize[0] / 2, kPixelCheckSize[1] / 2, expected);
397 EXPECT_PIXEL_RECT_EQ(center_x / 2 - kPixelCheckSize[0] / 4 + kWidth / 2,
398 center_y / 2 - kPixelCheckSize[1] / 4,
399 kPixelCheckSize[0] / 2, kPixelCheckSize[1] / 2, expected);
400 EXPECT_PIXEL_RECT_EQ(center_x / 2 - kPixelCheckSize[0] / 4,
401 center_y / 2 - kPixelCheckSize[1] / 4 + kHeight / 2,
402 kPixelCheckSize[0] / 2, kPixelCheckSize[1] / 2, expected);
403 EXPECT_PIXEL_RECT_EQ(center_x / 2 - kPixelCheckSize[0] / 4 + kWidth / 2,
404 center_y / 2 - kPixelCheckSize[1] / 4 + kHeight / 2,
405 kPixelCheckSize[0] / 2, kPixelCheckSize[1] / 2, expected);
406 }
407 else
408 {
409 EXPECT_PIXEL_RECT_EQ(center_x - kPixelCheckSize[0] / 2,
410 center_y - kPixelCheckSize[1] / 2, kPixelCheckSize[0],
411 kPixelCheckSize[1], expected);
412 }
413 }
414 }
415 }
416
TearDown()417 void TearDown() override
418 {
419 if (mNonIndexedVertexBuffer != 0u)
420 {
421 glDeleteBuffers(1, &mNonIndexedVertexBuffer);
422 }
423 if (mVertexBuffer != 0u)
424 {
425 glDeleteBuffers(1, &mVertexBuffer);
426 }
427 if (mIndexBuffer != 0u)
428 {
429 glDeleteBuffers(1, &mIndexBuffer);
430 }
431 if (mInstanceBuffer != 0u)
432 {
433 glDeleteBuffers(1, &mInstanceBuffer);
434 }
435 if (mProgram != 0)
436 {
437 glDeleteProgram(mProgram);
438 }
439 ANGLETestBase::ANGLETestTearDown();
440 }
441
requestMultiDrawExtension()442 bool requestMultiDrawExtension() { return EnsureGLExtensionEnabled("GL_ANGLE_multi_draw"); }
443
requestInstancedExtension()444 bool requestInstancedExtension()
445 {
446 return EnsureGLExtensionEnabled("GL_ANGLE_instanced_arrays");
447 }
448
requestExtensions()449 bool requestExtensions()
450 {
451 if (IsInstancedTest() && getClientMajorVersion() <= 2)
452 {
453 if (!requestInstancedExtension())
454 {
455 return false;
456 }
457 }
458 return requestMultiDrawExtension();
459 }
460
461 std::vector<GLushort> mIndices;
462 std::vector<GLfloat> mVertices;
463 std::vector<GLfloat> mNonIndexedVertices;
464 GLuint mNonIndexedVertexBuffer;
465 GLuint mVertexBuffer;
466 GLuint mIndexBuffer;
467 GLuint mInstanceBuffer;
468 GLuint mProgram;
469 GLint mPositionLoc;
470 GLint mInstanceLoc;
471 };
472
473 class MultiDrawTestES3 : public MultiDrawTest
474 {};
475
476 class MultiDrawNoInstancingSupportTest : public MultiDrawTest
477 {
SetUp()478 void SetUp() override
479 {
480 ASSERT_LE(getClientMajorVersion(), 2);
481 ASSERT_TRUE(IsInstancedTest());
482 MultiDrawTest::SetUp();
483 }
484 };
485
486 // The tests in MultiDrawIndirectTest check the correctness
487 // of the EXT_multi_draw_indirect extension.
488 // 4 magenta triangles are drawn at the corners of the screen
489 // in different orders from the same vertex and index arrays.
490 class MultiDrawIndirectTest : public ANGLETestBase,
491 public ::testing::TestWithParam<MultiDrawIndirectTestParams>
492 {
493 protected:
MultiDrawIndirectTest()494 MultiDrawIndirectTest()
495 : ANGLETestBase(GetParam()),
496 mPositionLoc(0u),
497 mColorLoc(0u),
498 mVertexBuffer(0u),
499 mColorBuffer(0u),
500 mIndexBuffer(0u),
501 mIndirectBuffer(0u),
502 mProgram(0u)
503 {
504 setWindowWidth(kWidth);
505 setWindowHeight(kHeight);
506 setConfigRedBits(8);
507 setConfigGreenBits(8);
508 setConfigBlueBits(8);
509 setConfigAlphaBits(8);
510 }
511
SetUp()512 void SetUp() override { ANGLETestBase::ANGLETestSetUp(); }
513
SetupProgramIndirect(bool isMultiColor)514 void SetupProgramIndirect(bool isMultiColor)
515 {
516 // Define the vertex and fragment shaders
517 std::stringstream kVS;
518 kVS << R"(#version 310 es
519 in vec3 aPos;
520 )"
521 << (isMultiColor ? R"(in vec4 aColor;
522 out vec4 vColor;)"
523 : "")
524 << R"(
525 void main()
526 {
527 gl_Position = vec4(aPos.x, aPos.y, 0, 1);
528 )" << (isMultiColor ? R"(vColor = vec4(aColor.x, aColor.y, aColor.z, 1.0);)" : "")
529 << R"(
530 })";
531
532 std::stringstream kFS;
533 kFS << R"(#version 310 es
534 precision mediump float;
535 )"
536 << (isMultiColor ? R"(in vec4 vColor;
537 )"
538 : "")
539 << R"(
540 out vec4 colorOut;
541 void main()
542 {
543 )" << (isMultiColor ? R"(colorOut = vColor;)" : R"(colorOut = vec4(1.0, 0.0, 1.0, 1.0);)")
544 << R"(
545 })";
546 mProgram = CompileProgram(kVS.str().c_str(), kFS.str().c_str());
547 EXPECT_GL_NO_ERROR();
548 ASSERT_GE(mProgram, 1u);
549 glUseProgram(mProgram);
550 mPositionLoc = glGetAttribLocation(mProgram, "aPos");
551 mColorLoc = glGetAttribLocation(mProgram, "aColor");
552 }
553
TearDown()554 void TearDown() override
555 {
556 if (mVertexBuffer != 0u)
557 {
558 glDeleteBuffers(1, &mVertexBuffer);
559 }
560 if (mColorBuffer != 0u)
561 {
562 glDeleteBuffers(1, &mColorBuffer);
563 }
564 if (mIndexBuffer != 0u)
565 {
566 glDeleteBuffers(1, &mIndexBuffer);
567 }
568 if (mProgram != 0)
569 {
570 glDeleteProgram(mProgram);
571 }
572 if (mIndirectBuffer != 0u)
573 {
574 glDeleteBuffers(1, &mIndirectBuffer);
575 }
576 ANGLETestBase::ANGLETestTearDown();
577 }
578
579 GLint mPositionLoc;
580 GLint mColorLoc;
581 GLuint mVertexBuffer;
582 GLuint mColorBuffer;
583 GLuint mIndexBuffer;
584 GLuint mIndirectBuffer;
585 GLuint mProgram;
586 };
587
588 // Test that compile a program with the extension succeeds
TEST_P(MultiDrawTest,CanCompile)589 TEST_P(MultiDrawTest, CanCompile)
590 {
591 ANGLE_SKIP_TEST_IF(!requestExtensions());
592 SetupProgram();
593 }
594
595 // Tests basic functionality of glMultiDrawArraysANGLE
TEST_P(MultiDrawTest,MultiDrawArrays)596 TEST_P(MultiDrawTest, MultiDrawArrays)
597 {
598 ANGLE_SKIP_TEST_IF(!requestExtensions());
599
600 // http://anglebug.com/40644769
601 ANGLE_SKIP_TEST_IF(IsInstancedTest() && IsMac() && IsIntelUHD630Mobile() && IsDesktopOpenGL());
602
603 SetupBuffers();
604 SetupProgram();
605 DoDrawArrays();
606 EXPECT_GL_NO_ERROR();
607 CheckDrawResult(DrawIDOptionOverride::Default);
608 }
609
610 // Tests basic functionality of glMultiDrawArraysANGLE after a failed program relink
TEST_P(MultiDrawTestES3,MultiDrawArraysAfterFailedRelink)611 TEST_P(MultiDrawTestES3, MultiDrawArraysAfterFailedRelink)
612 {
613 ANGLE_SKIP_TEST_IF(!requestExtensions());
614
615 // http://anglebug.com/40644769
616 ANGLE_SKIP_TEST_IF(IsInstancedTest() && IsMac() && IsIntelUHD630Mobile() && IsDesktopOpenGL());
617
618 SetupBuffers();
619 SetupProgram();
620
621 // mProgram is already installed. Destroy its state by a failed relink.
622 const char *tfVaryings = "invalidvaryingname";
623 glTransformFeedbackVaryings(mProgram, 1, &tfVaryings, GL_SEPARATE_ATTRIBS);
624 glLinkProgram(mProgram);
625 GLint linkStatus = 0;
626 glGetProgramiv(mProgram, GL_LINK_STATUS, &linkStatus);
627 ASSERT_GL_NO_ERROR();
628 ASSERT_EQ(linkStatus, GL_FALSE);
629
630 DoDrawArrays();
631 EXPECT_GL_NO_ERROR();
632 CheckDrawResult(DrawIDOptionOverride::Default);
633 }
634
635 // Tests basic functionality of glMultiDrawElementsANGLE
TEST_P(MultiDrawTest,MultiDrawElements)636 TEST_P(MultiDrawTest, MultiDrawElements)
637 {
638 ANGLE_SKIP_TEST_IF(!requestExtensions());
639 SetupBuffers();
640 SetupProgram();
641 DoDrawElements();
642 EXPECT_GL_NO_ERROR();
643 CheckDrawResult(DrawIDOptionOverride::Default);
644 }
645
646 // Tests that glMultiDrawArraysANGLE followed by glDrawArrays works. gl_DrawID in the second call
647 // must be 0.
TEST_P(MultiDrawTest,MultiDrawArraysThenDrawArrays)648 TEST_P(MultiDrawTest, MultiDrawArraysThenDrawArrays)
649 {
650 ANGLE_SKIP_TEST_IF(!requestExtensions());
651
652 // http://anglebug.com/40644769
653 ANGLE_SKIP_TEST_IF(IsInstancedTest() && IsMac() && IsIntelUHD630Mobile() && IsDesktopOpenGL());
654
655 SetupBuffers();
656 SetupProgram();
657 DoDrawArrays();
658 EXPECT_GL_NO_ERROR();
659 CheckDrawResult(DrawIDOptionOverride::Default);
660
661 if (IsInstancedTest())
662 {
663 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_instanced_arrays") &&
664 !IsGLExtensionEnabled("GL_ANGLE_instanced_arrays"));
665 if (IsGLExtensionEnabled("GL_EXT_instanced_arrays"))
666 {
667 glDrawArraysInstancedEXT(GL_TRIANGLES, 0, 3 * kTriCount, 4);
668 }
669 else
670 {
671 glDrawArraysInstancedANGLE(GL_TRIANGLES, 0, 3 * kTriCount, 4);
672 }
673 ASSERT_GL_NO_ERROR();
674 }
675 else
676 {
677 glDrawArrays(GL_TRIANGLES, 0, 3 * kTriCount);
678 ASSERT_GL_NO_ERROR();
679 }
680 CheckDrawResult(DrawIDOptionOverride::NoDrawID);
681 }
682
683 // Tests basic functionality of glMultiDrawArraysIndirectEXT
TEST_P(MultiDrawIndirectTest,MultiDrawArraysIndirect)684 TEST_P(MultiDrawIndirectTest, MultiDrawArraysIndirect)
685 {
686 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multi_draw_indirect"));
687
688 // Set up the vertex array
689 const GLint triangleCount = 4;
690 const std::vector<GLfloat> vertices = {
691 -1, 1, 0, -1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0,
692 -1, -1, 0, -1, 0, 0, 0, -1, 0, 1, -1, 0, 0, -1, 0, 1, 0, 0,
693 };
694
695 // Set up the vertex buffer
696 GLVertexArray vao;
697 glBindVertexArray(vao);
698
699 glGenBuffers(1, &mVertexBuffer);
700 glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
701 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * vertices.size(), vertices.data(),
702 GL_STATIC_DRAW);
703 EXPECT_GL_NO_ERROR();
704
705 // Generate program
706 SetupProgramIndirect(false);
707
708 // Set up the vertex array format
709 glEnableVertexAttribArray(mPositionLoc);
710 glVertexAttribPointer(mPositionLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
711 EXPECT_GL_NO_ERROR();
712
713 // Set up the indirect data array
714 std::array<DrawArraysIndirectCommand, triangleCount> indirectData;
715 const GLsizei icSize = sizeof(DrawArraysIndirectCommand);
716 for (auto i = 0; i < triangleCount; i++)
717 {
718 indirectData[i] = DrawArraysIndirectCommand(3, 1, 3 * i, i);
719 }
720
721 glGenBuffers(1, &mIndirectBuffer);
722 glBindBuffer(GL_DRAW_INDIRECT_BUFFER, mIndirectBuffer);
723 glBufferData(GL_DRAW_INDIRECT_BUFFER, icSize * indirectData.size(), indirectData.data(),
724 GL_STATIC_DRAW);
725 EXPECT_GL_NO_ERROR();
726
727 // Invalid value check for drawcount and stride
728 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
729 glMultiDrawArraysIndirectEXT(GL_TRIANGLES, nullptr, 0, 0);
730 EXPECT_GL_ERROR(GL_INVALID_VALUE);
731 glMultiDrawArraysIndirectEXT(GL_TRIANGLES, nullptr, -1, 0);
732 EXPECT_GL_ERROR(GL_INVALID_VALUE);
733 glMultiDrawArraysIndirectEXT(GL_TRIANGLES, nullptr, 1, 2);
734 EXPECT_GL_ERROR(GL_INVALID_VALUE);
735
736 // Check the error from sourcing beyond the allocated buffer size
737 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
738 glMultiDrawArraysIndirectEXT(
739 GL_TRIANGLES,
740 reinterpret_cast<const void *>(static_cast<uintptr_t>(icSize * triangleCount)), 1, 0);
741 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
742
743 // Draw all triangles using glMultiDrawArraysIndirect
744 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
745 glMultiDrawArraysIndirectEXT(GL_TRIANGLES, nullptr, triangleCount, 0);
746 EXPECT_GL_NO_ERROR();
747
748 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::magenta);
749 EXPECT_PIXEL_COLOR_EQ(0, kHeight - 1, GLColor::magenta);
750 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 0, GLColor::magenta);
751 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::magenta);
752 EXPECT_PIXEL_COLOR_EQ(kWidth / 2, kHeight / 2, GLColor::transparentBlack);
753
754 // Draw the triangles in different order
755 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
756 glMultiDrawArraysIndirectEXT(GL_TRIANGLES, nullptr, 1, 0);
757 glMultiDrawArraysIndirectEXT(GL_TRIANGLES,
758 reinterpret_cast<const void *>(static_cast<uintptr_t>(icSize * 2)),
759 triangleCount - 2, 0);
760 glMultiDrawArraysIndirectEXT(
761 GL_TRIANGLES, reinterpret_cast<const void *>(static_cast<uintptr_t>(icSize)), 1, 0);
762 EXPECT_GL_NO_ERROR();
763
764 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::magenta);
765 EXPECT_PIXEL_COLOR_EQ(0, kHeight - 1, GLColor::magenta);
766 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 0, GLColor::magenta);
767 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::magenta);
768 EXPECT_PIXEL_COLOR_EQ(kWidth / 2, kHeight / 2, GLColor::transparentBlack);
769
770 // Draw the triangles partially using stride
771 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
772 glMultiDrawArraysIndirectEXT(GL_TRIANGLES, nullptr, 2, icSize * 3);
773 EXPECT_GL_NO_ERROR();
774
775 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::transparentBlack);
776 EXPECT_PIXEL_COLOR_EQ(0, kHeight - 1, GLColor::magenta);
777 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 0, GLColor::magenta);
778 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::transparentBlack);
779 EXPECT_PIXEL_COLOR_EQ(kWidth / 2, kHeight / 2, GLColor::transparentBlack);
780 }
781
782 // Tests basic functionality of glMultiDrawElementsIndirectEXT
TEST_P(MultiDrawIndirectTest,MultiDrawElementsIndirect)783 TEST_P(MultiDrawIndirectTest, MultiDrawElementsIndirect)
784 {
785 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multi_draw_indirect"));
786
787 // Set up the vertex array
788 const GLint triangleCount = 4;
789 const std::vector<GLfloat> vertices = {
790 -1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, -1, 0, 0, -1, 0, -1, -1, 0, -1, 0, 0,
791 };
792 const std::vector<GLuint> indices = {
793 1, 2, 3, 3, 4, 5, 5, 6, 7, 7, 0, 1,
794 };
795
796 // Set up the vertex and index buffers
797 GLVertexArray vao;
798 glBindVertexArray(vao);
799
800 glGenBuffers(1, &mVertexBuffer);
801 glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
802 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * vertices.size(), vertices.data(),
803 GL_STATIC_DRAW);
804
805 glGenBuffers(1, &mIndexBuffer);
806 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
807 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * indices.size(), indices.data(),
808 GL_STATIC_DRAW);
809 EXPECT_GL_NO_ERROR();
810
811 // Generate program
812 SetupProgramIndirect(false);
813
814 // Set up the vertex array format
815 glEnableVertexAttribArray(mPositionLoc);
816 glVertexAttribPointer(mPositionLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
817 EXPECT_GL_NO_ERROR();
818
819 // Set up the indirect data array
820 std::array<DrawElementsIndirectCommand, triangleCount> indirectData;
821 const GLsizei icSize = sizeof(DrawElementsIndirectCommand);
822 for (auto i = 0; i < triangleCount; i++)
823 {
824 indirectData[i] = DrawElementsIndirectCommand(3, 1, 3 * i, 0, i);
825 }
826
827 glGenBuffers(1, &mIndirectBuffer);
828 glBindBuffer(GL_DRAW_INDIRECT_BUFFER, mIndirectBuffer);
829 glBufferData(GL_DRAW_INDIRECT_BUFFER, icSize * indirectData.size(), indirectData.data(),
830 GL_STATIC_DRAW);
831 EXPECT_GL_NO_ERROR();
832
833 // Invalid value check for drawcount and stride
834 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
835 glMultiDrawElementsIndirectEXT(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr, 0, 0);
836 EXPECT_GL_ERROR(GL_INVALID_VALUE);
837 glMultiDrawElementsIndirectEXT(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr, -1, 0);
838 EXPECT_GL_ERROR(GL_INVALID_VALUE);
839 glMultiDrawElementsIndirectEXT(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr, 1, 2);
840 EXPECT_GL_ERROR(GL_INVALID_VALUE);
841
842 // Check the error from sourcing beyond the allocated buffer size
843 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
844 glMultiDrawElementsIndirectEXT(
845 GL_TRIANGLES, GL_UNSIGNED_INT,
846 reinterpret_cast<const void *>(static_cast<uintptr_t>(icSize * triangleCount)), 1, 0);
847 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
848
849 // Draw all triangles using glMultiDrawElementsIndirect
850 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
851 glMultiDrawElementsIndirectEXT(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr, triangleCount, 0);
852 EXPECT_GL_NO_ERROR();
853
854 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::magenta);
855 EXPECT_PIXEL_COLOR_EQ(0, kHeight - 1, GLColor::magenta);
856 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 0, GLColor::magenta);
857 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::magenta);
858 EXPECT_PIXEL_COLOR_EQ(kWidth / 2, kHeight / 2, GLColor::transparentBlack);
859
860 // Draw the triangles in a different order
861 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
862 glMultiDrawElementsIndirectEXT(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr, 1, 0);
863 glMultiDrawElementsIndirectEXT(GL_TRIANGLES, GL_UNSIGNED_INT,
864 reinterpret_cast<const void *>(static_cast<uintptr_t>(icSize)),
865 triangleCount - 2, 0);
866 glMultiDrawElementsIndirectEXT(
867 GL_TRIANGLES, GL_UNSIGNED_INT,
868 reinterpret_cast<const void *>(static_cast<uintptr_t>(icSize * 3)), 1, 0);
869 EXPECT_GL_NO_ERROR();
870
871 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::magenta);
872 EXPECT_PIXEL_COLOR_EQ(0, kHeight - 1, GLColor::magenta);
873 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 0, GLColor::magenta);
874 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::magenta);
875 EXPECT_PIXEL_COLOR_EQ(kWidth / 2, kHeight / 2, GLColor::transparentBlack);
876
877 // Draw the triangles partially using stride
878 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
879 glMultiDrawElementsIndirectEXT(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr, 2, icSize * 3);
880 EXPECT_GL_NO_ERROR();
881
882 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::transparentBlack);
883 EXPECT_PIXEL_COLOR_EQ(0, kHeight - 1, GLColor::magenta);
884 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 0, GLColor::transparentBlack);
885 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::magenta);
886 EXPECT_PIXEL_COLOR_EQ(kWidth / 2, kHeight / 2, GLColor::transparentBlack);
887 }
888
889 // Test functionality glMultiDrawElementsIndirectEXT with unsigned short
890 // indices and instanced attributes.
TEST_P(MultiDrawIndirectTest,MultiDrawElementsIndirectInstancedUshort)891 TEST_P(MultiDrawIndirectTest, MultiDrawElementsIndirectInstancedUshort)
892 {
893 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multi_draw_indirect"));
894
895 // Set up the vertex array
896 const GLint triangleCount = 4;
897 const std::vector<GLfloat> vertices = {
898 -1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, -1, 0, 0, -1, 0, -1, -1, 0, -1, 0, 0,
899 };
900 const std::vector<GLushort> indices = {
901 1, 2, 3, 3, 4, 5, 5, 6, 7, 7, 0, 1,
902 };
903 const std::vector<GLuint> instancedColor = {GLColor::white.asUint(), GLColor::red.asUint(),
904 GLColor::green.asUint(), GLColor::blue.asUint()};
905
906 // Generate program
907 SetupProgramIndirect(true);
908
909 // Set up the vertex and index buffers
910 GLVertexArray vao;
911 glBindVertexArray(vao);
912
913 glGenBuffers(1, &mVertexBuffer);
914 glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
915 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * vertices.size(), vertices.data(),
916 GL_STATIC_DRAW);
917 glEnableVertexAttribArray(mPositionLoc);
918 glVertexAttribPointer(mPositionLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
919
920 GLBuffer instanceBuffer;
921 glBindBuffer(GL_ARRAY_BUFFER, instanceBuffer);
922 glBufferData(GL_ARRAY_BUFFER, sizeof(GLuint) * instancedColor.size(), instancedColor.data(),
923 GL_STATIC_DRAW);
924 glEnableVertexAttribArray(mColorLoc);
925 glVertexAttribPointer(mColorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, nullptr);
926 glVertexAttribDivisor(mColorLoc, 1);
927
928 glGenBuffers(1, &mIndexBuffer);
929 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
930 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort) * indices.size(), indices.data(),
931 GL_STATIC_DRAW);
932 EXPECT_GL_NO_ERROR();
933
934 // Set up the indirect data array
935 std::array<DrawElementsIndirectCommand, triangleCount> indirectData;
936 const GLsizei icSize = sizeof(DrawElementsIndirectCommand);
937 for (auto i = 0; i < triangleCount; i++)
938 {
939 indirectData[i] = DrawElementsIndirectCommand(3, 1, 3 * i, 0, i);
940 }
941
942 glGenBuffers(1, &mIndirectBuffer);
943 glBindBuffer(GL_DRAW_INDIRECT_BUFFER, mIndirectBuffer);
944 glBufferData(GL_DRAW_INDIRECT_BUFFER, icSize * indirectData.size(), indirectData.data(),
945 GL_STATIC_DRAW);
946 EXPECT_GL_NO_ERROR();
947
948 // Invalid value check for drawcount and stride
949 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
950 glMultiDrawElementsIndirectEXT(GL_TRIANGLES, GL_UNSIGNED_SHORT, nullptr, 0, 0);
951 EXPECT_GL_ERROR(GL_INVALID_VALUE);
952 glMultiDrawElementsIndirectEXT(GL_TRIANGLES, GL_UNSIGNED_SHORT, nullptr, -1, 0);
953 EXPECT_GL_ERROR(GL_INVALID_VALUE);
954 glMultiDrawElementsIndirectEXT(GL_TRIANGLES, GL_UNSIGNED_SHORT, nullptr, 1, 2);
955 EXPECT_GL_ERROR(GL_INVALID_VALUE);
956
957 // Check the error from sourcing beyond the allocated buffer size
958 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
959 glMultiDrawElementsIndirectEXT(
960 GL_TRIANGLES, GL_UNSIGNED_SHORT,
961 reinterpret_cast<const void *>(static_cast<uintptr_t>(icSize * triangleCount)), 1, 0);
962 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
963
964 // Draw all triangles using glMultiDrawElementsIndirect
965 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
966 glMultiDrawElementsIndirectEXT(GL_TRIANGLES, GL_UNSIGNED_SHORT, nullptr, triangleCount, 0);
967 EXPECT_GL_NO_ERROR();
968
969 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
970 EXPECT_PIXEL_COLOR_EQ(0, kHeight - 1, GLColor::blue);
971 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 0, GLColor::red);
972 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::white);
973 EXPECT_PIXEL_COLOR_EQ(kWidth / 2, kHeight / 2, GLColor::transparentBlack);
974
975 // Draw the triangles in a different order
976 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
977 glMultiDrawElementsIndirectEXT(GL_TRIANGLES, GL_UNSIGNED_SHORT, nullptr, 1, 0);
978 glMultiDrawElementsIndirectEXT(GL_TRIANGLES, GL_UNSIGNED_SHORT,
979 reinterpret_cast<const void *>(static_cast<uintptr_t>(icSize)),
980 triangleCount - 2, 0);
981 glMultiDrawElementsIndirectEXT(
982 GL_TRIANGLES, GL_UNSIGNED_SHORT,
983 reinterpret_cast<const void *>(static_cast<uintptr_t>(icSize * 3)), 1, 0);
984 EXPECT_GL_NO_ERROR();
985
986 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
987 EXPECT_PIXEL_COLOR_EQ(0, kHeight - 1, GLColor::blue);
988 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 0, GLColor::red);
989 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::white);
990 EXPECT_PIXEL_COLOR_EQ(kWidth / 2, kHeight / 2, GLColor::transparentBlack);
991
992 // Draw the triangles partially using stride
993 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
994 glMultiDrawElementsIndirectEXT(GL_TRIANGLES, GL_UNSIGNED_SHORT, nullptr, 2, icSize * 3);
995 EXPECT_GL_NO_ERROR();
996
997 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::transparentBlack);
998 EXPECT_PIXEL_COLOR_EQ(0, kHeight - 1, GLColor::blue);
999 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 0, GLColor::transparentBlack);
1000 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::white);
1001 EXPECT_PIXEL_COLOR_EQ(kWidth / 2, kHeight / 2, GLColor::transparentBlack);
1002 }
1003
1004 // Tests functionality of glMultiDrawElementsIndirectEXT with more than one triangle in one element
1005 // of the indirect buffer.
TEST_P(MultiDrawIndirectTest,MultiDrawElementsIndirectMultipleTriangles)1006 TEST_P(MultiDrawIndirectTest, MultiDrawElementsIndirectMultipleTriangles)
1007 {
1008 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multi_draw_indirect"));
1009
1010 // Set up the vertex array
1011 const GLint triangleCount = 4;
1012 const std::vector<GLfloat> vertices = {
1013 -1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, -1, 0, 0, -1, 0, -1, -1, 0, -1, 0, 0,
1014 };
1015 const std::vector<GLuint> indices = {
1016 1, 2, 3, 3, 4, 5, 5, 6, 7, 7, 0, 1,
1017 };
1018
1019 // Set up the vertex and index buffers
1020 GLVertexArray vao;
1021 glBindVertexArray(vao);
1022
1023 glGenBuffers(1, &mVertexBuffer);
1024 glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
1025 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * vertices.size(), vertices.data(),
1026 GL_STATIC_DRAW);
1027
1028 glGenBuffers(1, &mIndexBuffer);
1029 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
1030 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * indices.size(), indices.data(),
1031 GL_STATIC_DRAW);
1032 EXPECT_GL_NO_ERROR();
1033
1034 // Generate program
1035 SetupProgramIndirect(false);
1036
1037 // Set up the vertex array format
1038 glEnableVertexAttribArray(mPositionLoc);
1039 glVertexAttribPointer(mPositionLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
1040 EXPECT_GL_NO_ERROR();
1041
1042 // Set up the indirect data array; first element represents two triangles.
1043 std::array<DrawElementsIndirectCommand, triangleCount - 1> indirectData;
1044 const GLsizei icSize = sizeof(DrawElementsIndirectCommand);
1045 for (auto i = 0; i < triangleCount - 1; i++)
1046 {
1047 if (i == 0)
1048 {
1049 indirectData[i] = DrawElementsIndirectCommand(6, 2, 0, 0, i);
1050 }
1051 else
1052 {
1053 indirectData[i] = DrawElementsIndirectCommand(3, 1, 3 * (i + 1), 0, i);
1054 }
1055 }
1056
1057 glGenBuffers(1, &mIndirectBuffer);
1058 glBindBuffer(GL_DRAW_INDIRECT_BUFFER, mIndirectBuffer);
1059 glBufferData(GL_DRAW_INDIRECT_BUFFER, icSize * indirectData.size(), indirectData.data(),
1060 GL_STATIC_DRAW);
1061 EXPECT_GL_NO_ERROR();
1062
1063 // Draw all triangles using glMultiDrawElementsIndirect
1064 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1065 glMultiDrawElementsIndirectEXT(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr, triangleCount - 1, 0);
1066 EXPECT_GL_NO_ERROR();
1067
1068 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::magenta);
1069 EXPECT_PIXEL_COLOR_EQ(0, kHeight - 1, GLColor::magenta);
1070 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 0, GLColor::magenta);
1071 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::magenta);
1072 EXPECT_PIXEL_COLOR_EQ(kWidth / 2, kHeight / 2, GLColor::transparentBlack);
1073 }
1074
1075 // Tests glMultiDrawElementsIndirectEXT with glMultiDrawElementsANGLE to see if the index buffer
1076 // offset is being reset.
TEST_P(MultiDrawIndirectTest,MultiDrawElementsIndirectCheckBufferOffset)1077 TEST_P(MultiDrawIndirectTest, MultiDrawElementsIndirectCheckBufferOffset)
1078 {
1079 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multi_draw_indirect"));
1080
1081 // Set up the vertex array
1082 const GLint triangleCount = 4;
1083 const std::vector<GLfloat> vertices = {
1084 -1, 0, 0, -1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0,
1085 1, 0, 0, 1, -1, 0, 0, -1, 0, 0, -1, 0, -1, -1, 0, -1, 0, 0,
1086 };
1087 const std::vector<GLfloat> colors = {
1088 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0,
1089 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0,
1090 };
1091 const std::vector<GLuint> indices = {
1092 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, 1, 2,
1093 };
1094
1095 // Set up the vertex and index buffers
1096 GLVertexArray vao;
1097 glBindVertexArray(vao);
1098
1099 glGenBuffers(1, &mVertexBuffer);
1100 glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
1101 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * vertices.size(), vertices.data(),
1102 GL_STATIC_DRAW);
1103
1104 glGenBuffers(1, &mColorBuffer);
1105 glBindBuffer(GL_ARRAY_BUFFER, mColorBuffer);
1106 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * colors.size(), colors.data(), GL_STATIC_DRAW);
1107
1108 glGenBuffers(1, &mIndexBuffer);
1109 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
1110 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * indices.size(), indices.data(),
1111 GL_STATIC_DRAW);
1112 EXPECT_GL_NO_ERROR();
1113
1114 // Generate program
1115 SetupProgramIndirect(true);
1116
1117 // Set up the vertex array format
1118 glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
1119 glEnableVertexAttribArray(mPositionLoc);
1120 glVertexAttribPointer(mPositionLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
1121 EXPECT_GL_NO_ERROR();
1122
1123 glBindBuffer(GL_ARRAY_BUFFER, mColorBuffer);
1124 glEnableVertexAttribArray(mColorLoc);
1125 glVertexAttribPointer(mColorLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
1126 EXPECT_GL_NO_ERROR();
1127
1128 // Set up the arrays for the direct draw
1129 std::vector<GLsizei> counts(triangleCount, 3);
1130 std::vector<const GLvoid *> indicesDirect(triangleCount);
1131 for (auto i = 0; i < triangleCount; i++)
1132 {
1133 indicesDirect[i] =
1134 reinterpret_cast<GLvoid *>(static_cast<uintptr_t>(i * 3 * sizeof(GLuint)));
1135 }
1136
1137 // Set up the indirect data array for indirect draw
1138 std::array<DrawElementsIndirectCommand, triangleCount> indirectData;
1139 const GLsizei icSize = sizeof(DrawElementsIndirectCommand);
1140 for (auto i = 0; i < triangleCount; i++)
1141 {
1142 indirectData[i] = DrawElementsIndirectCommand(3, 1, 3 * i, 0, i);
1143 }
1144
1145 glGenBuffers(1, &mIndirectBuffer);
1146 glBindBuffer(GL_DRAW_INDIRECT_BUFFER, mIndirectBuffer);
1147 glBufferData(GL_DRAW_INDIRECT_BUFFER, icSize * indirectData.size(), indirectData.data(),
1148 GL_STATIC_DRAW);
1149 EXPECT_GL_NO_ERROR();
1150
1151 // Draw using glMultiDrawElementsIndirect
1152 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1153 glMultiDrawElementsIndirectEXT(
1154 GL_TRIANGLES, GL_UNSIGNED_INT,
1155 reinterpret_cast<const void *>(static_cast<uintptr_t>(icSize * 2)), triangleCount - 2, 0);
1156 EXPECT_GL_NO_ERROR();
1157
1158 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow);
1159 EXPECT_PIXEL_COLOR_EQ(0, kHeight - 1, GLColor::red);
1160 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 0, GLColor::transparentBlack);
1161 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::transparentBlack);
1162 EXPECT_PIXEL_COLOR_EQ(kWidth / 2, kHeight / 2, GLColor::transparentBlack);
1163
1164 // Draw using glMultiDrawElementsANGLE
1165 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1166 glMultiDrawElementsANGLE(GL_TRIANGLES, counts.data(), GL_UNSIGNED_INT, indicesDirect.data(),
1167 triangleCount);
1168 EXPECT_GL_NO_ERROR();
1169
1170 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow);
1171 EXPECT_PIXEL_COLOR_EQ(0, kHeight - 1, GLColor::red);
1172 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 0, GLColor::blue);
1173 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::green);
1174 EXPECT_PIXEL_COLOR_EQ(kWidth / 2, kHeight / 2, GLColor::transparentBlack);
1175
1176 // Draw using glMultiDrawElementsANGLE again
1177 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1178 glMultiDrawElementsANGLE(GL_TRIANGLES, counts.data(), GL_UNSIGNED_INT, indicesDirect.data(),
1179 triangleCount - 1);
1180 EXPECT_GL_NO_ERROR();
1181
1182 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow);
1183 EXPECT_PIXEL_COLOR_EQ(0, kHeight - 1, GLColor::transparentBlack);
1184 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 0, GLColor::blue);
1185 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::green);
1186 EXPECT_PIXEL_COLOR_EQ(kWidth / 2, kHeight / 2, GLColor::transparentBlack);
1187
1188 // Draw using glMultiDrawElementsIndirect again
1189 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1190 glMultiDrawElementsIndirectEXT(
1191 GL_TRIANGLES, GL_UNSIGNED_INT,
1192 reinterpret_cast<const void *>(static_cast<uintptr_t>(icSize * 3)), triangleCount - 3, 0);
1193 EXPECT_GL_NO_ERROR();
1194
1195 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::transparentBlack);
1196 EXPECT_PIXEL_COLOR_EQ(0, kHeight - 1, GLColor::red);
1197 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 0, GLColor::transparentBlack);
1198 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::transparentBlack);
1199 EXPECT_PIXEL_COLOR_EQ(kWidth / 2, kHeight / 2, GLColor::transparentBlack);
1200
1201 // Draw using glMultiDrawElementsIndirect one more time
1202 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1203 glMultiDrawElementsIndirectEXT(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr, triangleCount, 0);
1204 EXPECT_GL_NO_ERROR();
1205
1206 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow);
1207 EXPECT_PIXEL_COLOR_EQ(0, kHeight - 1, GLColor::red);
1208 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 0, GLColor::blue);
1209 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::green);
1210 EXPECT_PIXEL_COLOR_EQ(kWidth / 2, kHeight / 2, GLColor::transparentBlack);
1211 }
1212
1213 // Check that glMultiDraw*Instanced without instancing support results in GL_INVALID_OPERATION
TEST_P(MultiDrawNoInstancingSupportTest,InvalidOperation)1214 TEST_P(MultiDrawNoInstancingSupportTest, InvalidOperation)
1215 {
1216 ANGLE_SKIP_TEST_IF(IsGLExtensionEnabled("GL_ANGLE_instanced_arrays"));
1217 requestMultiDrawExtension();
1218 SetupBuffers();
1219 SetupProgram();
1220
1221 GLint first = 0;
1222 GLsizei count = 3;
1223 GLvoid *indices = nullptr;
1224 GLsizei instances = 1;
1225
1226 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1227 glBindBuffer(GL_ARRAY_BUFFER, mNonIndexedVertexBuffer);
1228 glEnableVertexAttribArray(mPositionLoc);
1229 glVertexAttribPointer(mPositionLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
1230 glMultiDrawArraysInstancedANGLE(GL_TRIANGLES, &first, &count, &instances, 1);
1231 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1232
1233 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1234 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
1235 glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
1236 glEnableVertexAttribArray(mPositionLoc);
1237 glVertexAttribPointer(mPositionLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
1238 glMultiDrawElementsInstancedANGLE(GL_TRIANGLES, &count, GL_UNSIGNED_SHORT, &indices, &instances,
1239 1);
1240 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1241 }
1242
1243 #define ANGLE_ALL_MULTIDRAW_TEST_PLATFORMS_ES2 \
1244 ES2_D3D11().enable(Feature::AlwaysEnableEmulatedMultidrawExtensions), \
1245 ES2_OPENGL().enable(Feature::AlwaysEnableEmulatedMultidrawExtensions), \
1246 ES2_OPENGLES().enable(Feature::AlwaysEnableEmulatedMultidrawExtensions), \
1247 ES2_VULKAN().enable(Feature::AlwaysEnableEmulatedMultidrawExtensions), \
1248 ES2_VULKAN_SWIFTSHADER().enable(Feature::AlwaysEnableEmulatedMultidrawExtensions), \
1249 ES2_METAL().enable(Feature::AlwaysEnableEmulatedMultidrawExtensions)
1250
1251 #define ANGLE_ALL_MULTIDRAW_TEST_PLATFORMS_ES3 \
1252 ES3_D3D11().enable(Feature::AlwaysEnableEmulatedMultidrawExtensions), \
1253 ES3_OPENGL().enable(Feature::AlwaysEnableEmulatedMultidrawExtensions), \
1254 ES3_OPENGLES().enable(Feature::AlwaysEnableEmulatedMultidrawExtensions), \
1255 ES3_VULKAN().enable(Feature::AlwaysEnableEmulatedMultidrawExtensions), \
1256 ES3_VULKAN_SWIFTSHADER().enable(Feature::AlwaysEnableEmulatedMultidrawExtensions), \
1257 ES3_METAL().enable(Feature::AlwaysEnableEmulatedMultidrawExtensions)
1258
1259 #define ANGLE_ALL_MULTIDRAW_TEST_PLATFORMS_ES3_1 \
1260 ES31_D3D11().enable(Feature::AlwaysEnableEmulatedMultidrawExtensions), \
1261 ES31_OPENGL().enable(Feature::AlwaysEnableEmulatedMultidrawExtensions), \
1262 ES31_OPENGLES().enable(Feature::AlwaysEnableEmulatedMultidrawExtensions), \
1263 ES31_VULKAN().enable(Feature::AlwaysEnableEmulatedMultidrawExtensions), \
1264 ES31_VULKAN_SWIFTSHADER().enable(Feature::AlwaysEnableEmulatedMultidrawExtensions), \
1265 ES31_VULKAN() \
1266 .enable(Feature::AlwaysEnableEmulatedMultidrawExtensions) \
1267 .disable(Feature::SupportsMultiDrawIndirect)
1268
1269 ANGLE_INSTANTIATE_TEST_COMBINE_3(MultiDrawTest,
1270 PrintToStringParamName(),
1271 testing::Values(DrawIDOption::NoDrawID, DrawIDOption::UseDrawID),
1272 testing::Values(InstancingOption::NoInstancing,
1273 InstancingOption::UseInstancing),
1274 testing::Values(BufferDataUsageOption::StaticDraw,
1275 BufferDataUsageOption::DynamicDraw),
1276 ANGLE_ALL_MULTIDRAW_TEST_PLATFORMS_ES2,
1277 ANGLE_ALL_MULTIDRAW_TEST_PLATFORMS_ES3);
1278
1279 ANGLE_INSTANTIATE_TEST_COMBINE_3(MultiDrawNoInstancingSupportTest,
1280 PrintToStringParamName(),
1281 testing::Values(DrawIDOption::NoDrawID, DrawIDOption::UseDrawID),
1282 testing::Values(InstancingOption::UseInstancing),
1283 testing::Values(BufferDataUsageOption::StaticDraw,
1284 BufferDataUsageOption::DynamicDraw),
1285 ANGLE_ALL_MULTIDRAW_TEST_PLATFORMS_ES2);
1286
1287 ANGLE_INSTANTIATE_TEST_COMBINE_3(MultiDrawTestES3,
1288 PrintToStringParamName(),
1289 testing::Values(DrawIDOption::NoDrawID, DrawIDOption::UseDrawID),
1290 testing::Values(InstancingOption::NoInstancing,
1291 InstancingOption::UseInstancing),
1292 testing::Values(BufferDataUsageOption::StaticDraw,
1293 BufferDataUsageOption::DynamicDraw),
1294 ANGLE_ALL_MULTIDRAW_TEST_PLATFORMS_ES3);
1295
1296 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MultiDrawIndirectTest);
1297 ANGLE_INSTANTIATE_TEST(MultiDrawIndirectTest, ANGLE_ALL_MULTIDRAW_TEST_PLATFORMS_ES3_1);
1298 } // namespace
1299