xref: /aosp_15_r20/external/angle/src/tests/gl_tests/DrawBaseVertexVariantsTest.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2020 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 // DrawBaseVertexVariantsTest: Tests variants of drawElements*BaseVertex* call from different
8 // extensions
9 
10 #include "gpu_info_util/SystemInfo.h"
11 #include "test_utils/ANGLETest.h"
12 #include "test_utils/gl_raii.h"
13 
14 #include <numeric>
15 
16 using namespace angle;
17 
18 namespace
19 {
20 
21 // Create a kWidth * kHeight canvas equally split into kCountX * kCountY tiles
22 // each containing a quad partially covering each tile
23 constexpr uint32_t kWidth                   = 256;
24 constexpr uint32_t kHeight                  = 256;
25 constexpr uint32_t kCountX                  = 8;
26 constexpr uint32_t kCountY                  = 8;
27 constexpr int kBoxCount                     = kCountX * kCountY;
28 constexpr uint32_t kIndexPatternRepeatCount = 3;
29 constexpr std::array<GLfloat, 2> kTileSize  = {
30     1.f / static_cast<GLfloat>(kCountX),
31     1.f / static_cast<GLfloat>(kCountY),
32 };
33 constexpr std::array<uint32_t, 2> kTilePixelSize  = {kWidth / kCountX, kHeight / kCountY};
34 constexpr std::array<GLfloat, 2> kQuadRadius      = {0.25f * kTileSize[0], 0.25f * kTileSize[1]};
35 constexpr std::array<uint32_t, 2> kPixelCheckSize = {
36     static_cast<uint32_t>(kQuadRadius[0] * kWidth),
37     static_cast<uint32_t>(kQuadRadius[1] * kHeight)};
38 constexpr GLenum kBufferDataUsage[] = {GL_STATIC_DRAW, GL_DYNAMIC_DRAW, GL_STREAM_DRAW};
39 
GetTileCenter(uint32_t x,uint32_t y)40 constexpr std::array<GLfloat, 2> GetTileCenter(uint32_t x, uint32_t y)
41 {
42     return {
43         kTileSize[0] * (0.5f + static_cast<GLfloat>(x)),
44         kTileSize[1] * (0.5f + static_cast<GLfloat>(y)),
45     };
46 }
GetQuadVertices(uint32_t x,uint32_t y)47 constexpr std::array<std::array<GLfloat, 2>, 4> GetQuadVertices(uint32_t x, uint32_t y)
48 {
49     const auto center = GetTileCenter(x, y);
50     return {
51         std::array<GLfloat, 2>{center[0] - kQuadRadius[0], center[1] - kQuadRadius[1]},
52         std::array<GLfloat, 2>{center[0] + kQuadRadius[0], center[1] - kQuadRadius[1]},
53         std::array<GLfloat, 2>{center[0] + kQuadRadius[0], center[1] + kQuadRadius[1]},
54         std::array<GLfloat, 2>{center[0] - kQuadRadius[0], center[1] + kQuadRadius[1]},
55     };
56 }
57 
58 enum class DrawCallVariants
59 {
60     DrawElementsBaseVertex,
61     DrawElementsInstancedBaseVertex,
62     DrawRangeElementsBaseVertex,
63     DrawElementsInstancedBaseVertexBaseInstance
64 };
65 
66 using DrawBaseVertexVariantsTestParams = std::tuple<angle::PlatformParameters, GLenum>;
67 
DrawBaseVertexVariantsTestPrint(const::testing::TestParamInfo<DrawBaseVertexVariantsTestParams> & paramsInfo)68 std::string DrawBaseVertexVariantsTestPrint(
69     const ::testing::TestParamInfo<DrawBaseVertexVariantsTestParams> &paramsInfo)
70 {
71     const DrawBaseVertexVariantsTestParams &params = paramsInfo.param;
72     std::ostringstream out;
73 
74     out << std::get<0>(params) << "__";
75 
76     switch (std::get<1>(params))
77     {
78         case GL_STATIC_DRAW:
79             out << "STATIC_DRAW";
80             break;
81         case GL_DYNAMIC_DRAW:
82             out << "DYNAMIC_DRAW";
83             break;
84         case GL_STREAM_DRAW:
85             out << "STREAM_DRAW";
86             break;
87         default:
88             out << "UPDATE_THIS_SWITCH";
89             break;
90     }
91 
92     return out.str();
93 }
94 
95 // These tests check correctness of variants of baseVertex draw calls from different extensions
96 
97 class DrawBaseVertexVariantsTest : public ANGLETest<DrawBaseVertexVariantsTestParams>
98 {
99   protected:
DrawBaseVertexVariantsTest()100     DrawBaseVertexVariantsTest()
101     {
102         setWindowWidth(kWidth);
103         setWindowHeight(kHeight);
104         setConfigRedBits(8);
105         setConfigGreenBits(8);
106         setConfigBlueBits(8);
107         setConfigAlphaBits(8);
108 
109         std::array<GLushort, 6> indices = {0, 1, 2, 0, 2, 3};
110         mIndices.resize(indices.size() * kIndexPatternRepeatCount);
111         for (uint32_t i = 0; i < kIndexPatternRepeatCount; i++)
112         {
113             size_t o  = i * indices.size();
114             size_t vo = i * 4;  // each quad has 4 vertices, index offset by 4
115             for (size_t j = 0; j < indices.size(); j++)
116             {
117                 mIndices[o + j] = vo + indices[j];
118             }
119         }
120 
121         mColorPalette = {GLColor(0x7f, 0x7f, 0x7f, 0xff),
122                          GLColor::red,
123                          GLColor::green,
124                          GLColor::yellow,
125                          GLColor::blue,
126                          GLColor::magenta,
127                          GLColor::cyan,
128                          GLColor::white};
129 
130         for (uint32_t y = 0; y < kCountY; ++y)
131         {
132             for (uint32_t x = 0; x < kCountX; ++x)
133             {
134                 // v3 ---- v2
135                 // |       |
136                 // |       |
137                 // v0 ---- v1
138 
139                 const auto vs = ::GetQuadVertices(x, y);
140 
141                 for (const auto &v : vs)
142                 {
143                     mVertices.insert(mVertices.end(), v.begin(), v.end());
144                 }
145 
146                 const auto &colorPicked = mColorPalette[(x + y) % mColorPalette.size()];
147                 for (int i = 0; i < 4; ++i)
148                 {
149                     mVertexColors.push_back(colorPicked.R);
150                     mVertexColors.push_back(colorPicked.G);
151                     mVertexColors.push_back(colorPicked.B);
152                     mVertexColors.push_back(colorPicked.A);
153                 }
154             }
155         }
156 
157         mRegularIndices.resize(kCountY * kCountX * mIndices.size());
158         for (uint32_t y = 0; y < kCountY; y++)
159         {
160             for (uint32_t x = 0; x < kCountX; x++)
161             {
162                 uint32_t i  = x + y * kCountX;
163                 uint32_t oi = 6 * i;
164                 uint32_t ov = 4 * i;
165                 for (uint32_t j = 0; j < 6; j++)
166                 {
167                     mRegularIndices[oi + j] = mIndices[j] + ov;
168                 }
169             }
170         }
171     }
172 
setupProgram(GLProgram & program)173     void setupProgram(GLProgram &program)
174     {
175         constexpr char vs[] = R"(
176 precision mediump float;
177 attribute vec2 vPosition;
178 attribute vec4 vColor;
179 varying vec4 color;
180 void main()
181 {
182     gl_Position = vec4(vec3(vPosition, 1.0) * 2.0 - 1.0, 1.0);
183     color = vColor;
184 })";
185         constexpr char fs[] = R"(
186 precision mediump float;
187 varying vec4 color;
188 void main()
189 {
190     gl_FragColor = color;
191 })";
192         program.makeRaster(vs, fs);
193         EXPECT_GL_NO_ERROR();
194         ASSERT_TRUE(program.valid());
195         glUseProgram(program);
196         mPositionLoc = glGetAttribLocation(program, "vPosition");
197         ASSERT_NE(-1, mPositionLoc);
198         mColorLoc = glGetAttribLocation(program, "vColor");
199         ASSERT_NE(-1, mColorLoc);
200     }
201 
setupIndexedBuffers(GLBuffer & vertexPositionBuffer,GLBuffer & vertexColorBuffer,GLBuffer & indexBuffer)202     void setupIndexedBuffers(GLBuffer &vertexPositionBuffer,
203                              GLBuffer &vertexColorBuffer,
204                              GLBuffer &indexBuffer)
205     {
206         GLenum usage = std::get<1>(GetParam());
207 
208         glBindBuffer(GL_ARRAY_BUFFER, vertexColorBuffer);
209         glBufferData(GL_ARRAY_BUFFER, sizeof(GLubyte) * mVertexColors.size(), mVertexColors.data(),
210                      usage);
211 
212         glEnableVertexAttribArray(mColorLoc);
213         glVertexAttribPointer(mColorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, 0);
214 
215         glBindBuffer(GL_ARRAY_BUFFER, vertexPositionBuffer);
216         glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * mVertices.size(), mVertices.data(), usage);
217 
218         glEnableVertexAttribArray(mPositionLoc);
219         glVertexAttribPointer(mPositionLoc, 2, GL_FLOAT, GL_FALSE, 0, 0);
220 
221         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
222         glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort) * mIndices.size(), mIndices.data(),
223                      usage);
224 
225         ASSERT_GL_NO_ERROR();
226     }
227 
doDrawElementsBaseVertexVariants(DrawCallVariants drawCallType)228     void doDrawElementsBaseVertexVariants(DrawCallVariants drawCallType)
229     {
230         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
231 
232         int baseRepetition = 0;
233         int i              = 0;
234 
235         // Start at various repetitions within the patterned index buffer to exercise base
236         // index.
237 
238         static_assert(kIndexPatternRepeatCount >= 3, "Repeat pattern count should be at least 3");
239 
240         while (i < kBoxCount)
241         {
242             int repetitionCount = std::min(3 - baseRepetition, kBoxCount - i);
243 
244             updateVertexColorData(i, repetitionCount);
245 
246             switch (drawCallType)
247             {
248                 case DrawCallVariants::DrawElementsInstancedBaseVertexBaseInstance:
249                     glDrawElementsInstancedBaseVertexBaseInstanceANGLE(
250                         GL_TRIANGLES, repetitionCount * 6, GL_UNSIGNED_SHORT,
251                         reinterpret_cast<GLvoid *>(
252                             static_cast<uintptr_t>(baseRepetition * 6 * sizeof(GLushort))),
253                         1, (i - baseRepetition) * 4, 0);
254                     break;
255                 case DrawCallVariants::DrawElementsBaseVertex:
256                     glDrawElementsBaseVertexEXT(
257                         GL_TRIANGLES, repetitionCount * 6, GL_UNSIGNED_SHORT,
258                         reinterpret_cast<GLvoid *>(
259                             static_cast<uintptr_t>(baseRepetition * 6 * sizeof(GLushort))),
260                         (i - baseRepetition) * 4);
261                     break;
262                 case DrawCallVariants::DrawElementsInstancedBaseVertex:
263                     glDrawElementsInstancedBaseVertexEXT(
264                         GL_TRIANGLES, repetitionCount * 6, GL_UNSIGNED_SHORT,
265                         reinterpret_cast<GLvoid *>(
266                             static_cast<uintptr_t>(baseRepetition * 6 * sizeof(GLushort))),
267                         1, (i - baseRepetition) * 4);
268                     break;
269                 case DrawCallVariants::DrawRangeElementsBaseVertex:
270                     glDrawRangeElementsBaseVertexEXT(
271                         GL_TRIANGLES, baseRepetition * 4,
272                         (baseRepetition + repetitionCount) * 4 - 1, repetitionCount * 6,
273                         GL_UNSIGNED_SHORT,
274                         reinterpret_cast<GLvoid *>(
275                             static_cast<uintptr_t>(baseRepetition * 6 * sizeof(GLushort))),
276                         (i - baseRepetition) * 4);
277                     break;
278                 default:
279                     EXPECT_TRUE(false);
280                     break;
281             }
282 
283             baseRepetition = (baseRepetition + 1) % 3;
284             i += repetitionCount;
285         }
286 
287         EXPECT_GL_NO_ERROR();
288         checkDrawResult();
289     }
290 
updateVertexColorData(GLint drawnQuadCount,GLint toDrawQuadCount)291     void updateVertexColorData(GLint drawnQuadCount, GLint toDrawQuadCount)
292     {
293         // update the vertex color of the next [count] of quads to draw
294         if (std::get<1>(GetParam()) == GL_STATIC_DRAW)
295         {
296             return;
297         }
298 
299         GLint offset = sizeof(GLubyte) * drawnQuadCount * 4 * sizeof(GLColor);
300 
301         for (GLint i = 0; i < toDrawQuadCount; i++)
302         {
303             const GLColor &color = mColorPalette[(drawnQuadCount + i) % mColorPalette.size()];
304             for (GLint j = 0; j < 4; j++)
305             {
306                 glBufferSubData(GL_ARRAY_BUFFER, offset, sizeof(GLColor), color.data());
307                 offset += sizeof(GLColor);
308             }
309         }
310     }
311 
checkDrawResult()312     void checkDrawResult()
313     {
314         bool dynamicLayout = std::get<1>(GetParam()) == GL_STATIC_DRAW ? false : true;
315 
316         for (uint32_t y = 0; y < kCountY; ++y)
317         {
318             for (uint32_t x = 0; x < kCountX; ++x)
319             {
320                 uint32_t center_x = x * kTilePixelSize[0] + kTilePixelSize[0] / 2;
321                 uint32_t center_y = y * kTilePixelSize[1] + kTilePixelSize[1] / 2;
322 
323                 const auto &color =
324                     mColorPalette[(dynamicLayout ? x : x + y) % mColorPalette.size()];
325 
326                 EXPECT_PIXEL_NEAR(center_x - kPixelCheckSize[0] / 2,
327                                   center_y - kPixelCheckSize[1] / 2, color[0], color[1], color[2],
328                                   color[3], 1);
329             }
330         }
331     }
332 
requestAngleBaseVertexBaseInstanceExtensions()333     bool requestAngleBaseVertexBaseInstanceExtensions()
334     {
335         if (getClientMajorVersion() <= 2)
336         {
337             if (!EnsureGLExtensionEnabled("GL_ANGLE_instanced_arrays"))
338             {
339                 return false;
340             }
341         }
342         if (!EnsureGLExtensionEnabled("GL_ANGLE_base_vertex_base_instance"))
343         {
344             return false;
345         }
346 
347         return EnsureGLExtensionEnabled("GL_ANGLE_base_vertex_base_instance_shader_builtin");
348     }
349 
requestNativeBaseVertexExtensions()350     bool requestNativeBaseVertexExtensions()
351     {
352         return (EnsureGLExtensionEnabled("GL_OES_draw_elements_base_vertex") ||
353                 EnsureGLExtensionEnabled("GL_EXT_draw_elements_base_vertex"));
354     }
355 
356     std::vector<GLushort> mIndices;
357     std::vector<GLfloat> mVertices;
358     std::vector<GLubyte> mVertexColors;
359 
360     std::vector<GLColor> mColorPalette;
361     std::vector<GLushort> mRegularIndices;
362     GLint mPositionLoc;
363     GLint mColorLoc;
364 };
365 
366 // Test drawElementsBaseVertex from OES/EXT_draw_elements_base_vertex
TEST_P(DrawBaseVertexVariantsTest,DrawElementsBaseVertex)367 TEST_P(DrawBaseVertexVariantsTest, DrawElementsBaseVertex)
368 {
369     ANGLE_SKIP_TEST_IF(!requestNativeBaseVertexExtensions());
370 
371     GLProgram program;
372     setupProgram(program);
373 
374     GLBuffer indexBuffer;
375     GLBuffer vertexPositionBuffer;
376     GLBuffer vertexColorBuffer;
377     setupIndexedBuffers(vertexPositionBuffer, vertexColorBuffer, indexBuffer);
378 
379     // for potential update vertex color later
380     glBindBuffer(GL_ARRAY_BUFFER, vertexColorBuffer);
381 
382     doDrawElementsBaseVertexVariants(DrawCallVariants::DrawElementsBaseVertex);
383 }
384 
385 // Test drawElementsInstancedBaseVertex from OES/EXT_draw_elements_base_vertex
TEST_P(DrawBaseVertexVariantsTest,DrawElementsInstancedBaseVertex)386 TEST_P(DrawBaseVertexVariantsTest, DrawElementsInstancedBaseVertex)
387 {
388     ANGLE_SKIP_TEST_IF(!requestNativeBaseVertexExtensions());
389 
390     GLProgram program;
391     setupProgram(program);
392 
393     GLBuffer indexBuffer;
394     GLBuffer vertexPositionBuffer;
395     GLBuffer vertexColorBuffer;
396     setupIndexedBuffers(vertexPositionBuffer, vertexColorBuffer, indexBuffer);
397 
398     // for potential update vertex color later
399     glBindBuffer(GL_ARRAY_BUFFER, vertexColorBuffer);
400 
401     doDrawElementsBaseVertexVariants(DrawCallVariants::DrawElementsInstancedBaseVertex);
402 }
403 
404 // Test drawRangeElementsBaseVertex from OES/EXT_draw_elements_base_vertex
TEST_P(DrawBaseVertexVariantsTest,DrawRangeElementsBaseVertex)405 TEST_P(DrawBaseVertexVariantsTest, DrawRangeElementsBaseVertex)
406 {
407     ANGLE_SKIP_TEST_IF(!requestNativeBaseVertexExtensions());
408 
409     GLProgram program;
410     setupProgram(program);
411 
412     GLBuffer indexBuffer;
413     GLBuffer vertexPositionBuffer;
414     GLBuffer vertexColorBuffer;
415     setupIndexedBuffers(vertexPositionBuffer, vertexColorBuffer, indexBuffer);
416 
417     // for potential update vertex color later
418     glBindBuffer(GL_ARRAY_BUFFER, vertexColorBuffer);
419 
420     doDrawElementsBaseVertexVariants(DrawCallVariants::DrawRangeElementsBaseVertex);
421 }
422 
423 // Test drawElementsInstancedBaseVertexBaseInstance from ANGLE_base_vertex_base_instance
TEST_P(DrawBaseVertexVariantsTest,DrawElementsInstancedBaseVertexBaseInstance)424 TEST_P(DrawBaseVertexVariantsTest, DrawElementsInstancedBaseVertexBaseInstance)
425 {
426     ANGLE_SKIP_TEST_IF(!requestAngleBaseVertexBaseInstanceExtensions());
427 
428     GLProgram program;
429     setupProgram(program);
430 
431     GLBuffer indexBuffer;
432     GLBuffer vertexPositionBuffer;
433     GLBuffer vertexColorBuffer;
434     setupIndexedBuffers(vertexPositionBuffer, vertexColorBuffer, indexBuffer);
435 
436     // for potential update vertex color later
437     glBindBuffer(GL_ARRAY_BUFFER, vertexColorBuffer);
438 
439     doDrawElementsBaseVertexVariants(DrawCallVariants::DrawElementsInstancedBaseVertexBaseInstance);
440 }
441 
442 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DrawBaseVertexVariantsTest);
443 ANGLE_INSTANTIATE_TEST_COMBINE_1(DrawBaseVertexVariantsTest,
444                                  DrawBaseVertexVariantsTestPrint,
445                                  testing::ValuesIn(kBufferDataUsage),
446                                  ES3_D3D11(),
447                                  ES3_METAL(),
448                                  ES3_OPENGL(),
449                                  ES3_OPENGLES(),
450                                  ES3_VULKAN());
451 
452 }  // namespace
453