• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.get());
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 // Counters matching across shader stages should fail if offsets aren't all specified.
72 // GLSL ES Spec 3.10.4, section 9.2.1.
TEST_P(AtomicCounterBufferTest31,OffsetNotAllSpecified)73 TEST_P(AtomicCounterBufferTest31, OffsetNotAllSpecified)
74 {
75     constexpr char kVS[] =
76         "#version 310 es\n"
77         "layout(binding = 0, offset = 4) uniform atomic_uint foo;\n"
78         "void main()\n"
79         "{\n"
80         "    atomicCounterIncrement(foo);\n"
81         "}\n";
82     constexpr char kFS[] =
83         "#version 310 es\n"
84         "layout(binding = 0) uniform atomic_uint foo;\n"
85         "void main()\n"
86         "{\n"
87         "}\n";
88 
89     GLuint program = CompileProgram(kVS, kFS);
90     EXPECT_EQ(0u, program);
91 }
92 
93 // Counters matching across shader stages should fail if offsets aren't all specified with same
94 // value.
TEST_P(AtomicCounterBufferTest31,OffsetNotAllSpecifiedWithSameValue)95 TEST_P(AtomicCounterBufferTest31, OffsetNotAllSpecifiedWithSameValue)
96 {
97     constexpr char kVS[] =
98         "#version 310 es\n"
99         "layout(binding = 0, offset = 4) uniform atomic_uint foo;\n"
100         "void main()\n"
101         "{\n"
102         "    atomicCounterIncrement(foo);\n"
103         "}\n";
104     constexpr char kFS[] =
105         "#version 310 es\n"
106         "layout(binding = 0, offset = 8) uniform atomic_uint foo;\n"
107         "void main()\n"
108         "{\n"
109         "}\n";
110 
111     GLuint program = CompileProgram(kVS, kFS);
112     EXPECT_EQ(0u, program);
113 }
114 
115 // Tests atomic counter reads using compute shaders. Used as a sanity check for the translator.
TEST_P(AtomicCounterBufferTest31,AtomicCounterReadCompute)116 TEST_P(AtomicCounterBufferTest31, AtomicCounterReadCompute)
117 {
118     // Skipping due to a bug on the Qualcomm Vulkan Android driver.
119     // http://anglebug.com/3726
120     ANGLE_SKIP_TEST_IF(IsAndroid() && IsVulkan());
121 
122     // Skipping due to a bug on the Adreno OpenGLES Android driver.
123     // http://anglebug.com/2925
124     ANGLE_SKIP_TEST_IF(IsAndroid() && IsAdreno() && IsOpenGLES());
125 
126     constexpr char kComputeShaderSource[] = R"(#version 310 es
127 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
128 
129 void atomicCounterInFunction(in atomic_uint counter[3]);
130 
131 layout(binding = 0, offset = 8) uniform atomic_uint ac[3];
132 
133 void atomicCounterInFunction(in atomic_uint counter[3])
134 {
135     atomicCounter(counter[0]);
136 }
137 
138 void main()
139 {
140     atomicCounterInFunction(ac);
141     atomicCounter(ac[gl_LocalInvocationIndex + 1u]);
142 })";
143 
144     ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShaderSource);
145     EXPECT_GL_NO_ERROR();
146 }
147 
148 // Test atomic counter read.
TEST_P(AtomicCounterBufferTest31,AtomicCounterRead)149 TEST_P(AtomicCounterBufferTest31, AtomicCounterRead)
150 {
151     // Skipping due to a bug on the Qualcomm Vulkan Android driver.
152     // http://anglebug.com/3726
153     ANGLE_SKIP_TEST_IF(IsAndroid() && IsVulkan());
154 
155     // Skipping test while we work on enabling atomic counter buffer support in th D3D renderer.
156     // http://anglebug.com/1729
157     ANGLE_SKIP_TEST_IF(IsD3D11());
158 
159     constexpr char kFS[] =
160         "#version 310 es\n"
161         "precision highp float;\n"
162         "layout(binding = 0, offset = 4) uniform atomic_uint ac;\n"
163         "out highp vec4 my_color;\n"
164         "void main()\n"
165         "{\n"
166         "    my_color = vec4(0.0);\n"
167         "    uint a1 = atomicCounter(ac);\n"
168         "    if (a1 == 3u) my_color = vec4(1.0);\n"
169         "}\n";
170 
171     ANGLE_GL_PROGRAM(program, essl31_shaders::vs::Simple(), kFS);
172 
173     glUseProgram(program.get());
174 
175     // The initial value of counter 'ac' is 3u.
176     unsigned int bufferData[3] = {11u, 3u, 1u};
177     GLBuffer atomicCounterBuffer;
178     glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicCounterBuffer);
179     glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(bufferData), bufferData, GL_STATIC_DRAW);
180 
181     glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, atomicCounterBuffer);
182 
183     drawQuad(program.get(), essl31_shaders::PositionAttrib(), 0.0f);
184     ASSERT_GL_NO_ERROR();
185     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white);
186 }
187 
188 // Test atomic counter increment and decrement.
TEST_P(AtomicCounterBufferTest31,AtomicCounterIncrementAndDecrement)189 TEST_P(AtomicCounterBufferTest31, AtomicCounterIncrementAndDecrement)
190 {
191     // Skipping due to a bug on the Qualcomm Vulkan Android driver.
192     // http://anglebug.com/3726
193     ANGLE_SKIP_TEST_IF(IsAndroid() && IsVulkan());
194 
195     constexpr char kCS[] =
196         "#version 310 es\n"
197         "layout(local_size_x=1, local_size_y=1, local_size_z=1) in;\n"
198         "layout(binding = 0, offset = 4) uniform atomic_uint ac[2];\n"
199         "void main()\n"
200         "{\n"
201         "    atomicCounterIncrement(ac[0]);\n"
202         "    atomicCounterDecrement(ac[1]);\n"
203         "}\n";
204 
205     ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
206 
207     glUseProgram(program.get());
208 
209     // The initial value of 'ac[0]' is 3u, 'ac[1]' is 1u.
210     unsigned int bufferData[3] = {11u, 3u, 1u};
211     GLBuffer atomicCounterBuffer;
212     glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicCounterBuffer);
213     glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(bufferData), bufferData, GL_STATIC_DRAW);
214 
215     glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, atomicCounterBuffer);
216 
217     glDispatchCompute(1, 1, 1);
218     EXPECT_GL_NO_ERROR();
219 
220     glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
221 
222     glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicCounterBuffer);
223     void *mappedBuffer =
224         glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint) * 3, GL_MAP_READ_BIT);
225     memcpy(bufferData, mappedBuffer, sizeof(bufferData));
226     glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
227 
228     EXPECT_EQ(11u, bufferData[0]);
229     EXPECT_EQ(4u, bufferData[1]);
230     EXPECT_EQ(0u, bufferData[2]);
231 }
232 
233 // Tests multiple atomic counter buffers.
TEST_P(AtomicCounterBufferTest31,AtomicCounterMultipleBuffers)234 TEST_P(AtomicCounterBufferTest31, AtomicCounterMultipleBuffers)
235 {
236     // Skipping due to a bug on the Qualcomm Vulkan Android driver.
237     // http://anglebug.com/3726
238     ANGLE_SKIP_TEST_IF(IsAndroid() && IsVulkan());
239 
240     GLint maxAtomicCounterBuffers = 0;
241     glGetIntegerv(GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS, &maxAtomicCounterBuffers);
242     constexpr unsigned int kBufferCount = 3;
243     // ES 3.1 table 20.45 only guarantees 1 atomic counter buffer
244     ANGLE_SKIP_TEST_IF(maxAtomicCounterBuffers < static_cast<int>(kBufferCount));
245 
246     constexpr char kComputeShaderSource[] = R"(#version 310 es
247 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
248 layout(binding = 0) uniform atomic_uint ac1;
249 layout(binding = 1) uniform atomic_uint ac2;
250 layout(binding = 2) uniform atomic_uint ac3;
251 
252 void main()
253 {
254     atomicCounterIncrement(ac1);
255     atomicCounterIncrement(ac2);
256     atomicCounterIncrement(ac3);
257 })";
258 
259     ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShaderSource);
260 
261     glUseProgram(program);
262 
263     GLBuffer atomicCounterBuffers[kBufferCount];
264 
265     for (unsigned int ii = 0; ii < kBufferCount; ++ii)
266     {
267         GLuint initialData[1] = {ii};
268         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicCounterBuffers[ii]);
269         glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(initialData), initialData, GL_STATIC_DRAW);
270 
271         glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, ii, atomicCounterBuffers[ii]);
272     }
273 
274     glDispatchCompute(1, 1, 1);
275     EXPECT_GL_NO_ERROR();
276 
277     glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
278 
279     for (unsigned int ii = 0; ii < kBufferCount; ++ii)
280     {
281         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicCounterBuffers[ii]);
282         GLuint *mappedBuffer = static_cast<GLuint *>(
283             glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint), GL_MAP_READ_BIT));
284         EXPECT_EQ(ii + 1, mappedBuffer[0]);
285         glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
286     }
287 }
288 
289 // Test atomic counter array of array.
TEST_P(AtomicCounterBufferTest31,AtomicCounterArrayOfArray)290 TEST_P(AtomicCounterBufferTest31, AtomicCounterArrayOfArray)
291 {
292     // Fails on D3D.  Some counters are double-incremented while some are untouched, hinting at a
293     // bug in index translation.  http://anglebug.com/3783
294     ANGLE_SKIP_TEST_IF(IsD3D11());
295 
296     // Nvidia's OpenGL driver fails to compile the shader.  http://anglebug.com/3791
297     ANGLE_SKIP_TEST_IF(IsOpenGL() && IsNVIDIA());
298 
299     // Intel's Windows OpenGL driver crashes in this test.  http://anglebug.com/3791
300     ANGLE_SKIP_TEST_IF(IsOpenGL() && IsIntel() && IsWindows());
301 
302     // Skipping due to a bug on the Qualcomm Vulkan Android driver.
303     // http://anglebug.com/3726
304     ANGLE_SKIP_TEST_IF(IsAndroid() && IsVulkan());
305 
306     constexpr char kCS[] = R"(#version 310 es
307 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
308 layout(binding = 0) uniform atomic_uint ac[7][5][3];
309 
310 void f0(in atomic_uint ac)
311 {
312     atomicCounterIncrement(ac);
313 }
314 
315 void f1(in atomic_uint ac[3])
316 {
317     atomicCounterIncrement(ac[0]);
318     f0(ac[1]);
319     int index = 2;
320     f0(ac[index]);
321 }
322 
323 void f2(in atomic_uint ac[5][3])
324 {
325     // Increment all in ac[0], ac[1] and ac[2]
326     for (int i = 0; i < 3; ++i)
327     {
328         for (int j = 0; j < 2; ++j)
329         {
330             f0(ac[i][j]);
331         }
332         f0(ac[i][2]);
333     }
334 
335     // Increment all in ac[3]
336     f1(ac[3]);
337 
338     // Increment all in ac[4]
339     for (int i = 0; i < 2; ++i)
340     {
341         atomicCounterIncrement(ac[4][i]);
342     }
343     f0(ac[4][2]);
344 }
345 
346 void f3(in atomic_uint ac[7][5][3])
347 {
348     // Increment all in ac[0], ac[1], ac[2] and ac[3]
349     f2(ac[0]);
350     for (int i = 1; i < 4; ++i)
351     {
352         f2(ac[i]);
353     }
354 
355     // Increment all in ac[5][0], ac[5][1], ac[5][2] and ac[5][3]
356     for (int i = 0; i < 4; ++i)
357     {
358         f1(ac[5][i]);
359     }
360 
361     // Increment all in ac[5][4][0], ac[5][4][1] and ac[5][4][2]
362     f0(ac[5][4][0]);
363     for (int i = 1; i < 3; ++i)
364     {
365         f0(ac[5][4][i]);
366     }
367 
368     // Increment all in ac[6]
369     for (int i = 0; i < 5; ++i)
370     {
371         for (int j = 0; j < 2; ++j)
372         {
373             atomicCounterIncrement(ac[6][i][j]);
374         }
375         atomicCounterIncrement(ac[6][i][2]);
376     }
377 }
378 
379 void main()
380 {
381     // Increment all in ac except ac[4]
382     f3(ac);
383 
384     // Increment all in ac[4]
385     f2(ac[4]);
386 })";
387 
388     constexpr uint32_t kAtomicCounterRows  = 7;
389     constexpr uint32_t kAtomicCounterCols  = 5;
390     constexpr uint32_t kAtomicCounterDepth = 3;
391     constexpr uint32_t kAtomicCounterCount =
392         kAtomicCounterRows * kAtomicCounterCols * kAtomicCounterDepth;
393 
394     GLint maxAtomicCounters = 0;
395     glGetIntegerv(GL_MAX_COMPUTE_ATOMIC_COUNTERS, &maxAtomicCounters);
396     EXPECT_GL_NO_ERROR();
397 
398     // Required minimum is 8 by the spec
399     EXPECT_GE(maxAtomicCounters, 8);
400     ANGLE_SKIP_TEST_IF(static_cast<uint32_t>(maxAtomicCounters) < kAtomicCounterCount);
401 
402     ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
403     glUseProgram(program.get());
404 
405     // The initial value of atomic counters is 0, 1, 2, ...
406     unsigned int bufferData[kAtomicCounterCount] = {};
407     for (uint32_t index = 0; index < kAtomicCounterCount; ++index)
408     {
409         bufferData[index] = index;
410     }
411 
412     GLBuffer atomicCounterBuffer;
413     glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicCounterBuffer);
414     glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(bufferData), bufferData, GL_STATIC_DRAW);
415 
416     glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, atomicCounterBuffer);
417 
418     glDispatchCompute(1, 1, 1);
419     EXPECT_GL_NO_ERROR();
420 
421     glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
422 
423     unsigned int result[kAtomicCounterCount] = {};
424     glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicCounterBuffer);
425     void *mappedBuffer =
426         glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(bufferData), GL_MAP_READ_BIT);
427     memcpy(result, mappedBuffer, sizeof(bufferData));
428     glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
429 
430     for (uint32_t index = 0; index < kAtomicCounterCount; ++index)
431     {
432         EXPECT_EQ(result[index], bufferData[index] + 1) << "index " << index;
433     }
434 }
435 
436 // Test inactive atomic counter
TEST_P(AtomicCounterBufferTest31,AtomicCounterInactive)437 TEST_P(AtomicCounterBufferTest31, AtomicCounterInactive)
438 {
439     constexpr char kFS[] =
440         "#version 310 es\n"
441         "precision highp float;\n"
442 
443         // This inactive atomic counter should be removed by RemoveInactiveInterfaceVariables
444         "layout(binding = 0) uniform atomic_uint inactive;\n"
445 
446         "out highp vec4 my_color;\n"
447         "void main()\n"
448         "{\n"
449         "    my_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
450         "}\n";
451 
452     ANGLE_GL_PROGRAM(program, essl31_shaders::vs::Simple(), kFS);
453     glUseProgram(program);
454 
455     drawQuad(program, essl31_shaders::PositionAttrib(), 0.0f);
456     ASSERT_GL_NO_ERROR();
457 
458     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
459 }
460 
461 // Test inactive memoryBarrierAtomicCounter
TEST_P(AtomicCounterBufferTest31,AtomicCounterMemoryBarrier)462 TEST_P(AtomicCounterBufferTest31, AtomicCounterMemoryBarrier)
463 {
464     constexpr char kFS[] =
465         "#version 310 es\n"
466         "precision highp float;\n"
467         // This inactive atomic counter should be removed by RemoveInactiveInterfaceVariables
468         "layout(binding = 0) uniform atomic_uint inactive;\n"
469         "out highp vec4 my_color;\n"
470         "void main()\n"
471         "{\n"
472         "    my_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
473         // This barrier should be removed by RemoveAtomicCounterBuiltins because
474         // there are no active atomic counters
475         "    memoryBarrierAtomicCounter();\n"
476         "}\n";
477 
478     ANGLE_GL_PROGRAM(program, essl31_shaders::vs::Simple(), kFS);
479     glUseProgram(program);
480 
481     drawQuad(program, essl31_shaders::PositionAttrib(), 0.0f);
482     ASSERT_GL_NO_ERROR();
483 
484     EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
485 }
486 
487 // TODO(syoussefi): re-enable tests on Vulkan once http://anglebug.com/3738 is resolved.  The issue
488 // is with WGL where if a Vulkan test is run first in the shard, it causes crashes when an OpenGL
489 // test is run afterwards.  AtomicCounter* tests are alphabetically first, and having them not run
490 // on Vulkan makes every shard our bots currently make do have at least some OpenGL test run before
491 // any Vulkan test. When these tests can be enabled on Vulkan, can replace the current macros with
492 // the updated macros below that include Vulkan:
493 #if !defined(ANGLE_PLATFORM_WINDOWS)
494 ANGLE_INSTANTIATE_TEST_ES3_AND_ES31(AtomicCounterBufferTest);
495 ANGLE_INSTANTIATE_TEST_ES31(AtomicCounterBufferTest31);
496 #else
497 ANGLE_INSTANTIATE_TEST(AtomicCounterBufferTest,
498                        ES3_OPENGL(),
499                        ES3_OPENGLES(),
500                        ES31_OPENGL(),
501                        ES31_OPENGLES(),
502                        ES31_D3D11());
503 ANGLE_INSTANTIATE_TEST(AtomicCounterBufferTest31, ES31_OPENGL(), ES31_OPENGLES(), ES31_D3D11());
504 #endif
505 
506 }  // namespace
507