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> ¶msInfo)
70 {
71 const DrawBaseVertexVariantsTestParams ¶ms = 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