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 ()__anon83b6334a0111::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__anon83b6334a0111::DrawArraysIndirectCommand93 DrawArraysIndirectCommand() : count(0u), instanceCount(0u), first(0u), baseInstance(0u) {}
DrawArraysIndirectCommand__anon83b6334a0111::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__anon83b6334a0111::DrawElementsIndirectCommand105 DrawElementsIndirectCommand()
106 : count(0), primCount(0), firstIndex(0), baseVertex(0), baseInstance(0)
107 {}
DrawElementsIndirectCommand__anon83b6334a0111::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
CheckDrawResult()366 void CheckDrawResult()
367 {
368 for (uint32_t y = 0; y < kCountY; ++y)
369 {
370 for (uint32_t x = 0; x < kCountX; ++x)
371 {
372 uint32_t center_x = x * kTilePixelSize[0] + kTilePixelSize[0] / 2;
373 uint32_t center_y = y * kTilePixelSize[1] + kTilePixelSize[1] / 2;
374 uint32_t quadID = IsDrawIDTest() ? y * kCountX + x : 0;
375 uint32_t colorID = quadID % 3u;
376 std::array<GLColor, 3> colors = {GLColor(255, 0, 0, 255), GLColor(0, 255, 0, 255),
377 GLColor(0, 0, 255, 255)};
378 GLColor expected = colors[colorID];
379
380 if (IsInstancedTest())
381 {
382 EXPECT_PIXEL_RECT_EQ(center_x / 2 - kPixelCheckSize[0] / 4,
383 center_y / 2 - kPixelCheckSize[1] / 4,
384 kPixelCheckSize[0] / 2, kPixelCheckSize[1] / 2, expected);
385 EXPECT_PIXEL_RECT_EQ(center_x / 2 - kPixelCheckSize[0] / 4 + kWidth / 2,
386 center_y / 2 - kPixelCheckSize[1] / 4,
387 kPixelCheckSize[0] / 2, kPixelCheckSize[1] / 2, expected);
388 EXPECT_PIXEL_RECT_EQ(center_x / 2 - kPixelCheckSize[0] / 4,
389 center_y / 2 - kPixelCheckSize[1] / 4 + kHeight / 2,
390 kPixelCheckSize[0] / 2, kPixelCheckSize[1] / 2, expected);
391 EXPECT_PIXEL_RECT_EQ(center_x / 2 - kPixelCheckSize[0] / 4 + kWidth / 2,
392 center_y / 2 - kPixelCheckSize[1] / 4 + kHeight / 2,
393 kPixelCheckSize[0] / 2, kPixelCheckSize[1] / 2, expected);
394 }
395 else
396 {
397 EXPECT_PIXEL_RECT_EQ(center_x - kPixelCheckSize[0] / 2,
398 center_y - kPixelCheckSize[1] / 2, kPixelCheckSize[0],
399 kPixelCheckSize[1], expected);
400 }
401 }
402 }
403 }
404
TearDown()405 void TearDown() override
406 {
407 if (mNonIndexedVertexBuffer != 0u)
408 {
409 glDeleteBuffers(1, &mNonIndexedVertexBuffer);
410 }
411 if (mVertexBuffer != 0u)
412 {
413 glDeleteBuffers(1, &mVertexBuffer);
414 }
415 if (mIndexBuffer != 0u)
416 {
417 glDeleteBuffers(1, &mIndexBuffer);
418 }
419 if (mInstanceBuffer != 0u)
420 {
421 glDeleteBuffers(1, &mInstanceBuffer);
422 }
423 if (mProgram != 0)
424 {
425 glDeleteProgram(mProgram);
426 }
427 ANGLETestBase::ANGLETestTearDown();
428 }
429
requestMultiDrawExtension()430 bool requestMultiDrawExtension() { return EnsureGLExtensionEnabled("GL_ANGLE_multi_draw"); }
431
requestInstancedExtension()432 bool requestInstancedExtension()
433 {
434 return EnsureGLExtensionEnabled("GL_ANGLE_instanced_arrays");
435 }
436
requestExtensions()437 bool requestExtensions()
438 {
439 if (IsInstancedTest() && getClientMajorVersion() <= 2)
440 {
441 if (!requestInstancedExtension())
442 {
443 return false;
444 }
445 }
446 return requestMultiDrawExtension();
447 }
448
449 std::vector<GLushort> mIndices;
450 std::vector<GLfloat> mVertices;
451 std::vector<GLfloat> mNonIndexedVertices;
452 GLuint mNonIndexedVertexBuffer;
453 GLuint mVertexBuffer;
454 GLuint mIndexBuffer;
455 GLuint mInstanceBuffer;
456 GLuint mProgram;
457 GLint mPositionLoc;
458 GLint mInstanceLoc;
459 };
460
461 class MultiDrawNoInstancingSupportTest : public MultiDrawTest
462 {
SetUp()463 void SetUp() override
464 {
465 ASSERT_LE(getClientMajorVersion(), 2);
466 ASSERT_TRUE(IsInstancedTest());
467 MultiDrawTest::SetUp();
468 }
469 };
470
471 // The tests in MultiDrawIndirectTest check the correctness
472 // of the EXT_multi_draw_indirect extension.
473 // 4 magenta triangles are drawn at the corners of the screen
474 // in different orders from the same vertex and index arrays.
475 class MultiDrawIndirectTest : public ANGLETestBase,
476 public ::testing::TestWithParam<MultiDrawIndirectTestParams>
477 {
478 protected:
MultiDrawIndirectTest()479 MultiDrawIndirectTest()
480 : ANGLETestBase(GetParam()),
481 mPositionLoc(0u),
482 mColorLoc(0u),
483 mVertexBuffer(0u),
484 mColorBuffer(0u),
485 mIndexBuffer(0u),
486 mIndirectBuffer(0u),
487 mProgram(0u)
488 {
489 setWindowWidth(kWidth);
490 setWindowHeight(kHeight);
491 setConfigRedBits(8);
492 setConfigGreenBits(8);
493 setConfigBlueBits(8);
494 setConfigAlphaBits(8);
495 }
496
SetUp()497 void SetUp() override { ANGLETestBase::ANGLETestSetUp(); }
498
SetupProgramIndirect(bool isMultiColor)499 void SetupProgramIndirect(bool isMultiColor)
500 {
501 // Define the vertex and fragment shaders
502 std::stringstream kVS;
503 kVS << R"(#version 310 es
504 in vec3 aPos;
505 )"
506 << (isMultiColor ? R"(in vec4 aColor;
507 out vec4 vColor;)"
508 : "")
509 << R"(
510 void main()
511 {
512 gl_Position = vec4(aPos.x, aPos.y, 0, 1);
513 )" << (isMultiColor ? R"(vColor = vec4(aColor.x, aColor.y, aColor.z, 1.0);)" : "")
514 << R"(
515 })";
516
517 std::stringstream kFS;
518 kFS << R"(#version 310 es
519 precision mediump float;
520 )"
521 << (isMultiColor ? R"(in vec4 vColor;
522 )"
523 : "")
524 << R"(
525 out vec4 colorOut;
526 void main()
527 {
528 )" << (isMultiColor ? R"(colorOut = vColor;)" : R"(colorOut = vec4(1.0, 0.0, 1.0, 1.0);)")
529 << R"(
530 })";
531 mProgram = CompileProgram(kVS.str().c_str(), kFS.str().c_str());
532 EXPECT_GL_NO_ERROR();
533 ASSERT_GE(mProgram, 1u);
534 glUseProgram(mProgram);
535 mPositionLoc = glGetAttribLocation(mProgram, "aPos");
536 mColorLoc = glGetAttribLocation(mProgram, "aColor");
537 }
538
TearDown()539 void TearDown() override
540 {
541 if (mVertexBuffer != 0u)
542 {
543 glDeleteBuffers(1, &mVertexBuffer);
544 }
545 if (mColorBuffer != 0u)
546 {
547 glDeleteBuffers(1, &mColorBuffer);
548 }
549 if (mIndexBuffer != 0u)
550 {
551 glDeleteBuffers(1, &mIndexBuffer);
552 }
553 if (mProgram != 0)
554 {
555 glDeleteProgram(mProgram);
556 }
557 if (mIndirectBuffer != 0u)
558 {
559 glDeleteBuffers(1, &mIndirectBuffer);
560 }
561 ANGLETestBase::ANGLETestTearDown();
562 }
563
564 GLint mPositionLoc;
565 GLint mColorLoc;
566 GLuint mVertexBuffer;
567 GLuint mColorBuffer;
568 GLuint mIndexBuffer;
569 GLuint mIndirectBuffer;
570 GLuint mProgram;
571 };
572
573 // glMultiDraw*ANGLE are emulated and should always be available
TEST_P(MultiDrawTest,RequestExtension)574 TEST_P(MultiDrawTest, RequestExtension)
575 {
576 EXPECT_TRUE(requestMultiDrawExtension());
577 }
578
579 // Test that compile a program with the extension succeeds
TEST_P(MultiDrawTest,CanCompile)580 TEST_P(MultiDrawTest, CanCompile)
581 {
582 ANGLE_SKIP_TEST_IF(!requestExtensions());
583 SetupProgram();
584 }
585
586 // Tests basic functionality of glMultiDrawArraysANGLE
TEST_P(MultiDrawTest,MultiDrawArrays)587 TEST_P(MultiDrawTest, MultiDrawArrays)
588 {
589 ANGLE_SKIP_TEST_IF(!requestExtensions());
590
591 // http://anglebug.com/5265
592 ANGLE_SKIP_TEST_IF(IsInstancedTest() && IsOSX() && IsIntelUHD630Mobile() && IsDesktopOpenGL());
593
594 SetupBuffers();
595 SetupProgram();
596 DoDrawArrays();
597 EXPECT_GL_NO_ERROR();
598 CheckDrawResult();
599 }
600
601 // Tests basic functionality of glMultiDrawElementsANGLE
TEST_P(MultiDrawTest,MultiDrawElements)602 TEST_P(MultiDrawTest, MultiDrawElements)
603 {
604 ANGLE_SKIP_TEST_IF(!requestExtensions());
605 SetupBuffers();
606 SetupProgram();
607 DoDrawElements();
608 EXPECT_GL_NO_ERROR();
609 CheckDrawResult();
610 }
611
612 // Tests basic functionality of glMultiDrawArraysIndirectEXT
TEST_P(MultiDrawIndirectTest,MultiDrawArraysIndirect)613 TEST_P(MultiDrawIndirectTest, MultiDrawArraysIndirect)
614 {
615 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multi_draw_indirect"));
616
617 // Set up the vertex array
618 const GLint triangleCount = 4;
619 const std::vector<GLfloat> vertices = {
620 -1, 1, 0, -1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0,
621 -1, -1, 0, -1, 0, 0, 0, -1, 0, 1, -1, 0, 0, -1, 0, 1, 0, 0,
622 };
623
624 // Set up the vertex buffer
625 GLVertexArray vao;
626 glBindVertexArray(vao);
627
628 glGenBuffers(1, &mVertexBuffer);
629 glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
630 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * vertices.size(), vertices.data(),
631 GL_STATIC_DRAW);
632 EXPECT_GL_NO_ERROR();
633
634 // Generate program
635 SetupProgramIndirect(false);
636
637 // Set up the vertex array format
638 glEnableVertexAttribArray(mPositionLoc);
639 glVertexAttribPointer(mPositionLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
640 EXPECT_GL_NO_ERROR();
641
642 // Set up the indirect data array
643 std::array<DrawArraysIndirectCommand, triangleCount> indirectData;
644 const GLsizei icSize = sizeof(DrawArraysIndirectCommand);
645 for (auto i = 0; i < triangleCount; i++)
646 {
647 indirectData[i] = DrawArraysIndirectCommand(3, 1, 3 * i, i);
648 }
649
650 glGenBuffers(1, &mIndirectBuffer);
651 glBindBuffer(GL_DRAW_INDIRECT_BUFFER, mIndirectBuffer);
652 glBufferData(GL_DRAW_INDIRECT_BUFFER, icSize * indirectData.size(), indirectData.data(),
653 GL_STATIC_DRAW);
654 EXPECT_GL_NO_ERROR();
655
656 // Invalid value check for drawcount and stride
657 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
658 glMultiDrawArraysIndirectEXT(GL_TRIANGLES, nullptr, 0, 0);
659 EXPECT_GL_ERROR(GL_INVALID_VALUE);
660 glMultiDrawArraysIndirectEXT(GL_TRIANGLES, nullptr, -1, 0);
661 EXPECT_GL_ERROR(GL_INVALID_VALUE);
662 glMultiDrawArraysIndirectEXT(GL_TRIANGLES, nullptr, 1, 2);
663 EXPECT_GL_ERROR(GL_INVALID_VALUE);
664
665 // Check the error from sourcing beyond the allocated buffer size
666 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
667 glMultiDrawArraysIndirectEXT(
668 GL_TRIANGLES,
669 reinterpret_cast<const void *>(static_cast<uintptr_t>(icSize * triangleCount)), 1, 0);
670 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
671
672 // Draw all triangles using glMultiDrawArraysIndirect
673 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
674 glMultiDrawArraysIndirectEXT(GL_TRIANGLES, nullptr, triangleCount, 0);
675 EXPECT_GL_NO_ERROR();
676
677 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::magenta);
678 EXPECT_PIXEL_COLOR_EQ(0, kHeight - 1, GLColor::magenta);
679 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 0, GLColor::magenta);
680 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::magenta);
681 EXPECT_PIXEL_COLOR_EQ(kWidth / 2, kHeight / 2, GLColor::transparentBlack);
682
683 // Draw the triangles in different order
684 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
685 glMultiDrawArraysIndirectEXT(GL_TRIANGLES, nullptr, 1, 0);
686 glMultiDrawArraysIndirectEXT(GL_TRIANGLES,
687 reinterpret_cast<const void *>(static_cast<uintptr_t>(icSize * 2)),
688 triangleCount - 2, 0);
689 glMultiDrawArraysIndirectEXT(
690 GL_TRIANGLES, reinterpret_cast<const void *>(static_cast<uintptr_t>(icSize)), 1, 0);
691 EXPECT_GL_NO_ERROR();
692
693 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::magenta);
694 EXPECT_PIXEL_COLOR_EQ(0, kHeight - 1, GLColor::magenta);
695 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 0, GLColor::magenta);
696 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::magenta);
697 EXPECT_PIXEL_COLOR_EQ(kWidth / 2, kHeight / 2, GLColor::transparentBlack);
698
699 // Draw the triangles partially using stride
700 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
701 glMultiDrawArraysIndirectEXT(GL_TRIANGLES, nullptr, 2, icSize * 3);
702 EXPECT_GL_NO_ERROR();
703
704 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::transparentBlack);
705 EXPECT_PIXEL_COLOR_EQ(0, kHeight - 1, GLColor::magenta);
706 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 0, GLColor::magenta);
707 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::transparentBlack);
708 EXPECT_PIXEL_COLOR_EQ(kWidth / 2, kHeight / 2, GLColor::transparentBlack);
709 }
710
711 // Tests basic functionality of glMultiDrawElementsIndirectEXT
TEST_P(MultiDrawIndirectTest,MultiDrawElementsIndirect)712 TEST_P(MultiDrawIndirectTest, MultiDrawElementsIndirect)
713 {
714 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multi_draw_indirect"));
715
716 // Set up the vertex array
717 const GLint triangleCount = 4;
718 const std::vector<GLfloat> vertices = {
719 -1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, -1, 0, 0, -1, 0, -1, -1, 0, -1, 0, 0,
720 };
721 const std::vector<GLuint> indices = {
722 1, 2, 3, 3, 4, 5, 5, 6, 7, 7, 0, 1,
723 };
724
725 // Set up the vertex and index buffers
726 GLVertexArray vao;
727 glBindVertexArray(vao);
728
729 glGenBuffers(1, &mVertexBuffer);
730 glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
731 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * vertices.size(), vertices.data(),
732 GL_STATIC_DRAW);
733
734 glGenBuffers(1, &mIndexBuffer);
735 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
736 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * indices.size(), indices.data(),
737 GL_STATIC_DRAW);
738 EXPECT_GL_NO_ERROR();
739
740 // Generate program
741 SetupProgramIndirect(false);
742
743 // Set up the vertex array format
744 glEnableVertexAttribArray(mPositionLoc);
745 glVertexAttribPointer(mPositionLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
746 EXPECT_GL_NO_ERROR();
747
748 // Set up the indirect data array
749 std::array<DrawElementsIndirectCommand, triangleCount> indirectData;
750 const GLsizei icSize = sizeof(DrawElementsIndirectCommand);
751 for (auto i = 0; i < triangleCount; i++)
752 {
753 indirectData[i] = DrawElementsIndirectCommand(3, 1, 3 * i, 0, i);
754 }
755
756 glGenBuffers(1, &mIndirectBuffer);
757 glBindBuffer(GL_DRAW_INDIRECT_BUFFER, mIndirectBuffer);
758 glBufferData(GL_DRAW_INDIRECT_BUFFER, icSize * indirectData.size(), indirectData.data(),
759 GL_STATIC_DRAW);
760 EXPECT_GL_NO_ERROR();
761
762 // Invalid value check for drawcount and stride
763 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
764 glMultiDrawElementsIndirectEXT(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr, 0, 0);
765 EXPECT_GL_ERROR(GL_INVALID_VALUE);
766 glMultiDrawElementsIndirectEXT(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr, -1, 0);
767 EXPECT_GL_ERROR(GL_INVALID_VALUE);
768 glMultiDrawElementsIndirectEXT(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr, 1, 2);
769 EXPECT_GL_ERROR(GL_INVALID_VALUE);
770
771 // Check the error from sourcing beyond the allocated buffer size
772 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
773 glMultiDrawElementsIndirectEXT(
774 GL_TRIANGLES, GL_UNSIGNED_INT,
775 reinterpret_cast<const void *>(static_cast<uintptr_t>(icSize * triangleCount)), 1, 0);
776 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
777
778 // Draw all triangles using glMultiDrawElementsIndirect
779 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
780 glMultiDrawElementsIndirectEXT(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr, triangleCount, 0);
781 EXPECT_GL_NO_ERROR();
782
783 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::magenta);
784 EXPECT_PIXEL_COLOR_EQ(0, kHeight - 1, GLColor::magenta);
785 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 0, GLColor::magenta);
786 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::magenta);
787 EXPECT_PIXEL_COLOR_EQ(kWidth / 2, kHeight / 2, GLColor::transparentBlack);
788
789 // Draw the triangles in a different order
790 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
791 glMultiDrawElementsIndirectEXT(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr, 1, 0);
792 glMultiDrawElementsIndirectEXT(GL_TRIANGLES, GL_UNSIGNED_INT,
793 reinterpret_cast<const void *>(static_cast<uintptr_t>(icSize)),
794 triangleCount - 2, 0);
795 glMultiDrawElementsIndirectEXT(
796 GL_TRIANGLES, GL_UNSIGNED_INT,
797 reinterpret_cast<const void *>(static_cast<uintptr_t>(icSize * 3)), 1, 0);
798 EXPECT_GL_NO_ERROR();
799
800 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::magenta);
801 EXPECT_PIXEL_COLOR_EQ(0, kHeight - 1, GLColor::magenta);
802 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 0, GLColor::magenta);
803 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::magenta);
804 EXPECT_PIXEL_COLOR_EQ(kWidth / 2, kHeight / 2, GLColor::transparentBlack);
805
806 // Draw the triangles partially using stride
807 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
808 glMultiDrawElementsIndirectEXT(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr, 2, icSize * 3);
809 EXPECT_GL_NO_ERROR();
810
811 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::transparentBlack);
812 EXPECT_PIXEL_COLOR_EQ(0, kHeight - 1, GLColor::magenta);
813 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 0, GLColor::transparentBlack);
814 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::magenta);
815 EXPECT_PIXEL_COLOR_EQ(kWidth / 2, kHeight / 2, GLColor::transparentBlack);
816 }
817
818 // Tests functionality of glMultiDrawElementsIndirectEXT with more than one triangle in one element
819 // of the indirect buffer.
TEST_P(MultiDrawIndirectTest,MultiDrawElementsIndirectMultipleTriangles)820 TEST_P(MultiDrawIndirectTest, MultiDrawElementsIndirectMultipleTriangles)
821 {
822 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multi_draw_indirect"));
823
824 // Set up the vertex array
825 const GLint triangleCount = 4;
826 const std::vector<GLfloat> vertices = {
827 -1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, -1, 0, 0, -1, 0, -1, -1, 0, -1, 0, 0,
828 };
829 const std::vector<GLuint> indices = {
830 1, 2, 3, 3, 4, 5, 5, 6, 7, 7, 0, 1,
831 };
832
833 // Set up the vertex and index buffers
834 GLVertexArray vao;
835 glBindVertexArray(vao);
836
837 glGenBuffers(1, &mVertexBuffer);
838 glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
839 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * vertices.size(), vertices.data(),
840 GL_STATIC_DRAW);
841
842 glGenBuffers(1, &mIndexBuffer);
843 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
844 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * indices.size(), indices.data(),
845 GL_STATIC_DRAW);
846 EXPECT_GL_NO_ERROR();
847
848 // Generate program
849 SetupProgramIndirect(false);
850
851 // Set up the vertex array format
852 glEnableVertexAttribArray(mPositionLoc);
853 glVertexAttribPointer(mPositionLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
854 EXPECT_GL_NO_ERROR();
855
856 // Set up the indirect data array; first element represents two triangles.
857 std::array<DrawElementsIndirectCommand, triangleCount - 1> indirectData;
858 const GLsizei icSize = sizeof(DrawElementsIndirectCommand);
859 for (auto i = 0; i < triangleCount - 1; i++)
860 {
861 if (i == 0)
862 {
863 indirectData[i] = DrawElementsIndirectCommand(6, 2, 0, 0, i);
864 }
865 else
866 {
867 indirectData[i] = DrawElementsIndirectCommand(3, 1, 3 * (i + 1), 0, i);
868 }
869 }
870
871 glGenBuffers(1, &mIndirectBuffer);
872 glBindBuffer(GL_DRAW_INDIRECT_BUFFER, mIndirectBuffer);
873 glBufferData(GL_DRAW_INDIRECT_BUFFER, icSize * indirectData.size(), indirectData.data(),
874 GL_STATIC_DRAW);
875 EXPECT_GL_NO_ERROR();
876
877 // Draw all triangles using glMultiDrawElementsIndirect
878 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
879 glMultiDrawElementsIndirectEXT(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr, triangleCount - 1, 0);
880 EXPECT_GL_NO_ERROR();
881
882 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::magenta);
883 EXPECT_PIXEL_COLOR_EQ(0, kHeight - 1, GLColor::magenta);
884 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 0, GLColor::magenta);
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 // Tests glMultiDrawElementsIndirectEXT with glMultiDrawElementsANGLE to see if the index buffer
890 // offset is being reset.
TEST_P(MultiDrawIndirectTest,MultiDrawElementsIndirectCheckBufferOffset)891 TEST_P(MultiDrawIndirectTest, MultiDrawElementsIndirectCheckBufferOffset)
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, 0, 0, -1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0,
899 1, 0, 0, 1, -1, 0, 0, -1, 0, 0, -1, 0, -1, -1, 0, -1, 0, 0,
900 };
901 const std::vector<GLfloat> colors = {
902 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,
903 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,
904 };
905 const std::vector<GLuint> indices = {
906 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, 1, 2,
907 };
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
918 glGenBuffers(1, &mColorBuffer);
919 glBindBuffer(GL_ARRAY_BUFFER, mColorBuffer);
920 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * colors.size(), colors.data(), GL_STATIC_DRAW);
921
922 glGenBuffers(1, &mIndexBuffer);
923 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
924 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * indices.size(), indices.data(),
925 GL_STATIC_DRAW);
926 EXPECT_GL_NO_ERROR();
927
928 // Generate program
929 SetupProgramIndirect(true);
930
931 // Set up the vertex array format
932 glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
933 glEnableVertexAttribArray(mPositionLoc);
934 glVertexAttribPointer(mPositionLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
935 EXPECT_GL_NO_ERROR();
936
937 glBindBuffer(GL_ARRAY_BUFFER, mColorBuffer);
938 glEnableVertexAttribArray(mColorLoc);
939 glVertexAttribPointer(mColorLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
940 EXPECT_GL_NO_ERROR();
941
942 // Set up the arrays for the direct draw
943 std::vector<GLsizei> counts(triangleCount, 3);
944 std::vector<const GLvoid *> indicesDirect(triangleCount);
945 for (auto i = 0; i < triangleCount; i++)
946 {
947 indicesDirect[i] =
948 reinterpret_cast<GLvoid *>(static_cast<uintptr_t>(i * 3 * sizeof(GLuint)));
949 }
950
951 // Set up the indirect data array for indirect draw
952 std::array<DrawElementsIndirectCommand, triangleCount> indirectData;
953 const GLsizei icSize = sizeof(DrawElementsIndirectCommand);
954 for (auto i = 0; i < triangleCount; i++)
955 {
956 indirectData[i] = DrawElementsIndirectCommand(3, 1, 3 * i, 0, i);
957 }
958
959 glGenBuffers(1, &mIndirectBuffer);
960 glBindBuffer(GL_DRAW_INDIRECT_BUFFER, mIndirectBuffer);
961 glBufferData(GL_DRAW_INDIRECT_BUFFER, icSize * indirectData.size(), indirectData.data(),
962 GL_STATIC_DRAW);
963 EXPECT_GL_NO_ERROR();
964
965 // Draw using glMultiDrawElementsIndirect
966 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
967 glMultiDrawElementsIndirectEXT(
968 GL_TRIANGLES, GL_UNSIGNED_INT,
969 reinterpret_cast<const void *>(static_cast<uintptr_t>(icSize * 2)), triangleCount - 2, 0);
970 EXPECT_GL_NO_ERROR();
971
972 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow);
973 EXPECT_PIXEL_COLOR_EQ(0, kHeight - 1, GLColor::red);
974 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 0, GLColor::transparentBlack);
975 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::transparentBlack);
976 EXPECT_PIXEL_COLOR_EQ(kWidth / 2, kHeight / 2, GLColor::transparentBlack);
977
978 // Draw using glMultiDrawElementsANGLE
979 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
980 glMultiDrawElementsANGLE(GL_TRIANGLES, counts.data(), GL_UNSIGNED_INT, indicesDirect.data(),
981 triangleCount);
982 EXPECT_GL_NO_ERROR();
983
984 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow);
985 EXPECT_PIXEL_COLOR_EQ(0, kHeight - 1, GLColor::red);
986 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 0, GLColor::blue);
987 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::green);
988 EXPECT_PIXEL_COLOR_EQ(kWidth / 2, kHeight / 2, GLColor::transparentBlack);
989
990 // Draw using glMultiDrawElementsANGLE again
991 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
992 glMultiDrawElementsANGLE(GL_TRIANGLES, counts.data(), GL_UNSIGNED_INT, indicesDirect.data(),
993 triangleCount - 1);
994 EXPECT_GL_NO_ERROR();
995
996 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow);
997 EXPECT_PIXEL_COLOR_EQ(0, kHeight - 1, GLColor::transparentBlack);
998 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 0, GLColor::blue);
999 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::green);
1000 EXPECT_PIXEL_COLOR_EQ(kWidth / 2, kHeight / 2, GLColor::transparentBlack);
1001
1002 // Draw using glMultiDrawElementsIndirect again
1003 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1004 glMultiDrawElementsIndirectEXT(
1005 GL_TRIANGLES, GL_UNSIGNED_INT,
1006 reinterpret_cast<const void *>(static_cast<uintptr_t>(icSize * 3)), triangleCount - 3, 0);
1007 EXPECT_GL_NO_ERROR();
1008
1009 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::transparentBlack);
1010 EXPECT_PIXEL_COLOR_EQ(0, kHeight - 1, GLColor::red);
1011 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 0, GLColor::transparentBlack);
1012 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::transparentBlack);
1013 EXPECT_PIXEL_COLOR_EQ(kWidth / 2, kHeight / 2, GLColor::transparentBlack);
1014
1015 // Draw using glMultiDrawElementsIndirect one more time
1016 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1017 glMultiDrawElementsIndirectEXT(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr, triangleCount, 0);
1018 EXPECT_GL_NO_ERROR();
1019
1020 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow);
1021 EXPECT_PIXEL_COLOR_EQ(0, kHeight - 1, GLColor::red);
1022 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 0, GLColor::blue);
1023 EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::green);
1024 EXPECT_PIXEL_COLOR_EQ(kWidth / 2, kHeight / 2, GLColor::transparentBlack);
1025 }
1026
1027 // Check that glMultiDraw*Instanced without instancing support results in GL_INVALID_OPERATION
TEST_P(MultiDrawNoInstancingSupportTest,InvalidOperation)1028 TEST_P(MultiDrawNoInstancingSupportTest, InvalidOperation)
1029 {
1030 ANGLE_SKIP_TEST_IF(IsGLExtensionEnabled("GL_ANGLE_instanced_arrays"));
1031 requestMultiDrawExtension();
1032 SetupBuffers();
1033 SetupProgram();
1034
1035 GLint first = 0;
1036 GLsizei count = 3;
1037 GLvoid *indices = nullptr;
1038 GLsizei instances = 1;
1039
1040 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1041 glBindBuffer(GL_ARRAY_BUFFER, mNonIndexedVertexBuffer);
1042 glEnableVertexAttribArray(mPositionLoc);
1043 glVertexAttribPointer(mPositionLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
1044 glMultiDrawArraysInstancedANGLE(GL_TRIANGLES, &first, &count, &instances, 1);
1045 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1046
1047 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1048 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
1049 glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
1050 glEnableVertexAttribArray(mPositionLoc);
1051 glVertexAttribPointer(mPositionLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
1052 glMultiDrawElementsInstancedANGLE(GL_TRIANGLES, &count, GL_UNSIGNED_SHORT, &indices, &instances,
1053 1);
1054 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1055 }
1056
1057 const angle::PlatformParameters platforms[] = {
1058 ES2_D3D9(), ES2_OPENGL(), ES2_OPENGLES(), ES2_VULKAN(),
1059 ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES(),
1060 };
1061
1062 const angle::PlatformParameters es2_platforms[] = {
1063 ES2_D3D9(),
1064 ES2_OPENGL(),
1065 ES2_OPENGLES(),
1066 ES2_VULKAN(),
1067 };
1068
1069 INSTANTIATE_TEST_SUITE_P(
1070 ,
1071 MultiDrawTest,
1072 testing::Combine(
1073 testing::ValuesIn(::angle::FilterTestParams(platforms, ArraySize(platforms))),
1074 testing::Values(DrawIDOption::NoDrawID, DrawIDOption::UseDrawID),
1075 testing::Values(InstancingOption::NoInstancing, InstancingOption::UseInstancing),
1076 testing::Values(BufferDataUsageOption::StaticDraw, BufferDataUsageOption::DynamicDraw)),
1077 PrintToStringParamName());
1078
1079 INSTANTIATE_TEST_SUITE_P(
1080 ,
1081 MultiDrawNoInstancingSupportTest,
1082 testing::Combine(
1083 testing::ValuesIn(::angle::FilterTestParams(es2_platforms, ArraySize(es2_platforms))),
1084 testing::Values(DrawIDOption::NoDrawID, DrawIDOption::UseDrawID),
1085 testing::Values(InstancingOption::UseInstancing),
1086 testing::Values(BufferDataUsageOption::StaticDraw, BufferDataUsageOption::DynamicDraw)),
1087 PrintToStringParamName());
1088
1089 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MultiDrawIndirectTest);
1090
1091 ANGLE_INSTANTIATE_TEST_ES31_AND(MultiDrawIndirectTest,
1092 ES31_VULKAN().disable(Feature::SupportsMultiDrawIndirect));
1093 } // namespace
1094