• 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 ()__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