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 ()__anon1c530e030111::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__anon1c530e030111::DrawArraysIndirectCommand93 DrawArraysIndirectCommand() : count(0u), instanceCount(0u), first(0u), baseInstance(0u) {}
DrawArraysIndirectCommand__anon1c530e030111::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__anon1c530e030111::DrawElementsIndirectCommand105 DrawElementsIndirectCommand()
106 : count(0), primCount(0), firstIndex(0), baseVertex(0), baseInstance(0)
107 {}
DrawElementsIndirectCommand__anon1c530e030111::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 << ";"
182 << R"(
183 float quad_id = float(id / 2);
184 float color_id = quad_id - (3.0 * floor(quad_id / 3.0));
185 if (color_id == 0.0) {
186 color = vec4(1, 0, 0, 1);
187 } else if (color_id == 1.0) {
188 color = vec4(0, 1, 0, 1);
189 } else {
190 color = vec4(0, 0, 1, 1);
191 }
192
193 mat3 transform = mat3(1.0);
194 )"
195 << (IsInstancedTest() ? R"(
196 transform[0][0] = 0.5;
197 transform[1][1] = 0.5;
198 if (vInstance == 0.0) {
199
200 } else if (vInstance == 1.0) {
201 transform[2][0] = 0.5;
202 } else if (vInstance == 2.0) {
203 transform[2][1] = 0.5;
204 } else if (vInstance == 3.0) {
205 transform[2][0] = 0.5;
206 transform[2][1] = 0.5;
207 }
208 )"
209 : "")
210 << R"(
211 gl_Position = vec4(transform * vec3(vPosition, 1.0) * 2.0 - 1.0, 1);
212 })";
213
214 return shader.str();
215 }
216
FragmentShaderSource()217 std::string FragmentShaderSource()
218 {
219 return
220 R"(precision mediump float;
221 varying vec4 color;
222 void main()
223 {
224 gl_FragColor = color;
225 })";
226 }
227
SetupProgram()228 void SetupProgram()
229 {
230 mProgram = CompileProgram(VertexShaderSource().c_str(), FragmentShaderSource().c_str());
231 EXPECT_GL_NO_ERROR();
232 ASSERT_GE(mProgram, 1u);
233 glUseProgram(mProgram);
234 mPositionLoc = glGetAttribLocation(mProgram, "vPosition");
235 mInstanceLoc = glGetAttribLocation(mProgram, "vInstance");
236 }
237
SetupBuffers()238 void SetupBuffers()
239 {
240 for (uint32_t y = 0; y < kCountY; ++y)
241 {
242 for (uint32_t x = 0; x < kCountX; ++x)
243 {
244 // v3 ---- v2
245 // | |
246 // | |
247 // v0 ---- v1
248 uint32_t quadIndex = y * kCountX + x;
249 GLushort starting_index = static_cast<GLushort>(4 * quadIndex);
250 std::array<GLushort, 6> is = {0, 1, 2, 0, 2, 3};
251 const auto vs = getQuadVertices(x, y);
252 for (GLushort i : is)
253 {
254 mIndices.push_back(starting_index + i);
255 }
256
257 for (const auto &v : vs)
258 {
259 mVertices.insert(mVertices.end(), v.begin(), v.end());
260 }
261
262 for (GLushort i : is)
263 {
264 mNonIndexedVertices.insert(mNonIndexedVertices.end(), vs[i].begin(),
265 vs[i].end());
266 }
267 }
268 }
269
270 std::array<GLfloat, 4> instances{0, 1, 2, 3};
271
272 glGenBuffers(1, &mNonIndexedVertexBuffer);
273 glBindBuffer(GL_ARRAY_BUFFER, mNonIndexedVertexBuffer);
274 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * mNonIndexedVertices.size(),
275 mNonIndexedVertices.data(), getBufferDataUsage());
276
277 glGenBuffers(1, &mVertexBuffer);
278 glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
279 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * mVertices.size(), mVertices.data(),
280 getBufferDataUsage());
281
282 glGenBuffers(1, &mIndexBuffer);
283 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
284 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort) * mIndices.size(), mIndices.data(),
285 getBufferDataUsage());
286
287 glGenBuffers(1, &mInstanceBuffer);
288 glBindBuffer(GL_ARRAY_BUFFER, mInstanceBuffer);
289 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * instances.size(), instances.data(),
290 getBufferDataUsage());
291
292 ASSERT_GL_NO_ERROR();
293 }
294
DoVertexAttribDivisor(GLint location,GLuint divisor)295 void DoVertexAttribDivisor(GLint location, GLuint divisor)
296 {
297 if (getClientMajorVersion() <= 2)
298 {
299 ASSERT_TRUE(IsGLExtensionEnabled("GL_ANGLE_instanced_arrays"));
300 glVertexAttribDivisorANGLE(location, divisor);
301 }
302 else
303 {
304 glVertexAttribDivisor(location, divisor);
305 }
306 }
307
DoDrawArrays()308 void DoDrawArrays()
309 {
310 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
311 glBindBuffer(GL_ARRAY_BUFFER, mNonIndexedVertexBuffer);
312 glEnableVertexAttribArray(mPositionLoc);
313 glVertexAttribPointer(mPositionLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
314
315 std::vector<GLint> firsts(kTriCount);
316 std::vector<GLsizei> counts(kTriCount, 3);
317 for (uint32_t i = 0; i < kTriCount; ++i)
318 firsts[i] = i * 3;
319
320 if (IsInstancedTest())
321 {
322 glBindBuffer(GL_ARRAY_BUFFER, mInstanceBuffer);
323 glEnableVertexAttribArray(mInstanceLoc);
324 glVertexAttribPointer(mInstanceLoc, 1, GL_FLOAT, GL_FALSE, 0, nullptr);
325 DoVertexAttribDivisor(mInstanceLoc, 1);
326 std::vector<GLsizei> instanceCounts(kTriCount, 4);
327 glMultiDrawArraysInstancedANGLE(GL_TRIANGLES, firsts.data(), counts.data(),
328 instanceCounts.data(), kTriCount);
329 }
330 else
331 {
332 glMultiDrawArraysANGLE(GL_TRIANGLES, firsts.data(), counts.data(), kTriCount);
333 }
334 }
335
DoDrawElements()336 void DoDrawElements()
337 {
338 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
339 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
340 glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
341 glEnableVertexAttribArray(mPositionLoc);
342 glVertexAttribPointer(mPositionLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
343
344 std::vector<GLsizei> counts(kTriCount, 3);
345 std::vector<const GLvoid *> indices(kTriCount);
346 for (uint32_t i = 0; i < kTriCount; ++i)
347 indices[i] = reinterpret_cast<GLvoid *>(static_cast<uintptr_t>(i * 3 * 2));
348
349 if (IsInstancedTest())
350 {
351 glBindBuffer(GL_ARRAY_BUFFER, mInstanceBuffer);
352 glEnableVertexAttribArray(mInstanceLoc);
353 glVertexAttribPointer(mInstanceLoc, 1, GL_FLOAT, GL_FALSE, 0, nullptr);
354 DoVertexAttribDivisor(mInstanceLoc, 1);
355 std::vector<GLsizei> instanceCounts(kTriCount, 4);
356 glMultiDrawElementsInstancedANGLE(GL_TRIANGLES, counts.data(), GL_UNSIGNED_SHORT,
357 indices.data(), instanceCounts.data(), kTriCount);
358 }
359 else
360 {
361 glMultiDrawElementsANGLE(GL_TRIANGLES, counts.data(), GL_UNSIGNED_SHORT, indices.data(),
362 kTriCount);
363 }
364 }
365
366 enum class DrawIDOptionOverride
367 {
368 Default,
369 NoDrawID,
370 UseDrawID,
371 };
372
CheckDrawResult(DrawIDOptionOverride overrideDrawID)373 void CheckDrawResult(DrawIDOptionOverride overrideDrawID)
374 {
375 for (uint32_t y = 0; y < kCountY; ++y)
376 {
377 for (uint32_t x = 0; x < kCountX; ++x)
378 {
379 uint32_t center_x = x * kTilePixelSize[0] + kTilePixelSize[0] / 2;
380 uint32_t center_y = y * kTilePixelSize[1] + kTilePixelSize[1] / 2;
381 uint32_t quadID = IsDrawIDTest() && overrideDrawID != DrawIDOptionOverride::NoDrawID
382 ? y * kCountX + x
383 : 0;
384 uint32_t colorID = quadID % 3u;
385 std::array<GLColor, 3> colors = {GLColor(255, 0, 0, 255), GLColor(0, 255, 0, 255),
386 GLColor(0, 0, 255, 255)};
387 GLColor expected = colors[colorID];
388
389 if (IsInstancedTest())
390 {
391 EXPECT_PIXEL_RECT_EQ(center_x / 2 - kPixelCheckSize[0] / 4,
392 center_y / 2 - kPixelCheckSize[1] / 4,
393 kPixelCheckSize[0] / 2, kPixelCheckSize[1] / 2, expected);
394 EXPECT_PIXEL_RECT_EQ(center_x / 2 - kPixelCheckSize[0] / 4 + kWidth / 2,
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,
398 center_y / 2 - kPixelCheckSize[1] / 4 + kHeight / 2,
399 kPixelCheckSize[0] / 2, kPixelCheckSize[1] / 2, expected);
400 EXPECT_PIXEL_RECT_EQ(center_x / 2 - kPixelCheckSize[0] / 4 + kWidth / 2,
401 center_y / 2 - kPixelCheckSize[1] / 4 + kHeight / 2,
402 kPixelCheckSize[0] / 2, kPixelCheckSize[1] / 2, expected);
403 }
404 else
405 {
406 EXPECT_PIXEL_RECT_EQ(center_x - kPixelCheckSize[0] / 2,
407 center_y - kPixelCheckSize[1] / 2, kPixelCheckSize[0],
408 kPixelCheckSize[1], expected);
409 }
410 }
411 }
412 }
413
TearDown()414 void TearDown() override
415 {
416 if (mNonIndexedVertexBuffer != 0u)
417 {
418 glDeleteBuffers(1, &mNonIndexedVertexBuffer);
419 }
420 if (mVertexBuffer != 0u)
421 {
422 glDeleteBuffers(1, &mVertexBuffer);
423 }
424 if (mIndexBuffer != 0u)
425 {
426 glDeleteBuffers(1, &mIndexBuffer);
427 }
428 if (mInstanceBuffer != 0u)
429 {
430 glDeleteBuffers(1, &mInstanceBuffer);
431 }
432 if (mProgram != 0)
433 {
434 glDeleteProgram(mProgram);
435 }
436 ANGLETestBase::ANGLETestTearDown();
437 }
438
requestMultiDrawExtension()439 bool requestMultiDrawExtension() { return EnsureGLExtensionEnabled("GL_ANGLE_multi_draw"); }
440
requestInstancedExtension()441 bool requestInstancedExtension()
442 {
443 return EnsureGLExtensionEnabled("GL_ANGLE_instanced_arrays");
444 }
445
requestExtensions()446 bool requestExtensions()
447 {
448 if (IsInstancedTest() && getClientMajorVersion() <= 2)
449 {
450 if (!requestInstancedExtension())
451 {
452 return false;
453 }
454 }
455 return requestMultiDrawExtension();
456 }
457
458 std::vector<GLushort> mIndices;
459 std::vector<GLfloat> mVertices;
460 std::vector<GLfloat> mNonIndexedVertices;
461 GLuint mNonIndexedVertexBuffer;
462 GLuint mVertexBuffer;
463 GLuint mIndexBuffer;
464 GLuint mInstanceBuffer;
465 GLuint mProgram;
466 GLint mPositionLoc;
467 GLint mInstanceLoc;
468 };
469
470 class MultiDrawNoInstancingSupportTest : public MultiDrawTest
471 {
SetUp()472 void SetUp() override
473 {
474 ASSERT_LE(getClientMajorVersion(), 2);
475 ASSERT_TRUE(IsInstancedTest());
476 MultiDrawTest::SetUp();
477 }
478 };
479
480 // The tests in MultiDrawIndirectTest check the correctness
481 // of the EXT_multi_draw_indirect extension.
482 // 4 magenta triangles are drawn at the corners of the screen
483 // in different orders from the same vertex and index arrays.
484 class MultiDrawIndirectTest : public ANGLETestBase,
485 public ::testing::TestWithParam<MultiDrawIndirectTestParams>
486 {
487 protected:
MultiDrawIndirectTest()488 MultiDrawIndirectTest()
489 : ANGLETestBase(GetParam()),
490 mPositionLoc(0u),
491 mColorLoc(0u),
492 mVertexBuffer(0u),
493 mColorBuffer(0u),
494 mIndexBuffer(0u),
495 mIndirectBuffer(0u),
496 mProgram(0u)
497 {
498 setWindowWidth(kWidth);
499 setWindowHeight(kHeight);
500 setConfigRedBits(8);
501 setConfigGreenBits(8);
502 setConfigBlueBits(8);
503 setConfigAlphaBits(8);
504 }
505
SetUp()506 void SetUp() override { ANGLETestBase::ANGLETestSetUp(); }
507
SetupProgramIndirect(bool isMultiColor)508 void SetupProgramIndirect(bool isMultiColor)
509 {
510 // Define the vertex and fragment shaders
511 std::stringstream kVS;
512 kVS << R"(#version 310 es
513 in vec3 aPos;
514 )"
515 << (isMultiColor ? R"(in vec4 aColor;
516 out vec4 vColor;)"
517 : "")
518 << R"(
519 void main()
520 {
521 gl_Position = vec4(aPos.x, aPos.y, 0, 1);
522 )" << (isMultiColor ? R"(vColor = vec4(aColor.x, aColor.y, aColor.z, 1.0);)" : "")
523 << R"(
524 })";
525
526 std::stringstream kFS;
527 kFS << R"(#version 310 es
528 precision mediump float;
529 )"
530 << (isMultiColor ? R"(in vec4 vColor;
531 )"
532 : "")
533 << R"(
534 out vec4 colorOut;
535 void main()
536 {
537 )" << (isMultiColor ? R"(colorOut = vColor;)" : R"(colorOut = vec4(1.0, 0.0, 1.0, 1.0);)")
538 << R"(
539 })";
540 mProgram = CompileProgram(kVS.str().c_str(), kFS.str().c_str());
541 EXPECT_GL_NO_ERROR();
542 ASSERT_GE(mProgram, 1u);
543 glUseProgram(mProgram);
544 mPositionLoc = glGetAttribLocation(mProgram, "aPos");
545 mColorLoc = glGetAttribLocation(mProgram, "aColor");
546 }
547
TearDown()548 void TearDown() override
549 {
550 if (mVertexBuffer != 0u)
551 {
552 glDeleteBuffers(1, &mVertexBuffer);
553 }
554 if (mColorBuffer != 0u)
555 {
556 glDeleteBuffers(1, &mColorBuffer);
557 }
558 if (mIndexBuffer != 0u)
559 {
560 glDeleteBuffers(1, &mIndexBuffer);
561 }
562 if (mProgram != 0)
563 {
564 glDeleteProgram(mProgram);
565 }
566 if (mIndirectBuffer != 0u)
567 {
568 glDeleteBuffers(1, &mIndirectBuffer);
569 }
570 ANGLETestBase::ANGLETestTearDown();
571 }
572
573 GLint mPositionLoc;
574 GLint mColorLoc;
575 GLuint mVertexBuffer;
576 GLuint mColorBuffer;
577 GLuint mIndexBuffer;
578 GLuint mIndirectBuffer;
579 GLuint mProgram;
580 };
581
582 // glMultiDraw*ANGLE are emulated and should always be available
TEST_P(MultiDrawTest,RequestExtension)583 TEST_P(MultiDrawTest, RequestExtension)
584 {
585 EXPECT_TRUE(requestMultiDrawExtension());
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/5265
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 glMultiDrawElementsANGLE
TEST_P(MultiDrawTest,MultiDrawElements)611 TEST_P(MultiDrawTest, MultiDrawElements)
612 {
613 ANGLE_SKIP_TEST_IF(!requestExtensions());
614 SetupBuffers();
615 SetupProgram();
616 DoDrawElements();
617 EXPECT_GL_NO_ERROR();
618 CheckDrawResult(DrawIDOptionOverride::Default);
619 }
620
621 // Tests that glMultiDrawArraysANGLE followed by glDrawArrays works. gl_DrawID in the second call
622 // must be 0.
TEST_P(MultiDrawTest,MultiDrawArraysThenDrawArrays)623 TEST_P(MultiDrawTest, MultiDrawArraysThenDrawArrays)
624 {
625 ANGLE_SKIP_TEST_IF(!requestExtensions());
626
627 // http://anglebug.com/5265
628 ANGLE_SKIP_TEST_IF(IsInstancedTest() && IsMac() && IsIntelUHD630Mobile() && IsDesktopOpenGL());
629
630 SetupBuffers();
631 SetupProgram();
632 DoDrawArrays();
633 EXPECT_GL_NO_ERROR();
634 CheckDrawResult(DrawIDOptionOverride::Default);
635
636 if (IsInstancedTest())
637 {
638 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_instanced_arrays") &&
639 !IsGLExtensionEnabled("GL_ANGLE_instanced_arrays"));
640 if (IsGLExtensionEnabled("GL_EXT_instanced_arrays"))
641 {
642 glDrawArraysInstancedEXT(GL_TRIANGLES, 0, 3 * kTriCount, 4);
643 }
644 else
645 {
646 glDrawArraysInstancedANGLE(GL_TRIANGLES, 0, 3 * kTriCount, 4);
647 }
648 ASSERT_GL_NO_ERROR();
649 }
650 else
651 {
652 glDrawArrays(GL_TRIANGLES, 0, 3 * kTriCount);
653 ASSERT_GL_NO_ERROR();
654 }
655 CheckDrawResult(DrawIDOptionOverride::NoDrawID);
656 }
657
658 // Tests basic functionality of glMultiDrawArraysIndirectEXT
TEST_P(MultiDrawIndirectTest,MultiDrawArraysIndirect)659 TEST_P(MultiDrawIndirectTest, MultiDrawArraysIndirect)
660 {
661 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multi_draw_indirect"));
662
663 // Set up the vertex array
664 const GLint triangleCount = 4;
665 const std::vector<GLfloat> vertices = {
666 -1, 1, 0, -1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0,
667 -1, -1, 0, -1, 0, 0, 0, -1, 0, 1, -1, 0, 0, -1, 0, 1, 0, 0,
668 };
669
670 // Set up the vertex buffer
671 GLVertexArray vao;
672 glBindVertexArray(vao);
673
674 glGenBuffers(1, &mVertexBuffer);
675 glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
676 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * vertices.size(), vertices.data(),
677 GL_STATIC_DRAW);
678 EXPECT_GL_NO_ERROR();
679
680 // Generate program
681 SetupProgramIndirect(false);
682
683 // Set up the vertex array format
684 glEnableVertexAttribArray(mPositionLoc);
685 glVertexAttribPointer(mPositionLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
686 EXPECT_GL_NO_ERROR();
687
688 // Set up the indirect data array
689 std::array<DrawArraysIndirectCommand, triangleCount> indirectData;
690 const GLsizei icSize = sizeof(DrawArraysIndirectCommand);
691 for (auto i = 0; i < triangleCount; i++)
692 {
693 indirectData[i] = DrawArraysIndirectCommand(3, 1, 3 * i, i);
694 }
695
696 glGenBuffers(1, &mIndirectBuffer);
697 glBindBuffer(GL_DRAW_INDIRECT_BUFFER, mIndirectBuffer);
698 glBufferData(GL_DRAW_INDIRECT_BUFFER, icSize * indirectData.size(), indirectData.data(),
699 GL_STATIC_DRAW);
700 EXPECT_GL_NO_ERROR();
701
702 // Invalid value check for drawcount and stride
703 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
704 glMultiDrawArraysIndirectEXT(GL_TRIANGLES, nullptr, 0, 0);
705 EXPECT_GL_ERROR(GL_INVALID_VALUE);
706 glMultiDrawArraysIndirectEXT(GL_TRIANGLES, nullptr, -1, 0);
707 EXPECT_GL_ERROR(GL_INVALID_VALUE);
708 glMultiDrawArraysIndirectEXT(GL_TRIANGLES, nullptr, 1, 2);
709 EXPECT_GL_ERROR(GL_INVALID_VALUE);
710
711 // Check the error from sourcing beyond the allocated buffer size
712 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
713 glMultiDrawArraysIndirectEXT(
714 GL_TRIANGLES,
715 reinterpret_cast<const void *>(static_cast<uintptr_t>(icSize * triangleCount)), 1, 0);
716 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
717
718 // Draw all triangles using glMultiDrawArraysIndirect
719 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
720 glMultiDrawArraysIndirectEXT(GL_TRIANGLES, nullptr, triangleCount, 0);
721 EXPECT_GL_NO_ERROR();
722
723 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::magenta);
724 EXPECT_PIXEL_COLOR_EQ(0, kHeight - 1, GLColor::magenta);
725 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 0, GLColor::magenta);
726 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::magenta);
727 EXPECT_PIXEL_COLOR_EQ(kWidth / 2, kHeight / 2, GLColor::transparentBlack);
728
729 // Draw the triangles in different order
730 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
731 glMultiDrawArraysIndirectEXT(GL_TRIANGLES, nullptr, 1, 0);
732 glMultiDrawArraysIndirectEXT(GL_TRIANGLES,
733 reinterpret_cast<const void *>(static_cast<uintptr_t>(icSize * 2)),
734 triangleCount - 2, 0);
735 glMultiDrawArraysIndirectEXT(
736 GL_TRIANGLES, reinterpret_cast<const void *>(static_cast<uintptr_t>(icSize)), 1, 0);
737 EXPECT_GL_NO_ERROR();
738
739 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::magenta);
740 EXPECT_PIXEL_COLOR_EQ(0, kHeight - 1, GLColor::magenta);
741 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 0, GLColor::magenta);
742 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::magenta);
743 EXPECT_PIXEL_COLOR_EQ(kWidth / 2, kHeight / 2, GLColor::transparentBlack);
744
745 // Draw the triangles partially using stride
746 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
747 glMultiDrawArraysIndirectEXT(GL_TRIANGLES, nullptr, 2, icSize * 3);
748 EXPECT_GL_NO_ERROR();
749
750 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::transparentBlack);
751 EXPECT_PIXEL_COLOR_EQ(0, kHeight - 1, GLColor::magenta);
752 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 0, GLColor::magenta);
753 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::transparentBlack);
754 EXPECT_PIXEL_COLOR_EQ(kWidth / 2, kHeight / 2, GLColor::transparentBlack);
755 }
756
757 // Tests basic functionality of glMultiDrawElementsIndirectEXT
TEST_P(MultiDrawIndirectTest,MultiDrawElementsIndirect)758 TEST_P(MultiDrawIndirectTest, MultiDrawElementsIndirect)
759 {
760 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multi_draw_indirect"));
761
762 // Set up the vertex array
763 const GLint triangleCount = 4;
764 const std::vector<GLfloat> vertices = {
765 -1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, -1, 0, 0, -1, 0, -1, -1, 0, -1, 0, 0,
766 };
767 const std::vector<GLuint> indices = {
768 1, 2, 3, 3, 4, 5, 5, 6, 7, 7, 0, 1,
769 };
770
771 // Set up the vertex and index buffers
772 GLVertexArray vao;
773 glBindVertexArray(vao);
774
775 glGenBuffers(1, &mVertexBuffer);
776 glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
777 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * vertices.size(), vertices.data(),
778 GL_STATIC_DRAW);
779
780 glGenBuffers(1, &mIndexBuffer);
781 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
782 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * indices.size(), indices.data(),
783 GL_STATIC_DRAW);
784 EXPECT_GL_NO_ERROR();
785
786 // Generate program
787 SetupProgramIndirect(false);
788
789 // Set up the vertex array format
790 glEnableVertexAttribArray(mPositionLoc);
791 glVertexAttribPointer(mPositionLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
792 EXPECT_GL_NO_ERROR();
793
794 // Set up the indirect data array
795 std::array<DrawElementsIndirectCommand, triangleCount> indirectData;
796 const GLsizei icSize = sizeof(DrawElementsIndirectCommand);
797 for (auto i = 0; i < triangleCount; i++)
798 {
799 indirectData[i] = DrawElementsIndirectCommand(3, 1, 3 * i, 0, i);
800 }
801
802 glGenBuffers(1, &mIndirectBuffer);
803 glBindBuffer(GL_DRAW_INDIRECT_BUFFER, mIndirectBuffer);
804 glBufferData(GL_DRAW_INDIRECT_BUFFER, icSize * indirectData.size(), indirectData.data(),
805 GL_STATIC_DRAW);
806 EXPECT_GL_NO_ERROR();
807
808 // Invalid value check for drawcount and stride
809 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
810 glMultiDrawElementsIndirectEXT(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr, 0, 0);
811 EXPECT_GL_ERROR(GL_INVALID_VALUE);
812 glMultiDrawElementsIndirectEXT(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr, -1, 0);
813 EXPECT_GL_ERROR(GL_INVALID_VALUE);
814 glMultiDrawElementsIndirectEXT(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr, 1, 2);
815 EXPECT_GL_ERROR(GL_INVALID_VALUE);
816
817 // Check the error from sourcing beyond the allocated buffer size
818 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
819 glMultiDrawElementsIndirectEXT(
820 GL_TRIANGLES, GL_UNSIGNED_INT,
821 reinterpret_cast<const void *>(static_cast<uintptr_t>(icSize * triangleCount)), 1, 0);
822 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
823
824 // Draw all triangles using glMultiDrawElementsIndirect
825 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
826 glMultiDrawElementsIndirectEXT(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr, triangleCount, 0);
827 EXPECT_GL_NO_ERROR();
828
829 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::magenta);
830 EXPECT_PIXEL_COLOR_EQ(0, kHeight - 1, GLColor::magenta);
831 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 0, GLColor::magenta);
832 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::magenta);
833 EXPECT_PIXEL_COLOR_EQ(kWidth / 2, kHeight / 2, GLColor::transparentBlack);
834
835 // Draw the triangles in a different order
836 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
837 glMultiDrawElementsIndirectEXT(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr, 1, 0);
838 glMultiDrawElementsIndirectEXT(GL_TRIANGLES, GL_UNSIGNED_INT,
839 reinterpret_cast<const void *>(static_cast<uintptr_t>(icSize)),
840 triangleCount - 2, 0);
841 glMultiDrawElementsIndirectEXT(
842 GL_TRIANGLES, GL_UNSIGNED_INT,
843 reinterpret_cast<const void *>(static_cast<uintptr_t>(icSize * 3)), 1, 0);
844 EXPECT_GL_NO_ERROR();
845
846 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::magenta);
847 EXPECT_PIXEL_COLOR_EQ(0, kHeight - 1, GLColor::magenta);
848 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 0, GLColor::magenta);
849 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::magenta);
850 EXPECT_PIXEL_COLOR_EQ(kWidth / 2, kHeight / 2, GLColor::transparentBlack);
851
852 // Draw the triangles partially using stride
853 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
854 glMultiDrawElementsIndirectEXT(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr, 2, icSize * 3);
855 EXPECT_GL_NO_ERROR();
856
857 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::transparentBlack);
858 EXPECT_PIXEL_COLOR_EQ(0, kHeight - 1, GLColor::magenta);
859 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 0, GLColor::transparentBlack);
860 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::magenta);
861 EXPECT_PIXEL_COLOR_EQ(kWidth / 2, kHeight / 2, GLColor::transparentBlack);
862 }
863
864 // Test functionality glMultiDrawElementsIndirectEXT with unsigned short
865 // indices and instanced attributes.
TEST_P(MultiDrawIndirectTest,MultiDrawElementsIndirectInstancedUshort)866 TEST_P(MultiDrawIndirectTest, MultiDrawElementsIndirectInstancedUshort)
867 {
868 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multi_draw_indirect"));
869
870 // Set up the vertex array
871 const GLint triangleCount = 4;
872 const std::vector<GLfloat> vertices = {
873 -1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, -1, 0, 0, -1, 0, -1, -1, 0, -1, 0, 0,
874 };
875 const std::vector<GLushort> indices = {
876 1, 2, 3, 3, 4, 5, 5, 6, 7, 7, 0, 1,
877 };
878 const std::vector<GLuint> instancedColor = {GLColor::white.asUint(), GLColor::red.asUint(),
879 GLColor::green.asUint(), GLColor::blue.asUint()};
880
881 // Generate program
882 SetupProgramIndirect(true);
883
884 // Set up the vertex and index buffers
885 GLVertexArray vao;
886 glBindVertexArray(vao);
887
888 glGenBuffers(1, &mVertexBuffer);
889 glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
890 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * vertices.size(), vertices.data(),
891 GL_STATIC_DRAW);
892 glEnableVertexAttribArray(mPositionLoc);
893 glVertexAttribPointer(mPositionLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
894
895 GLBuffer instanceBuffer;
896 glBindBuffer(GL_ARRAY_BUFFER, instanceBuffer);
897 glBufferData(GL_ARRAY_BUFFER, sizeof(GLuint) * instancedColor.size(), instancedColor.data(),
898 GL_STATIC_DRAW);
899 glEnableVertexAttribArray(mColorLoc);
900 glVertexAttribPointer(mColorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, nullptr);
901 glVertexAttribDivisor(mColorLoc, 1);
902
903 glGenBuffers(1, &mIndexBuffer);
904 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
905 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort) * indices.size(), indices.data(),
906 GL_STATIC_DRAW);
907 EXPECT_GL_NO_ERROR();
908
909 // Set up the indirect data array
910 std::array<DrawElementsIndirectCommand, triangleCount> indirectData;
911 const GLsizei icSize = sizeof(DrawElementsIndirectCommand);
912 for (auto i = 0; i < triangleCount; i++)
913 {
914 indirectData[i] = DrawElementsIndirectCommand(3, 1, 3 * i, 0, i);
915 }
916
917 glGenBuffers(1, &mIndirectBuffer);
918 glBindBuffer(GL_DRAW_INDIRECT_BUFFER, mIndirectBuffer);
919 glBufferData(GL_DRAW_INDIRECT_BUFFER, icSize * indirectData.size(), indirectData.data(),
920 GL_STATIC_DRAW);
921 EXPECT_GL_NO_ERROR();
922
923 // Invalid value check for drawcount and stride
924 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
925 glMultiDrawElementsIndirectEXT(GL_TRIANGLES, GL_UNSIGNED_SHORT, nullptr, 0, 0);
926 EXPECT_GL_ERROR(GL_INVALID_VALUE);
927 glMultiDrawElementsIndirectEXT(GL_TRIANGLES, GL_UNSIGNED_SHORT, nullptr, -1, 0);
928 EXPECT_GL_ERROR(GL_INVALID_VALUE);
929 glMultiDrawElementsIndirectEXT(GL_TRIANGLES, GL_UNSIGNED_SHORT, nullptr, 1, 2);
930 EXPECT_GL_ERROR(GL_INVALID_VALUE);
931
932 // Check the error from sourcing beyond the allocated buffer size
933 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
934 glMultiDrawElementsIndirectEXT(
935 GL_TRIANGLES, GL_UNSIGNED_SHORT,
936 reinterpret_cast<const void *>(static_cast<uintptr_t>(icSize * triangleCount)), 1, 0);
937 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
938
939 // Draw all triangles using glMultiDrawElementsIndirect
940 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
941 glMultiDrawElementsIndirectEXT(GL_TRIANGLES, GL_UNSIGNED_SHORT, nullptr, triangleCount, 0);
942 EXPECT_GL_NO_ERROR();
943
944 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
945 EXPECT_PIXEL_COLOR_EQ(0, kHeight - 1, GLColor::blue);
946 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 0, GLColor::red);
947 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::white);
948 EXPECT_PIXEL_COLOR_EQ(kWidth / 2, kHeight / 2, GLColor::transparentBlack);
949
950 // Draw the triangles in a different order
951 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
952 glMultiDrawElementsIndirectEXT(GL_TRIANGLES, GL_UNSIGNED_SHORT, nullptr, 1, 0);
953 glMultiDrawElementsIndirectEXT(GL_TRIANGLES, GL_UNSIGNED_SHORT,
954 reinterpret_cast<const void *>(static_cast<uintptr_t>(icSize)),
955 triangleCount - 2, 0);
956 glMultiDrawElementsIndirectEXT(
957 GL_TRIANGLES, GL_UNSIGNED_SHORT,
958 reinterpret_cast<const void *>(static_cast<uintptr_t>(icSize * 3)), 1, 0);
959 EXPECT_GL_NO_ERROR();
960
961 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
962 EXPECT_PIXEL_COLOR_EQ(0, kHeight - 1, GLColor::blue);
963 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 0, GLColor::red);
964 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::white);
965 EXPECT_PIXEL_COLOR_EQ(kWidth / 2, kHeight / 2, GLColor::transparentBlack);
966
967 // Draw the triangles partially using stride
968 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
969 glMultiDrawElementsIndirectEXT(GL_TRIANGLES, GL_UNSIGNED_SHORT, nullptr, 2, icSize * 3);
970 EXPECT_GL_NO_ERROR();
971
972 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::transparentBlack);
973 EXPECT_PIXEL_COLOR_EQ(0, kHeight - 1, GLColor::blue);
974 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 0, GLColor::transparentBlack);
975 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::white);
976 EXPECT_PIXEL_COLOR_EQ(kWidth / 2, kHeight / 2, GLColor::transparentBlack);
977 }
978
979 // Tests functionality of glMultiDrawElementsIndirectEXT with more than one triangle in one element
980 // of the indirect buffer.
TEST_P(MultiDrawIndirectTest,MultiDrawElementsIndirectMultipleTriangles)981 TEST_P(MultiDrawIndirectTest, MultiDrawElementsIndirectMultipleTriangles)
982 {
983 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multi_draw_indirect"));
984
985 // Set up the vertex array
986 const GLint triangleCount = 4;
987 const std::vector<GLfloat> vertices = {
988 -1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, -1, 0, 0, -1, 0, -1, -1, 0, -1, 0, 0,
989 };
990 const std::vector<GLuint> indices = {
991 1, 2, 3, 3, 4, 5, 5, 6, 7, 7, 0, 1,
992 };
993
994 // Set up the vertex and index buffers
995 GLVertexArray vao;
996 glBindVertexArray(vao);
997
998 glGenBuffers(1, &mVertexBuffer);
999 glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
1000 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * vertices.size(), vertices.data(),
1001 GL_STATIC_DRAW);
1002
1003 glGenBuffers(1, &mIndexBuffer);
1004 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
1005 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * indices.size(), indices.data(),
1006 GL_STATIC_DRAW);
1007 EXPECT_GL_NO_ERROR();
1008
1009 // Generate program
1010 SetupProgramIndirect(false);
1011
1012 // Set up the vertex array format
1013 glEnableVertexAttribArray(mPositionLoc);
1014 glVertexAttribPointer(mPositionLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
1015 EXPECT_GL_NO_ERROR();
1016
1017 // Set up the indirect data array; first element represents two triangles.
1018 std::array<DrawElementsIndirectCommand, triangleCount - 1> indirectData;
1019 const GLsizei icSize = sizeof(DrawElementsIndirectCommand);
1020 for (auto i = 0; i < triangleCount - 1; i++)
1021 {
1022 if (i == 0)
1023 {
1024 indirectData[i] = DrawElementsIndirectCommand(6, 2, 0, 0, i);
1025 }
1026 else
1027 {
1028 indirectData[i] = DrawElementsIndirectCommand(3, 1, 3 * (i + 1), 0, i);
1029 }
1030 }
1031
1032 glGenBuffers(1, &mIndirectBuffer);
1033 glBindBuffer(GL_DRAW_INDIRECT_BUFFER, mIndirectBuffer);
1034 glBufferData(GL_DRAW_INDIRECT_BUFFER, icSize * indirectData.size(), indirectData.data(),
1035 GL_STATIC_DRAW);
1036 EXPECT_GL_NO_ERROR();
1037
1038 // Draw all triangles using glMultiDrawElementsIndirect
1039 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1040 glMultiDrawElementsIndirectEXT(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr, triangleCount - 1, 0);
1041 EXPECT_GL_NO_ERROR();
1042
1043 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::magenta);
1044 EXPECT_PIXEL_COLOR_EQ(0, kHeight - 1, GLColor::magenta);
1045 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 0, GLColor::magenta);
1046 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::magenta);
1047 EXPECT_PIXEL_COLOR_EQ(kWidth / 2, kHeight / 2, GLColor::transparentBlack);
1048 }
1049
1050 // Tests glMultiDrawElementsIndirectEXT with glMultiDrawElementsANGLE to see if the index buffer
1051 // offset is being reset.
TEST_P(MultiDrawIndirectTest,MultiDrawElementsIndirectCheckBufferOffset)1052 TEST_P(MultiDrawIndirectTest, MultiDrawElementsIndirectCheckBufferOffset)
1053 {
1054 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multi_draw_indirect"));
1055
1056 // Set up the vertex array
1057 const GLint triangleCount = 4;
1058 const std::vector<GLfloat> vertices = {
1059 -1, 0, 0, -1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0,
1060 1, 0, 0, 1, -1, 0, 0, -1, 0, 0, -1, 0, -1, -1, 0, -1, 0, 0,
1061 };
1062 const std::vector<GLfloat> colors = {
1063 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,
1064 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,
1065 };
1066 const std::vector<GLuint> indices = {
1067 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, 1, 2,
1068 };
1069
1070 // Set up the vertex and index buffers
1071 GLVertexArray vao;
1072 glBindVertexArray(vao);
1073
1074 glGenBuffers(1, &mVertexBuffer);
1075 glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
1076 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * vertices.size(), vertices.data(),
1077 GL_STATIC_DRAW);
1078
1079 glGenBuffers(1, &mColorBuffer);
1080 glBindBuffer(GL_ARRAY_BUFFER, mColorBuffer);
1081 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * colors.size(), colors.data(), GL_STATIC_DRAW);
1082
1083 glGenBuffers(1, &mIndexBuffer);
1084 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
1085 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * indices.size(), indices.data(),
1086 GL_STATIC_DRAW);
1087 EXPECT_GL_NO_ERROR();
1088
1089 // Generate program
1090 SetupProgramIndirect(true);
1091
1092 // Set up the vertex array format
1093 glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
1094 glEnableVertexAttribArray(mPositionLoc);
1095 glVertexAttribPointer(mPositionLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
1096 EXPECT_GL_NO_ERROR();
1097
1098 glBindBuffer(GL_ARRAY_BUFFER, mColorBuffer);
1099 glEnableVertexAttribArray(mColorLoc);
1100 glVertexAttribPointer(mColorLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
1101 EXPECT_GL_NO_ERROR();
1102
1103 // Set up the arrays for the direct draw
1104 std::vector<GLsizei> counts(triangleCount, 3);
1105 std::vector<const GLvoid *> indicesDirect(triangleCount);
1106 for (auto i = 0; i < triangleCount; i++)
1107 {
1108 indicesDirect[i] =
1109 reinterpret_cast<GLvoid *>(static_cast<uintptr_t>(i * 3 * sizeof(GLuint)));
1110 }
1111
1112 // Set up the indirect data array for indirect draw
1113 std::array<DrawElementsIndirectCommand, triangleCount> indirectData;
1114 const GLsizei icSize = sizeof(DrawElementsIndirectCommand);
1115 for (auto i = 0; i < triangleCount; i++)
1116 {
1117 indirectData[i] = DrawElementsIndirectCommand(3, 1, 3 * i, 0, i);
1118 }
1119
1120 glGenBuffers(1, &mIndirectBuffer);
1121 glBindBuffer(GL_DRAW_INDIRECT_BUFFER, mIndirectBuffer);
1122 glBufferData(GL_DRAW_INDIRECT_BUFFER, icSize * indirectData.size(), indirectData.data(),
1123 GL_STATIC_DRAW);
1124 EXPECT_GL_NO_ERROR();
1125
1126 // Draw using glMultiDrawElementsIndirect
1127 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1128 glMultiDrawElementsIndirectEXT(
1129 GL_TRIANGLES, GL_UNSIGNED_INT,
1130 reinterpret_cast<const void *>(static_cast<uintptr_t>(icSize * 2)), triangleCount - 2, 0);
1131 EXPECT_GL_NO_ERROR();
1132
1133 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow);
1134 EXPECT_PIXEL_COLOR_EQ(0, kHeight - 1, GLColor::red);
1135 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 0, GLColor::transparentBlack);
1136 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::transparentBlack);
1137 EXPECT_PIXEL_COLOR_EQ(kWidth / 2, kHeight / 2, GLColor::transparentBlack);
1138
1139 // Draw using glMultiDrawElementsANGLE
1140 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1141 glMultiDrawElementsANGLE(GL_TRIANGLES, counts.data(), GL_UNSIGNED_INT, indicesDirect.data(),
1142 triangleCount);
1143 EXPECT_GL_NO_ERROR();
1144
1145 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow);
1146 EXPECT_PIXEL_COLOR_EQ(0, kHeight - 1, GLColor::red);
1147 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 0, GLColor::blue);
1148 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::green);
1149 EXPECT_PIXEL_COLOR_EQ(kWidth / 2, kHeight / 2, GLColor::transparentBlack);
1150
1151 // Draw using glMultiDrawElementsANGLE again
1152 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1153 glMultiDrawElementsANGLE(GL_TRIANGLES, counts.data(), GL_UNSIGNED_INT, indicesDirect.data(),
1154 triangleCount - 1);
1155 EXPECT_GL_NO_ERROR();
1156
1157 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow);
1158 EXPECT_PIXEL_COLOR_EQ(0, kHeight - 1, GLColor::transparentBlack);
1159 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 0, GLColor::blue);
1160 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::green);
1161 EXPECT_PIXEL_COLOR_EQ(kWidth / 2, kHeight / 2, GLColor::transparentBlack);
1162
1163 // Draw using glMultiDrawElementsIndirect again
1164 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1165 glMultiDrawElementsIndirectEXT(
1166 GL_TRIANGLES, GL_UNSIGNED_INT,
1167 reinterpret_cast<const void *>(static_cast<uintptr_t>(icSize * 3)), triangleCount - 3, 0);
1168 EXPECT_GL_NO_ERROR();
1169
1170 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::transparentBlack);
1171 EXPECT_PIXEL_COLOR_EQ(0, kHeight - 1, GLColor::red);
1172 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 0, GLColor::transparentBlack);
1173 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::transparentBlack);
1174 EXPECT_PIXEL_COLOR_EQ(kWidth / 2, kHeight / 2, GLColor::transparentBlack);
1175
1176 // Draw using glMultiDrawElementsIndirect one more time
1177 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1178 glMultiDrawElementsIndirectEXT(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr, triangleCount, 0);
1179 EXPECT_GL_NO_ERROR();
1180
1181 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow);
1182 EXPECT_PIXEL_COLOR_EQ(0, kHeight - 1, GLColor::red);
1183 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 0, GLColor::blue);
1184 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::green);
1185 EXPECT_PIXEL_COLOR_EQ(kWidth / 2, kHeight / 2, GLColor::transparentBlack);
1186 }
1187
1188 // Check that glMultiDraw*Instanced without instancing support results in GL_INVALID_OPERATION
TEST_P(MultiDrawNoInstancingSupportTest,InvalidOperation)1189 TEST_P(MultiDrawNoInstancingSupportTest, InvalidOperation)
1190 {
1191 ANGLE_SKIP_TEST_IF(IsGLExtensionEnabled("GL_ANGLE_instanced_arrays"));
1192 requestMultiDrawExtension();
1193 SetupBuffers();
1194 SetupProgram();
1195
1196 GLint first = 0;
1197 GLsizei count = 3;
1198 GLvoid *indices = nullptr;
1199 GLsizei instances = 1;
1200
1201 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1202 glBindBuffer(GL_ARRAY_BUFFER, mNonIndexedVertexBuffer);
1203 glEnableVertexAttribArray(mPositionLoc);
1204 glVertexAttribPointer(mPositionLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
1205 glMultiDrawArraysInstancedANGLE(GL_TRIANGLES, &first, &count, &instances, 1);
1206 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1207
1208 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1209 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
1210 glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
1211 glEnableVertexAttribArray(mPositionLoc);
1212 glVertexAttribPointer(mPositionLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
1213 glMultiDrawElementsInstancedANGLE(GL_TRIANGLES, &count, GL_UNSIGNED_SHORT, &indices, &instances,
1214 1);
1215 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1216 }
1217
1218 const angle::PlatformParameters platforms[] = {
1219 ES2_D3D9(), ES2_OPENGL(), ES2_OPENGLES(), ES2_VULKAN(),
1220 ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES(),
1221 };
1222
1223 const angle::PlatformParameters es2_platforms[] = {
1224 ES2_D3D9(),
1225 ES2_OPENGL(),
1226 ES2_OPENGLES(),
1227 ES2_VULKAN(),
1228 };
1229
1230 INSTANTIATE_TEST_SUITE_P(
1231 ,
1232 MultiDrawTest,
1233 testing::Combine(
1234 testing::ValuesIn(::angle::FilterTestParams(platforms, ArraySize(platforms))),
1235 testing::Values(DrawIDOption::NoDrawID, DrawIDOption::UseDrawID),
1236 testing::Values(InstancingOption::NoInstancing, InstancingOption::UseInstancing),
1237 testing::Values(BufferDataUsageOption::StaticDraw, BufferDataUsageOption::DynamicDraw)),
1238 PrintToStringParamName());
1239
1240 INSTANTIATE_TEST_SUITE_P(
1241 ,
1242 MultiDrawNoInstancingSupportTest,
1243 testing::Combine(
1244 testing::ValuesIn(::angle::FilterTestParams(es2_platforms, ArraySize(es2_platforms))),
1245 testing::Values(DrawIDOption::NoDrawID, DrawIDOption::UseDrawID),
1246 testing::Values(InstancingOption::UseInstancing),
1247 testing::Values(BufferDataUsageOption::StaticDraw, BufferDataUsageOption::DynamicDraw)),
1248 PrintToStringParamName());
1249
1250 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MultiDrawIndirectTest);
1251
1252 ANGLE_INSTANTIATE_TEST_ES31_AND(MultiDrawIndirectTest,
1253 ES31_VULKAN().disable(Feature::SupportsMultiDrawIndirect));
1254 } // namespace
1255