• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 ()__anonff24a2230111::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__anonff24a2230111::DrawArraysIndirectCommand93     DrawArraysIndirectCommand() : count(0u), instanceCount(0u), first(0u), baseInstance(0u) {}
DrawArraysIndirectCommand__anonff24a2230111::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__anonff24a2230111::DrawElementsIndirectCommand105     DrawElementsIndirectCommand()
106         : count(0), primCount(0), firstIndex(0), baseVertex(0), baseInstance(0)
107     {}
DrawElementsIndirectCommand__anonff24a2230111::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           mVertexBuffer(0u),
483           mIndexBuffer(0u),
484           mIndirectBuffer(0u),
485           mProgram(0u)
486     {
487         setWindowWidth(kWidth);
488         setWindowHeight(kHeight);
489         setConfigRedBits(8);
490         setConfigGreenBits(8);
491         setConfigBlueBits(8);
492         setConfigAlphaBits(8);
493     }
494 
SetUp()495     void SetUp() override { ANGLETestBase::ANGLETestSetUp(); }
496 
SetupProgramIndirect()497     void SetupProgramIndirect()
498     {
499         // Define the vertex and fragment shaders
500         constexpr char kVS[] = R"(#version 310 es
501 in vec3 aPos;
502 void main()
503 {
504     gl_Position = vec4(aPos.x, aPos.y, 0, 1);
505 })";
506 
507         constexpr char kFS[] = R"(#version 310 es
508 precision mediump float;
509 out vec4 colorOut;
510 void main()
511 {
512     colorOut = vec4(1.0, 0.0, 1.0, 1.0);
513 })";
514         mProgram             = CompileProgram(kVS, kFS);
515         EXPECT_GL_NO_ERROR();
516         ASSERT_GE(mProgram, 1u);
517         glUseProgram(mProgram);
518         mPositionLoc = glGetAttribLocation(mProgram, "aPos");
519     }
520 
TearDown()521     void TearDown() override
522     {
523         if (mVertexBuffer != 0u)
524         {
525             glDeleteBuffers(1, &mVertexBuffer);
526         }
527         if (mIndexBuffer != 0u)
528         {
529             glDeleteBuffers(1, &mIndexBuffer);
530         }
531         if (mProgram != 0)
532         {
533             glDeleteProgram(mProgram);
534         }
535         if (mIndirectBuffer != 0u)
536         {
537             glDeleteBuffers(1, &mIndirectBuffer);
538         }
539         ANGLETestBase::ANGLETestTearDown();
540     }
541 
542     GLint mPositionLoc;
543     GLuint mVertexBuffer;
544     GLuint mIndexBuffer;
545     GLuint mIndirectBuffer;
546     GLuint mProgram;
547 };
548 
549 // glMultiDraw*ANGLE are emulated and should always be available
TEST_P(MultiDrawTest,RequestExtension)550 TEST_P(MultiDrawTest, RequestExtension)
551 {
552     EXPECT_TRUE(requestMultiDrawExtension());
553 }
554 
555 // Test that compile a program with the extension succeeds
TEST_P(MultiDrawTest,CanCompile)556 TEST_P(MultiDrawTest, CanCompile)
557 {
558     ANGLE_SKIP_TEST_IF(!requestExtensions());
559     SetupProgram();
560 }
561 
562 // Tests basic functionality of glMultiDrawArraysANGLE
TEST_P(MultiDrawTest,MultiDrawArrays)563 TEST_P(MultiDrawTest, MultiDrawArrays)
564 {
565     ANGLE_SKIP_TEST_IF(!requestExtensions());
566 
567     // http://anglebug.com/5265
568     ANGLE_SKIP_TEST_IF(IsInstancedTest() && IsOSX() && IsIntelUHD630Mobile() && IsDesktopOpenGL());
569 
570     SetupBuffers();
571     SetupProgram();
572     DoDrawArrays();
573     EXPECT_GL_NO_ERROR();
574     CheckDrawResult();
575 }
576 
577 // Tests basic functionality of glMultiDrawElementsANGLE
TEST_P(MultiDrawTest,MultiDrawElements)578 TEST_P(MultiDrawTest, MultiDrawElements)
579 {
580     ANGLE_SKIP_TEST_IF(!requestExtensions());
581     SetupBuffers();
582     SetupProgram();
583     DoDrawElements();
584     EXPECT_GL_NO_ERROR();
585     CheckDrawResult();
586 }
587 
588 // Tests basic functionality of glMultiDrawArraysIndirectEXT
TEST_P(MultiDrawIndirectTest,MultiDrawArraysIndirect)589 TEST_P(MultiDrawIndirectTest, MultiDrawArraysIndirect)
590 {
591     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multi_draw_indirect"));
592 
593     // Set up the vertex array
594     const GLint triangleCount           = 4;
595     const std::vector<GLfloat> vertices = {
596         -1, 1,  0, -1, 0, 0, 0, 1,  0, 1, 1,  0, 1, 0,  0, 0, 1, 0,
597         -1, -1, 0, -1, 0, 0, 0, -1, 0, 1, -1, 0, 0, -1, 0, 1, 0, 0,
598     };
599 
600     // Set up the vertex buffer
601     GLVertexArray vao;
602     glBindVertexArray(vao);
603 
604     glGenBuffers(1, &mVertexBuffer);
605     glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
606     glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * vertices.size(), vertices.data(),
607                  GL_STATIC_DRAW);
608     EXPECT_GL_NO_ERROR();
609 
610     // Generate program
611     SetupProgramIndirect();
612 
613     // Set up the vertex array format
614     glEnableVertexAttribArray(mPositionLoc);
615     glVertexAttribPointer(mPositionLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
616     EXPECT_GL_NO_ERROR();
617 
618     // Set up the indirect data array
619     std::array<DrawArraysIndirectCommand, triangleCount> indirectData;
620     const GLsizei icSize = sizeof(DrawArraysIndirectCommand);
621     for (auto i = 0; i < triangleCount; i++)
622     {
623         indirectData[i] = DrawArraysIndirectCommand(3, 1, 3 * i, i);
624     }
625 
626     glGenBuffers(1, &mIndirectBuffer);
627     glBindBuffer(GL_DRAW_INDIRECT_BUFFER, mIndirectBuffer);
628     glBufferData(GL_DRAW_INDIRECT_BUFFER, icSize * indirectData.size(), indirectData.data(),
629                  GL_STATIC_DRAW);
630     EXPECT_GL_NO_ERROR();
631 
632     // Invalid value check for drawcount and stride
633     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
634     glMultiDrawArraysIndirectEXT(GL_TRIANGLES, nullptr, 0, 0);
635     EXPECT_GL_ERROR(GL_INVALID_VALUE);
636     glMultiDrawArraysIndirectEXT(GL_TRIANGLES, nullptr, -1, 0);
637     EXPECT_GL_ERROR(GL_INVALID_VALUE);
638     glMultiDrawArraysIndirectEXT(GL_TRIANGLES, nullptr, 1, 2);
639     EXPECT_GL_ERROR(GL_INVALID_VALUE);
640 
641     // Check the error from sourcing beyond the allocated buffer size
642     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
643     glMultiDrawArraysIndirectEXT(
644         GL_TRIANGLES,
645         reinterpret_cast<const void *>(static_cast<uintptr_t>(icSize * triangleCount)), 1, 0);
646     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
647 
648     // Draw all triangles using glMultiDrawArraysIndirect
649     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
650     glMultiDrawArraysIndirectEXT(GL_TRIANGLES, nullptr, triangleCount, 0);
651     EXPECT_GL_NO_ERROR();
652 
653     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::magenta);
654     EXPECT_PIXEL_COLOR_EQ(0, kHeight - 1, GLColor::magenta);
655     EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 0, GLColor::magenta);
656     EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::magenta);
657     EXPECT_PIXEL_COLOR_EQ(kWidth / 2, kHeight / 2, GLColor::transparentBlack);
658 
659     // Draw the triangles in different order
660     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
661     glMultiDrawArraysIndirectEXT(GL_TRIANGLES, nullptr, 1, 0);
662     glMultiDrawArraysIndirectEXT(GL_TRIANGLES,
663                                  reinterpret_cast<const void *>(static_cast<uintptr_t>(icSize * 2)),
664                                  triangleCount - 2, 0);
665     glMultiDrawArraysIndirectEXT(
666         GL_TRIANGLES, reinterpret_cast<const void *>(static_cast<uintptr_t>(icSize)), 1, 0);
667     EXPECT_GL_NO_ERROR();
668 
669     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::magenta);
670     EXPECT_PIXEL_COLOR_EQ(0, kHeight - 1, GLColor::magenta);
671     EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 0, GLColor::magenta);
672     EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::magenta);
673     EXPECT_PIXEL_COLOR_EQ(kWidth / 2, kHeight / 2, GLColor::transparentBlack);
674 
675     // Draw the triangles partially using stride
676     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
677     glMultiDrawArraysIndirectEXT(GL_TRIANGLES, nullptr, 2, icSize * 3);
678     EXPECT_GL_NO_ERROR();
679 
680     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::transparentBlack);
681     EXPECT_PIXEL_COLOR_EQ(0, kHeight - 1, GLColor::magenta);
682     EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 0, GLColor::magenta);
683     EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::transparentBlack);
684     EXPECT_PIXEL_COLOR_EQ(kWidth / 2, kHeight / 2, GLColor::transparentBlack);
685 }
686 
687 // Tests basic functionality of glMultiDrawElementsIndirectEXT
TEST_P(MultiDrawIndirectTest,MultiDrawElementsIndirect)688 TEST_P(MultiDrawIndirectTest, MultiDrawElementsIndirect)
689 {
690     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multi_draw_indirect"));
691 
692     // Set up the vertex array
693     const GLint triangleCount           = 4;
694     const std::vector<GLfloat> vertices = {
695         -1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, -1, 0, 0, -1, 0, -1, -1, 0, -1, 0, 0,
696     };
697     const std::vector<GLuint> indices = {
698         1, 2, 3, 3, 4, 5, 5, 6, 7, 7, 0, 1,
699     };
700 
701     // Set up the vertex and index buffers
702     GLVertexArray vao;
703     glBindVertexArray(vao);
704 
705     glGenBuffers(1, &mVertexBuffer);
706     glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
707     glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * vertices.size(), vertices.data(),
708                  GL_STATIC_DRAW);
709 
710     glGenBuffers(1, &mIndexBuffer);
711     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
712     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * indices.size(), indices.data(),
713                  GL_STATIC_DRAW);
714     EXPECT_GL_NO_ERROR();
715 
716     // Generate program
717     SetupProgramIndirect();
718 
719     // Set up the vertex array format
720     glEnableVertexAttribArray(mPositionLoc);
721     glVertexAttribPointer(mPositionLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
722     EXPECT_GL_NO_ERROR();
723 
724     // Set up the indirect data array
725     std::array<DrawElementsIndirectCommand, triangleCount> indirectData;
726     const GLsizei icSize = sizeof(DrawElementsIndirectCommand);
727     for (auto i = 0; i < triangleCount; i++)
728     {
729         indirectData[i] = DrawElementsIndirectCommand(3, 1, 3 * i, 0, i);
730     }
731 
732     glGenBuffers(1, &mIndirectBuffer);
733     glBindBuffer(GL_DRAW_INDIRECT_BUFFER, mIndirectBuffer);
734     glBufferData(GL_DRAW_INDIRECT_BUFFER, icSize * indirectData.size(), indirectData.data(),
735                  GL_STATIC_DRAW);
736     EXPECT_GL_NO_ERROR();
737 
738     // Invalid value check for drawcount and stride
739     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
740     glMultiDrawElementsIndirectEXT(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr, 0, 0);
741     EXPECT_GL_ERROR(GL_INVALID_VALUE);
742     glMultiDrawElementsIndirectEXT(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr, -1, 0);
743     EXPECT_GL_ERROR(GL_INVALID_VALUE);
744     glMultiDrawElementsIndirectEXT(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr, 1, 2);
745     EXPECT_GL_ERROR(GL_INVALID_VALUE);
746 
747     // Check the error from sourcing beyond the allocated buffer size
748     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
749     glMultiDrawElementsIndirectEXT(
750         GL_TRIANGLES, GL_UNSIGNED_INT,
751         reinterpret_cast<const void *>(static_cast<uintptr_t>(icSize * triangleCount)), 1, 0);
752     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
753 
754     // Draw all triangles using glMultiDrawElementsIndirect
755     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
756     glMultiDrawElementsIndirectEXT(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr, triangleCount, 0);
757     EXPECT_GL_NO_ERROR();
758 
759     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::magenta);
760     EXPECT_PIXEL_COLOR_EQ(0, kHeight - 1, GLColor::magenta);
761     EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 0, GLColor::magenta);
762     EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::magenta);
763     EXPECT_PIXEL_COLOR_EQ(kWidth / 2, kHeight / 2, GLColor::transparentBlack);
764 
765     // Draw the triangles in a different order
766     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
767     glMultiDrawElementsIndirectEXT(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr, 1, 0);
768     glMultiDrawElementsIndirectEXT(GL_TRIANGLES, GL_UNSIGNED_INT,
769                                    reinterpret_cast<const void *>(static_cast<uintptr_t>(icSize)),
770                                    triangleCount - 2, 0);
771     glMultiDrawElementsIndirectEXT(
772         GL_TRIANGLES, GL_UNSIGNED_INT,
773         reinterpret_cast<const void *>(static_cast<uintptr_t>(icSize * 3)), 1, 0);
774     EXPECT_GL_NO_ERROR();
775 
776     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::magenta);
777     EXPECT_PIXEL_COLOR_EQ(0, kHeight - 1, GLColor::magenta);
778     EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 0, GLColor::magenta);
779     EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::magenta);
780     EXPECT_PIXEL_COLOR_EQ(kWidth / 2, kHeight / 2, GLColor::transparentBlack);
781 
782     // Draw the triangles partially using stride
783     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
784     glMultiDrawElementsIndirectEXT(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr, 2, icSize * 3);
785     EXPECT_GL_NO_ERROR();
786 
787     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::transparentBlack);
788     EXPECT_PIXEL_COLOR_EQ(0, kHeight - 1, GLColor::magenta);
789     EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 0, GLColor::transparentBlack);
790     EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::magenta);
791     EXPECT_PIXEL_COLOR_EQ(kWidth / 2, kHeight / 2, GLColor::transparentBlack);
792 }
793 
794 // Tests functionality of glMultiDrawElementsIndirectEXT with more than one triangle in one element
795 // of the indirect buffer.
TEST_P(MultiDrawIndirectTest,MultiDrawElementsIndirectMultipleTriangles)796 TEST_P(MultiDrawIndirectTest, MultiDrawElementsIndirectMultipleTriangles)
797 {
798     ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_multi_draw_indirect"));
799 
800     // Set up the vertex array
801     const GLint triangleCount           = 4;
802     const std::vector<GLfloat> vertices = {
803         -1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, -1, 0, 0, -1, 0, -1, -1, 0, -1, 0, 0,
804     };
805     const std::vector<GLuint> indices = {
806         1, 2, 3, 3, 4, 5, 5, 6, 7, 7, 0, 1,
807     };
808 
809     // Set up the vertex and index buffers
810     GLVertexArray vao;
811     glBindVertexArray(vao);
812 
813     glGenBuffers(1, &mVertexBuffer);
814     glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
815     glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * vertices.size(), vertices.data(),
816                  GL_STATIC_DRAW);
817 
818     glGenBuffers(1, &mIndexBuffer);
819     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
820     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * indices.size(), indices.data(),
821                  GL_STATIC_DRAW);
822     EXPECT_GL_NO_ERROR();
823 
824     // Generate program
825     SetupProgramIndirect();
826 
827     // Set up the vertex array format
828     glEnableVertexAttribArray(mPositionLoc);
829     glVertexAttribPointer(mPositionLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
830     EXPECT_GL_NO_ERROR();
831 
832     // Set up the indirect data array; first element represents two triangles.
833     std::array<DrawElementsIndirectCommand, triangleCount - 1> indirectData;
834     const GLsizei icSize = sizeof(DrawElementsIndirectCommand);
835     for (auto i = 0; i < triangleCount - 1; i++)
836     {
837         if (i == 0)
838         {
839             indirectData[i] = DrawElementsIndirectCommand(6, 2, 0, 0, i);
840         }
841         else
842         {
843             indirectData[i] = DrawElementsIndirectCommand(3, 1, 3 * (i + 1), 0, i);
844         }
845     }
846 
847     glGenBuffers(1, &mIndirectBuffer);
848     glBindBuffer(GL_DRAW_INDIRECT_BUFFER, mIndirectBuffer);
849     glBufferData(GL_DRAW_INDIRECT_BUFFER, icSize * indirectData.size(), indirectData.data(),
850                  GL_STATIC_DRAW);
851     EXPECT_GL_NO_ERROR();
852 
853     // Draw all triangles using glMultiDrawElementsIndirect
854     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
855     glMultiDrawElementsIndirectEXT(GL_TRIANGLES, GL_UNSIGNED_INT, nullptr, triangleCount - 1, 0);
856     EXPECT_GL_NO_ERROR();
857 
858     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::magenta);
859     EXPECT_PIXEL_COLOR_EQ(0, kHeight - 1, GLColor::magenta);
860     EXPECT_PIXEL_COLOR_EQ(kWidth - 1, 0, GLColor::magenta);
861     EXPECT_PIXEL_COLOR_EQ(kWidth - 1, kHeight - 1, GLColor::magenta);
862     EXPECT_PIXEL_COLOR_EQ(kWidth / 2, kHeight / 2, GLColor::transparentBlack);
863 }
864 
865 // Check that glMultiDraw*Instanced without instancing support results in GL_INVALID_OPERATION
TEST_P(MultiDrawNoInstancingSupportTest,InvalidOperation)866 TEST_P(MultiDrawNoInstancingSupportTest, InvalidOperation)
867 {
868     ANGLE_SKIP_TEST_IF(IsGLExtensionEnabled("GL_ANGLE_instanced_arrays"));
869     requestMultiDrawExtension();
870     SetupBuffers();
871     SetupProgram();
872 
873     GLint first       = 0;
874     GLsizei count     = 3;
875     GLvoid *indices   = nullptr;
876     GLsizei instances = 1;
877 
878     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
879     glBindBuffer(GL_ARRAY_BUFFER, mNonIndexedVertexBuffer);
880     glEnableVertexAttribArray(mPositionLoc);
881     glVertexAttribPointer(mPositionLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
882     glMultiDrawArraysInstancedANGLE(GL_TRIANGLES, &first, &count, &instances, 1);
883     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
884 
885     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
886     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer);
887     glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
888     glEnableVertexAttribArray(mPositionLoc);
889     glVertexAttribPointer(mPositionLoc, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
890     glMultiDrawElementsInstancedANGLE(GL_TRIANGLES, &count, GL_UNSIGNED_SHORT, &indices, &instances,
891                                       1);
892     EXPECT_GL_ERROR(GL_INVALID_OPERATION);
893 }
894 
895 const angle::PlatformParameters platforms[] = {
896     ES2_D3D9(),  ES2_OPENGL(), ES2_OPENGLES(), ES2_VULKAN(),
897     ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES(),
898 };
899 
900 const angle::PlatformParameters es2_platforms[] = {
901     ES2_D3D9(),
902     ES2_OPENGL(),
903     ES2_OPENGLES(),
904     ES2_VULKAN(),
905 };
906 
907 INSTANTIATE_TEST_SUITE_P(
908     ,
909     MultiDrawTest,
910     testing::Combine(
911         testing::ValuesIn(::angle::FilterTestParams(platforms, ArraySize(platforms))),
912         testing::Values(DrawIDOption::NoDrawID, DrawIDOption::UseDrawID),
913         testing::Values(InstancingOption::NoInstancing, InstancingOption::UseInstancing),
914         testing::Values(BufferDataUsageOption::StaticDraw, BufferDataUsageOption::DynamicDraw)),
915     PrintToStringParamName());
916 
917 INSTANTIATE_TEST_SUITE_P(
918     ,
919     MultiDrawNoInstancingSupportTest,
920     testing::Combine(
921         testing::ValuesIn(::angle::FilterTestParams(es2_platforms, ArraySize(es2_platforms))),
922         testing::Values(DrawIDOption::NoDrawID, DrawIDOption::UseDrawID),
923         testing::Values(InstancingOption::UseInstancing),
924         testing::Values(BufferDataUsageOption::StaticDraw, BufferDataUsageOption::DynamicDraw)),
925     PrintToStringParamName());
926 
927 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MultiDrawIndirectTest);
928 
929 ANGLE_INSTANTIATE_TEST_ES31_AND(MultiDrawIndirectTest,
930                                 WithNoVulkanMultiDrawIndirect(ES31_VULKAN()));
931 }  // namespace
932