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