xref: /aosp_15_r20/external/angle/src/tests/gl_tests/AtomicCounterBufferTest.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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