1 //
2 // Copyright 2017 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 // AtomicCounterBufferTest:
7 // Various tests related for atomic counter buffers.
8 //
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 class AtomicCounterBufferTest : public ANGLETest<>
19 {
20 protected:
AtomicCounterBufferTest()21 AtomicCounterBufferTest()
22 {
23 setWindowWidth(128);
24 setWindowHeight(128);
25 setConfigRedBits(8);
26 setConfigGreenBits(8);
27 setConfigBlueBits(8);
28 setConfigAlphaBits(8);
29 }
30 };
31
32 // Test GL_ATOMIC_COUNTER_BUFFER is not supported with version lower than ES31.
TEST_P(AtomicCounterBufferTest,AtomicCounterBufferBindings)33 TEST_P(AtomicCounterBufferTest, AtomicCounterBufferBindings)
34 {
35 ASSERT_EQ(3, getClientMajorVersion());
36 GLBuffer atomicCounterBuffer;
37 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, atomicCounterBuffer);
38 if (getClientMinorVersion() < 1)
39 {
40 EXPECT_GL_ERROR(GL_INVALID_ENUM);
41 }
42 else
43 {
44 EXPECT_GL_NO_ERROR();
45 }
46 }
47
48 class AtomicCounterBufferTest31 : public AtomicCounterBufferTest
49 {};
50
51 // Linking should fail if counters in vertex shader exceed gl_MaxVertexAtomicCounters.
TEST_P(AtomicCounterBufferTest31,ExceedMaxVertexAtomicCounters)52 TEST_P(AtomicCounterBufferTest31, ExceedMaxVertexAtomicCounters)
53 {
54 constexpr char kVS[] =
55 "#version 310 es\n"
56 "layout(binding = 0) uniform atomic_uint foo[gl_MaxVertexAtomicCounters + 1];\n"
57 "void main()\n"
58 "{\n"
59 " atomicCounterIncrement(foo[0]);\n"
60 "}\n";
61 constexpr char kFS[] =
62 "#version 310 es\n"
63 "void main()\n"
64 "{\n"
65 "}\n";
66
67 GLuint program = CompileProgram(kVS, kFS);
68 EXPECT_EQ(0u, program);
69 }
70
71 // Test that Tessellation Control Shader Can Read/Write to atomic counter buffers
TEST_P(AtomicCounterBufferTest31,TessellationControlShaderMaxAtomicCounterTests)72 TEST_P(AtomicCounterBufferTest31, TessellationControlShaderMaxAtomicCounterTests)
73 {
74 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_tessellation_shader"));
75 GLint maxTessellationControlAtomicCounters = 0;
76 glGetIntegerv(GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS, &maxTessellationControlAtomicCounters);
77 ANGLE_SKIP_TEST_IF(maxTessellationControlAtomicCounters <= 0);
78
79 // Cap the atomic counters to an arbitrary value 16 in case we do not have a limit for
80 // GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS on certain devices
81 GLint maxTessellationControlAtomicCountersCap = 16u;
82 maxTessellationControlAtomicCounters =
83 std::min(maxTessellationControlAtomicCounters, maxTessellationControlAtomicCountersCap);
84
85 const unsigned int tessellationControlPointsCount = 3;
86
87 // Vertex Shader Code
88 const char *kVS =
89 "#version 310 es\n"
90 "\n"
91 "in vec4 a_position;\n"
92 "flat out int vertex_id;\n"
93 "\n"
94 "void main()\n"
95 "{\n"
96 " gl_Position = a_position;\n"
97 "}\n";
98
99 // Tessellation Control Shader Code
100 // gl_InvocationID = 0: increment all elements in atomic counters acs[].
101 // gl_InvocationID = 1: increment acs[index] where index==0
102 // gl_InvocationID = 2: increment acs[index] where index==0,1
103 // We have tessellationControlPointsCount=3 vertices output from the Tessellation Control
104 // Shader Stage, meaning we have three tessellation shader code running in parallel, each with a
105 // unique gl_InvocationID.
106 std::stringstream tcs_code_sstream;
107 tcs_code_sstream
108 << "#version 310 es\n"
109 "#extension GL_EXT_tessellation_shader : require\n"
110 "layout(vertices ="
111 << tessellationControlPointsCount
112 << ") out;\n"
113 "uniform int nLoopIterations;\n"
114 "layout(binding = 0) uniform atomic_uint acs["
115 << maxTessellationControlAtomicCounters
116 << "];\n"
117 "void main()\n"
118 "{\n"
119 "for (int counter_id = 1;\n"
120 "counter_id <= nLoopIterations;\n"
121 "++counter_id)\n"
122 "{\n"
123 "if ((gl_InvocationID % counter_id) == 0)\n"
124 "{\n"
125 " atomicCounterIncrement(acs[counter_id - 1]);\n"
126 "}\n"
127 "}\n"
128 "\n"
129 " gl_out [gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
130 " gl_TessLevelInner[0] = 1.0;\n"
131 " gl_TessLevelOuter[0] = 1.0;\n"
132 " gl_TessLevelOuter[1] = 1.0;\n"
133 " gl_TessLevelOuter[2] = 1.0;\n"
134 "}\n";
135 std::string tcs_code = tcs_code_sstream.str();
136 const char *kTC = tcs_code.c_str();
137
138 // Tessellation Evaluation Shader Code
139 constexpr char kTES[] =
140 "#version 310 es\n"
141 "#extension GL_EXT_tessellation_shader : require\n"
142 "layout (triangles) in;\n"
143 "void main()\n"
144 "{\n"
145 " gl_Position = gl_TessCoord[0] * gl_in[0].gl_Position +"
146 " gl_TessCoord[1] * gl_in[1].gl_Position +"
147 " gl_TessCoord[2] * gl_in[2].gl_Position;\n"
148 "}\n";
149
150 // Fragment Shader Code
151 const char *kFS =
152 "#version 310 es\n"
153 "\n"
154 "precision highp float;\n"
155 "\n"
156 "out vec4 result;\n"
157 "\n"
158 "void main()\n"
159 "{\n"
160 " result = vec4(1.0);\n"
161 "}\n";
162 GLuint program = CompileProgramWithTESS(kVS, kTC, kTES, kFS);
163 EXPECT_NE(0u, program);
164 glUseProgram(program);
165
166 // Create and Bind Atomic Counter Buffer Object
167 GLuint atomicBufferID;
168 glGenBuffers(1, &atomicBufferID);
169 GLuint *atomicBufferData = new GLuint[maxTessellationControlAtomicCounters];
170 memset(atomicBufferData, 0, sizeof(GLuint) * maxTessellationControlAtomicCounters);
171 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicBufferID);
172 glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(GLuint) * maxTessellationControlAtomicCounters,
173 NULL, GL_DYNAMIC_COPY);
174 glBufferSubData(GL_ATOMIC_COUNTER_BUFFER, 0,
175 sizeof(GLuint) * maxTessellationControlAtomicCounters, atomicBufferData);
176 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, atomicBufferID);
177
178 // Bind nLoopIterationsUniformLocation uniform
179 GLint nLoopIterationsUniformLocation = -1;
180 nLoopIterationsUniformLocation = glGetUniformLocation(program, "nLoopIterations");
181 EXPECT_NE(-1, nLoopIterationsUniformLocation);
182 glUniform1i(nLoopIterationsUniformLocation, maxTessellationControlAtomicCounters);
183
184 // Issue a Drawcall
185 std::array<Vector3, 3> triangleVertices = {
186 Vector3(-1.0f, 1.0f, 0.5f), Vector3(-1.0f, -1.0f, 0.5f), Vector3(1.0f, -1.0f, 0.5f)};
187 GLint positionLocation = glGetAttribLocation(program, "a_position");
188 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, triangleVertices.data());
189 glEnableVertexAttribArray(positionLocation);
190 glDrawArrays(GL_PATCHES, 0, 3);
191 ASSERT_GL_NO_ERROR();
192
193 // Check the value of atomic counter buffer
194 GLuint *atomicBufferResult = (GLuint *)glMapBufferRange(
195 GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint) * maxTessellationControlAtomicCounters,
196 GL_MAP_READ_BIT);
197
198 for (GLint n_ac = 1; n_ac <= maxTessellationControlAtomicCounters; ++n_ac)
199 {
200 unsigned int expected_value = 0;
201 for (unsigned int n_draw_call_vertex = 0;
202 n_draw_call_vertex < tessellationControlPointsCount; ++n_draw_call_vertex)
203 {
204 if ((n_draw_call_vertex % n_ac) == 0)
205 {
206 expected_value++;
207 }
208 }
209 EXPECT_EQ(atomicBufferResult[n_ac - 1], expected_value);
210 }
211
212 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
213 glDisableVertexAttribArray(positionLocation);
214 glDeleteBuffers(1, &atomicBufferID);
215 glDeleteProgram(program);
216 }
217
218 // Test that Tessellation Evaluation Shader Can Read/Write to atomic counter buffers
TEST_P(AtomicCounterBufferTest31,TessellationEvaluationShaderMaxAtomicCounterTests)219 TEST_P(AtomicCounterBufferTest31, TessellationEvaluationShaderMaxAtomicCounterTests)
220 {
221 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_tessellation_shader"));
222 GLint maxTessellationEvaluationAtomicCounters = 0;
223 glGetIntegerv(GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS, &maxTessellationEvaluationAtomicCounters);
224 ANGLE_SKIP_TEST_IF(maxTessellationEvaluationAtomicCounters <= 0);
225
226 // Cap the atomic counters to an arbitrary value 16 in case we do not have a limit for
227 // GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS on certain devices
228 GLint maxTessellationEvaluationAtomicCountersCap = 16u;
229 maxTessellationEvaluationAtomicCounters = std::min(maxTessellationEvaluationAtomicCounters,
230 maxTessellationEvaluationAtomicCountersCap);
231
232 const unsigned int tessellationControlPointsCount = 3;
233
234 // Vertex Shader Code
235 const char *kVS =
236 "#version 310 es\n"
237 "\n"
238 "in vec4 a_position;\n"
239 "\n"
240 "void main()\n"
241 "{\n"
242 " gl_Position = a_position;\n"
243 "}\n";
244
245 // Tessellation Control Shader Code
246 std::stringstream tcs_code_sstream;
247 tcs_code_sstream
248 << "#version 310 es\n"
249 "#extension GL_EXT_tessellation_shader : require\n"
250 "layout(vertices = "
251 << tessellationControlPointsCount
252 << ") out;\n"
253 "void main()\n"
254 "{\n"
255 " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
256 " gl_TessLevelInner[0] = 1.0;\n"
257 " gl_TessLevelOuter[0] = 1.0;\n"
258 " gl_TessLevelOuter[1] = 1.0;\n"
259 " gl_TessLevelOuter[2] = 1.0;\n"
260 "}\n";
261 std::string tcs_code = tcs_code_sstream.str();
262 const char *kTC = tcs_code.c_str();
263
264 // Tessellation Evaluation Shader Code
265 // The gl_TessLevelInner and gl_TessLevelOuter values in tessellation control shader (tcs) code
266 // are set to 1, meaning we do not subdivide the patch and create more vertices. The number of
267 // tessellation evaluation shader (tes) invocations is the same as number of vertex output from
268 // tcs (e.g. tessellationControlPointsCount).
269 // Increment all elements in atomic counters acs[] in every tes invocation.
270 // Final value in atomic counters acs[] should be the same as the number of
271 // tes invocations (e.g. tessellationControlPointsCount).
272 std::stringstream tes_code_sstream;
273 tes_code_sstream << "#version 310 es\n"
274 "#extension GL_EXT_tessellation_shader : require\n"
275 "layout (triangles) in;\n"
276 "uniform int nLoopIterations;\n"
277 "layout(binding = 0) uniform atomic_uint acs["
278 << maxTessellationEvaluationAtomicCounters
279 << "];\n"
280 "void main()\n"
281 "{\n"
282 "for (int counter_id = 0;\n"
283 "counter_id < nLoopIterations;\n"
284 "++counter_id)\n"
285 "{\n"
286 " atomicCounterIncrement(acs[counter_id]);\n"
287 "}\n"
288 "\n"
289 " gl_Position = gl_TessCoord[0] * gl_in[0].gl_Position +"
290 " gl_TessCoord[1] * gl_in[1].gl_Position +"
291 " gl_TessCoord[2] * gl_in[2].gl_Position;\n"
292 "}\n";
293 std::string tes_code = tes_code_sstream.str();
294 const char *kTES = tes_code.c_str();
295
296 // Fragment Shader Code
297 const char *kFS =
298 "#version 310 es\n"
299 "\n"
300 "precision highp float;\n"
301 "\n"
302 "out vec4 result;\n"
303 "\n"
304 "void main()\n"
305 "{\n"
306 " result = vec4(1.0);\n"
307 "}\n";
308 GLuint program = CompileProgramWithTESS(kVS, kTC, kTES, kFS);
309 EXPECT_NE(0u, program);
310 glUseProgram(program);
311
312 // Create and Bind Atomic Counter Buffer Object
313 GLuint atomicBufferID;
314 glGenBuffers(1, &atomicBufferID);
315 GLuint *atomicBufferData = new GLuint[maxTessellationEvaluationAtomicCounters];
316 memset(atomicBufferData, 0, sizeof(GLuint) * maxTessellationEvaluationAtomicCounters);
317 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicBufferID);
318 glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(GLuint) * maxTessellationEvaluationAtomicCounters,
319 NULL, GL_DYNAMIC_COPY);
320 glBufferSubData(GL_ATOMIC_COUNTER_BUFFER, 0,
321 sizeof(GLuint) * maxTessellationEvaluationAtomicCounters, atomicBufferData);
322 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, atomicBufferID);
323
324 // Bind nLoopIterationsUniformLocation uniform
325 GLint nLoopIterationsUniformLocation = -1;
326 nLoopIterationsUniformLocation = glGetUniformLocation(program, "nLoopIterations");
327 EXPECT_NE(-1, nLoopIterationsUniformLocation);
328 glUniform1i(nLoopIterationsUniformLocation, maxTessellationEvaluationAtomicCounters);
329
330 // Issue Drawcall
331 std::array<Vector3, 3> triangleVertices = {
332 Vector3(-1.0f, 1.0f, 0.5f), Vector3(-1.0f, -1.0f, 0.5f), Vector3(1.0f, -1.0f, 0.5f)};
333 GLint positionLocation = glGetAttribLocation(program, "a_position");
334 glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, triangleVertices.data());
335 glEnableVertexAttribArray(positionLocation);
336 glDrawArrays(GL_PATCHES, 0, 3);
337 ASSERT_GL_NO_ERROR();
338
339 // Check the value of atomic counter buffer
340 GLuint *atomicBufferResult = (GLuint *)glMapBufferRange(
341 GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint) * maxTessellationEvaluationAtomicCounters,
342 GL_MAP_READ_BIT);
343 unsigned int expected_value = tessellationControlPointsCount;
344 for (GLint n_ac = 0; n_ac < maxTessellationEvaluationAtomicCounters; ++n_ac)
345 {
346 EXPECT_EQ(atomicBufferResult[n_ac], expected_value);
347 }
348
349 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
350 glDisableVertexAttribArray(positionLocation);
351 glDeleteBuffers(1, &atomicBufferID);
352 glDeleteProgram(program);
353 }
354
355 // Counters matching across shader stages should fail if offsets aren't all specified.
356 // GLSL ES Spec 3.10.4, section 9.2.1.
TEST_P(AtomicCounterBufferTest31,OffsetNotAllSpecified)357 TEST_P(AtomicCounterBufferTest31, OffsetNotAllSpecified)
358 {
359 constexpr char kVS[] =
360 "#version 310 es\n"
361 "layout(binding = 0, offset = 4) uniform atomic_uint foo;\n"
362 "void main()\n"
363 "{\n"
364 " atomicCounterIncrement(foo);\n"
365 "}\n";
366 constexpr char kFS[] =
367 "#version 310 es\n"
368 "layout(binding = 0) uniform atomic_uint foo;\n"
369 "void main()\n"
370 "{\n"
371 "}\n";
372
373 GLuint program = CompileProgram(kVS, kFS);
374 EXPECT_EQ(0u, program);
375 }
376
377 // Counters matching across shader stages should fail if offsets aren't all specified with same
378 // value.
TEST_P(AtomicCounterBufferTest31,OffsetNotAllSpecifiedWithSameValue)379 TEST_P(AtomicCounterBufferTest31, OffsetNotAllSpecifiedWithSameValue)
380 {
381 constexpr char kVS[] =
382 "#version 310 es\n"
383 "layout(binding = 0, offset = 4) uniform atomic_uint foo;\n"
384 "void main()\n"
385 "{\n"
386 " atomicCounterIncrement(foo);\n"
387 "}\n";
388 constexpr char kFS[] =
389 "#version 310 es\n"
390 "layout(binding = 0, offset = 8) uniform atomic_uint foo;\n"
391 "void main()\n"
392 "{\n"
393 "}\n";
394
395 GLuint program = CompileProgram(kVS, kFS);
396 EXPECT_EQ(0u, program);
397 }
398
399 // Tests atomic counter reads using compute shaders. Used as a confidence check for the translator.
TEST_P(AtomicCounterBufferTest31,AtomicCounterReadCompute)400 TEST_P(AtomicCounterBufferTest31, AtomicCounterReadCompute)
401 {
402 // Skipping due to a bug on the Adreno OpenGLES Android driver.
403 // http://anglebug.com/42261624
404 ANGLE_SKIP_TEST_IF(IsAndroid() && IsAdreno() && IsOpenGLES());
405
406 constexpr char kComputeShaderSource[] = R"(#version 310 es
407 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
408
409 void atomicCounterInFunction(in atomic_uint counter[3]);
410
411 layout(binding = 0, offset = 8) uniform atomic_uint ac[3];
412
413 void atomicCounterInFunction(in atomic_uint counter[3])
414 {
415 atomicCounter(counter[0]);
416 }
417
418 void main()
419 {
420 atomicCounterInFunction(ac);
421 atomicCounter(ac[gl_LocalInvocationIndex + 1u]);
422 })";
423
424 ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShaderSource);
425 EXPECT_GL_NO_ERROR();
426 }
427
428 // Test atomic counter read.
TEST_P(AtomicCounterBufferTest31,AtomicCounterRead)429 TEST_P(AtomicCounterBufferTest31, AtomicCounterRead)
430 {
431 // Skipping test while we work on enabling atomic counter buffer support in th D3D renderer.
432 // http://anglebug.com/42260658
433 ANGLE_SKIP_TEST_IF(IsD3D11());
434
435 constexpr char kFS[] =
436 "#version 310 es\n"
437 "precision highp float;\n"
438 "layout(binding = 0, offset = 4) uniform atomic_uint ac;\n"
439 "out highp vec4 my_color;\n"
440 "void main()\n"
441 "{\n"
442 " my_color = vec4(0.0);\n"
443 " uint a1 = atomicCounter(ac);\n"
444 " if (a1 == 3u) my_color = vec4(1.0);\n"
445 "}\n";
446
447 ANGLE_GL_PROGRAM(program, essl31_shaders::vs::Simple(), kFS);
448
449 glUseProgram(program);
450
451 // The initial value of counter 'ac' is 3u.
452 unsigned int bufferData[3] = {11u, 3u, 1u};
453 GLBuffer atomicCounterBuffer;
454 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicCounterBuffer);
455 glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(bufferData), bufferData, GL_STATIC_DRAW);
456
457 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, atomicCounterBuffer);
458
459 drawQuad(program, essl31_shaders::PositionAttrib(), 0.0f);
460 ASSERT_GL_NO_ERROR();
461 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white);
462 }
463
464 // Test a bug in vulkan back-end where recreating the atomic counter storage should trigger state
465 // update in the context
TEST_P(AtomicCounterBufferTest31,DependentAtomicCounterBufferChange)466 TEST_P(AtomicCounterBufferTest31, DependentAtomicCounterBufferChange)
467 {
468 // Skipping test while we work on enabling atomic counter buffer support in th D3D renderer.
469 // http://anglebug.com/42260658
470 ANGLE_SKIP_TEST_IF(IsD3D11());
471
472 constexpr char kFS[] =
473 "#version 310 es\n"
474 "precision highp float;\n"
475 "layout(binding = 0, offset = 4) uniform atomic_uint ac;\n"
476 "out highp vec4 my_color;\n"
477 "void main()\n"
478 "{\n"
479 " my_color = vec4(0.0);\n"
480 " uint a1 = atomicCounter(ac);\n"
481 " if (a1 == 3u) my_color = vec4(1.0);\n"
482 " if (a1 == 19u) my_color = vec4(1.0, 0.0, 0.0, 1.0);\n"
483 "}\n";
484
485 ANGLE_GL_PROGRAM(program, essl31_shaders::vs::Simple(), kFS);
486
487 glUseProgram(program);
488
489 // The initial value of counter 'ac' is 3u.
490 unsigned int bufferDataLeft[3] = {11u, 3u, 1u};
491 GLBuffer atomicCounterBuffer;
492 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicCounterBuffer);
493 glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(bufferDataLeft), bufferDataLeft, GL_STATIC_DRAW);
494
495 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, atomicCounterBuffer);
496 // Draw left quad
497 glViewport(0, 0, getWindowWidth() / 2, getWindowHeight());
498 drawQuad(program, essl31_shaders::PositionAttrib(), 0.0f);
499 // Draw right quad
500 unsigned int bufferDataRight[3] = {11u, 19u, 1u};
501 glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(bufferDataRight), bufferDataRight,
502 GL_STATIC_DRAW);
503 glViewport(getWindowWidth() / 2, 0, getWindowWidth() / 2, getWindowHeight());
504 drawQuad(program, essl31_shaders::PositionAttrib(), 0.0f);
505 ASSERT_GL_NO_ERROR();
506 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white);
507 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, 0, GLColor::red);
508 }
509
510 // Updating atomic counter buffer's offsets was optimized based on a count of valid bindings.
511 // This test will fail if there are bugs in how we count valid bindings.
TEST_P(AtomicCounterBufferTest31,AtomicCounterBufferRangeRead)512 TEST_P(AtomicCounterBufferTest31, AtomicCounterBufferRangeRead)
513 {
514 // Skipping due to a bug on the Qualcomm driver.
515 // http://anglebug.com/42262383
516 ANGLE_SKIP_TEST_IF(IsNexus5X() && IsOpenGLES());
517
518 // Skipping test while we work on enabling atomic counter buffer support in th D3D renderer.
519 // http://anglebug.com/42260658
520 ANGLE_SKIP_TEST_IF(IsD3D11());
521
522 constexpr char kFS[] =
523 "#version 310 es\n"
524 "precision highp float;\n"
525 "layout(binding = 0, offset = 4) uniform atomic_uint ac;\n"
526 "out highp vec4 my_color;\n"
527 "void main()\n"
528 "{\n"
529 " my_color = vec4(0.0);\n"
530 " uint a1 = atomicCounter(ac);\n"
531 " if (a1 == 3u) my_color = vec4(1.0);\n"
532 "}\n";
533
534 ANGLE_GL_PROGRAM(program, essl31_shaders::vs::Simple(), kFS);
535
536 glUseProgram(program);
537
538 // The initial value of counter 'ac' is 3u.
539 unsigned int bufferData[] = {0u, 0u, 0u, 0u, 0u, 11u, 3u, 1u};
540 constexpr GLintptr kOffset = 20;
541 GLint maxAtomicCounterBuffers = 0;
542 GLBuffer atomicCounterBuffer;
543
544 glGetIntegerv(GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS, &maxAtomicCounterBuffers);
545 // Repeatedly bind the same buffer (GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS + 1) times
546 // A bug in counting valid atomic counter buffers will cause a crash when we
547 // exceed GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS
548 for (int32_t i = 0; i < maxAtomicCounterBuffers + 1; i++)
549 {
550 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicCounterBuffer);
551 glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(bufferData), bufferData, GL_STATIC_DRAW);
552 glBindBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, atomicCounterBuffer, kOffset,
553 sizeof(bufferData) - kOffset);
554 }
555
556 drawQuad(program, essl31_shaders::PositionAttrib(), 0.0f);
557 ASSERT_GL_NO_ERROR();
558 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white);
559 }
560
561 // Updating atomic counter buffer's offsets was optimized based on a count of valid bindings.
562 // Repeatedly bind/unbind buffers across available binding points. The test will fail if
563 // there are bugs in how we count valid bindings.
TEST_P(AtomicCounterBufferTest31,AtomicCounterBufferRepeatedBindUnbind)564 TEST_P(AtomicCounterBufferTest31, AtomicCounterBufferRepeatedBindUnbind)
565 {
566 // Skipping test while we work on enabling atomic counter buffer support in th D3D renderer.
567 // http://anglebug.com/42260658
568 ANGLE_SKIP_TEST_IF(IsD3D11());
569
570 constexpr char kFS[] =
571 "#version 310 es\n"
572 "precision highp float;\n"
573 "layout(binding = 0, offset = 4) uniform atomic_uint ac;\n"
574 "out highp vec4 my_color;\n"
575 "void main()\n"
576 "{\n"
577 " my_color = vec4(0.0);\n"
578 " uint a1 = atomicCounter(ac);\n"
579 " if (a1 == 3u) my_color = vec4(1.0);\n"
580 "}\n";
581
582 ANGLE_GL_PROGRAM(program, essl31_shaders::vs::Simple(), kFS);
583
584 glUseProgram(program);
585
586 constexpr int32_t kBufferCount = 16;
587 // The initial value of counter 'ac' is 3u.
588 unsigned int bufferData[3] = {11u, 3u, 1u};
589 GLBuffer atomicCounterBuffer[kBufferCount];
590 // Populate atomicCounterBuffer[0] with valid data and the rest with nullptr
591 for (int32_t bufferIndex = 0; bufferIndex < kBufferCount; bufferIndex++)
592 {
593 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicCounterBuffer[bufferIndex]);
594 glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(bufferData),
595 (bufferIndex == 0) ? bufferData : nullptr, GL_STATIC_DRAW);
596 }
597
598 GLint maxAtomicCounterBuffers = 0;
599 glGetIntegerv(GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS, &maxAtomicCounterBuffers);
600
601 // Cycle through multiple buffers
602 for (int32_t i = 0; i < kBufferCount; i++)
603 {
604 constexpr int32_t kBufferIndices[kBufferCount] = {7, 12, 15, 5, 13, 14, 1, 2,
605 0, 6, 4, 9, 8, 11, 3, 10};
606 int32_t bufferIndex = kBufferIndices[i];
607
608 // Randomly bind/unbind buffers to/from different binding points,
609 // capped by GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS
610 for (int32_t bufferCount = 0; bufferCount < maxAtomicCounterBuffers; bufferCount++)
611 {
612 constexpr uint32_t kBindingSlotsSize = kBufferCount;
613 constexpr uint32_t kBindingSlots[kBindingSlotsSize] = {1, 3, 4, 14, 15, 9, 0, 6,
614 12, 11, 8, 5, 10, 2, 7, 13};
615
616 uint32_t bindingSlotIndex = bufferCount % kBindingSlotsSize;
617 uint32_t bindingSlot = kBindingSlots[bindingSlotIndex];
618 uint32_t bindingPoint = bindingSlot % maxAtomicCounterBuffers;
619 bool even = (bufferCount % 2 == 0);
620 int32_t bufferId = (even) ? 0 : atomicCounterBuffer[bufferIndex];
621
622 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, bindingPoint, bufferId);
623 }
624 }
625
626 // Bind atomicCounterBuffer[0] to slot 0 and verify result
627 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, atomicCounterBuffer[0]);
628 drawQuad(program, essl31_shaders::PositionAttrib(), 0.0f);
629 ASSERT_GL_NO_ERROR();
630 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white);
631 }
632
633 // Test atomic counter increment and decrement.
TEST_P(AtomicCounterBufferTest31,AtomicCounterIncrementAndDecrement)634 TEST_P(AtomicCounterBufferTest31, AtomicCounterIncrementAndDecrement)
635 {
636 constexpr char kCS[] =
637 "#version 310 es\n"
638 "layout(local_size_x=1, local_size_y=1, local_size_z=1) in;\n"
639 "layout(binding = 0, offset = 4) uniform atomic_uint ac[2];\n"
640 "void main()\n"
641 "{\n"
642 " atomicCounterIncrement(ac[0]);\n"
643 " atomicCounterDecrement(ac[1]);\n"
644 "}\n";
645
646 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
647
648 glUseProgram(program);
649
650 // The initial value of 'ac[0]' is 3u, 'ac[1]' is 1u.
651 unsigned int bufferData[3] = {11u, 3u, 1u};
652 GLBuffer atomicCounterBuffer;
653 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicCounterBuffer);
654 glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(bufferData), bufferData, GL_STATIC_DRAW);
655
656 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, atomicCounterBuffer);
657
658 glDispatchCompute(1, 1, 1);
659 EXPECT_GL_NO_ERROR();
660
661 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
662
663 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicCounterBuffer);
664 void *mappedBuffer =
665 glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint) * 3, GL_MAP_READ_BIT);
666 memcpy(bufferData, mappedBuffer, sizeof(bufferData));
667 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
668
669 EXPECT_EQ(11u, bufferData[0]);
670 EXPECT_EQ(4u, bufferData[1]);
671 EXPECT_EQ(0u, bufferData[2]);
672 }
673
674 // Tests multiple atomic counter buffers.
TEST_P(AtomicCounterBufferTest31,AtomicCounterMultipleBuffers)675 TEST_P(AtomicCounterBufferTest31, AtomicCounterMultipleBuffers)
676 {
677 GLint maxAtomicCounterBuffers = 0;
678 glGetIntegerv(GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS, &maxAtomicCounterBuffers);
679 constexpr unsigned int kBufferCount = 3;
680 // ES 3.1 table 20.45 only guarantees 1 atomic counter buffer
681 ANGLE_SKIP_TEST_IF(maxAtomicCounterBuffers < static_cast<int>(kBufferCount));
682
683 constexpr char kComputeShaderSource[] = R"(#version 310 es
684 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
685 layout(binding = 0) uniform atomic_uint ac1;
686 layout(binding = 1) uniform atomic_uint ac2;
687 layout(binding = 2) uniform atomic_uint ac3;
688
689 void main()
690 {
691 atomicCounterIncrement(ac1);
692 atomicCounterIncrement(ac2);
693 atomicCounterIncrement(ac3);
694 })";
695
696 ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShaderSource);
697
698 glUseProgram(program);
699
700 GLBuffer atomicCounterBuffers[kBufferCount];
701
702 for (unsigned int ii = 0; ii < kBufferCount; ++ii)
703 {
704 GLuint initialData[1] = {ii};
705 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicCounterBuffers[ii]);
706 glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(initialData), initialData, GL_STATIC_DRAW);
707
708 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, ii, atomicCounterBuffers[ii]);
709 }
710
711 glDispatchCompute(1, 1, 1);
712 EXPECT_GL_NO_ERROR();
713
714 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
715
716 for (unsigned int ii = 0; ii < kBufferCount; ++ii)
717 {
718 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicCounterBuffers[ii]);
719 GLuint *mappedBuffer = static_cast<GLuint *>(
720 glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint), GL_MAP_READ_BIT));
721 EXPECT_EQ(ii + 1, mappedBuffer[0]);
722 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
723 }
724 }
725
726 // Test atomic counter array of array.
TEST_P(AtomicCounterBufferTest31,AtomicCounterArrayOfArray)727 TEST_P(AtomicCounterBufferTest31, AtomicCounterArrayOfArray)
728 {
729 // Fails on D3D. Some counters are double-incremented while some are untouched, hinting at a
730 // bug in index translation. http://anglebug.com/42262427
731 ANGLE_SKIP_TEST_IF(IsD3D11());
732
733 // Nvidia's OpenGL driver fails to compile the shader. http://anglebug.com/42262434
734 ANGLE_SKIP_TEST_IF(IsOpenGL() && IsNVIDIA());
735
736 // Intel's Windows OpenGL driver crashes in this test. http://anglebug.com/42262434
737 ANGLE_SKIP_TEST_IF(IsOpenGL() && IsIntel() && IsWindows());
738
739 constexpr char kCS[] = R"(#version 310 es
740 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
741 layout(binding = 0) uniform atomic_uint ac[7][5][3];
742
743 void f0(in atomic_uint ac)
744 {
745 atomicCounterIncrement(ac);
746 }
747
748 void f1(in atomic_uint ac[3])
749 {
750 atomicCounterIncrement(ac[0]);
751 f0(ac[1]);
752 int index = 2;
753 f0(ac[index]);
754 }
755
756 void f2(in atomic_uint ac[5][3])
757 {
758 // Increment all in ac[0], ac[1] and ac[2]
759 for (int i = 0; i < 3; ++i)
760 {
761 for (int j = 0; j < 2; ++j)
762 {
763 f0(ac[i][j]);
764 }
765 f0(ac[i][2]);
766 }
767
768 // Increment all in ac[3]
769 f1(ac[3]);
770
771 // Increment all in ac[4]
772 for (int i = 0; i < 2; ++i)
773 {
774 atomicCounterIncrement(ac[4][i]);
775 }
776 f0(ac[4][2]);
777 }
778
779 void f3(in atomic_uint ac[7][5][3])
780 {
781 // Increment all in ac[0], ac[1], ac[2] and ac[3]
782 f2(ac[0]);
783 for (int i = 1; i < 4; ++i)
784 {
785 f2(ac[i]);
786 }
787
788 // Increment all in ac[5][0], ac[5][1], ac[5][2] and ac[5][3]
789 for (int i = 0; i < 4; ++i)
790 {
791 f1(ac[5][i]);
792 }
793
794 // Increment all in ac[5][4][0], ac[5][4][1] and ac[5][4][2]
795 f0(ac[5][4][0]);
796 for (int i = 1; i < 3; ++i)
797 {
798 f0(ac[5][4][i]);
799 }
800
801 // Increment all in ac[6]
802 for (int i = 0; i < 5; ++i)
803 {
804 for (int j = 0; j < 2; ++j)
805 {
806 atomicCounterIncrement(ac[6][i][j]);
807 }
808 atomicCounterIncrement(ac[6][i][2]);
809 }
810 }
811
812 void main()
813 {
814 // Increment all in ac except ac[4]
815 f3(ac);
816
817 // Increment all in ac[4]
818 f2(ac[4]);
819 })";
820
821 constexpr uint32_t kAtomicCounterRows = 7;
822 constexpr uint32_t kAtomicCounterCols = 5;
823 constexpr uint32_t kAtomicCounterDepth = 3;
824 constexpr uint32_t kAtomicCounterCount =
825 kAtomicCounterRows * kAtomicCounterCols * kAtomicCounterDepth;
826
827 GLint maxAtomicCounters = 0;
828 glGetIntegerv(GL_MAX_COMPUTE_ATOMIC_COUNTERS, &maxAtomicCounters);
829 EXPECT_GL_NO_ERROR();
830
831 // Required minimum is 8 by the spec
832 EXPECT_GE(maxAtomicCounters, 8);
833 ANGLE_SKIP_TEST_IF(static_cast<uint32_t>(maxAtomicCounters) < kAtomicCounterCount);
834
835 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
836 glUseProgram(program);
837
838 // The initial value of atomic counters is 0, 1, 2, ...
839 unsigned int bufferData[kAtomicCounterCount] = {};
840 for (uint32_t index = 0; index < kAtomicCounterCount; ++index)
841 {
842 bufferData[index] = index;
843 }
844
845 GLBuffer atomicCounterBuffer;
846 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicCounterBuffer);
847 glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(bufferData), bufferData, GL_STATIC_DRAW);
848
849 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, atomicCounterBuffer);
850
851 glDispatchCompute(1, 1, 1);
852 EXPECT_GL_NO_ERROR();
853
854 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
855
856 unsigned int result[kAtomicCounterCount] = {};
857 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicCounterBuffer);
858 void *mappedBuffer =
859 glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(bufferData), GL_MAP_READ_BIT);
860 memcpy(result, mappedBuffer, sizeof(bufferData));
861 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
862
863 for (uint32_t index = 0; index < kAtomicCounterCount; ++index)
864 {
865 EXPECT_EQ(result[index], bufferData[index] + 1) << "index " << index;
866 }
867 }
868
869 // Test inactive atomic counter
TEST_P(AtomicCounterBufferTest31,AtomicCounterInactive)870 TEST_P(AtomicCounterBufferTest31, AtomicCounterInactive)
871 {
872 constexpr char kFS[] =
873 "#version 310 es\n"
874 "precision highp float;\n"
875
876 // This inactive atomic counter should be removed by RemoveInactiveInterfaceVariables
877 "layout(binding = 0) uniform atomic_uint inactive;\n"
878
879 "out highp vec4 my_color;\n"
880 "void main()\n"
881 "{\n"
882 " my_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
883 "}\n";
884
885 ANGLE_GL_PROGRAM(program, essl31_shaders::vs::Simple(), kFS);
886 glUseProgram(program);
887
888 drawQuad(program, essl31_shaders::PositionAttrib(), 0.0f);
889 ASSERT_GL_NO_ERROR();
890
891 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
892 }
893
894 // Test inactive memoryBarrierAtomicCounter
TEST_P(AtomicCounterBufferTest31,AtomicCounterMemoryBarrier)895 TEST_P(AtomicCounterBufferTest31, AtomicCounterMemoryBarrier)
896 {
897 constexpr char kFS[] =
898 "#version 310 es\n"
899 "precision highp float;\n"
900 // This inactive atomic counter should be removed by RemoveInactiveInterfaceVariables
901 "layout(binding = 0) uniform atomic_uint inactive;\n"
902 "out highp vec4 my_color;\n"
903 "void main()\n"
904 "{\n"
905 " my_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
906 // This barrier should be removed by RemoveAtomicCounterBuiltins because
907 // there are no active atomic counters
908 " memoryBarrierAtomicCounter();\n"
909 "}\n";
910
911 ANGLE_GL_PROGRAM(program, essl31_shaders::vs::Simple(), kFS);
912 glUseProgram(program);
913
914 drawQuad(program, essl31_shaders::PositionAttrib(), 0.0f);
915 ASSERT_GL_NO_ERROR();
916
917 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
918 }
919
920 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AtomicCounterBufferTest);
921 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AtomicCounterBufferTest31);
922 ANGLE_INSTANTIATE_TEST_ES3_AND_ES31(AtomicCounterBufferTest);
923 ANGLE_INSTANTIATE_TEST_ES31(AtomicCounterBufferTest31);
924
925 } // namespace
926