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