1 //
2 // Copyright 2016 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 // ComputeShaderTest:
7 // Compute shader specific tests.
8
9 #include <vector>
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 ComputeShaderTest : public ANGLETest
19 {
20 protected:
ComputeShaderTest()21 ComputeShaderTest() {}
22
createDummyOutputImage(GLuint texture,GLenum internalFormat,GLint width,GLint height)23 void createDummyOutputImage(GLuint texture, GLenum internalFormat, GLint width, GLint height)
24 {
25 glBindTexture(GL_TEXTURE_2D, texture);
26 glTexStorage2D(GL_TEXTURE_2D, 1, internalFormat, width, height);
27 EXPECT_GL_NO_ERROR();
28
29 glBindImageTexture(0, texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, internalFormat);
30 EXPECT_GL_NO_ERROR();
31 }
32
33 template <class T, GLint kWidth, GLint kHeight>
runSharedMemoryTest(const char * kCS,GLenum internalFormat,GLenum format,const std::array<T,kWidth * kHeight> & inputData,const std::array<T,kWidth * kHeight> & expectedValues)34 void runSharedMemoryTest(const char *kCS,
35 GLenum internalFormat,
36 GLenum format,
37 const std::array<T, kWidth * kHeight> &inputData,
38 const std::array<T, kWidth * kHeight> &expectedValues)
39 {
40 GLTexture texture[2];
41 GLFramebuffer framebuffer;
42
43 glBindTexture(GL_TEXTURE_2D, texture[0]);
44 glTexStorage2D(GL_TEXTURE_2D, 1, internalFormat, kWidth, kHeight);
45 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, format,
46 inputData.data());
47 EXPECT_GL_NO_ERROR();
48
49 constexpr T initData[kWidth * kHeight] = {};
50 glBindTexture(GL_TEXTURE_2D, texture[1]);
51 glTexStorage2D(GL_TEXTURE_2D, 1, internalFormat, kWidth, kHeight);
52 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, format, initData);
53 EXPECT_GL_NO_ERROR();
54
55 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
56 glUseProgram(program.get());
57
58 glBindImageTexture(0, texture[0], 0, GL_FALSE, 0, GL_READ_ONLY, internalFormat);
59 EXPECT_GL_NO_ERROR();
60
61 glBindImageTexture(1, texture[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, internalFormat);
62 EXPECT_GL_NO_ERROR();
63
64 glDispatchCompute(1, 1, 1);
65 EXPECT_GL_NO_ERROR();
66
67 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
68
69 T outputValues[kWidth * kHeight] = {};
70 glUseProgram(0);
71 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
72
73 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture[1],
74 0);
75 EXPECT_GL_NO_ERROR();
76 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, format, outputValues);
77 EXPECT_GL_NO_ERROR();
78
79 for (int i = 0; i < kWidth * kHeight; i++)
80 {
81 EXPECT_EQ(expectedValues[i], outputValues[i]);
82 }
83 }
84 };
85
86 class ComputeShaderTestES3 : public ANGLETest
87 {
88 protected:
ComputeShaderTestES3()89 ComputeShaderTestES3() {}
90 };
91
92 class WebGL2ComputeTest : public ComputeShaderTest
93 {
94 protected:
WebGL2ComputeTest()95 WebGL2ComputeTest() { setWebGLCompatibilityEnabled(true); }
96 };
97
98 // link a simple compute program. It should be successful.
TEST_P(ComputeShaderTest,LinkComputeProgram)99 TEST_P(ComputeShaderTest, LinkComputeProgram)
100 {
101 constexpr char kCS[] = R"(#version 310 es
102 layout(local_size_x=1) in;
103 void main()
104 {
105 })";
106
107 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
108
109 EXPECT_GL_NO_ERROR();
110 }
111
112 // Link a simple compute program. Then detach the shader and dispatch compute.
113 // It should be successful.
TEST_P(ComputeShaderTest,DetachShaderAfterLinkSuccess)114 TEST_P(ComputeShaderTest, DetachShaderAfterLinkSuccess)
115 {
116 constexpr char kCS[] = R"(#version 310 es
117 layout(local_size_x=1) in;
118 void main()
119 {
120 })";
121
122 GLuint program = glCreateProgram();
123
124 GLuint cs = CompileShader(GL_COMPUTE_SHADER, kCS);
125 EXPECT_NE(0u, cs);
126
127 glAttachShader(program, cs);
128 glDeleteShader(cs);
129
130 glLinkProgram(program);
131 GLint linkStatus;
132 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
133 EXPECT_GL_TRUE(linkStatus);
134
135 glDetachShader(program, cs);
136 EXPECT_GL_NO_ERROR();
137
138 glUseProgram(program);
139 glDispatchCompute(8, 4, 2);
140 EXPECT_GL_NO_ERROR();
141 }
142
143 // link a simple compute program. There is no local size and linking should fail.
TEST_P(ComputeShaderTest,LinkComputeProgramNoLocalSizeLinkError)144 TEST_P(ComputeShaderTest, LinkComputeProgramNoLocalSizeLinkError)
145 {
146 constexpr char kCS[] = R"(#version 310 es
147 void main()
148 {
149 })";
150
151 GLuint program = CompileComputeProgram(kCS, false);
152 EXPECT_EQ(0u, program);
153
154 glDeleteProgram(program);
155
156 EXPECT_GL_NO_ERROR();
157 }
158
159 // link a simple compute program.
160 // make sure that uniforms and uniform samplers get recorded
TEST_P(ComputeShaderTest,LinkComputeProgramWithUniforms)161 TEST_P(ComputeShaderTest, LinkComputeProgramWithUniforms)
162 {
163 constexpr char kCS[] = R"(#version 310 es
164 precision mediump sampler2D;
165 layout(local_size_x=1) in;
166 uniform int myUniformInt;
167 uniform sampler2D myUniformSampler;
168 layout(rgba32i) uniform highp writeonly iimage2D imageOut;
169 void main()
170 {
171 int q = myUniformInt;
172 vec4 v = textureLod(myUniformSampler, vec2(0.0), 0.0);
173 imageStore(imageOut, ivec2(0), ivec4(v) * q);
174 })";
175
176 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
177
178 GLint uniformLoc = glGetUniformLocation(program.get(), "myUniformInt");
179 EXPECT_NE(-1, uniformLoc);
180
181 uniformLoc = glGetUniformLocation(program.get(), "myUniformSampler");
182 EXPECT_NE(-1, uniformLoc);
183
184 EXPECT_GL_NO_ERROR();
185 }
186
187 // Attach both compute and non-compute shaders. A link time error should occur.
188 // OpenGL ES 3.10, 7.3 Program Objects
TEST_P(ComputeShaderTest,AttachMultipleShaders)189 TEST_P(ComputeShaderTest, AttachMultipleShaders)
190 {
191 constexpr char kCS[] = R"(#version 310 es
192 layout(local_size_x=1) in;
193 void main()
194 {
195 })";
196
197 constexpr char kVS[] = R"(#version 310 es
198 void main()
199 {
200 })";
201
202 constexpr char kFS[] = R"(#version 310 es
203 void main()
204 {
205 })";
206
207 GLuint program = glCreateProgram();
208
209 GLuint vs = CompileShader(GL_VERTEX_SHADER, kVS);
210 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, kFS);
211 GLuint cs = CompileShader(GL_COMPUTE_SHADER, kCS);
212
213 EXPECT_NE(0u, vs);
214 EXPECT_NE(0u, fs);
215 EXPECT_NE(0u, cs);
216
217 glAttachShader(program, vs);
218 glDeleteShader(vs);
219
220 glAttachShader(program, fs);
221 glDeleteShader(fs);
222
223 glAttachShader(program, cs);
224 glDeleteShader(cs);
225
226 glLinkProgram(program);
227
228 GLint linkStatus;
229 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
230
231 EXPECT_GL_FALSE(linkStatus);
232
233 EXPECT_GL_NO_ERROR();
234 }
235
236 // Attach a vertex, fragment and compute shader.
237 // Query for the number of attached shaders and check the count.
TEST_P(ComputeShaderTest,AttachmentCount)238 TEST_P(ComputeShaderTest, AttachmentCount)
239 {
240 constexpr char kCS[] = R"(#version 310 es
241 layout(local_size_x=1) in;
242 void main()
243 {
244 })";
245
246 constexpr char kVS[] = R"(#version 310 es
247 void main()
248 {
249 })";
250
251 constexpr char kFS[] = R"(#version 310 es
252 void main()
253 {
254 })";
255
256 GLuint program = glCreateProgram();
257
258 GLuint vs = CompileShader(GL_VERTEX_SHADER, kVS);
259 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, kFS);
260 GLuint cs = CompileShader(GL_COMPUTE_SHADER, kCS);
261
262 EXPECT_NE(0u, vs);
263 EXPECT_NE(0u, fs);
264 EXPECT_NE(0u, cs);
265
266 glAttachShader(program, vs);
267 glDeleteShader(vs);
268
269 glAttachShader(program, fs);
270 glDeleteShader(fs);
271
272 glAttachShader(program, cs);
273 glDeleteShader(cs);
274
275 GLint numAttachedShaders;
276 glGetProgramiv(program, GL_ATTACHED_SHADERS, &numAttachedShaders);
277
278 EXPECT_EQ(3, numAttachedShaders);
279
280 glDeleteProgram(program);
281
282 EXPECT_GL_NO_ERROR();
283 }
284
285 // Attach a compute shader and link, but start rendering.
TEST_P(ComputeShaderTest,StartRenderingWithComputeProgram)286 TEST_P(ComputeShaderTest, StartRenderingWithComputeProgram)
287 {
288 constexpr char kCS[] = R"(#version 310 es
289 layout(local_size_x=1) in;
290 void main()
291 {
292 })";
293
294 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
295 EXPECT_GL_NO_ERROR();
296
297 glUseProgram(program);
298 glDrawArrays(GL_POINTS, 0, 2);
299 EXPECT_GL_NO_ERROR();
300 }
301
302 // Attach a vertex and fragment shader and link, but dispatch compute.
TEST_P(ComputeShaderTest,DispatchComputeWithRenderingProgram)303 TEST_P(ComputeShaderTest, DispatchComputeWithRenderingProgram)
304 {
305 constexpr char kVS[] = R"(#version 310 es
306 void main() {})";
307
308 constexpr char kFS[] = R"(#version 310 es
309 void main() {})";
310
311 GLuint program = glCreateProgram();
312
313 GLuint vs = CompileShader(GL_VERTEX_SHADER, kVS);
314 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, kFS);
315
316 EXPECT_NE(0u, vs);
317 EXPECT_NE(0u, fs);
318
319 glAttachShader(program, vs);
320 glDeleteShader(vs);
321
322 glAttachShader(program, fs);
323 glDeleteShader(fs);
324
325 glLinkProgram(program);
326
327 GLint linkStatus;
328 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
329 EXPECT_GL_TRUE(linkStatus);
330
331 EXPECT_GL_NO_ERROR();
332
333 glUseProgram(program);
334 glDispatchCompute(8, 4, 2);
335 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
336 }
337
338 // Access all compute shader special variables.
TEST_P(ComputeShaderTest,AccessAllSpecialVariables)339 TEST_P(ComputeShaderTest, AccessAllSpecialVariables)
340 {
341 constexpr char kCS[] = R"(#version 310 es
342 layout(local_size_x=4, local_size_y=3, local_size_z=2) in;
343 layout(rgba32ui) uniform highp writeonly uimage2D imageOut;
344 void main()
345 {
346 uvec3 temp1 = gl_NumWorkGroups;
347 uvec3 temp2 = gl_WorkGroupSize;
348 uvec3 temp3 = gl_WorkGroupID;
349 uvec3 temp4 = gl_LocalInvocationID;
350 uvec3 temp5 = gl_GlobalInvocationID;
351 uint temp6 = gl_LocalInvocationIndex;
352 imageStore(imageOut, ivec2(gl_LocalInvocationIndex, 0), uvec4(temp1 + temp2 + temp3 + temp4 + temp5, temp6));
353 })";
354
355 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
356 }
357
358 // Access part compute shader special variables.
TEST_P(ComputeShaderTest,AccessPartSpecialVariables)359 TEST_P(ComputeShaderTest, AccessPartSpecialVariables)
360 {
361 constexpr char kCS[] = R"(#version 310 es
362 layout(local_size_x=4, local_size_y=3, local_size_z=2) in;
363 layout(rgba32ui) uniform highp writeonly uimage2D imageOut;
364 void main()
365 {
366 uvec3 temp1 = gl_WorkGroupSize;
367 uvec3 temp2 = gl_WorkGroupID;
368 uint temp3 = gl_LocalInvocationIndex;
369 imageStore(imageOut, ivec2(gl_LocalInvocationIndex, 0), uvec4(temp1 + temp2, temp3));
370 })";
371
372 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
373 }
374
375 // Use glDispatchCompute to define work group count.
TEST_P(ComputeShaderTest,DispatchCompute)376 TEST_P(ComputeShaderTest, DispatchCompute)
377 {
378 constexpr char kCS[] = R"(#version 310 es
379 layout(local_size_x=4, local_size_y=3, local_size_z=2) in;
380 layout(rgba32ui) uniform highp writeonly uimage2D imageOut;
381 void main()
382 {
383 uvec3 temp = gl_NumWorkGroups;
384 imageStore(imageOut, ivec2(gl_GlobalInvocationID.xy), uvec4(temp, 0u));
385 })";
386
387 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
388
389 GLTexture texture;
390 createDummyOutputImage(texture, GL_RGBA32UI, 4, 3);
391
392 glUseProgram(program.get());
393 glDispatchCompute(8, 4, 2);
394 EXPECT_GL_NO_ERROR();
395 }
396
397 // Test that binds UAV with type buffer to slot 0, then binds UAV with type image to slot 0, then
398 // buffer again.
TEST_P(ComputeShaderTest,BufferImageBuffer)399 TEST_P(ComputeShaderTest, BufferImageBuffer)
400 {
401 // See http://anglebug.com/3536
402 ANGLE_SKIP_TEST_IF(IsOpenGL() && IsIntel() && IsWindows());
403
404 // Skipping due to a bug on the Qualcomm Vulkan Android driver.
405 // http://anglebug.com/3726
406 ANGLE_SKIP_TEST_IF(IsAndroid() && IsVulkan());
407
408 constexpr char kCS0[] = R"(#version 310 es
409 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
410 layout(binding = 0, offset = 4) uniform atomic_uint ac[2];
411 void main()
412 {
413 atomicCounterIncrement(ac[0]);
414 atomicCounterDecrement(ac[1]);
415 })";
416
417 ANGLE_GL_COMPUTE_PROGRAM(program0, kCS0);
418 glUseProgram(program0);
419
420 unsigned int bufferData[3] = {11u, 4u, 4u};
421 GLBuffer atomicCounterBuffer;
422 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicCounterBuffer);
423 glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(bufferData), bufferData, GL_STATIC_DRAW);
424
425 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, atomicCounterBuffer);
426
427 glDispatchCompute(1, 1, 1);
428 EXPECT_GL_NO_ERROR();
429
430 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
431 void *mappedBuffer =
432 glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint) * 3, GL_MAP_READ_BIT);
433 memcpy(bufferData, mappedBuffer, sizeof(bufferData));
434 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
435
436 EXPECT_EQ(11u, bufferData[0]);
437 EXPECT_EQ(5u, bufferData[1]);
438 EXPECT_EQ(3u, bufferData[2]);
439
440 constexpr char kCS1[] = R"(#version 310 es
441 layout(local_size_x=4, local_size_y=3, local_size_z=2) in;
442 layout(rgba32ui) uniform highp writeonly uimage2D imageOut;
443 void main()
444 {
445 uvec3 temp = gl_NumWorkGroups;
446 imageStore(imageOut, ivec2(gl_GlobalInvocationID.xy), uvec4(temp, 0u));
447 })";
448
449 ANGLE_GL_COMPUTE_PROGRAM(program1, kCS1);
450
451 GLTexture texture;
452 createDummyOutputImage(texture, GL_RGBA32UI, 4, 3);
453
454 glUseProgram(program1);
455 glDispatchCompute(8, 4, 2);
456
457 glMemoryBarrier(GL_ATOMIC_COUNTER_BARRIER_BIT);
458 glUseProgram(program0);
459 glDispatchCompute(1, 1, 1);
460 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
461 mappedBuffer =
462 glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint) * 3, GL_MAP_READ_BIT);
463 memcpy(bufferData, mappedBuffer, sizeof(bufferData));
464 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
465
466 EXPECT_EQ(11u, bufferData[0]);
467 EXPECT_EQ(6u, bufferData[1]);
468 EXPECT_EQ(2u, bufferData[2]);
469
470 EXPECT_GL_NO_ERROR();
471 }
472
473 // Test that binds UAV with type image to slot 0, then binds UAV with type buffer to slot 0.
TEST_P(ComputeShaderTest,ImageAtomicCounterBuffer)474 TEST_P(ComputeShaderTest, ImageAtomicCounterBuffer)
475 {
476 // Flaky hang. http://anglebug.com/3636
477 ANGLE_SKIP_TEST_IF(IsWindows() && IsNVIDIA() && IsDesktopOpenGL());
478
479 // Skipping due to a bug on the Qualcomm Vulkan Android driver.
480 // http://anglebug.com/3726
481 ANGLE_SKIP_TEST_IF(IsAndroid() && IsVulkan());
482
483 constexpr char kCS0[] = R"(#version 310 es
484 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
485 layout(r32ui, binding = 0) writeonly uniform highp uimage2D uImage[2];
486 void main()
487 {
488 imageStore(uImage[0], ivec2(gl_LocalInvocationIndex, gl_WorkGroupID.x), uvec4(100, 0,
489 0, 0));
490 imageStore(uImage[1], ivec2(gl_LocalInvocationIndex, gl_WorkGroupID.x), uvec4(100, 0,
491 0, 0));
492 })";
493
494 ANGLE_GL_COMPUTE_PROGRAM(program0, kCS0);
495 glUseProgram(program0);
496 int width = 1, height = 1;
497 GLuint inputValues[] = {200};
498 GLTexture mTexture[2];
499 glBindTexture(GL_TEXTURE_2D, mTexture[0]);
500 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, width, height);
501 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RED_INTEGER, GL_UNSIGNED_INT,
502 inputValues);
503
504 glBindTexture(GL_TEXTURE_2D, mTexture[1]);
505 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, width, height);
506 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RED_INTEGER, GL_UNSIGNED_INT,
507 inputValues);
508
509 glBindImageTexture(0, mTexture[0], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
510 glBindImageTexture(1, mTexture[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
511
512 glDispatchCompute(1, 1, 1);
513 EXPECT_GL_NO_ERROR();
514
515 constexpr char kCS1[] = R"(#version 310 es
516 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
517 layout(binding = 0, offset = 4) uniform atomic_uint ac[2];
518 void main()
519 {
520 atomicCounterIncrement(ac[0]);
521 atomicCounterDecrement(ac[1]);
522 })";
523
524 ANGLE_GL_COMPUTE_PROGRAM(program1, kCS1);
525
526 unsigned int bufferData[3] = {11u, 4u, 4u};
527 GLBuffer atomicCounterBuffer;
528 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicCounterBuffer);
529 glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(bufferData), bufferData, GL_STATIC_DRAW);
530
531 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, atomicCounterBuffer);
532
533 glUseProgram(program1);
534 glDispatchCompute(1, 1, 1);
535 EXPECT_GL_NO_ERROR();
536
537 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
538 void *mappedBuffer =
539 glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint) * 3, GL_MAP_READ_BIT);
540 memcpy(bufferData, mappedBuffer, sizeof(bufferData));
541 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
542
543 EXPECT_EQ(11u, bufferData[0]);
544 EXPECT_EQ(5u, bufferData[1]);
545 EXPECT_EQ(3u, bufferData[2]);
546
547 EXPECT_GL_NO_ERROR();
548 }
549
550 // Test that binds UAV with type image to slot 0, then binds UAV with type buffer to slot 0.
TEST_P(ComputeShaderTest,ImageShaderStorageBuffer)551 TEST_P(ComputeShaderTest, ImageShaderStorageBuffer)
552 {
553 constexpr char kCS0[] = R"(#version 310 es
554 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
555 layout(r32ui, binding = 0) writeonly uniform highp uimage2D uImage[2];
556 void main()
557 {
558 imageStore(uImage[0], ivec2(gl_LocalInvocationIndex, gl_WorkGroupID.x), uvec4(100, 0,
559 0, 0));
560 imageStore(uImage[1], ivec2(gl_LocalInvocationIndex, gl_WorkGroupID.x), uvec4(100, 0,
561 0, 0));
562 })";
563
564 ANGLE_GL_COMPUTE_PROGRAM(program0, kCS0);
565 glUseProgram(program0);
566 int width = 1, height = 1;
567 GLuint inputValues[] = {200};
568 GLTexture mTexture[2];
569 glBindTexture(GL_TEXTURE_2D, mTexture[0]);
570 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, width, height);
571 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RED_INTEGER, GL_UNSIGNED_INT,
572 inputValues);
573
574 glBindTexture(GL_TEXTURE_2D, mTexture[1]);
575 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, width, height);
576 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RED_INTEGER, GL_UNSIGNED_INT,
577 inputValues);
578
579 glBindImageTexture(0, mTexture[0], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
580 glBindImageTexture(1, mTexture[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
581
582 glDispatchCompute(1, 1, 1);
583 EXPECT_GL_NO_ERROR();
584
585 constexpr char kCS1[] =
586 R"(#version 310 es
587 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
588 layout(std140, binding = 0) buffer blockOut {
589 uvec2 data;
590 } instanceOut;
591 layout(std140, binding = 1) buffer blockIn {
592 uvec2 data;
593 } instanceIn;
594 void main()
595 {
596 instanceOut.data = instanceIn.data;
597 }
598 )";
599
600 ANGLE_GL_COMPUTE_PROGRAM(program1, kCS1);
601
602 constexpr unsigned int kBufferSize = 2;
603 constexpr unsigned int kBufferData[kBufferSize] = {10, 20};
604
605 GLBuffer blockIn;
606 glBindBuffer(GL_SHADER_STORAGE_BUFFER, blockIn);
607 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(kBufferData), kBufferData, GL_STATIC_DRAW);
608 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, blockIn);
609
610 GLBuffer blockOut;
611 glBindBuffer(GL_SHADER_STORAGE_BUFFER, blockOut);
612 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(kBufferData), nullptr, GL_STATIC_DRAW);
613 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, blockOut);
614
615 glUseProgram(program1);
616 glDispatchCompute(1, 1, 1);
617 EXPECT_GL_NO_ERROR();
618
619 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
620
621 glBindBuffer(GL_SHADER_STORAGE_BUFFER, blockOut);
622 unsigned int bufferDataOut[kBufferSize] = {};
623 const GLColor *ptr = reinterpret_cast<GLColor *>(
624 glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(kBufferData), GL_MAP_READ_BIT));
625 memcpy(bufferDataOut, ptr, sizeof(kBufferData));
626 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
627
628 for (unsigned int index = 0; index < kBufferSize; ++index)
629 {
630 EXPECT_EQ(bufferDataOut[index], kBufferData[index]) << " index " << index;
631 }
632 }
633
634 // Basic test for DispatchComputeIndirect.
TEST_P(ComputeShaderTest,DispatchComputeIndirect)635 TEST_P(ComputeShaderTest, DispatchComputeIndirect)
636 {
637 // Flaky crash on teardown, see http://anglebug.com/3349
638 ANGLE_SKIP_TEST_IF(IsD3D11() && IsIntel() && IsWindows());
639
640 GLTexture texture;
641 GLFramebuffer framebuffer;
642 const char kCSSource[] = R"(#version 310 es
643 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
644 layout(r32ui, binding = 0) uniform highp uimage2D uImage;
645 void main()
646 {
647 imageStore(uImage, ivec2(gl_WorkGroupID.x, gl_WorkGroupID.y), uvec4(100, 0, 0, 0));
648 })";
649
650 ANGLE_GL_COMPUTE_PROGRAM(program, kCSSource);
651 glUseProgram(program.get());
652 const int kWidth = 4, kHeight = 6;
653 GLuint inputValues[kWidth][kHeight] = {};
654
655 GLBuffer buffer;
656 glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, buffer);
657 GLuint params[] = {kWidth, kHeight, 1};
658 glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(params), params, GL_STATIC_DRAW);
659
660 glBindTexture(GL_TEXTURE_2D, texture);
661 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kWidth, kHeight);
662 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
663 inputValues);
664 EXPECT_GL_NO_ERROR();
665
666 glBindImageTexture(0, texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
667 EXPECT_GL_NO_ERROR();
668
669 glDispatchComputeIndirect(0);
670 EXPECT_GL_NO_ERROR();
671
672 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
673 glUseProgram(0);
674 GLuint outputValues[kWidth][kHeight];
675 GLuint expectedValue = 100u;
676 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
677
678 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
679 EXPECT_GL_NO_ERROR();
680 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
681 EXPECT_GL_NO_ERROR();
682
683 for (int i = 0; i < kWidth; i++)
684 {
685 for (int j = 0; j < kHeight; j++)
686 {
687 EXPECT_EQ(expectedValue, outputValues[i][j]);
688 }
689 }
690 }
691
692 // Use image uniform to write texture in compute shader, and verify the content is expected.
TEST_P(ComputeShaderTest,BindImageTexture)693 TEST_P(ComputeShaderTest, BindImageTexture)
694 {
695 GLTexture mTexture[2];
696 GLFramebuffer mFramebuffer;
697 constexpr char kCS[] = R"(#version 310 es
698 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
699 layout(r32ui, binding = 0) writeonly uniform highp uimage2D uImage[2];
700 void main()
701 {
702 imageStore(uImage[0], ivec2(gl_LocalInvocationIndex, gl_WorkGroupID.x), uvec4(100, 0,
703 0, 0));
704 imageStore(uImage[1], ivec2(gl_LocalInvocationIndex, gl_WorkGroupID.x), uvec4(100, 0,
705 0, 0));
706 })";
707
708 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
709 glUseProgram(program.get());
710 int width = 1, height = 1;
711 GLuint inputValues[] = {200};
712
713 glBindTexture(GL_TEXTURE_2D, mTexture[0]);
714 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, width, height);
715 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RED_INTEGER, GL_UNSIGNED_INT,
716 inputValues);
717 EXPECT_GL_NO_ERROR();
718
719 glBindImageTexture(0, mTexture[0], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
720 EXPECT_GL_NO_ERROR();
721
722 glBindTexture(GL_TEXTURE_2D, mTexture[1]);
723 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, width, height);
724 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RED_INTEGER, GL_UNSIGNED_INT,
725 inputValues);
726 EXPECT_GL_NO_ERROR();
727
728 glBindImageTexture(1, mTexture[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
729 EXPECT_GL_NO_ERROR();
730
731 glDispatchCompute(1, 1, 1);
732 EXPECT_GL_NO_ERROR();
733
734 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
735 glUseProgram(0);
736 GLuint outputValues[2][1];
737 GLuint expectedValue = 100;
738 glBindFramebuffer(GL_READ_FRAMEBUFFER, mFramebuffer);
739
740 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTexture[0],
741 0);
742 EXPECT_GL_NO_ERROR();
743 glReadPixels(0, 0, width, height, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues[0]);
744 EXPECT_GL_NO_ERROR();
745
746 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTexture[1],
747 0);
748 EXPECT_GL_NO_ERROR();
749 glReadPixels(0, 0, width, height, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues[1]);
750 EXPECT_GL_NO_ERROR();
751
752 for (int i = 0; i < width * height; i++)
753 {
754 EXPECT_EQ(expectedValue, outputValues[0][i]);
755 EXPECT_EQ(expectedValue, outputValues[1][i]);
756 }
757 }
758
759 // When declare a image array without a binding qualifier, all elements are bound to unit zero.
TEST_P(ComputeShaderTest,ImageArrayWithoutBindingQualifier)760 TEST_P(ComputeShaderTest, ImageArrayWithoutBindingQualifier)
761 {
762 ANGLE_SKIP_TEST_IF(IsD3D11());
763
764 // TODO(xinghua.cao@intel.com): On AMD desktop OpenGL, bind two image variables to unit 0,
765 // only one variable is valid.
766 ANGLE_SKIP_TEST_IF(IsAMD() && IsDesktopOpenGL());
767
768 GLTexture mTexture;
769 GLFramebuffer mFramebuffer;
770 constexpr char kCS[] = R"(#version 310 es
771 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
772 layout(r32ui) writeonly uniform highp uimage2D uImage[2];
773 void main()
774 {
775 imageStore(uImage[0], ivec2(gl_LocalInvocationIndex, 0), uvec4(100, 0, 0, 0));
776 imageStore(uImage[1], ivec2(gl_LocalInvocationIndex, 1), uvec4(100, 0, 0, 0));
777 })";
778
779 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
780 glUseProgram(program.get());
781 constexpr int kTextureWidth = 1, kTextureHeight = 2;
782 GLuint inputValues[] = {200, 200};
783
784 glBindTexture(GL_TEXTURE_2D, mTexture);
785 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kTextureWidth, kTextureHeight);
786 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kTextureWidth, kTextureHeight, GL_RED_INTEGER,
787 GL_UNSIGNED_INT, inputValues);
788 EXPECT_GL_NO_ERROR();
789
790 glBindImageTexture(0, mTexture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
791 glDispatchCompute(1, 1, 1);
792 EXPECT_GL_NO_ERROR();
793
794 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
795 glUseProgram(0);
796 glBindFramebuffer(GL_READ_FRAMEBUFFER, mFramebuffer);
797
798 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTexture, 0);
799 GLuint outputValues[kTextureWidth * kTextureHeight];
800 glReadPixels(0, 0, kTextureWidth, kTextureHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
801 outputValues);
802 EXPECT_GL_NO_ERROR();
803
804 GLuint expectedValue = 100;
805 for (int i = 0; i < kTextureWidth * kTextureHeight; i++)
806 {
807 EXPECT_EQ(expectedValue, outputValues[i]);
808 }
809 }
810
811 // imageLoad functions
TEST_P(ComputeShaderTest,ImageLoad)812 TEST_P(ComputeShaderTest, ImageLoad)
813 {
814 constexpr char kCS[] = R"(#version 310 es
815 layout(local_size_x=8) in;
816 layout(rgba8) uniform highp readonly image2D mImage2DInput;
817 layout(rgba16i) uniform highp readonly iimageCube mImageCubeInput;
818 layout(rgba32ui) uniform highp readonly uimage3D mImage3DInput;
819 layout(r32i) uniform highp writeonly iimage2D imageOut;
820 void main()
821 {
822 vec4 result2d = imageLoad(mImage2DInput, ivec2(gl_LocalInvocationID.xy));
823 ivec4 resultCube = imageLoad(mImageCubeInput, ivec3(gl_LocalInvocationID.xyz));
824 uvec4 result3d = imageLoad(mImage3DInput, ivec3(gl_LocalInvocationID.xyz));
825 imageStore(imageOut, ivec2(gl_LocalInvocationIndex, 0), ivec4(result2d) + resultCube + ivec4(result3d));
826 })";
827
828 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
829 EXPECT_GL_NO_ERROR();
830 }
831
832 // imageStore functions
TEST_P(ComputeShaderTest,ImageStore)833 TEST_P(ComputeShaderTest, ImageStore)
834 {
835 constexpr char kCS[] = R"(#version 310 es
836 layout(local_size_x=8) in;
837 layout(rgba16f) uniform highp writeonly imageCube mImageCubeOutput;
838 layout(r32f) uniform highp writeonly image3D mImage3DOutput;
839 layout(rgba8ui) uniform highp writeonly uimage2DArray mImage2DArrayOutput;
840 void main()
841 {
842 imageStore(mImageCubeOutput, ivec3(gl_LocalInvocationID.xyz), vec4(0.0));
843 imageStore(mImage3DOutput, ivec3(gl_LocalInvocationID.xyz), vec4(0.0));
844 imageStore(mImage2DArrayOutput, ivec3(gl_LocalInvocationID.xyz), uvec4(0));
845 })";
846
847 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
848 EXPECT_GL_NO_ERROR();
849 }
850
851 // imageSize functions
TEST_P(ComputeShaderTest,ImageSize)852 TEST_P(ComputeShaderTest, ImageSize)
853 {
854 constexpr char kCS[] = R"(#version 310 es
855 layout(local_size_x=8) in;
856 layout(rgba8) uniform highp readonly imageCube mImageCubeInput;
857 layout(r32i) uniform highp readonly iimage2D mImage2DInput;
858 layout(rgba16ui) uniform highp readonly uimage2DArray mImage2DArrayInput;
859 layout(r32i) uniform highp writeonly iimage2D imageOut;
860 void main()
861 {
862 ivec2 sizeCube = imageSize(mImageCubeInput);
863 ivec2 size2D = imageSize(mImage2DInput);
864 ivec3 size2DArray = imageSize(mImage2DArrayInput);
865 imageStore(imageOut, ivec2(gl_LocalInvocationIndex, 0), ivec4(sizeCube, size2D.x, size2DArray.x));
866 })";
867
868 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
869 EXPECT_GL_NO_ERROR();
870 }
871
872 // Test that texelFetch works well in compute shader.
TEST_P(ComputeShaderTest,TexelFetchFunction)873 TEST_P(ComputeShaderTest, TexelFetchFunction)
874 {
875 // http://anglebug.com/4092
876 ANGLE_SKIP_TEST_IF(isSwiftshader());
877 constexpr char kCS[] = R"(#version 310 es
878 layout(local_size_x=16, local_size_y=16) in;
879 precision highp usampler2D;
880 uniform usampler2D tex;
881 layout(std140, binding = 0) buffer buf {
882 uint outData[16][16];
883 };
884
885 void main()
886 {
887 uint x = gl_LocalInvocationID.x;
888 uint y = gl_LocalInvocationID.y;
889 outData[y][x] = texelFetch(tex, ivec2(x, y), 0).x;
890 })";
891
892 constexpr unsigned int kWidth = 16;
893 constexpr unsigned int kHeight = 16;
894 GLTexture tex;
895 glBindTexture(GL_TEXTURE_2D, tex);
896 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
897 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
898 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kWidth, kHeight);
899 GLuint texels[kHeight][kWidth] = {{0}};
900 for (unsigned int y = 0; y < kHeight; ++y)
901 {
902 for (unsigned int x = 0; x < kWidth; ++x)
903 {
904 texels[y][x] = x + y * kWidth;
905 }
906 }
907 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
908 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
909 texels);
910 glBindTexture(GL_TEXTURE_2D, 0);
911
912 // The array stride are rounded up to the base alignment of a vec4 for std140 layout.
913 constexpr unsigned int kArrayStride = 16;
914 GLBuffer ssbo;
915 glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
916 glBufferData(GL_SHADER_STORAGE_BUFFER, kWidth * kHeight * kArrayStride, nullptr,
917 GL_STREAM_DRAW);
918 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
919 EXPECT_GL_NO_ERROR();
920
921 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
922 glUseProgram(program);
923
924 glActiveTexture(GL_TEXTURE0);
925 glBindTexture(GL_TEXTURE_2D, tex);
926 glUniform1i(glGetUniformLocation(program, "tex"), 0);
927 glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
928 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, ssbo);
929
930 glDispatchCompute(1, 1, 1);
931
932 glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
933 const GLuint *ptr = reinterpret_cast<const GLuint *>(glMapBufferRange(
934 GL_SHADER_STORAGE_BUFFER, 0, kWidth * kHeight * kArrayStride, GL_MAP_READ_BIT));
935 EXPECT_GL_NO_ERROR();
936 for (unsigned int idx = 0; idx < kWidth * kHeight; idx++)
937 {
938 EXPECT_EQ(idx, *(ptr + idx * kArrayStride / 4));
939 }
940 }
941
942 // Test that texture function works well in compute shader.
TEST_P(ComputeShaderTest,TextureFunction)943 TEST_P(ComputeShaderTest, TextureFunction)
944 {
945 // http://anglebug.com/4092
946 ANGLE_SKIP_TEST_IF(isSwiftshader());
947 constexpr char kCS[] = R"(#version 310 es
948 layout(local_size_x=16, local_size_y=16) in;
949 precision highp usampler2D;
950 uniform usampler2D tex;
951 layout(std140, binding = 0) buffer buf {
952 uint outData[16][16];
953 };
954
955 void main()
956 {
957 uint x = gl_LocalInvocationID.x;
958 uint y = gl_LocalInvocationID.y;
959 float xCoord = float(x) / float(16);
960 float yCoord = float(y) / float(16);
961 outData[y][x] = texture(tex, vec2(xCoord, yCoord)).x;
962 })";
963
964 constexpr unsigned int kWidth = 16;
965 constexpr unsigned int kHeight = 16;
966 GLTexture tex;
967 glBindTexture(GL_TEXTURE_2D, tex);
968 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
969 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
970 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kWidth, kHeight);
971 GLuint texels[kHeight][kWidth] = {{0}};
972 for (unsigned int y = 0; y < kHeight; ++y)
973 {
974 for (unsigned int x = 0; x < kWidth; ++x)
975 {
976 texels[y][x] = x + y * kWidth;
977 }
978 }
979 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
980 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
981 texels);
982 glBindTexture(GL_TEXTURE_2D, 0);
983
984 // The array stride are rounded up to the base alignment of a vec4 for std140 layout.
985 constexpr unsigned int kArrayStride = 16;
986 GLBuffer ssbo;
987 glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
988 glBufferData(GL_SHADER_STORAGE_BUFFER, kWidth * kHeight * kArrayStride, nullptr,
989 GL_STREAM_DRAW);
990 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
991 EXPECT_GL_NO_ERROR();
992
993 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
994 glUseProgram(program);
995
996 glActiveTexture(GL_TEXTURE0);
997 glBindTexture(GL_TEXTURE_2D, tex);
998 glUniform1i(glGetUniformLocation(program, "tex"), 0);
999 glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
1000 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, ssbo);
1001
1002 glDispatchCompute(1, 1, 1);
1003
1004 glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
1005 const GLuint *ptr = reinterpret_cast<const GLuint *>(glMapBufferRange(
1006 GL_SHADER_STORAGE_BUFFER, 0, kWidth * kHeight * kArrayStride, GL_MAP_READ_BIT));
1007 EXPECT_GL_NO_ERROR();
1008 for (unsigned int idx = 0; idx < kWidth * kHeight; idx++)
1009 {
1010 EXPECT_EQ(idx, *(ptr + idx * kArrayStride / 4));
1011 }
1012 }
1013
1014 // Test mixed use of sampler and image.
TEST_P(ComputeShaderTest,SamplingAndImageReadWrite)1015 TEST_P(ComputeShaderTest, SamplingAndImageReadWrite)
1016 {
1017 GLTexture texture[3];
1018 GLFramebuffer framebuffer;
1019 constexpr char kCS[] = R"(#version 310 es
1020 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
1021 layout(r32ui, binding = 0) readonly uniform highp uimage2D uImage_1;
1022 layout(r32ui, binding = 1) writeonly uniform highp uimage2D uImage_2;
1023 precision highp usampler2D;
1024 uniform usampler2D tex;
1025 void main()
1026 {
1027 uvec4 value_1 = texelFetch(tex, ivec2(gl_LocalInvocationID.xy), 0);
1028 uvec4 value_2 = imageLoad(uImage_1, ivec2(gl_LocalInvocationID.xy));
1029 imageStore(uImage_2, ivec2(gl_LocalInvocationID.xy), value_1 + value_2);
1030 })";
1031
1032 constexpr int kWidth = 1, kHeight = 1;
1033 constexpr GLuint kInputValues[3][1] = {{50}, {100}, {20}};
1034
1035 glBindTexture(GL_TEXTURE_2D, texture[0]);
1036 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kWidth, kHeight);
1037 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
1038 kInputValues[0]);
1039 glBindTexture(GL_TEXTURE_2D, texture[2]);
1040 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kWidth, kHeight);
1041 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
1042 kInputValues[2]);
1043 EXPECT_GL_NO_ERROR();
1044 glBindTexture(GL_TEXTURE_2D, 0);
1045
1046 glBindTexture(GL_TEXTURE_2D, texture[1]);
1047 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1048 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1049 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kWidth, kHeight);
1050 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1051 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
1052 kInputValues[1]);
1053
1054 EXPECT_GL_NO_ERROR();
1055
1056 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
1057 glUseProgram(program.get());
1058
1059 glBindImageTexture(0, texture[0], 0, GL_FALSE, 0, GL_READ_ONLY, GL_R32UI);
1060 glBindImageTexture(1, texture[2], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
1061 EXPECT_GL_NO_ERROR();
1062
1063 glDispatchCompute(1, 1, 1);
1064 EXPECT_GL_NO_ERROR();
1065
1066 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
1067 GLuint outputValues[kWidth * kHeight];
1068 constexpr GLuint expectedValue = 150;
1069 glUseProgram(0);
1070 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
1071
1072 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture[2], 0);
1073 EXPECT_GL_NO_ERROR();
1074 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
1075 EXPECT_GL_NO_ERROR();
1076
1077 for (int i = 0; i < kWidth * kHeight; i++)
1078 {
1079 EXPECT_EQ(expectedValue, outputValues[i]);
1080 }
1081 }
1082
1083 // Use image uniform to read and write Texture2D in compute shader, and verify the contents.
TEST_P(ComputeShaderTest,BindImageTextureWithTexture2D)1084 TEST_P(ComputeShaderTest, BindImageTextureWithTexture2D)
1085 {
1086 GLTexture texture[2];
1087 GLFramebuffer framebuffer;
1088 constexpr char kCS[] = R"(#version 310 es
1089 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
1090 layout(r32ui, binding = 0) readonly uniform highp uimage2D uImage_1;
1091 layout(r32ui, binding = 1) writeonly uniform highp uimage2D uImage_2;
1092 void main()
1093 {
1094 uvec4 value = imageLoad(uImage_1, ivec2(gl_LocalInvocationID.xy));
1095 imageStore(uImage_2, ivec2(gl_LocalInvocationID.xy), value);
1096 })";
1097
1098 constexpr int kWidth = 1, kHeight = 1;
1099 constexpr GLuint kInputValues[2][1] = {{200}, {100}};
1100
1101 glBindTexture(GL_TEXTURE_2D, texture[0]);
1102 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kWidth, kHeight);
1103 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
1104 kInputValues[0]);
1105 EXPECT_GL_NO_ERROR();
1106
1107 glBindTexture(GL_TEXTURE_2D, texture[1]);
1108 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kWidth, kHeight);
1109 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
1110 kInputValues[1]);
1111 EXPECT_GL_NO_ERROR();
1112
1113 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
1114 glUseProgram(program.get());
1115
1116 glBindImageTexture(0, texture[0], 0, GL_FALSE, 0, GL_READ_ONLY, GL_R32UI);
1117 EXPECT_GL_NO_ERROR();
1118
1119 glBindImageTexture(1, texture[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
1120 EXPECT_GL_NO_ERROR();
1121
1122 glDispatchCompute(1, 1, 1);
1123 EXPECT_GL_NO_ERROR();
1124
1125 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
1126 GLuint outputValues[kWidth * kHeight];
1127 constexpr GLuint expectedValue = 200;
1128 glUseProgram(0);
1129 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
1130
1131 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture[1], 0);
1132 EXPECT_GL_NO_ERROR();
1133 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
1134 EXPECT_GL_NO_ERROR();
1135
1136 for (int i = 0; i < kWidth * kHeight; i++)
1137 {
1138 EXPECT_EQ(expectedValue, outputValues[i]);
1139 }
1140 }
1141
1142 // Use image uniform to read and write Texture2DArray in compute shader, and verify the contents.
TEST_P(ComputeShaderTest,BindImageTextureWithTexture2DArray)1143 TEST_P(ComputeShaderTest, BindImageTextureWithTexture2DArray)
1144 {
1145 GLTexture texture[2];
1146 GLFramebuffer framebuffer;
1147 constexpr char kCS[] = R"(#version 310 es
1148 layout(local_size_x=2, local_size_y=2, local_size_z=2) in;
1149 layout(r32ui, binding = 0) readonly uniform highp uimage2DArray uImage_1;
1150 layout(r32ui, binding = 1) writeonly uniform highp uimage2DArray uImage_2;
1151 void main()
1152 {
1153 uvec4 value = imageLoad(uImage_1, ivec3(gl_LocalInvocationID.xyz));
1154 imageStore(uImage_2, ivec3(gl_LocalInvocationID.xyz), value);
1155 })";
1156
1157 constexpr int kWidth = 1, kHeight = 1, kDepth = 2;
1158 constexpr GLuint kInputValues[2][2] = {{200, 200}, {100, 100}};
1159
1160 glBindTexture(GL_TEXTURE_2D_ARRAY, texture[0]);
1161 glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_R32UI, kWidth, kHeight, kDepth);
1162 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, kWidth, kHeight, kDepth, GL_RED_INTEGER,
1163 GL_UNSIGNED_INT, kInputValues[0]);
1164 EXPECT_GL_NO_ERROR();
1165
1166 glBindTexture(GL_TEXTURE_2D_ARRAY, texture[1]);
1167 glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_R32UI, kWidth, kHeight, kDepth);
1168 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, kWidth, kHeight, kDepth, GL_RED_INTEGER,
1169 GL_UNSIGNED_INT, kInputValues[1]);
1170 EXPECT_GL_NO_ERROR();
1171
1172 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
1173 glUseProgram(program.get());
1174
1175 glBindImageTexture(0, texture[0], 0, GL_TRUE, 0, GL_READ_ONLY, GL_R32UI);
1176 EXPECT_GL_NO_ERROR();
1177
1178 glBindImageTexture(1, texture[1], 0, GL_TRUE, 0, GL_WRITE_ONLY, GL_R32UI);
1179 EXPECT_GL_NO_ERROR();
1180
1181 glDispatchCompute(1, 1, 1);
1182 EXPECT_GL_NO_ERROR();
1183
1184 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
1185 GLuint outputValues[kWidth * kHeight];
1186 constexpr GLuint expectedValue = 200;
1187 glUseProgram(0);
1188 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
1189
1190 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture[1], 0, 0);
1191 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, texture[1], 0, 1);
1192 EXPECT_GL_NO_ERROR();
1193 glReadBuffer(GL_COLOR_ATTACHMENT0);
1194 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
1195 EXPECT_GL_NO_ERROR();
1196 for (int i = 0; i < kWidth * kHeight; i++)
1197 {
1198 EXPECT_EQ(expectedValue, outputValues[i]);
1199 }
1200 glReadBuffer(GL_COLOR_ATTACHMENT1);
1201 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
1202 EXPECT_GL_NO_ERROR();
1203 for (int i = 0; i < kWidth * kHeight; i++)
1204 {
1205 EXPECT_EQ(expectedValue, outputValues[i]);
1206 }
1207 }
1208
1209 // Use image uniform to read and write Texture3D in compute shader, and verify the contents.
TEST_P(ComputeShaderTest,BindImageTextureWithTexture3D)1210 TEST_P(ComputeShaderTest, BindImageTextureWithTexture3D)
1211 {
1212 GLTexture texture[2];
1213 GLFramebuffer framebuffer;
1214 constexpr char kCS[] = R"(#version 310 es
1215 layout(local_size_x=1, local_size_y=1, local_size_z=2) in;
1216 layout(r32ui, binding = 0) readonly uniform highp uimage3D uImage_1;
1217 layout(r32ui, binding = 1) writeonly uniform highp uimage3D uImage_2;
1218 void main()
1219 {
1220 uvec4 value = imageLoad(uImage_1, ivec3(gl_LocalInvocationID.xyz));
1221 imageStore(uImage_2, ivec3(gl_LocalInvocationID.xyz), value);
1222 })";
1223
1224 constexpr int kWidth = 1, kHeight = 1, kDepth = 2;
1225 constexpr GLuint kInputValues[2][2] = {{200, 200}, {100, 100}};
1226
1227 glBindTexture(GL_TEXTURE_3D, texture[0]);
1228 glTexStorage3D(GL_TEXTURE_3D, 1, GL_R32UI, kWidth, kHeight, kDepth);
1229 glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, kWidth, kHeight, kDepth, GL_RED_INTEGER,
1230 GL_UNSIGNED_INT, kInputValues[0]);
1231 EXPECT_GL_NO_ERROR();
1232
1233 glBindTexture(GL_TEXTURE_3D, texture[1]);
1234 glTexStorage3D(GL_TEXTURE_3D, 1, GL_R32UI, kWidth, kHeight, kDepth);
1235 glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, kWidth, kHeight, kDepth, GL_RED_INTEGER,
1236 GL_UNSIGNED_INT, kInputValues[1]);
1237 EXPECT_GL_NO_ERROR();
1238
1239 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
1240 glUseProgram(program.get());
1241
1242 glBindImageTexture(0, texture[0], 0, GL_TRUE, 0, GL_READ_ONLY, GL_R32UI);
1243 EXPECT_GL_NO_ERROR();
1244
1245 glBindImageTexture(1, texture[1], 0, GL_TRUE, 0, GL_WRITE_ONLY, GL_R32UI);
1246 EXPECT_GL_NO_ERROR();
1247
1248 glDispatchCompute(1, 1, 1);
1249 EXPECT_GL_NO_ERROR();
1250
1251 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
1252 GLuint outputValues[kWidth * kHeight];
1253 constexpr GLuint expectedValue = 200;
1254 glUseProgram(0);
1255 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
1256
1257 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture[1], 0, 0);
1258 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, texture[1], 0, 1);
1259 EXPECT_GL_NO_ERROR();
1260 glReadBuffer(GL_COLOR_ATTACHMENT0);
1261 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
1262 EXPECT_GL_NO_ERROR();
1263 for (int i = 0; i < kWidth * kHeight; i++)
1264 {
1265 EXPECT_EQ(expectedValue, outputValues[i]);
1266 }
1267 glReadBuffer(GL_COLOR_ATTACHMENT1);
1268 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
1269 EXPECT_GL_NO_ERROR();
1270 for (int i = 0; i < kWidth * kHeight; i++)
1271 {
1272 EXPECT_EQ(expectedValue, outputValues[i]);
1273 }
1274 }
1275
1276 // Use image uniform to read and write TextureCube in compute shader, and verify the contents.
TEST_P(ComputeShaderTest,BindImageTextureWithTextureCube)1277 TEST_P(ComputeShaderTest, BindImageTextureWithTextureCube)
1278 {
1279 GLTexture texture[2];
1280 GLFramebuffer framebuffer;
1281 constexpr char kCS[] = R"(#version 310 es
1282 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
1283 layout(r32ui, binding = 0) readonly uniform highp uimageCube uImage_1;
1284 layout(r32ui, binding = 1) writeonly uniform highp uimageCube uImage_2;
1285 void main()
1286 {
1287 for (int i = 0; i < 6; i++)
1288 {
1289 uvec4 value = imageLoad(uImage_1, ivec3(gl_LocalInvocationID.xy, i));
1290 imageStore(uImage_2, ivec3(gl_LocalInvocationID.xy, i), value);
1291 }
1292 })";
1293
1294 constexpr int kWidth = 1, kHeight = 1;
1295 constexpr GLuint kInputValues[2][1] = {{200}, {100}};
1296
1297 glBindTexture(GL_TEXTURE_CUBE_MAP, texture[0]);
1298 glTexStorage2D(GL_TEXTURE_CUBE_MAP, 1, GL_R32UI, kWidth, kHeight);
1299 for (GLenum face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
1300 face++)
1301 {
1302 glTexSubImage2D(face, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
1303 kInputValues[0]);
1304 }
1305 EXPECT_GL_NO_ERROR();
1306
1307 glBindTexture(GL_TEXTURE_CUBE_MAP, texture[1]);
1308 glTexStorage2D(GL_TEXTURE_CUBE_MAP, 1, GL_R32UI, kWidth, kHeight);
1309 for (GLenum face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
1310 face++)
1311 {
1312 glTexSubImage2D(face, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
1313 kInputValues[1]);
1314 }
1315 EXPECT_GL_NO_ERROR();
1316
1317 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
1318 glUseProgram(program.get());
1319
1320 glBindImageTexture(0, texture[0], 0, GL_TRUE, 0, GL_READ_ONLY, GL_R32UI);
1321 EXPECT_GL_NO_ERROR();
1322
1323 glBindImageTexture(1, texture[1], 0, GL_TRUE, 0, GL_WRITE_ONLY, GL_R32UI);
1324 EXPECT_GL_NO_ERROR();
1325
1326 glDispatchCompute(1, 1, 1);
1327 EXPECT_GL_NO_ERROR();
1328
1329 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
1330 GLuint outputValues[kWidth * kHeight];
1331 constexpr GLuint expectedValue = 200;
1332 glUseProgram(0);
1333 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
1334
1335 for (GLenum face = 0; face < 6; face++)
1336 {
1337 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
1338 GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, texture[1], 0);
1339 EXPECT_GL_NO_ERROR();
1340 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
1341 EXPECT_GL_NO_ERROR();
1342
1343 for (int i = 0; i < kWidth * kHeight; i++)
1344 {
1345 EXPECT_EQ(expectedValue, outputValues[i]);
1346 }
1347 }
1348 }
1349
1350 // Use image uniform to read and write one layer of Texture2DArray in compute shader, and verify the
1351 // contents.
TEST_P(ComputeShaderTest,BindImageTextureWithOneLayerTexture2DArray)1352 TEST_P(ComputeShaderTest, BindImageTextureWithOneLayerTexture2DArray)
1353 {
1354 GLTexture texture[2];
1355 GLFramebuffer framebuffer;
1356 constexpr char kCS[] = R"(#version 310 es
1357 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
1358 layout(r32ui, binding = 0) readonly uniform highp uimage2D uImage_1;
1359 layout(r32ui, binding = 1) writeonly uniform highp uimage2D uImage_2;
1360 void main()
1361 {
1362 uvec4 value = imageLoad(uImage_1, ivec2(gl_LocalInvocationID.xy));
1363 imageStore(uImage_2, ivec2(gl_LocalInvocationID.xy), value);
1364 })";
1365
1366 constexpr int kWidth = 1, kHeight = 1, kDepth = 2;
1367 constexpr int kResultSize = kWidth * kHeight;
1368 constexpr GLuint kInputValues[2][2] = {{200, 150}, {100, 50}};
1369 constexpr GLuint expectedValue_1 = 200;
1370 constexpr GLuint expectedValue_2 = 100;
1371 GLuint outputValues[kResultSize];
1372
1373 glBindTexture(GL_TEXTURE_2D_ARRAY, texture[0]);
1374 glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_R32UI, kWidth, kHeight, kDepth);
1375 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, kWidth, kHeight, kDepth, GL_RED_INTEGER,
1376 GL_UNSIGNED_INT, kInputValues[0]);
1377 EXPECT_GL_NO_ERROR();
1378
1379 glBindTexture(GL_TEXTURE_2D_ARRAY, texture[1]);
1380 glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_R32UI, kWidth, kHeight, kDepth);
1381 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, kWidth, kHeight, kDepth, GL_RED_INTEGER,
1382 GL_UNSIGNED_INT, kInputValues[1]);
1383 EXPECT_GL_NO_ERROR();
1384
1385 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
1386 glUseProgram(program.get());
1387
1388 glBindImageTexture(0, texture[0], 0, GL_FALSE, 0, GL_READ_ONLY, GL_R32UI);
1389 EXPECT_GL_NO_ERROR();
1390 glBindImageTexture(1, texture[1], 0, GL_FALSE, 1, GL_WRITE_ONLY, GL_R32UI);
1391 EXPECT_GL_NO_ERROR();
1392 glDispatchCompute(1, 1, 1);
1393 EXPECT_GL_NO_ERROR();
1394
1395 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
1396 glUseProgram(0);
1397 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
1398 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture[1], 0, 0);
1399 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, texture[1], 0, 1);
1400 EXPECT_GL_NO_ERROR();
1401 glReadBuffer(GL_COLOR_ATTACHMENT0);
1402 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
1403 EXPECT_GL_NO_ERROR();
1404 for (int i = 0; i < kResultSize; i++)
1405 {
1406 EXPECT_EQ(expectedValue_2, outputValues[i]);
1407 }
1408 glReadBuffer(GL_COLOR_ATTACHMENT1);
1409 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
1410 EXPECT_GL_NO_ERROR();
1411 for (int i = 0; i < kResultSize; i++)
1412 {
1413 EXPECT_EQ(expectedValue_1, outputValues[i]);
1414 }
1415 }
1416
1417 // Use image uniform to read and write one layer of Texture3D in compute shader, and verify the
1418 // contents.
TEST_P(ComputeShaderTest,BindImageTextureWithOneLayerTexture3D)1419 TEST_P(ComputeShaderTest, BindImageTextureWithOneLayerTexture3D)
1420 {
1421 // Vulkan validation error creating a 2D image view of a 3D image layer.
1422 // http://anglebug.com/3886
1423 ANGLE_SKIP_TEST_IF(IsVulkan());
1424
1425 GLTexture texture[2];
1426 GLFramebuffer framebuffer;
1427 constexpr char kCS[] = R"(#version 310 es
1428 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
1429 layout(r32ui, binding = 0) readonly uniform highp uimage2D uImage_1;
1430 layout(r32ui, binding = 1) writeonly uniform highp uimage2D uImage_2;
1431 void main()
1432 {
1433 uvec4 value = imageLoad(uImage_1, ivec2(gl_LocalInvocationID.xy));
1434 imageStore(uImage_2, ivec2(gl_LocalInvocationID.xy), value);
1435 })";
1436
1437 constexpr int kWidth = 1, kHeight = 1, kDepth = 2;
1438 constexpr int kResultSize = kWidth * kHeight;
1439 constexpr GLuint kInputValues[2][2] = {{200, 150}, {100, 50}};
1440 constexpr GLuint expectedValue_1 = 150;
1441 constexpr GLuint expectedValue_2 = 50;
1442 GLuint outputValues[kResultSize];
1443
1444 glBindTexture(GL_TEXTURE_3D, texture[0]);
1445 glTexStorage3D(GL_TEXTURE_3D, 1, GL_R32UI, kWidth, kHeight, kDepth);
1446 glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, kWidth, kHeight, kDepth, GL_RED_INTEGER,
1447 GL_UNSIGNED_INT, kInputValues[0]);
1448 EXPECT_GL_NO_ERROR();
1449
1450 glBindTexture(GL_TEXTURE_3D, texture[1]);
1451 glTexStorage3D(GL_TEXTURE_3D, 1, GL_R32UI, kWidth, kHeight, kDepth);
1452 glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, kWidth, kHeight, kDepth, GL_RED_INTEGER,
1453 GL_UNSIGNED_INT, kInputValues[1]);
1454 EXPECT_GL_NO_ERROR();
1455
1456 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
1457 glUseProgram(program.get());
1458
1459 glBindImageTexture(0, texture[0], 0, GL_FALSE, 1, GL_READ_ONLY, GL_R32UI);
1460 EXPECT_GL_NO_ERROR();
1461 glBindImageTexture(1, texture[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
1462 EXPECT_GL_NO_ERROR();
1463 glDispatchCompute(1, 1, 1);
1464 EXPECT_GL_NO_ERROR();
1465
1466 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
1467 glUseProgram(0);
1468 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
1469 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture[1], 0, 0);
1470 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, texture[1], 0, 1);
1471 EXPECT_GL_NO_ERROR();
1472 glReadBuffer(GL_COLOR_ATTACHMENT0);
1473 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
1474 EXPECT_GL_NO_ERROR();
1475 for (int i = 0; i < kResultSize; i++)
1476 {
1477 EXPECT_EQ(expectedValue_1, outputValues[i]);
1478 }
1479 glReadBuffer(GL_COLOR_ATTACHMENT1);
1480 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
1481 EXPECT_GL_NO_ERROR();
1482 for (int i = 0; i < kResultSize; i++)
1483 {
1484 EXPECT_EQ(expectedValue_2, outputValues[i]);
1485 }
1486 }
1487
1488 // Use image uniform to read and write one layer of TextureCube in compute shader, and verify the
1489 // contents.
TEST_P(ComputeShaderTest,BindImageTextureWithOneLayerTextureCube)1490 TEST_P(ComputeShaderTest, BindImageTextureWithOneLayerTextureCube)
1491 {
1492 // GL_FRAMEBUFFER_BARRIER_BIT is invalid on Nvidia Linux platform.
1493 // http://anglebug.com/3736
1494 ANGLE_SKIP_TEST_IF(IsNVIDIA() && IsOpenGL() && IsLinux());
1495
1496 GLTexture texture[2];
1497 GLFramebuffer framebuffer;
1498 constexpr char kCS[] = R"(#version 310 es
1499 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
1500 layout(r32ui, binding = 0) readonly uniform highp uimage2D uImage_1;
1501 layout(r32ui, binding = 1) writeonly uniform highp uimage2D uImage_2;
1502 void main()
1503 {
1504 uvec4 value = imageLoad(uImage_1, ivec2(gl_LocalInvocationID.xy));
1505 imageStore(uImage_2, ivec2(gl_LocalInvocationID.xy), value);
1506 })";
1507
1508 constexpr int kWidth = 1, kHeight = 1;
1509 constexpr int kResultSize = kWidth * kHeight;
1510 constexpr GLuint kInputValues[2][1] = {{200}, {100}};
1511 constexpr GLuint expectedValue_1 = 200;
1512 constexpr GLuint expectedValue_2 = 100;
1513 GLuint outputValues[kResultSize];
1514
1515 glBindTexture(GL_TEXTURE_CUBE_MAP, texture[0]);
1516 glTexStorage2D(GL_TEXTURE_CUBE_MAP, 1, GL_R32UI, kWidth, kHeight);
1517 for (GLenum face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
1518 face++)
1519 {
1520 glTexSubImage2D(face, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
1521 kInputValues[0]);
1522 }
1523 EXPECT_GL_NO_ERROR();
1524
1525 glBindTexture(GL_TEXTURE_CUBE_MAP, texture[1]);
1526 glTexStorage2D(GL_TEXTURE_CUBE_MAP, 1, GL_R32UI, kWidth, kHeight);
1527 for (GLenum face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
1528 face++)
1529 {
1530 glTexSubImage2D(face, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
1531 kInputValues[1]);
1532 }
1533 EXPECT_GL_NO_ERROR();
1534
1535 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
1536 glUseProgram(program.get());
1537
1538 glBindImageTexture(0, texture[0], 0, GL_FALSE, 3, GL_READ_ONLY, GL_R32UI);
1539 EXPECT_GL_NO_ERROR();
1540 glBindImageTexture(1, texture[1], 0, GL_FALSE, 4, GL_WRITE_ONLY, GL_R32UI);
1541 EXPECT_GL_NO_ERROR();
1542 glDispatchCompute(1, 1, 1);
1543 EXPECT_GL_NO_ERROR();
1544
1545 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
1546 glUseProgram(0);
1547 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
1548
1549 for (GLenum face = 0; face < 6; face++)
1550 {
1551 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
1552 GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, texture[1], 0);
1553 EXPECT_GL_NO_ERROR();
1554 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
1555 EXPECT_GL_NO_ERROR();
1556
1557 if (face == 4)
1558 {
1559 for (int i = 0; i < kResultSize; i++)
1560 {
1561 EXPECT_EQ(expectedValue_1, outputValues[i]);
1562 }
1563 }
1564 else
1565 {
1566 for (int i = 0; i < kResultSize; i++)
1567 {
1568 EXPECT_EQ(expectedValue_2, outputValues[i]);
1569 }
1570 }
1571 }
1572 }
1573
1574 // Test to bind kinds of texture types, bind either the entire texture
1575 // level or a single layer or face of the face level.
TEST_P(ComputeShaderTest,BindImageTextureWithMixTextureTypes)1576 TEST_P(ComputeShaderTest, BindImageTextureWithMixTextureTypes)
1577 {
1578 // GL_FRAMEBUFFER_BARRIER_BIT is invalid on Nvidia Linux platform.
1579 // http://anglebug.com/3736
1580 ANGLE_SKIP_TEST_IF(IsNVIDIA() && IsOpenGL() && IsLinux());
1581
1582 GLTexture texture[4];
1583 GLFramebuffer framebuffer;
1584 const char csSource[] =
1585 R"(#version 310 es
1586 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
1587 layout(r32ui, binding = 0) readonly uniform highp uimage2D uImage_1;
1588 layout(r32ui, binding = 1) readonly uniform highp uimage2D uImage_2;
1589 layout(r32ui, binding = 2) readonly uniform highp uimage3D uImage_3;
1590 layout(r32ui, binding = 3) writeonly uniform highp uimage2D uImage_4;
1591 void main()
1592 {
1593 uvec4 value_1 = imageLoad(uImage_1, ivec2(gl_LocalInvocationID.xy));
1594 uvec4 value_2 = imageLoad(uImage_2, ivec2(gl_LocalInvocationID.xy));
1595 uvec4 value_3 = imageLoad(uImage_3, ivec3(gl_LocalInvocationID.xyz));
1596 imageStore(uImage_4, ivec2(gl_LocalInvocationID.xy), value_1 + value_2 + value_3);
1597 })";
1598
1599 constexpr int kWidth = 1, kHeight = 1, kDepth = 2;
1600 constexpr int kResultSize = kWidth * kHeight;
1601 constexpr GLuint kInputValues2D[1] = {11};
1602 constexpr GLuint KInputValues2DArray[2] = {23, 35};
1603 constexpr GLuint KInputValues3D[2] = {102, 67};
1604 constexpr GLuint KInputValuesCube[1] = {232};
1605
1606 constexpr GLuint expectedValue_1 = 148;
1607 constexpr GLuint expectedValue_2 = 232;
1608 GLuint outputValues[kResultSize];
1609
1610 glBindTexture(GL_TEXTURE_2D, texture[0]);
1611 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kWidth, kHeight);
1612 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
1613 kInputValues2D);
1614 EXPECT_GL_NO_ERROR();
1615
1616 glBindTexture(GL_TEXTURE_2D_ARRAY, texture[1]);
1617 glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_R32UI, kWidth, kHeight, kDepth);
1618 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, kWidth, kHeight, kDepth, GL_RED_INTEGER,
1619 GL_UNSIGNED_INT, KInputValues2DArray);
1620 EXPECT_GL_NO_ERROR();
1621
1622 glBindTexture(GL_TEXTURE_3D, texture[2]);
1623 glTexStorage3D(GL_TEXTURE_3D, 1, GL_R32UI, kWidth, kHeight, kDepth);
1624 glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, kWidth, kHeight, kDepth, GL_RED_INTEGER,
1625 GL_UNSIGNED_INT, KInputValues3D);
1626 EXPECT_GL_NO_ERROR();
1627
1628 glBindTexture(GL_TEXTURE_CUBE_MAP, texture[3]);
1629 glTexStorage2D(GL_TEXTURE_CUBE_MAP, 1, GL_R32UI, kWidth, kHeight);
1630 for (GLenum face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
1631 face++)
1632 {
1633 glTexSubImage2D(face, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
1634 KInputValuesCube);
1635 }
1636 EXPECT_GL_NO_ERROR();
1637
1638 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
1639 glUseProgram(program.get());
1640
1641 glBindImageTexture(0, texture[0], 0, GL_TRUE, 0, GL_READ_ONLY, GL_R32UI);
1642 EXPECT_GL_NO_ERROR();
1643 glBindImageTexture(1, texture[1], 0, GL_FALSE, 1, GL_READ_ONLY, GL_R32UI);
1644 EXPECT_GL_NO_ERROR();
1645 glBindImageTexture(2, texture[2], 0, GL_TRUE, 0, GL_READ_ONLY, GL_R32UI);
1646 EXPECT_GL_NO_ERROR();
1647 glBindImageTexture(3, texture[3], 0, GL_FALSE, 4, GL_WRITE_ONLY, GL_R32UI);
1648 EXPECT_GL_NO_ERROR();
1649 glDispatchCompute(1, 1, 1);
1650 EXPECT_GL_NO_ERROR();
1651
1652 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
1653 glUseProgram(0);
1654 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
1655
1656 for (GLenum face = 0; face < 6; face++)
1657 {
1658 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
1659 GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, texture[3], 0);
1660 EXPECT_GL_NO_ERROR();
1661 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
1662 EXPECT_GL_NO_ERROR();
1663
1664 if (face == 4)
1665 {
1666 for (int i = 0; i < kResultSize; i++)
1667 {
1668 EXPECT_EQ(expectedValue_1, outputValues[i]);
1669 }
1670 }
1671 else
1672 {
1673 for (int i = 0; i < kResultSize; i++)
1674 {
1675 EXPECT_EQ(expectedValue_2, outputValues[i]);
1676 }
1677 }
1678 }
1679 }
1680
1681 // Verify an INVALID_OPERATION error is reported when querying GL_COMPUTE_WORK_GROUP_SIZE for a
1682 // program which has not been linked successfully or which does not contain objects to form a
1683 // compute shader.
TEST_P(ComputeShaderTest,QueryComputeWorkGroupSize)1684 TEST_P(ComputeShaderTest, QueryComputeWorkGroupSize)
1685 {
1686 constexpr char kVS[] = R"(#version 310 es
1687 void main()
1688 {
1689 })";
1690
1691 constexpr char kFS[] = R"(#version 310 es
1692 void main()
1693 {
1694 })";
1695
1696 GLint workGroupSize[3];
1697
1698 ANGLE_GL_PROGRAM(graphicsProgram, kVS, kFS);
1699 glGetProgramiv(graphicsProgram, GL_COMPUTE_WORK_GROUP_SIZE, workGroupSize);
1700 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1701
1702 GLuint computeProgram = glCreateProgram();
1703 GLShader computeShader(GL_COMPUTE_SHADER);
1704 glAttachShader(computeProgram, computeShader);
1705 glLinkProgram(computeProgram);
1706 glDetachShader(computeProgram, computeShader);
1707
1708 GLint linkStatus;
1709 glGetProgramiv(computeProgram, GL_LINK_STATUS, &linkStatus);
1710 ASSERT_GL_FALSE(linkStatus);
1711
1712 glGetProgramiv(computeProgram, GL_COMPUTE_WORK_GROUP_SIZE, workGroupSize);
1713 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1714
1715 glDeleteProgram(computeProgram);
1716
1717 ASSERT_GL_NO_ERROR();
1718 }
1719
1720 // Use groupMemoryBarrier and barrier to sync reads/writes order and the execution
1721 // order of multiple shader invocations in compute shader.
TEST_P(ComputeShaderTest,groupMemoryBarrierAndBarrierTest)1722 TEST_P(ComputeShaderTest, groupMemoryBarrierAndBarrierTest)
1723 {
1724 // TODO(xinghua.cao@intel.com): Figure out why we get this error message
1725 // that shader uses features not recognized by this D3D version.
1726 ANGLE_SKIP_TEST_IF((IsAMD() || IsNVIDIA()) && IsD3D11());
1727 ANGLE_SKIP_TEST_IF(IsARM64() && IsWindows() && IsD3D());
1728
1729 GLTexture texture;
1730 GLFramebuffer framebuffer;
1731
1732 // Each invocation first stores a single value in an image, then each invocation sums up
1733 // all the values in the image and stores the sum in the image. groupMemoryBarrier is
1734 // used to order reads/writes to variables stored in memory accessible to other shader
1735 // invocations, and barrier is used to control the relative execution order of multiple
1736 // shader invocations used to process a local work group.
1737 constexpr char kCS[] = R"(#version 310 es
1738 layout(local_size_x=2, local_size_y=2, local_size_z=1) in;
1739 layout(r32i, binding = 0) uniform highp iimage2D image;
1740 void main()
1741 {
1742 uint x = gl_LocalInvocationID.x;
1743 uint y = gl_LocalInvocationID.y;
1744 imageStore(image, ivec2(gl_LocalInvocationID.xy), ivec4(x + y));
1745 groupMemoryBarrier();
1746 barrier();
1747 int sum = 0;
1748 for (int i = 0; i < 2; i++)
1749 {
1750 for(int j = 0; j < 2; j++)
1751 {
1752 sum += imageLoad(image, ivec2(i, j)).x;
1753 }
1754 }
1755 groupMemoryBarrier();
1756 barrier();
1757 imageStore(image, ivec2(gl_LocalInvocationID.xy), ivec4(sum));
1758 })";
1759
1760 constexpr int kWidth = 2, kHeight = 2;
1761 glBindTexture(GL_TEXTURE_2D, texture);
1762 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32I, kWidth, kHeight);
1763 EXPECT_GL_NO_ERROR();
1764
1765 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
1766 glUseProgram(program.get());
1767
1768 glBindImageTexture(0, texture, 0, GL_FALSE, 0, GL_READ_WRITE, GL_R32I);
1769 EXPECT_GL_NO_ERROR();
1770
1771 glDispatchCompute(1, 1, 1);
1772 EXPECT_GL_NO_ERROR();
1773
1774 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
1775 GLuint outputValues[kWidth * kHeight];
1776 constexpr GLuint kExpectedValue = 4;
1777 glUseProgram(0);
1778 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
1779
1780 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
1781 EXPECT_GL_NO_ERROR();
1782 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_INT, outputValues);
1783 EXPECT_GL_NO_ERROR();
1784
1785 for (int i = 0; i < kWidth * kHeight; i++)
1786 {
1787 EXPECT_EQ(kExpectedValue, outputValues[i]);
1788 }
1789 }
1790
1791 // Verify that a link error is generated when the sum of the number of active image uniforms and
1792 // active shader storage blocks in a compute shader exceeds GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES.
TEST_P(ComputeShaderTest,ExceedCombinedShaderOutputResourcesInCS)1793 TEST_P(ComputeShaderTest, ExceedCombinedShaderOutputResourcesInCS)
1794 {
1795 GLint maxCombinedShaderOutputResources;
1796 GLint maxComputeShaderStorageBlocks;
1797 GLint maxComputeImageUniforms;
1798
1799 glGetIntegerv(GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES, &maxCombinedShaderOutputResources);
1800 glGetIntegerv(GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS, &maxComputeShaderStorageBlocks);
1801 glGetIntegerv(GL_MAX_COMPUTE_IMAGE_UNIFORMS, &maxComputeImageUniforms);
1802
1803 ANGLE_SKIP_TEST_IF(maxCombinedShaderOutputResources >=
1804 maxComputeShaderStorageBlocks + maxComputeImageUniforms);
1805
1806 std::ostringstream computeShaderStream;
1807 computeShaderStream << "#version 310 es\n"
1808 "layout(local_size_x = 3, local_size_y = 1, local_size_z = 1) in;\n"
1809 "layout(shared, binding = 0) buffer blockName"
1810 "{\n"
1811 " uint data;\n"
1812 "} instance["
1813 << maxComputeShaderStorageBlocks << "];\n";
1814
1815 ASSERT_GE(maxComputeImageUniforms, 4);
1816 int numImagesInArray = maxComputeImageUniforms / 2;
1817 int numImagesNonArray = maxComputeImageUniforms - numImagesInArray;
1818 for (int i = 0; i < numImagesNonArray; ++i)
1819 {
1820 computeShaderStream << "layout(r32f, binding = " << i << ") uniform highp image2D image"
1821 << i << ";\n";
1822 }
1823
1824 computeShaderStream << "layout(r32f, binding = " << numImagesNonArray
1825 << ") uniform highp image2D imageArray[" << numImagesInArray << "];\n";
1826
1827 computeShaderStream << "void main()\n"
1828 "{\n"
1829 " uint val = 0u;\n"
1830 " vec4 val2 = vec4(0.0);\n";
1831
1832 for (int i = 0; i < maxComputeShaderStorageBlocks; ++i)
1833 {
1834 computeShaderStream << " val += instance[" << i << "].data; \n";
1835 }
1836
1837 for (int i = 0; i < numImagesNonArray; ++i)
1838 {
1839 computeShaderStream << " val2 += imageLoad(image" << i
1840 << ", ivec2(gl_LocalInvocationID.xy)); \n";
1841 }
1842
1843 for (int i = 0; i < numImagesInArray; ++i)
1844 {
1845 computeShaderStream << " val2 += imageLoad(imageArray[" << i << "]"
1846 << ", ivec2(gl_LocalInvocationID.xy)); \n";
1847 }
1848
1849 computeShaderStream << " instance[0].data = val + uint(val2.x);\n"
1850 "}\n";
1851
1852 GLuint computeProgram = CompileComputeProgram(computeShaderStream.str().c_str());
1853 EXPECT_EQ(0u, computeProgram);
1854 }
1855
1856 // Test that uniform block with struct member in compute shader is supported.
TEST_P(ComputeShaderTest,UniformBlockWithStructMember)1857 TEST_P(ComputeShaderTest, UniformBlockWithStructMember)
1858 {
1859 constexpr char kCS[] = R"(#version 310 es
1860 layout(local_size_x=8) in;
1861 layout(rgba8) uniform highp readonly image2D mImage2DInput;
1862 layout(rgba8) uniform highp writeonly image2D mImage2DOutput;
1863 struct S {
1864 ivec3 a;
1865 ivec2 b;
1866 };
1867
1868 layout(std140, binding=0) uniform blockName {
1869 S bd;
1870 } instanceName;
1871 void main()
1872 {
1873 ivec2 t1 = instanceName.bd.b;
1874 vec4 result2d = imageLoad(mImage2DInput, t1);
1875 imageStore(mImage2DOutput, ivec2(gl_LocalInvocationID.xy), result2d);
1876 })";
1877
1878 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
1879 EXPECT_GL_NO_ERROR();
1880 }
1881
1882 // Verify shared non-array variables can work correctly.
TEST_P(ComputeShaderTest,NonArraySharedVariable)1883 TEST_P(ComputeShaderTest, NonArraySharedVariable)
1884 {
1885 const char kCSShader[] = R"(#version 310 es
1886 layout (local_size_x = 2, local_size_y = 2, local_size_z = 1) in;
1887 layout (r32ui, binding = 0) readonly uniform highp uimage2D srcImage;
1888 layout (r32ui, binding = 1) writeonly uniform highp uimage2D dstImage;
1889 shared uint temp;
1890 void main()
1891 {
1892 if (gl_LocalInvocationID == uvec3(0, 0, 0))
1893 {
1894 temp = imageLoad(srcImage, ivec2(gl_LocalInvocationID.xy)).x;
1895 }
1896 groupMemoryBarrier();
1897 barrier();
1898 if (gl_LocalInvocationID == uvec3(1, 1, 0))
1899 {
1900 imageStore(dstImage, ivec2(gl_LocalInvocationID.xy), uvec4(temp));
1901 }
1902 else
1903 {
1904 uint inputValue = imageLoad(srcImage, ivec2(gl_LocalInvocationID.xy)).x;
1905 imageStore(dstImage, ivec2(gl_LocalInvocationID.xy), uvec4(inputValue));
1906 }
1907 })";
1908
1909 const std::array<GLuint, 4> inputData = {{250, 200, 150, 100}};
1910 const std::array<GLuint, 4> expectedValues = {{250, 200, 150, 250}};
1911 runSharedMemoryTest<GLuint, 2, 2>(kCSShader, GL_R32UI, GL_UNSIGNED_INT, inputData,
1912 expectedValues);
1913 }
1914
1915 // Verify shared non-struct array variables can work correctly.
TEST_P(ComputeShaderTest,NonStructArrayAsSharedVariable)1916 TEST_P(ComputeShaderTest, NonStructArrayAsSharedVariable)
1917 {
1918 const char kCSShader[] = R"(#version 310 es
1919 layout (local_size_x = 2, local_size_y = 2, local_size_z = 1) in;
1920 layout (r32ui, binding = 0) readonly uniform highp uimage2D srcImage;
1921 layout (r32ui, binding = 1) writeonly uniform highp uimage2D dstImage;
1922 shared uint sharedData[2][2];
1923 void main()
1924 {
1925 uint inputData = imageLoad(srcImage, ivec2(gl_LocalInvocationID.xy)).x;
1926 sharedData[gl_LocalInvocationID.x][gl_LocalInvocationID.y] = inputData;
1927 groupMemoryBarrier();
1928 barrier();
1929 imageStore(dstImage, ivec2(gl_LocalInvocationID.xy),
1930 uvec4(sharedData[gl_LocalInvocationID.y][gl_LocalInvocationID.x]));
1931 })";
1932
1933 const std::array<GLuint, 4> inputData = {{250, 200, 150, 100}};
1934 const std::array<GLuint, 4> expectedValues = {{250, 150, 200, 100}};
1935 runSharedMemoryTest<GLuint, 2, 2>(kCSShader, GL_R32UI, GL_UNSIGNED_INT, inputData,
1936 expectedValues);
1937 }
1938
1939 // Verify shared struct array variables work correctly.
TEST_P(ComputeShaderTest,StructArrayAsSharedVariable)1940 TEST_P(ComputeShaderTest, StructArrayAsSharedVariable)
1941 {
1942 const char kCSShader[] = R"(#version 310 es
1943 layout (local_size_x = 2, local_size_y = 2, local_size_z = 1) in;
1944 layout (r32ui, binding = 0) readonly uniform highp uimage2D srcImage;
1945 layout (r32ui, binding = 1) writeonly uniform highp uimage2D dstImage;
1946 struct SharedStruct
1947 {
1948 uint data;
1949 };
1950 shared SharedStruct sharedData[2][2];
1951 void main()
1952 {
1953 uint inputData = imageLoad(srcImage, ivec2(gl_LocalInvocationID.xy)).x;
1954 sharedData[gl_LocalInvocationID.x][gl_LocalInvocationID.y].data = inputData;
1955 groupMemoryBarrier();
1956 barrier();
1957 imageStore(dstImage, ivec2(gl_LocalInvocationID.xy),
1958 uvec4(sharedData[gl_LocalInvocationID.y][gl_LocalInvocationID.x].data));
1959 })";
1960
1961 const std::array<GLuint, 4> inputData = {{250, 200, 150, 100}};
1962 const std::array<GLuint, 4> expectedValues = {{250, 150, 200, 100}};
1963 runSharedMemoryTest<GLuint, 2, 2>(kCSShader, GL_R32UI, GL_UNSIGNED_INT, inputData,
1964 expectedValues);
1965 }
1966
1967 // Verify using atomic functions without return value can work correctly.
TEST_P(ComputeShaderTest,AtomicFunctionsNoReturnValue)1968 TEST_P(ComputeShaderTest, AtomicFunctionsNoReturnValue)
1969 {
1970 // Fails on AMD windows drivers. http://anglebug.com/3872
1971 ANGLE_SKIP_TEST_IF(IsWindows() && IsAMD() && IsVulkan());
1972
1973 // Fails to link on Android. http://anglebug.com/3874
1974 ANGLE_SKIP_TEST_IF(IsAndroid());
1975
1976 ANGLE_SKIP_TEST_IF(IsARM64() && IsWindows() && IsD3D());
1977
1978 const char kCSShader[] = R"(#version 310 es
1979 layout (local_size_x = 8, local_size_y = 1, local_size_z = 1) in;
1980 layout (r32ui, binding = 0) readonly uniform highp uimage2D srcImage;
1981 layout (r32ui, binding = 1) writeonly uniform highp uimage2D dstImage;
1982
1983 const uint kSumIndex = 0u;
1984 const uint kMinIndex = 1u;
1985 const uint kMaxIndex = 2u;
1986 const uint kOrIndex = 3u;
1987 const uint kAndIndex = 4u;
1988 const uint kXorIndex = 5u;
1989 const uint kExchangeIndex = 6u;
1990 const uint kCompSwapIndex = 7u;
1991
1992 shared highp uint results[8];
1993
1994 void main()
1995 {
1996 if (gl_LocalInvocationID.x == kMinIndex || gl_LocalInvocationID.x == kAndIndex)
1997 {
1998 results[gl_LocalInvocationID.x] = 0xFFFFu;
1999 }
2000 else if (gl_LocalInvocationID.x == kCompSwapIndex)
2001 {
2002 results[gl_LocalInvocationID.x] = 1u;
2003 }
2004 else
2005 {
2006 results[gl_LocalInvocationID.x] = 0u;
2007 }
2008 memoryBarrierShared();
2009 barrier();
2010
2011 uint value = imageLoad(srcImage, ivec2(gl_LocalInvocationID.xy)).x;
2012 atomicAdd(results[kSumIndex], value);
2013 atomicMin(results[kMinIndex], value);
2014 atomicMax(results[kMaxIndex], value);
2015 atomicOr(results[kOrIndex], value);
2016 atomicAnd(results[kAndIndex], value);
2017 atomicXor(results[kXorIndex], value);
2018 atomicExchange(results[kExchangeIndex], value);
2019 atomicCompSwap(results[kCompSwapIndex], value, 256u);
2020 memoryBarrierShared();
2021 barrier();
2022
2023 imageStore(dstImage, ivec2(gl_LocalInvocationID.xy),
2024 uvec4(results[gl_LocalInvocationID.x]));
2025 })";
2026
2027 const std::array<GLuint, 8> inputData = {{1, 2, 4, 8, 16, 32, 64, 128}};
2028 const std::array<GLuint, 8> expectedValues = {{255, 1, 128, 255, 0, 255, 128, 256}};
2029 runSharedMemoryTest<GLuint, 8, 1>(kCSShader, GL_R32UI, GL_UNSIGNED_INT, inputData,
2030 expectedValues);
2031 }
2032
2033 // Verify using atomic functions in a non-initializer single assignment can work correctly.
TEST_P(ComputeShaderTest,AtomicFunctionsInNonInitializerSingleAssignment)2034 TEST_P(ComputeShaderTest, AtomicFunctionsInNonInitializerSingleAssignment)
2035 {
2036 // Fails on AMD windows drivers. http://anglebug.com/3872
2037 ANGLE_SKIP_TEST_IF(IsWindows() && IsAMD() && IsVulkan());
2038
2039 const char kCSShader[] = R"(#version 310 es
2040 layout (local_size_x = 9, local_size_y = 1, local_size_z = 1) in;
2041 layout (r32i, binding = 0) readonly uniform highp iimage2D srcImage;
2042 layout (r32i, binding = 1) writeonly uniform highp iimage2D dstImage;
2043
2044 shared highp int sharedVariable;
2045
2046 shared highp int inputData[9];
2047 shared highp int outputData[9];
2048
2049 void main()
2050 {
2051 int inputValue = imageLoad(srcImage, ivec2(gl_LocalInvocationID.xy)).x;
2052 inputData[gl_LocalInvocationID.x] = inputValue;
2053 memoryBarrierShared();
2054 barrier();
2055
2056 if (gl_LocalInvocationID.x == 0u)
2057 {
2058 sharedVariable = 0;
2059
2060 outputData[0] = atomicAdd(sharedVariable, inputData[0]);
2061 outputData[1] = atomicMin(sharedVariable, inputData[1]);
2062 outputData[2] = atomicMax(sharedVariable, inputData[2]);
2063 outputData[3] = atomicAnd(sharedVariable, inputData[3]);
2064 outputData[4] = atomicOr(sharedVariable, inputData[4]);
2065 outputData[5] = atomicXor(sharedVariable, inputData[5]);
2066 outputData[6] = atomicExchange(sharedVariable, inputData[6]);
2067 outputData[7] = atomicCompSwap(sharedVariable, 64, inputData[7]);
2068 outputData[8] = atomicAdd(sharedVariable, inputData[8]);
2069 }
2070 memoryBarrierShared();
2071 barrier();
2072
2073 imageStore(dstImage, ivec2(gl_LocalInvocationID.xy),
2074 ivec4(outputData[gl_LocalInvocationID.x]));
2075 })";
2076
2077 const std::array<GLint, 9> inputData = {{1, 2, 4, 8, 16, 32, 64, 128, 1}};
2078 const std::array<GLint, 9> expectedValues = {{0, 1, 1, 4, 0, 16, 48, 64, 128}};
2079 runSharedMemoryTest<GLint, 9, 1>(kCSShader, GL_R32I, GL_INT, inputData, expectedValues);
2080 }
2081
2082 // Verify using atomic functions in an initializers and using unsigned int works correctly.
TEST_P(ComputeShaderTest,AtomicFunctionsInitializerWithUnsigned)2083 TEST_P(ComputeShaderTest, AtomicFunctionsInitializerWithUnsigned)
2084 {
2085 // Fails on AMD windows drivers. http://anglebug.com/3872
2086 ANGLE_SKIP_TEST_IF(IsWindows() && IsAMD() && IsVulkan());
2087
2088 constexpr char kCShader[] = R"(#version 310 es
2089 layout (local_size_x = 9, local_size_y = 1, local_size_z = 1) in;
2090 layout (r32ui, binding = 0) readonly uniform highp uimage2D srcImage;
2091 layout (r32ui, binding = 1) writeonly uniform highp uimage2D dstImage;
2092
2093 shared highp uint sharedVariable;
2094
2095 shared highp uint inputData[9];
2096 shared highp uint outputData[9];
2097
2098 void main()
2099 {
2100 uint inputValue = imageLoad(srcImage, ivec2(gl_LocalInvocationID.xy)).x;
2101 inputData[gl_LocalInvocationID.x] = inputValue;
2102 memoryBarrierShared();
2103 barrier();
2104
2105 if (gl_LocalInvocationID.x == 0u)
2106 {
2107 sharedVariable = 0u;
2108
2109 uint addValue = atomicAdd(sharedVariable, inputData[0]);
2110 outputData[0] = addValue;
2111 uint minValue = atomicMin(sharedVariable, inputData[1]);
2112 outputData[1] = minValue;
2113 uint maxValue = atomicMax(sharedVariable, inputData[2]);
2114 outputData[2] = maxValue;
2115 uint andValue = atomicAnd(sharedVariable, inputData[3]);
2116 outputData[3] = andValue;
2117 uint orValue = atomicOr(sharedVariable, inputData[4]);
2118 outputData[4] = orValue;
2119 uint xorValue = atomicXor(sharedVariable, inputData[5]);
2120 outputData[5] = xorValue;
2121 uint exchangeValue = atomicExchange(sharedVariable, inputData[6]);
2122 outputData[6] = exchangeValue;
2123 uint compSwapValue = atomicCompSwap(sharedVariable, 64u, inputData[7]);
2124 outputData[7] = compSwapValue;
2125 uint sharedVariable = atomicAdd(sharedVariable, inputData[8]);
2126 outputData[8] = sharedVariable;
2127
2128 }
2129 memoryBarrierShared();
2130 barrier();
2131
2132 imageStore(dstImage, ivec2(gl_LocalInvocationID.xy),
2133 uvec4(outputData[gl_LocalInvocationID.x]));
2134 })";
2135
2136 constexpr std::array<GLuint, 9> kInputData = {{1, 2, 4, 8, 16, 32, 64, 128, 1}};
2137 constexpr std::array<GLuint, 9> kExpectedValues = {{0, 1, 1, 4, 0, 16, 48, 64, 128}};
2138 runSharedMemoryTest<GLuint, 9, 1>(kCShader, GL_R32UI, GL_UNSIGNED_INT, kInputData,
2139 kExpectedValues);
2140 }
2141
2142 // Verify using atomic functions inside expressions as unsigned int.
TEST_P(ComputeShaderTest,AtomicFunctionsReturnWithUnsigned)2143 TEST_P(ComputeShaderTest, AtomicFunctionsReturnWithUnsigned)
2144 {
2145 // Fails on AMD windows drivers. http://anglebug.com/3872
2146 ANGLE_SKIP_TEST_IF(IsWindows() && IsAMD() && IsVulkan());
2147
2148 constexpr char kCShader[] = R"(#version 310 es
2149 layout (local_size_x = 9, local_size_y = 1, local_size_z = 1) in;
2150 layout (r32ui, binding = 0) readonly uniform highp uimage2D srcImage;
2151 layout (r32ui, binding = 1) writeonly uniform highp uimage2D dstImage;
2152
2153 shared highp uint sharedVariable;
2154
2155 shared highp uint inputData[9];
2156 shared highp uint outputData[9];
2157
2158 void main()
2159 {
2160 uint inputValue = imageLoad(srcImage, ivec2(gl_LocalInvocationID.xy)).x;
2161 inputData[gl_LocalInvocationID.x] = inputValue;
2162 memoryBarrierShared();
2163 barrier();
2164
2165 if (gl_LocalInvocationID.x == 0u)
2166 {
2167 sharedVariable = 0u;
2168
2169 outputData[0] = 1u + atomicAdd(sharedVariable, inputData[0]);
2170 outputData[1] = 1u + atomicMin(sharedVariable, inputData[1]);
2171 outputData[2] = 1u + atomicMax(sharedVariable, inputData[2]);
2172 outputData[3] = 1u + atomicAnd(sharedVariable, inputData[3]);
2173 outputData[4] = 1u + atomicOr(sharedVariable, inputData[4]);
2174 outputData[5] = 1u + atomicXor(sharedVariable, inputData[5]);
2175 outputData[6] = 1u + atomicExchange(sharedVariable, inputData[6]);
2176 outputData[7] = 1u + atomicCompSwap(sharedVariable, 64u, inputData[7]);
2177 outputData[8] = 1u + atomicAdd(sharedVariable, inputData[8]);
2178 }
2179 memoryBarrierShared();
2180 barrier();
2181
2182 imageStore(dstImage, ivec2(gl_LocalInvocationID.xy),
2183 uvec4(outputData[gl_LocalInvocationID.x]));
2184 })";
2185
2186 constexpr std::array<GLuint, 9> kInputData = {{1, 2, 4, 8, 16, 32, 64, 128, 1}};
2187 constexpr std::array<GLuint, 9> kExpectedValues = {{1, 2, 2, 5, 1, 17, 49, 65, 129}};
2188 runSharedMemoryTest<GLuint, 9, 1>(kCShader, GL_R32UI, GL_UNSIGNED_INT, kInputData,
2189 kExpectedValues);
2190 }
2191
2192 // Verify using nested atomic functions in expressions.
TEST_P(ComputeShaderTest,AtomicFunctionsReturnWithMultipleTypes)2193 TEST_P(ComputeShaderTest, AtomicFunctionsReturnWithMultipleTypes)
2194 {
2195 constexpr char kCShader[] = R"(#version 310 es
2196 layout (local_size_x = 4, local_size_y = 1, local_size_z = 1) in;
2197 layout (r32ui, binding = 0) readonly uniform highp uimage2D srcImage;
2198 layout (r32ui, binding = 1) writeonly uniform highp uimage2D dstImage;
2199
2200 shared highp uint sharedVariable;
2201 shared highp int indexVariable;
2202
2203 shared highp uint inputData[4];
2204 shared highp uint outputData[4];
2205
2206 void main()
2207 {
2208 uint inputValue = imageLoad(srcImage, ivec2(gl_LocalInvocationID.xy)).x;
2209 inputData[gl_LocalInvocationID.x] = inputValue;
2210 memoryBarrierShared();
2211 barrier();
2212
2213 if (gl_LocalInvocationID.x == 0u)
2214 {
2215 sharedVariable = 0u;
2216 indexVariable = 2;
2217
2218 outputData[0] = 1u + atomicAdd(sharedVariable, inputData[atomicAdd(indexVariable, -1)]);
2219 outputData[1] = 1u + atomicAdd(sharedVariable, inputData[atomicAdd(indexVariable, -1)]);
2220 outputData[2] = 1u + atomicAdd(sharedVariable, inputData[atomicAdd(indexVariable, -1)]);
2221 outputData[3] = atomicAdd(sharedVariable, 0u);
2222
2223 }
2224 memoryBarrierShared();
2225 barrier();
2226
2227 imageStore(dstImage, ivec2(gl_LocalInvocationID.xy),
2228 uvec4(outputData[gl_LocalInvocationID.x]));
2229 })";
2230
2231 constexpr std::array<GLuint, 4> kInputData = {{1, 2, 3, 0}};
2232 constexpr std::array<GLuint, 4> kExpectedValues = {{1, 4, 6, 6}};
2233 runSharedMemoryTest<GLuint, 4, 1>(kCShader, GL_R32UI, GL_UNSIGNED_INT, kInputData,
2234 kExpectedValues);
2235 }
2236
2237 // Basic uniform buffer functionality.
TEST_P(ComputeShaderTest,UniformBuffer)2238 TEST_P(ComputeShaderTest, UniformBuffer)
2239 {
2240 GLTexture texture;
2241 GLBuffer buffer;
2242 GLFramebuffer framebuffer;
2243 constexpr char kCS[] = R"(#version 310 es
2244 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
2245 uniform uni
2246 {
2247 uvec4 value;
2248 };
2249 layout(rgba32ui, binding = 0) writeonly uniform highp uimage2D uImage;
2250 void main()
2251 {
2252 imageStore(uImage, ivec2(gl_LocalInvocationID.xy), value);
2253 })";
2254
2255 constexpr int kWidth = 1, kHeight = 1;
2256 constexpr GLuint kInputValues[4] = {56, 57, 58, 59};
2257
2258 glBindTexture(GL_TEXTURE_2D, texture);
2259 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32UI, kWidth, kHeight);
2260 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RGBA_INTEGER, GL_UNSIGNED_INT,
2261 kInputValues);
2262 EXPECT_GL_NO_ERROR();
2263
2264 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
2265 glUseProgram(program.get());
2266
2267 GLint uniformBufferIndex = glGetUniformBlockIndex(program, "uni");
2268 EXPECT_NE(uniformBufferIndex, -1);
2269 GLuint data[4] = {201, 202, 203, 204};
2270 glBindBuffer(GL_UNIFORM_BUFFER, buffer);
2271 glBufferData(GL_UNIFORM_BUFFER, sizeof(GLuint) * 4, data, GL_STATIC_DRAW);
2272 glBindBufferBase(GL_UNIFORM_BUFFER, 0, buffer);
2273 glUniformBlockBinding(program, uniformBufferIndex, 0);
2274 EXPECT_GL_NO_ERROR();
2275
2276 glBindImageTexture(0, texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32UI);
2277 EXPECT_GL_NO_ERROR();
2278
2279 glDispatchCompute(1, 1, 1);
2280 EXPECT_GL_NO_ERROR();
2281
2282 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
2283 GLuint outputValues[kWidth * kHeight * 4];
2284 glUseProgram(0);
2285 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
2286
2287 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
2288 EXPECT_GL_NO_ERROR();
2289 glReadPixels(0, 0, kWidth, kHeight, GL_RGBA_INTEGER, GL_UNSIGNED_INT, outputValues);
2290 EXPECT_GL_NO_ERROR();
2291
2292 for (int i = 0; i < kWidth * kHeight * 4; i++)
2293 {
2294 EXPECT_EQ(data[i], outputValues[i]);
2295 }
2296 }
2297
2298 // Test that storing data to image and then loading the same image data works correctly.
TEST_P(ComputeShaderTest,StoreImageThenLoad)2299 TEST_P(ComputeShaderTest, StoreImageThenLoad)
2300 {
2301 const char kCSSource[] = R"(#version 310 es
2302 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
2303 layout(r32ui, binding = 0) readonly uniform highp uimage2D uImage_1;
2304 layout(r32ui, binding = 1) writeonly uniform highp uimage2D uImage_2;
2305 void main()
2306 {
2307 uvec4 value = imageLoad(uImage_1, ivec2(gl_LocalInvocationID.xy));
2308 imageStore(uImage_2, ivec2(gl_LocalInvocationID.xy), value);
2309 })";
2310
2311 constexpr GLuint kInputValues[3][1] = {{300}, {200}, {100}};
2312 GLTexture texture[3];
2313 glBindTexture(GL_TEXTURE_2D, texture[0]);
2314 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, 1, 1);
2315 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RED_INTEGER, GL_UNSIGNED_INT, kInputValues[0]);
2316 EXPECT_GL_NO_ERROR();
2317
2318 glBindTexture(GL_TEXTURE_2D, texture[1]);
2319 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, 1, 1);
2320 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RED_INTEGER, GL_UNSIGNED_INT, kInputValues[1]);
2321 EXPECT_GL_NO_ERROR();
2322
2323 glBindTexture(GL_TEXTURE_2D, texture[2]);
2324 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, 1, 1);
2325 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RED_INTEGER, GL_UNSIGNED_INT, kInputValues[2]);
2326 EXPECT_GL_NO_ERROR();
2327
2328 ANGLE_GL_COMPUTE_PROGRAM(program, kCSSource);
2329 glUseProgram(program.get());
2330
2331 glBindImageTexture(0, texture[0], 0, GL_FALSE, 0, GL_READ_ONLY, GL_R32UI);
2332 glBindImageTexture(1, texture[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
2333
2334 glDispatchCompute(1, 1, 1);
2335 glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
2336 EXPECT_GL_NO_ERROR();
2337
2338 glBindImageTexture(0, texture[1], 0, GL_FALSE, 0, GL_READ_ONLY, GL_R32UI);
2339 glBindImageTexture(1, texture[2], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
2340
2341 glDispatchCompute(1, 1, 1);
2342 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
2343 EXPECT_GL_NO_ERROR();
2344
2345 GLuint outputValue;
2346 GLFramebuffer framebuffer;
2347 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
2348 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture[2], 0);
2349 glReadPixels(0, 0, 1, 1, GL_RED_INTEGER, GL_UNSIGNED_INT, &outputValue);
2350 EXPECT_GL_NO_ERROR();
2351
2352 EXPECT_EQ(300u, outputValue);
2353 }
2354
2355 // Test that loading image data and then storing data to the same image works correctly.
TEST_P(ComputeShaderTest,LoadImageThenStore)2356 TEST_P(ComputeShaderTest, LoadImageThenStore)
2357 {
2358 const char kCSSource[] = R"(#version 310 es
2359 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
2360 layout(r32ui, binding = 0) readonly uniform highp uimage2D uImage_1;
2361 layout(r32ui, binding = 1) writeonly uniform highp uimage2D uImage_2;
2362 void main()
2363 {
2364 uvec4 value = imageLoad(uImage_1, ivec2(gl_LocalInvocationID.xy));
2365 imageStore(uImage_2, ivec2(gl_LocalInvocationID.xy), value);
2366 })";
2367
2368 constexpr GLuint kInputValues[3][1] = {{300}, {200}, {100}};
2369 GLTexture texture[3];
2370 glBindTexture(GL_TEXTURE_2D, texture[0]);
2371 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, 1, 1);
2372 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RED_INTEGER, GL_UNSIGNED_INT, kInputValues[0]);
2373 EXPECT_GL_NO_ERROR();
2374
2375 glBindTexture(GL_TEXTURE_2D, texture[1]);
2376 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, 1, 1);
2377 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RED_INTEGER, GL_UNSIGNED_INT, kInputValues[1]);
2378 EXPECT_GL_NO_ERROR();
2379
2380 glBindTexture(GL_TEXTURE_2D, texture[2]);
2381 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, 1, 1);
2382 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RED_INTEGER, GL_UNSIGNED_INT, kInputValues[2]);
2383 EXPECT_GL_NO_ERROR();
2384
2385 ANGLE_GL_COMPUTE_PROGRAM(program, kCSSource);
2386 glUseProgram(program.get());
2387
2388 glBindImageTexture(0, texture[0], 0, GL_FALSE, 0, GL_READ_ONLY, GL_R32UI);
2389 glBindImageTexture(1, texture[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
2390
2391 glDispatchCompute(1, 1, 1);
2392 glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
2393 EXPECT_GL_NO_ERROR();
2394
2395 glBindImageTexture(0, texture[2], 0, GL_FALSE, 0, GL_READ_ONLY, GL_R32UI);
2396 glBindImageTexture(1, texture[0], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
2397
2398 glDispatchCompute(1, 1, 1);
2399 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
2400 EXPECT_GL_NO_ERROR();
2401
2402 GLuint outputValue;
2403 GLFramebuffer framebuffer;
2404 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
2405 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture[0], 0);
2406 glReadPixels(0, 0, 1, 1, GL_RED_INTEGER, GL_UNSIGNED_INT, &outputValue);
2407 EXPECT_GL_NO_ERROR();
2408
2409 EXPECT_EQ(100u, outputValue);
2410 }
2411
2412 // Test that scalar buffer variables are supported.
TEST_P(ComputeShaderTest,ShaderStorageBlocksScalar)2413 TEST_P(ComputeShaderTest, ShaderStorageBlocksScalar)
2414 {
2415 const char kCSSource[] = R"(#version 310 es
2416 layout(local_size_x=1) in;
2417 layout(std140, binding = 0) buffer blockA {
2418 uvec3 uv;
2419 float f;
2420 } instanceA;
2421 layout(std140, binding = 1) buffer blockB {
2422 vec2 v;
2423 uint u[3];
2424 float f;
2425 };
2426 void main()
2427 {
2428 f = instanceA.f;
2429 })";
2430
2431 ANGLE_GL_COMPUTE_PROGRAM(program, kCSSource);
2432 EXPECT_GL_NO_ERROR();
2433 }
2434
2435 // Test that vector buffer variables are supported.
TEST_P(ComputeShaderTest,ShaderStorageBlocksVector)2436 TEST_P(ComputeShaderTest, ShaderStorageBlocksVector)
2437 {
2438 const char kCSSource[] = R"(#version 310 es
2439 layout(local_size_x=1) in;
2440 layout(std140, binding = 0) buffer blockA {
2441 vec2 f;
2442 } instanceA;
2443 layout(std140, binding = 1) buffer blockB {
2444 vec3 f;
2445 };
2446 void main()
2447 {
2448 f[1] = instanceA.f[0];
2449 })";
2450
2451 ANGLE_GL_COMPUTE_PROGRAM(program, kCSSource);
2452 EXPECT_GL_NO_ERROR();
2453 }
2454
2455 // Test that matrix buffer variables are supported.
TEST_P(ComputeShaderTest,ShaderStorageBlocksMatrix)2456 TEST_P(ComputeShaderTest, ShaderStorageBlocksMatrix)
2457 {
2458 const char kCSSource[] = R"(#version 310 es
2459 layout(local_size_x=1) in;
2460 layout(std140, binding = 0) buffer blockA {
2461 mat3x4 m;
2462 } instanceA;
2463 layout(std140, binding = 1) buffer blockB {
2464 mat3x4 m;
2465 };
2466 void main()
2467 {
2468 m[0][1] = instanceA.m[0][1];
2469 })";
2470
2471 ANGLE_GL_COMPUTE_PROGRAM(program, kCSSource);
2472 EXPECT_GL_NO_ERROR();
2473 }
2474
2475 // Test that scalar array buffer variables are supported.
TEST_P(ComputeShaderTest,ShaderStorageBlocksScalarArray)2476 TEST_P(ComputeShaderTest, ShaderStorageBlocksScalarArray)
2477 {
2478 const char kCSSource[] = R"(#version 310 es
2479 layout(local_size_x=8) in;
2480 layout(std140, binding = 0) buffer blockA {
2481 float f[8];
2482 } instanceA;
2483 layout(std140, binding = 1) buffer blockB {
2484 float f[8];
2485 };
2486 void main()
2487 {
2488 f[gl_LocalInvocationIndex] = instanceA.f[gl_LocalInvocationIndex];
2489 })";
2490
2491 ANGLE_GL_COMPUTE_PROGRAM(program, kCSSource);
2492 EXPECT_GL_NO_ERROR();
2493 }
2494
2495 // Test that vector array buffer variables are supported.
TEST_P(ComputeShaderTest,ShaderStorageBlocksVectorArray)2496 TEST_P(ComputeShaderTest, ShaderStorageBlocksVectorArray)
2497 {
2498 const char kCSSource[] = R"(#version 310 es
2499 layout(local_size_x=4) in;
2500 layout(std140, binding = 0) buffer blockA {
2501 vec2 v[4];
2502 } instanceA;
2503 layout(std140, binding = 1) buffer blockB {
2504 vec4 v[4];
2505 };
2506 void main()
2507 {
2508 v[0][gl_LocalInvocationIndex] = instanceA.v[gl_LocalInvocationIndex][1];
2509 })";
2510
2511 ANGLE_GL_COMPUTE_PROGRAM(program, kCSSource);
2512 EXPECT_GL_NO_ERROR();
2513 }
2514
2515 // Test that matrix array buffer variables are supported.
TEST_P(ComputeShaderTest,ShaderStorageBlocksMatrixArray)2516 TEST_P(ComputeShaderTest, ShaderStorageBlocksMatrixArray)
2517 {
2518 const char kCSSource[] = R"(#version 310 es
2519 layout(local_size_x=8) in;
2520 layout(std140, binding = 0) buffer blockA {
2521 float v1[5];
2522 mat4 m[8];
2523 } instanceA;
2524 layout(std140, binding = 1) buffer blockB {
2525 vec2 v1[3];
2526 mat4 m[8];
2527 };
2528 void main()
2529 {
2530 float data = instanceA.m[gl_LocalInvocationIndex][0][0];
2531 m[gl_LocalInvocationIndex][gl_LocalInvocationIndex][gl_LocalInvocationIndex] = data;
2532 })";
2533
2534 ANGLE_GL_COMPUTE_PROGRAM(program, kCSSource);
2535 EXPECT_GL_NO_ERROR();
2536 }
2537
2538 // Test that shader storage blocks only in assignment right is supported.
TEST_P(ComputeShaderTest,ShaderStorageBlocksInAssignmentRight)2539 TEST_P(ComputeShaderTest, ShaderStorageBlocksInAssignmentRight)
2540 {
2541 const char kCSSource[] = R"(#version 310 es
2542 layout(local_size_x=8) in;
2543 layout(std140, binding = 0) buffer blockA {
2544 float data[8];
2545 } instanceA;
2546 layout(r32f, binding = 0) writeonly uniform highp image2D imageOut;
2547
2548 void main()
2549 {
2550 float data = 1.0;
2551 data = instanceA.data[gl_LocalInvocationIndex];
2552 imageStore(imageOut, ivec2(gl_LocalInvocationID.xy), vec4(data));
2553 })";
2554
2555 ANGLE_GL_COMPUTE_PROGRAM(program, kCSSource);
2556 EXPECT_GL_NO_ERROR();
2557 }
2558
2559 // Test that shader storage blocks with unsized array are supported.
TEST_P(ComputeShaderTest,ShaderStorageBlocksWithUnsizedArray)2560 TEST_P(ComputeShaderTest, ShaderStorageBlocksWithUnsizedArray)
2561 {
2562 const char kCSSource[] = R"(#version 310 es
2563 layout(local_size_x=8) in;
2564 layout(std140, binding = 0) buffer blockA {
2565 float v[];
2566 } instanceA;
2567 layout(std140, binding = 0) buffer blockB {
2568 float v[];
2569 } instanceB[1];
2570
2571 void main()
2572 {
2573 float data = instanceA.v[gl_LocalInvocationIndex];
2574 instanceB[0].v[gl_LocalInvocationIndex * 2u + 1u] = data;
2575 }
2576 )";
2577
2578 ANGLE_GL_COMPUTE_PROGRAM(program, kCSSource);
2579 EXPECT_GL_NO_ERROR();
2580 }
2581
2582 // Test that EOpIndexDirect/EOpIndexIndirect/EOpIndexDirectStruct nodes in ssbo EOpIndexInDirect
2583 // don't need to calculate the offset and should be translated by OutputHLSL directly.
TEST_P(ComputeShaderTest,IndexAndDotOperatorsInSSBOIndexIndirectOperator)2584 TEST_P(ComputeShaderTest, IndexAndDotOperatorsInSSBOIndexIndirectOperator)
2585 {
2586 constexpr char kComputeShaderSource[] = R"(#version 310 es
2587 layout(local_size_x=1) in;
2588 layout(std140, binding = 0) buffer blockA {
2589 float v[4];
2590 };
2591 layout(std140, binding = 1) buffer blockB {
2592 float v[4];
2593 } instanceB[1];
2594 struct S
2595 {
2596 uvec4 index[2];
2597 } s;
2598 void main()
2599 {
2600 s.index[0] = uvec4(0u, 1u, 2u, 3u);
2601 float data = v[s.index[0].y];
2602 instanceB[0].v[s.index[0].x] = data;
2603 })";
2604
2605 ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShaderSource);
2606 EXPECT_GL_NO_ERROR();
2607 }
2608
2609 // Test that swizzle node in non-SSBO symbol works well.
TEST_P(ComputeShaderTest,ShaderStorageBlocksWithNonSSBOSwizzle)2610 TEST_P(ComputeShaderTest, ShaderStorageBlocksWithNonSSBOSwizzle)
2611 {
2612 constexpr char kComputeShaderSource[] = R"(#version 310 es
2613 layout(local_size_x=8) in;
2614 layout(std140, binding = 0) buffer blockA {
2615 float v[8];
2616 };
2617 layout(std140, binding = 1) buffer blockB {
2618 float v[8];
2619 } instanceB[1];
2620
2621 void main()
2622 {
2623 float data = v[gl_GlobalInvocationID.x];
2624 instanceB[0].v[gl_GlobalInvocationID.x] = data;
2625 })";
2626
2627 ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShaderSource);
2628 EXPECT_GL_NO_ERROR();
2629 }
2630
2631 // Test that swizzle node in SSBO symbol works well.
TEST_P(ComputeShaderTest,ShaderStorageBlocksWithSSBOSwizzle)2632 TEST_P(ComputeShaderTest, ShaderStorageBlocksWithSSBOSwizzle)
2633 {
2634 constexpr char kComputeShaderSource[] = R"(#version 310 es
2635 layout(local_size_x=1) in;
2636 layout(std140, binding = 0) buffer blockA {
2637 vec2 v;
2638 };
2639 layout(std140, binding = 1) buffer blockB {
2640 float v;
2641 } instanceB[1];
2642
2643 void main()
2644 {
2645 instanceB[0].v = v.x;
2646 })";
2647
2648 ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShaderSource);
2649 EXPECT_GL_NO_ERROR();
2650 }
2651
2652 // Test that a large struct array in std140 uniform block won't consume too much time.
TEST_P(ComputeShaderTest,LargeStructArraySize)2653 TEST_P(ComputeShaderTest, LargeStructArraySize)
2654 {
2655 constexpr char kComputeShaderSource[] = R"(#version 310 es
2656 layout(local_size_x=8) in;
2657 precision mediump float;
2658
2659 struct InstancingData
2660 {
2661 mat4 transformation;
2662 };
2663
2664 #define MAX_INSTANCE_COUNT 800
2665
2666 layout(std140) uniform InstanceBlock
2667 {
2668 InstancingData instances[MAX_INSTANCE_COUNT];
2669 };
2670
2671 layout(std140, binding = 1) buffer blockB {
2672 mat4 v[];
2673 } instanceB;
2674
2675 void main()
2676 {
2677 instanceB.v[gl_GlobalInvocationID.x] = instances[gl_GlobalInvocationID.x].transformation;
2678 })";
2679
2680 ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShaderSource);
2681 EXPECT_GL_NO_ERROR();
2682 }
2683
2684 // Check that it is not possible to create a compute shader when the context does not support ES
2685 // 3.10
TEST_P(ComputeShaderTestES3,NotSupported)2686 TEST_P(ComputeShaderTestES3, NotSupported)
2687 {
2688 GLuint computeShaderHandle = glCreateShader(GL_COMPUTE_SHADER);
2689 EXPECT_EQ(0u, computeShaderHandle);
2690 EXPECT_GL_ERROR(GL_INVALID_ENUM);
2691 }
2692
2693 // The contents of shared variables should be cleared to zero at the beginning of shader execution.
TEST_P(WebGL2ComputeTest,sharedVariablesShouldBeZero)2694 TEST_P(WebGL2ComputeTest, sharedVariablesShouldBeZero)
2695 {
2696 // http://anglebug.com/3226
2697 ANGLE_SKIP_TEST_IF(IsD3D11());
2698
2699 // Fails on Android, AMD/windows and Intel/windows. Probably works by chance on other
2700 // platforms, so suppressing on all platforms to avoid possible flakiness.
2701 // http://anglebug.com/3869
2702 ANGLE_SKIP_TEST_IF(IsVulkan());
2703
2704 // http://anglebug.com/4092
2705 ANGLE_SKIP_TEST_IF(IsAndroid() && IsOpenGLES());
2706 ANGLE_SKIP_TEST_IF(IsOpenGL() &&
2707 ((getClientMajorVersion() == 3) && (getClientMinorVersion() >= 1)));
2708
2709 const char kCSShader[] = R"(#version 310 es
2710 layout (local_size_x = 4, local_size_y = 4, local_size_z = 1) in;
2711 layout (r32ui, binding = 0) readonly uniform highp uimage2D srcImage;
2712 layout (r32ui, binding = 1) writeonly uniform highp uimage2D dstImage;
2713 struct S {
2714 float f;
2715 int i;
2716 uint u;
2717 bool b;
2718 vec4 v[64];
2719 };
2720
2721 shared S vars[16];
2722 void main()
2723 {
2724 S zeroS;
2725 zeroS.f = 0.0f;
2726 zeroS.i = 0;
2727 zeroS.u = 0u;
2728 zeroS.b = false;
2729 for (int i = 0; i < 64; i++)
2730 {
2731 zeroS.v[i] = vec4(0.0f);
2732 }
2733
2734 uint tid = gl_LocalInvocationID.x + gl_LocalInvocationID.y * 4u;
2735 uint value = (zeroS == vars[tid] ? 127u : 0u);
2736 imageStore(dstImage, ivec2(gl_LocalInvocationID.xy), uvec4(value));
2737 })";
2738
2739 const std::array<GLuint, 16> inputData = {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
2740 const std::array<GLuint, 16> expectedValues = {
2741 {127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127}};
2742 runSharedMemoryTest<GLuint, 4, 4>(kCSShader, GL_R32UI, GL_UNSIGNED_INT, inputData,
2743 expectedValues);
2744 }
2745
2746 // Test uniform dirty in compute shader, and verify the contents.
TEST_P(ComputeShaderTest,UniformDirty)2747 TEST_P(ComputeShaderTest, UniformDirty)
2748 {
2749 // glReadPixels is getting the result of the first dispatch call. http://anglebug.com/3879
2750 ANGLE_SKIP_TEST_IF(IsVulkan() && IsWindows() && (IsAMD() || IsNVIDIA()));
2751
2752 GLTexture texture[2];
2753 GLFramebuffer framebuffer;
2754 constexpr char kCS[] = R"(#version 310 es
2755 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
2756 layout(r32ui, binding = 0) readonly uniform highp uimage2D uImage_1;
2757 layout(r32ui, binding = 1) writeonly uniform highp uimage2D uImage_2;
2758 uniform uint factor;
2759 void main()
2760 {
2761 uvec4 value = imageLoad(uImage_1, ivec2(gl_LocalInvocationID.xy));
2762 imageStore(uImage_2, ivec2(gl_LocalInvocationID.xy), value * factor);
2763 })";
2764
2765 constexpr int kWidth = 1, kHeight = 1;
2766 constexpr GLuint kInputValues[2][1] = {{200}, {100}};
2767
2768 glBindTexture(GL_TEXTURE_2D, texture[0]);
2769 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kWidth, kHeight);
2770 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
2771 kInputValues[0]);
2772 EXPECT_GL_NO_ERROR();
2773
2774 glBindTexture(GL_TEXTURE_2D, texture[1]);
2775 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kWidth, kHeight);
2776 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
2777 kInputValues[1]);
2778 EXPECT_GL_NO_ERROR();
2779
2780 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
2781 glUseProgram(program);
2782
2783 glBindImageTexture(0, texture[0], 0, GL_FALSE, 0, GL_READ_ONLY, GL_R32UI);
2784 EXPECT_GL_NO_ERROR();
2785
2786 glBindImageTexture(1, texture[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
2787 EXPECT_GL_NO_ERROR();
2788
2789 glUniform1ui(glGetUniformLocation(program, "factor"), 2);
2790 EXPECT_GL_NO_ERROR();
2791
2792 glDispatchCompute(1, 1, 1);
2793 EXPECT_GL_NO_ERROR();
2794
2795 glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
2796
2797 glUniform1ui(glGetUniformLocation(program, "factor"), 3);
2798 EXPECT_GL_NO_ERROR();
2799
2800 glDispatchCompute(1, 1, 1);
2801 EXPECT_GL_NO_ERROR();
2802
2803 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
2804 GLuint outputValues[kWidth * kHeight];
2805 GLuint expectedValue = 600;
2806 glUseProgram(0);
2807 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
2808
2809 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture[1], 0);
2810 EXPECT_GL_NO_ERROR();
2811 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
2812 EXPECT_GL_NO_ERROR();
2813
2814 for (int i = 0; i < kWidth * kHeight; i++)
2815 {
2816 EXPECT_EQ(expectedValue, outputValues[i]) << " index " << i;
2817 }
2818 }
2819
2820 // Test storage buffer bound is unchanged, shader writes it, buffer content should be updated.
TEST_P(ComputeShaderTest,StorageBufferBoundUnchanged)2821 TEST_P(ComputeShaderTest, StorageBufferBoundUnchanged)
2822 {
2823 // http://anglebug.com/4092
2824 ANGLE_SKIP_TEST_IF(isSwiftshader());
2825 constexpr char kCS[] = R"(#version 310 es
2826 layout(local_size_x=16, local_size_y=16) in;
2827 precision highp usampler2D;
2828 uniform usampler2D tex;
2829 uniform uint factor;
2830 layout(std140, binding = 0) buffer buf {
2831 uint outData[16][16];
2832 };
2833
2834 void main()
2835 {
2836 uint x = gl_LocalInvocationID.x;
2837 uint y = gl_LocalInvocationID.y;
2838 float xCoord = float(x) / float(16);
2839 float yCoord = float(y) / float(16);
2840 outData[y][x] = texture(tex, vec2(xCoord, yCoord)).x + factor;
2841 })";
2842
2843 constexpr unsigned int kWidth = 16;
2844 constexpr unsigned int kHeight = 16;
2845 GLTexture tex;
2846 glBindTexture(GL_TEXTURE_2D, tex);
2847 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2848 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2849 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kWidth, kHeight);
2850 GLuint texels[kHeight][kWidth] = {{0}};
2851 for (unsigned int y = 0; y < kHeight; ++y)
2852 {
2853 for (unsigned int x = 0; x < kWidth; ++x)
2854 {
2855 texels[y][x] = x + y * kWidth;
2856 }
2857 }
2858 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
2859 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
2860 texels);
2861 glBindTexture(GL_TEXTURE_2D, 0);
2862
2863 // The array stride are rounded up to the base alignment of a vec4 for std140 layout.
2864 constexpr unsigned int kArrayStride = 16;
2865 GLBuffer ssbo;
2866 glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
2867 glBufferData(GL_SHADER_STORAGE_BUFFER, kWidth * kHeight * kArrayStride, nullptr,
2868 GL_STREAM_DRAW);
2869 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
2870 EXPECT_GL_NO_ERROR();
2871
2872 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
2873 glUseProgram(program);
2874
2875 glActiveTexture(GL_TEXTURE0);
2876 glBindTexture(GL_TEXTURE_2D, tex);
2877 glUniform1i(glGetUniformLocation(program, "tex"), 0);
2878 glUniform1ui(glGetUniformLocation(program, "factor"), 2);
2879 glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
2880 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, ssbo);
2881
2882 glDispatchCompute(1, 1, 1);
2883
2884 const GLuint *ptr1 = reinterpret_cast<const GLuint *>(glMapBufferRange(
2885 GL_SHADER_STORAGE_BUFFER, 0, kWidth * kHeight * kArrayStride, GL_MAP_READ_BIT));
2886 EXPECT_GL_NO_ERROR();
2887 for (unsigned int idx = 0; idx < kWidth * kHeight; idx++)
2888 {
2889 EXPECT_EQ(idx + 2, *(ptr1 + idx * kArrayStride / 4));
2890 }
2891 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
2892 glUniform1ui(glGetUniformLocation(program, "factor"), 3);
2893 glDispatchCompute(1, 1, 1);
2894
2895 const GLuint *ptr2 = reinterpret_cast<const GLuint *>(glMapBufferRange(
2896 GL_SHADER_STORAGE_BUFFER, 0, kWidth * kHeight * kArrayStride, GL_MAP_READ_BIT));
2897 EXPECT_GL_NO_ERROR();
2898 for (unsigned int idx = 0; idx < kWidth * kHeight; idx++)
2899 {
2900 EXPECT_EQ(idx + 3, *(ptr2 + idx * kArrayStride / 4));
2901 }
2902 }
2903
2904 // Test imageSize to access mipmap slice.
TEST_P(ComputeShaderTest,ImageSizeMipmapSlice)2905 TEST_P(ComputeShaderTest, ImageSizeMipmapSlice)
2906 {
2907 // TODO(xinghua.cao@intel.com): http://anglebug.com/3101
2908 ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux());
2909
2910 // http://anglebug.com/4392
2911 ANGLE_SKIP_TEST_IF(IsWindows() && IsNVIDIA() && IsD3D11());
2912
2913 GLTexture texture[2];
2914 GLFramebuffer framebuffer;
2915 const char kCS[] = R"(#version 310 es
2916 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
2917 layout(r32ui, binding = 0) readonly uniform highp uimage2D uImage_1;
2918 layout(rgba32ui, binding = 1) writeonly uniform highp uimage2D uImage_2;
2919 void main()
2920 {
2921 ivec2 size = imageSize(uImage_1);
2922 imageStore(uImage_2, ivec2(gl_LocalInvocationID.xy), uvec4(size, 0, 0));
2923 })";
2924
2925 constexpr int kWidth1 = 8, kHeight1 = 4, kWidth2 = 1, kHeight2 = 1;
2926 constexpr GLuint kInputValues[] = {0, 0, 0, 0};
2927
2928 glBindTexture(GL_TEXTURE_2D, texture[0]);
2929 glTexStorage2D(GL_TEXTURE_2D, 2, GL_R32UI, kWidth1, kHeight1);
2930 EXPECT_GL_NO_ERROR();
2931
2932 glBindTexture(GL_TEXTURE_2D, texture[1]);
2933 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32UI, kWidth2, kHeight2);
2934 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth2, kHeight2, GL_RGBA_INTEGER, GL_UNSIGNED_INT,
2935 kInputValues);
2936 EXPECT_GL_NO_ERROR();
2937
2938 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
2939 glUseProgram(program);
2940
2941 glBindImageTexture(0, texture[0], 1, GL_FALSE, 0, GL_READ_ONLY, GL_R32UI);
2942 glBindImageTexture(1, texture[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32UI);
2943
2944 glDispatchCompute(1, 1, 1);
2945 EXPECT_GL_NO_ERROR();
2946
2947 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
2948 GLuint outputValues[kWidth2 * kHeight2 * 4];
2949 constexpr GLuint expectedValue[] = {4, 2};
2950 glUseProgram(0);
2951 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
2952
2953 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture[1], 0);
2954 EXPECT_GL_NO_ERROR();
2955 glReadPixels(0, 0, kWidth2, kHeight2, GL_RGBA_INTEGER, GL_UNSIGNED_INT, outputValues);
2956 EXPECT_GL_NO_ERROR();
2957
2958 for (int i = 0; i < kWidth2 * kHeight2; i++)
2959 {
2960 EXPECT_EQ(expectedValue[i], outputValues[i]);
2961 EXPECT_EQ(expectedValue[i + 1], outputValues[i + 1]);
2962 }
2963 }
2964
2965 // Test imageLoad to access mipmap slice.
TEST_P(ComputeShaderTest,ImageLoadMipmapSlice)2966 TEST_P(ComputeShaderTest, ImageLoadMipmapSlice)
2967 {
2968 // TODO(xinghua.cao@intel.com): http://anglebug.com/3101
2969 ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux());
2970
2971 GLTexture texture[2];
2972 GLFramebuffer framebuffer;
2973 constexpr char kCS[] = R"(#version 310 es
2974 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
2975 layout(r32ui, binding = 0) readonly uniform highp uimage2D uImage_1;
2976 layout(r32ui, binding = 1) writeonly uniform highp uimage2D uImage_2;
2977 void main()
2978 {
2979 uvec4 value = imageLoad(uImage_1, ivec2(gl_LocalInvocationID.xy));
2980 imageStore(uImage_2, ivec2(gl_LocalInvocationID.xy), value);
2981 })";
2982
2983 constexpr int kWidth1 = 2, kHeight1 = 2, kWidth2 = 1, kHeight2 = 1;
2984 constexpr GLuint kInputValues11[] = {3, 3, 3, 3};
2985 constexpr GLuint kInputValues12[] = {2};
2986 constexpr GLuint kInputValues2[] = {1};
2987
2988 glBindTexture(GL_TEXTURE_2D, texture[0]);
2989 glTexStorage2D(GL_TEXTURE_2D, 2, GL_R32UI, kWidth1, kHeight1);
2990 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth1, kHeight1, GL_RED_INTEGER, GL_UNSIGNED_INT,
2991 kInputValues11);
2992 glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, kWidth2, kHeight2, GL_RED_INTEGER, GL_UNSIGNED_INT,
2993 kInputValues12);
2994 EXPECT_GL_NO_ERROR();
2995
2996 glBindTexture(GL_TEXTURE_2D, texture[1]);
2997 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kWidth2, kHeight2);
2998 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth2, kHeight2, GL_RED_INTEGER, GL_UNSIGNED_INT,
2999 kInputValues2);
3000 EXPECT_GL_NO_ERROR();
3001
3002 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
3003 glUseProgram(program);
3004
3005 glBindImageTexture(0, texture[0], 1, GL_FALSE, 0, GL_READ_ONLY, GL_R32UI);
3006 glBindImageTexture(1, texture[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
3007
3008 glDispatchCompute(1, 1, 1);
3009 EXPECT_GL_NO_ERROR();
3010
3011 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
3012 GLuint outputValues;
3013 constexpr GLuint expectedValue = 2;
3014 glUseProgram(0);
3015 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
3016
3017 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture[1], 0);
3018 EXPECT_GL_NO_ERROR();
3019 glReadPixels(0, 0, kWidth2, kHeight2, GL_RED_INTEGER, GL_UNSIGNED_INT, &outputValues);
3020 EXPECT_GL_NO_ERROR();
3021 EXPECT_EQ(expectedValue, outputValues);
3022 }
3023
3024 // Test imageStore to access mipmap slice.
TEST_P(ComputeShaderTest,ImageStoreMipmapSlice)3025 TEST_P(ComputeShaderTest, ImageStoreMipmapSlice)
3026 {
3027 // TODO(xinghua.cao@intel.com): http://anglebug.com/3101
3028 ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux() && IsOpenGL());
3029
3030 GLTexture texture[2];
3031 GLFramebuffer framebuffer;
3032 constexpr char kCS[] = R"(#version 310 es
3033 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
3034 layout(r32ui, binding = 0) readonly uniform highp uimage2D uImage_1;
3035 layout(r32ui, binding = 1) writeonly uniform highp uimage2D uImage_2;
3036 void main()
3037 {
3038 uvec4 value = imageLoad(uImage_1, ivec2(gl_LocalInvocationID.xy));
3039 imageStore(uImage_2, ivec2(gl_LocalInvocationID.xy), value);
3040 })";
3041
3042 constexpr int kWidth1 = 1, kHeight1 = 1, kWidth2 = 2, kHeight2 = 2;
3043 constexpr GLuint kInputValues1[] = {3};
3044 constexpr GLuint kInputValues21[] = {2, 2, 2, 2};
3045 constexpr GLuint kInputValues22[] = {1};
3046
3047 glBindTexture(GL_TEXTURE_2D, texture[0]);
3048 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kWidth1, kHeight1);
3049 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth1, kHeight1, GL_RED_INTEGER, GL_UNSIGNED_INT,
3050 kInputValues1);
3051 EXPECT_GL_NO_ERROR();
3052
3053 glBindTexture(GL_TEXTURE_2D, texture[1]);
3054 glTexStorage2D(GL_TEXTURE_2D, 2, GL_R32UI, kWidth2, kHeight2);
3055 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth2, kHeight2, GL_RED_INTEGER, GL_UNSIGNED_INT,
3056 kInputValues21);
3057 glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, kWidth1, kHeight1, GL_RED_INTEGER, GL_UNSIGNED_INT,
3058 kInputValues22);
3059 EXPECT_GL_NO_ERROR();
3060
3061 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
3062 glUseProgram(program);
3063
3064 glBindImageTexture(0, texture[0], 0, GL_FALSE, 0, GL_READ_ONLY, GL_R32UI);
3065 glBindImageTexture(1, texture[1], 1, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
3066
3067 glDispatchCompute(1, 1, 1);
3068 EXPECT_GL_NO_ERROR();
3069
3070 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
3071 GLuint outputValues;
3072 constexpr GLuint expectedValue = 3;
3073 glUseProgram(0);
3074 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
3075
3076 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture[1], 1);
3077 EXPECT_GL_NO_ERROR();
3078 glReadPixels(0, 0, kWidth1, kHeight1, GL_RED_INTEGER, GL_UNSIGNED_INT, &outputValues);
3079 EXPECT_GL_NO_ERROR();
3080 EXPECT_EQ(expectedValue, outputValues);
3081 }
3082
3083 // Test that a resource is bound on render pipeline output, and then it's bound as the compute
3084 // pipeline input. It works well. See http://anglebug.com/3658
TEST_P(ComputeShaderTest,DrawTexture1DispatchTexture2)3085 TEST_P(ComputeShaderTest, DrawTexture1DispatchTexture2)
3086 {
3087 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_color_buffer_float"));
3088
3089 const char kCSSource[] = R"(#version 310 es
3090 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
3091 precision highp sampler2D;
3092 uniform sampler2D tex;
3093 layout(rgba32f, binding = 0) writeonly uniform highp image2D image;
3094 void main()
3095 {
3096 vec4 value = texelFetch(tex, ivec2(gl_LocalInvocationID.xy), 0);
3097 imageStore(image, ivec2(gl_LocalInvocationID.xy), vec4(value.x - 1.0, 1.0, 0.0, value.w - 1.0));
3098 })";
3099
3100 const char kVSSource[] = R"(#version 310 es
3101 layout (location = 0) in vec2 pos;
3102 out vec2 texCoord;
3103 void main(void) {
3104 texCoord = 0.5*pos + 0.5;
3105 gl_Position = vec4(pos, 0.0, 1.0);
3106 })";
3107
3108 const char kFSSource[] = R"(#version 310 es
3109 precision highp float;
3110 uniform sampler2D tex;
3111 in vec2 texCoord;
3112 out vec4 fragColor;
3113 void main(void) {
3114 fragColor = texture(tex, texCoord);
3115 })";
3116
3117 GLuint aPosLoc = 0;
3118 ANGLE_GL_PROGRAM(program, kVSSource, kFSSource);
3119 ANGLE_GL_COMPUTE_PROGRAM(csProgram, kCSSource);
3120 glBindAttribLocation(program, aPosLoc, "pos");
3121 GLuint buffer;
3122 glGenBuffers(1, &buffer);
3123 glBindBuffer(GL_ARRAY_BUFFER, buffer);
3124 GLfloat vertices[] = {-1, -1, 1, -1, -1, 1, 1, 1};
3125 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 8, vertices, GL_STATIC_DRAW);
3126 glVertexAttribPointer(aPosLoc, 2, GL_FLOAT, GL_FALSE, 0, 0);
3127 glEnableVertexAttribArray(aPosLoc);
3128
3129 constexpr GLfloat kInputValues[4] = {1.0, 0.0, 0.0, 1.0};
3130 constexpr GLfloat kZero[4] = {0.0, 0.0, 0.0, 0.0};
3131 GLFramebuffer framebuffer;
3132 GLTexture texture[3];
3133 glBindTexture(GL_TEXTURE_2D, texture[0]);
3134 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32F, 1, 1);
3135 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_FLOAT, kInputValues);
3136 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3137 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3138
3139 glBindTexture(GL_TEXTURE_2D, texture[1]);
3140 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32F, 1, 1);
3141 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_FLOAT, kZero);
3142 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3143 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3144
3145 glBindTexture(GL_TEXTURE_2D, texture[2]);
3146 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32F, 1, 1);
3147 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_FLOAT, kZero);
3148 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3149 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3150
3151 glUseProgram(program);
3152 glActiveTexture(GL_TEXTURE0);
3153 glBindTexture(GL_TEXTURE_2D, texture[0]);
3154 glUniform1i(glGetUniformLocation(program, "tex"), 0);
3155 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
3156 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture[1], 0);
3157 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3158 EXPECT_GL_NO_ERROR();
3159 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
3160 GLfloat actual[4];
3161 glReadPixels(0, 0, 1, 1, GL_RGBA, GL_FLOAT, actual);
3162 EXPECT_GL_NO_ERROR();
3163 EXPECT_EQ(1.0, actual[0]);
3164 EXPECT_EQ(0.0, actual[1]);
3165 EXPECT_EQ(0.0, actual[2]);
3166 EXPECT_EQ(1.0, actual[3]);
3167
3168 glUseProgram(csProgram);
3169 glActiveTexture(GL_TEXTURE0);
3170 glBindTexture(GL_TEXTURE_2D, texture[1]);
3171 glUniform1i(glGetUniformLocation(program, "tex"), 0);
3172 glBindImageTexture(0, texture[2], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
3173 glDispatchCompute(1, 1, 1);
3174 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
3175
3176 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
3177 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture[2], 0);
3178 glReadPixels(0, 0, 1, 1, GL_RGBA, GL_FLOAT, actual);
3179 EXPECT_GL_NO_ERROR();
3180 EXPECT_EQ(0.0, actual[0]);
3181 EXPECT_EQ(1.0, actual[1]);
3182 EXPECT_EQ(0.0, actual[2]);
3183 EXPECT_EQ(0.0, actual[3]);
3184 }
3185
3186 // Test that render pipeline and compute pipeline access to the same texture.
3187 // Steps:
3188 // 1. DispatchCompute.
3189 // 2. DrawArrays.
TEST_P(ComputeShaderTest,DispatchDraw)3190 TEST_P(ComputeShaderTest, DispatchDraw)
3191 {
3192 const char kCSSource[] = R"(#version 310 es
3193 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
3194 layout(rgba32f, binding = 0) writeonly uniform highp image2D image;
3195 void main()
3196 {
3197 imageStore(image, ivec2(gl_LocalInvocationID.xy), vec4(0.0, 0.0, 1.0, 1.0));
3198 })";
3199
3200 const char kVSSource[] = R"(#version 310 es
3201 layout (location = 0) in vec2 pos;
3202 out vec2 texCoord;
3203 void main(void) {
3204 texCoord = 0.5*pos + 0.5;
3205 gl_Position = vec4(pos, 0.0, 1.0);
3206 })";
3207
3208 const char kFSSource[] = R"(#version 310 es
3209 precision highp float;
3210 uniform sampler2D tex;
3211 in vec2 texCoord;
3212 out vec4 fragColor;
3213 void main(void) {
3214 fragColor = texture(tex, texCoord);
3215 })";
3216
3217 GLuint aPosLoc = 0;
3218 ANGLE_GL_PROGRAM(program, kVSSource, kFSSource);
3219 glBindAttribLocation(program, aPosLoc, "pos");
3220 GLuint buffer;
3221 glGenBuffers(1, &buffer);
3222 glBindBuffer(GL_ARRAY_BUFFER, buffer);
3223 GLfloat vertices[] = {-1, -1, 1, -1, -1, 1, 1, 1};
3224 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 8, vertices, GL_STATIC_DRAW);
3225 glVertexAttribPointer(aPosLoc, 2, GL_FLOAT, GL_FALSE, 0, 0);
3226 glEnableVertexAttribArray(aPosLoc);
3227
3228 constexpr GLfloat kInputValues[4] = {1.0, 0.0, 0.0, 1.0};
3229 GLTexture texture;
3230 glBindTexture(GL_TEXTURE_2D, texture);
3231 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32F, 1, 1);
3232 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_FLOAT, kInputValues);
3233 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3234 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3235 EXPECT_GL_NO_ERROR();
3236
3237 ANGLE_GL_COMPUTE_PROGRAM(csProgram, kCSSource);
3238 glUseProgram(csProgram);
3239
3240 glBindImageTexture(0, texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
3241
3242 glDispatchCompute(1, 1, 1);
3243 EXPECT_GL_NO_ERROR();
3244
3245 glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT);
3246 glUseProgram(program);
3247 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3248 EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::blue);
3249 }
3250
3251 // Test that render pipeline and compute pipeline access to the same texture.
3252 // Steps:
3253 // 1. DrawArrays.
3254 // 2. DispatchCompute.
3255 // 3. DispatchCompute.
3256 // 4. DrawArrays.
TEST_P(ComputeShaderTest,DrawDispatchDispatchDraw)3257 TEST_P(ComputeShaderTest, DrawDispatchDispatchDraw)
3258 {
3259 // Fails on Intel and AMD windows drivers. http://anglebug.com/3871
3260 ANGLE_SKIP_TEST_IF(IsWindows() && (IsIntel() || IsAMD()) && IsVulkan());
3261
3262 const char kCSSource[] = R"(#version 310 es
3263 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
3264 layout(rgba32f, binding = 0) writeonly uniform highp image2D image;
3265 uniform float factor;
3266 void main()
3267 {
3268 imageStore(image, ivec2(gl_LocalInvocationID.xy), vec4(factor, 0.0, 1.0, 1.0));
3269 })";
3270
3271 const char kVSSource[] = R"(#version 310 es
3272 layout (location = 0) in vec2 pos;
3273 out vec2 texCoord;
3274 void main(void) {
3275 texCoord = 0.5*pos + 0.5;
3276 gl_Position = vec4(pos, 0.0, 1.0);
3277 })";
3278
3279 const char kFSSource[] = R"(#version 310 es
3280 precision highp float;
3281 uniform sampler2D tex;
3282 in vec2 texCoord;
3283 out vec4 fragColor;
3284 void main(void) {
3285 fragColor = texture(tex, texCoord);
3286 })";
3287
3288 GLuint aPosLoc = 0;
3289 ANGLE_GL_PROGRAM(program, kVSSource, kFSSource);
3290 glBindAttribLocation(program, aPosLoc, "pos");
3291 GLuint buffer;
3292 glGenBuffers(1, &buffer);
3293 glBindBuffer(GL_ARRAY_BUFFER, buffer);
3294 GLfloat vertices[] = {-1, -1, 1, -1, -1, 1, 1, 1};
3295 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 8, vertices, GL_STATIC_DRAW);
3296 glVertexAttribPointer(aPosLoc, 2, GL_FLOAT, GL_FALSE, 0, 0);
3297 glEnableVertexAttribArray(aPosLoc);
3298
3299 constexpr GLfloat kInputValues[4] = {1.0, 0.0, 0.0, 1.0};
3300 GLTexture texture;
3301 glBindTexture(GL_TEXTURE_2D, texture);
3302 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32F, 1, 1);
3303 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_FLOAT, kInputValues);
3304 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3305 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3306 glUseProgram(program);
3307 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3308 EXPECT_GL_NO_ERROR();
3309
3310 ANGLE_GL_COMPUTE_PROGRAM(csProgram, kCSSource);
3311 glUseProgram(csProgram);
3312 glUniform1f(glGetUniformLocation(csProgram, "factor"), 0.0);
3313 glBindImageTexture(0, texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
3314 EXPECT_GL_NO_ERROR();
3315
3316 glDispatchCompute(1, 1, 1);
3317 glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
3318 EXPECT_GL_NO_ERROR();
3319
3320 glUniform1f(glGetUniformLocation(csProgram, "factor"), 1.0);
3321 glDispatchCompute(1, 1, 1);
3322 glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT);
3323 EXPECT_GL_NO_ERROR();
3324
3325 glUseProgram(program);
3326 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3327 EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::magenta);
3328 }
3329
3330 // Test that render pipeline and compute pipeline access to the same texture.
3331 // Steps:
3332 // 1. DispatchCompute.
3333 // 2. DrawArrays.
3334 // 3. DrawArrays.
3335 // 4. DispatchCompute.
TEST_P(ComputeShaderTest,DispatchDrawDrawDispatch)3336 TEST_P(ComputeShaderTest, DispatchDrawDrawDispatch)
3337 {
3338 const char kCSSource[] = R"(#version 310 es
3339 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
3340 layout(rgba32f, binding = 0) writeonly uniform highp image2D image;
3341
3342 void main()
3343 {
3344 imageStore(image, ivec2(gl_LocalInvocationID.xy), vec4(0.0, 0.0, 1.0, 1.0));
3345 })";
3346
3347 const char kVSSource[] = R"(#version 310 es
3348 layout (location = 0) in vec2 pos;
3349 out vec2 texCoord;
3350 void main(void) {
3351 texCoord = 0.5*pos + 0.5;
3352 gl_Position = vec4(pos, 0.0, 1.0);
3353 })";
3354
3355 const char kFSSource[] = R"(#version 310 es
3356 precision highp float;
3357 uniform sampler2D tex;
3358 in vec2 texCoord;
3359 uniform float factor;
3360 out vec4 fragColor;
3361 void main(void) {
3362 fragColor = texture(tex, texCoord) + vec4(factor, 0.0, 0.0, 0.0);
3363 })";
3364
3365 GLuint aPosLoc = 0;
3366 ANGLE_GL_PROGRAM(program, kVSSource, kFSSource);
3367 glBindAttribLocation(program, aPosLoc, "pos");
3368 GLuint buffer;
3369 glGenBuffers(1, &buffer);
3370 glBindBuffer(GL_ARRAY_BUFFER, buffer);
3371 GLfloat vertices[] = {-1, -1, 1, -1, -1, 1, 1, 1};
3372 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 8, vertices, GL_STATIC_DRAW);
3373 glVertexAttribPointer(aPosLoc, 2, GL_FLOAT, GL_FALSE, 0, 0);
3374 glEnableVertexAttribArray(aPosLoc);
3375
3376 constexpr GLfloat kInputValues[4] = {1.0, 0.0, 0.0, 1.0};
3377 GLTexture texture;
3378 glBindTexture(GL_TEXTURE_2D, texture);
3379 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32F, 1, 1);
3380 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_FLOAT, kInputValues);
3381 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3382 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3383
3384 ANGLE_GL_COMPUTE_PROGRAM(csProgram, kCSSource);
3385 glUseProgram(csProgram);
3386 glBindImageTexture(0, texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
3387
3388 glDispatchCompute(1, 1, 1);
3389 glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT);
3390 EXPECT_GL_NO_ERROR();
3391
3392 glUseProgram(program);
3393 glUniform1f(glGetUniformLocation(program, "factor"), 0.0);
3394 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3395 EXPECT_GL_NO_ERROR();
3396
3397 glUniform1f(glGetUniformLocation(program, "factor"), 1.0);
3398 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3399 EXPECT_GL_NO_ERROR();
3400
3401 glUseProgram(csProgram);
3402 glDispatchCompute(1, 1, 1);
3403 glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT);
3404 EXPECT_GL_NO_ERROR();
3405
3406 glUseProgram(program);
3407 glUniform1f(glGetUniformLocation(program, "factor"), 0.0);
3408 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3409 EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::blue);
3410 }
3411
3412 // Test that invalid memory barrier will produce an error.
TEST_P(ComputeShaderTest,InvalidMemoryBarrier)3413 TEST_P(ComputeShaderTest, InvalidMemoryBarrier)
3414 {
3415 GLbitfield barriers = 0;
3416 glMemoryBarrier(barriers);
3417 EXPECT_GL_ERROR(GL_INVALID_VALUE);
3418 }
3419
3420 // test atomic counter increment
3421 // http://anglebug.com/3246
TEST_P(ComputeShaderTest,AtomicCounterIncrement)3422 TEST_P(ComputeShaderTest, AtomicCounterIncrement)
3423 {
3424 constexpr char kComputeShader[] = R"(#version 310 es
3425 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
3426 layout(binding = 1, std430) buffer Output {
3427 uint preGet[1];
3428 uint increment[1];
3429 uint postGet[1];
3430 } sb_in;
3431 layout(binding=0) uniform atomic_uint counter0;
3432
3433 void main(void)
3434 {
3435 uint id = (gl_GlobalInvocationID.x);
3436 sb_in.preGet[0u] = atomicCounter(counter0);
3437 sb_in.increment[0u] = atomicCounterIncrement(counter0);
3438 sb_in.postGet[0u] = atomicCounter(counter0);
3439 }
3440 )";
3441 ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShader);
3442 EXPECT_GL_NO_ERROR();
3443
3444 glUseProgram(program);
3445
3446 constexpr unsigned int kBytesPerComponent = sizeof(GLuint);
3447
3448 GLBuffer shaderStorageBuffer;
3449 glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer);
3450 glBufferData(GL_SHADER_STORAGE_BUFFER, 3 * kBytesPerComponent, nullptr, GL_STATIC_DRAW);
3451 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, shaderStorageBuffer);
3452 EXPECT_GL_NO_ERROR();
3453
3454 constexpr GLuint atomicBufferInitialData[] = {2u};
3455 GLuint atomicBuffer;
3456 glGenBuffers(1, &atomicBuffer);
3457 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicBuffer);
3458 glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(atomicBufferInitialData), atomicBufferInitialData,
3459 GL_DYNAMIC_DRAW);
3460 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, atomicBuffer);
3461 EXPECT_GL_NO_ERROR();
3462
3463 glDispatchCompute(1, 1, 1);
3464 glFinish();
3465 EXPECT_GL_NO_ERROR();
3466
3467 // read back
3468 const GLuint *ptr = reinterpret_cast<const GLuint *>(
3469 glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 3 * kBytesPerComponent, GL_MAP_READ_BIT));
3470 EXPECT_EQ(2u, ptr[0]);
3471 EXPECT_EQ(2u, ptr[1]);
3472 EXPECT_EQ(3u, ptr[2]);
3473
3474 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
3475 }
3476
3477 // Create a 'very large' array inside of a function in a compute shader.
TEST_P(ComputeShaderTest,VeryLargeArrayInsideFunction)3478 TEST_P(ComputeShaderTest, VeryLargeArrayInsideFunction)
3479 {
3480 constexpr char kComputeShader[] = R"(#version 310 es
3481 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
3482 layout(binding = 0, std430) buffer Output {
3483 int value[1];
3484 } output_data;
3485
3486 void main()
3487 {
3488 int values[1000];
3489 for (int i = 0; i < values.length(); i++)
3490 {
3491 values[i] = 0;
3492 }
3493
3494 int total = 0;
3495 for (int i = 0; i < values.length(); i++)
3496 {
3497 total += i;
3498 values[i] = total;
3499 }
3500 output_data.value[0u] = values[1000-1];
3501 })";
3502
3503 ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShader);
3504 EXPECT_GL_NO_ERROR();
3505
3506 glUseProgram(program);
3507
3508 constexpr unsigned int kBytesPerComponent = sizeof(GLint);
3509
3510 GLBuffer shaderStorageBuffer;
3511 glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer);
3512 glBufferData(GL_SHADER_STORAGE_BUFFER, 1 * kBytesPerComponent, nullptr, GL_STATIC_DRAW);
3513 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, shaderStorageBuffer);
3514 EXPECT_GL_NO_ERROR();
3515
3516 glDispatchCompute(1, 1, 1);
3517 glFinish();
3518 EXPECT_GL_NO_ERROR();
3519
3520 // read back
3521 const GLint *ptr = reinterpret_cast<const GLint *>(
3522 glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 1 * kBytesPerComponent, GL_MAP_READ_BIT));
3523 EXPECT_EQ(499500, ptr[0]);
3524
3525 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
3526 }
3527
3528 // Test that render pipeline and compute pipeline access to the same texture.
3529 // Steps:
3530 // 1. Clear the texture and DrawArrays.
3531 // 2. DispatchCompute to set the image's first pixel to a specific color.
3532 // 3. DrawArrays and check data.
TEST_P(ComputeShaderTest,DrawDispatchDrawPreserve)3533 TEST_P(ComputeShaderTest, DrawDispatchDrawPreserve)
3534 {
3535 const char kCSSource[] = R"(#version 310 es
3536 layout(local_size_x=1, local_size_y=1) in;
3537 layout(rgba8, binding = 0) writeonly uniform highp image2D image;
3538 void main()
3539 {
3540 imageStore(image, ivec2(0, 0), vec4(0.0, 0.0, 1.0, 1.0));
3541 })";
3542
3543 const char kVSSource[] = R"(#version 310 es
3544 layout (location = 0) in vec2 pos;
3545 in vec4 inTex;
3546 out vec4 texCoord;
3547 void main(void) {
3548 texCoord = inTex;
3549 gl_Position = vec4(pos, 0.0, 1.0);
3550 })";
3551
3552 const char kFSSource[] = R"(#version 310 es
3553 precision highp float;
3554 uniform sampler2D tex;
3555 in vec4 texCoord;
3556 out vec4 fragColor;
3557 void main(void) {
3558 fragColor = texture(tex, texCoord.xy);
3559 })";
3560 GLuint aPosLoc = 0;
3561 ANGLE_GL_PROGRAM(program, kVSSource, kFSSource);
3562 glBindAttribLocation(program, aPosLoc, "pos");
3563
3564 unsigned char *data = new unsigned char[4 * getWindowWidth() * getWindowHeight()];
3565 for (int i = 0; i < getWindowWidth() * getWindowHeight(); i++)
3566 {
3567 data[i * 4] = 0xff;
3568 data[i * 4 + 1] = 0;
3569 data[i * 4 + 2] = 0;
3570 data[i * 4 + 3] = 0xff;
3571 }
3572 GLTexture texture;
3573 glBindTexture(GL_TEXTURE_2D, texture);
3574 glTexStorage2D(GL_TEXTURE_2D, 2, GL_RGBA8, getWindowWidth(), getWindowHeight());
3575 // Clear the texture level 0 to Red.
3576 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA,
3577 GL_UNSIGNED_BYTE, data);
3578 for (int i = 0; i < getWindowWidth() * getWindowHeight(); i++)
3579 {
3580 data[i * 4] = 0;
3581 data[i * 4 + 1] = 0xff;
3582 data[i * 4 + 2] = 0;
3583 data[i * 4 + 3] = 0xff;
3584 }
3585 // Clear the texture level 1 to Green.
3586 glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, getWindowWidth() / 2, getWindowHeight() / 2, GL_RGBA,
3587 GL_UNSIGNED_BYTE, data);
3588 delete[] data;
3589 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
3590 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3591 glUseProgram(program);
3592 GLfloat vertices[] = {-1, -1, 1, -1, -1, 1, 1, 1};
3593 GLfloat texCoords[] = {0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f};
3594 GLint pos = glGetAttribLocation(program, "pos");
3595 glEnableVertexAttribArray(pos);
3596 glVertexAttribPointer(pos, 2, GL_FLOAT, GL_FALSE, 0, vertices);
3597 GLint posTex = glGetAttribLocation(program, "inTex");
3598 glEnableVertexAttribArray(posTex);
3599 glVertexAttribPointer(posTex, 2, GL_FLOAT, GL_FALSE, 0, texCoords);
3600
3601 // Draw with level 0, the whole framebuffer should be Red.
3602 glViewport(0, 0, getWindowWidth(), getWindowHeight());
3603 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3604 EXPECT_GL_NO_ERROR();
3605 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
3606 EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::red);
3607 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() - 1, getWindowHeight() - 1, GLColor::red);
3608 // Draw with level 1, a quarter of the framebuffer should be Green.
3609 glViewport(0, 0, getWindowWidth() / 2, getWindowHeight() / 2);
3610 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3611 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
3612 EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::green);
3613 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2 - 1, getWindowHeight() / 2 - 1, GLColor::green);
3614
3615 // Clear the texture level 0's (0, 0) position to Blue.
3616 glBindImageTexture(0, texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA8);
3617 ANGLE_GL_COMPUTE_PROGRAM(csProgram, kCSSource);
3618 glUseProgram(csProgram);
3619 glDispatchCompute(1, 1, 1);
3620 glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT);
3621 EXPECT_GL_NO_ERROR();
3622 glFinish();
3623
3624 glUseProgram(program);
3625 // Draw with level 0, the first position should be Blue.
3626 glViewport(0, 0, getWindowWidth(), getWindowHeight());
3627 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3628 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
3629 EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::red);
3630 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() - 1, getWindowHeight() - 1, GLColor::red);
3631 // Draw with level 1, a quarter of the framebuffer should be Green.
3632 glViewport(0, 0, getWindowWidth() / 2, getWindowHeight() / 2);
3633 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3634 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
3635 EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::green);
3636 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2 - 1, getWindowHeight() / 2 - 1, GLColor::green);
3637 }
3638
3639 // Test that maxComputeWorkGroupCount is valid number.
TEST_P(ComputeShaderTest,ValidateMaxComputeWorkGroupCount)3640 TEST_P(ComputeShaderTest, ValidateMaxComputeWorkGroupCount)
3641 {
3642 constexpr char kCS[] = R"(#version 310 es
3643 layout(local_size_x=1) in;
3644 void main()
3645 {
3646 })";
3647
3648 GLuint program = glCreateProgram();
3649 GLuint cs = CompileShader(GL_COMPUTE_SHADER, kCS);
3650 EXPECT_NE(0u, cs);
3651
3652 glAttachShader(program, cs);
3653 glDeleteShader(cs);
3654
3655 GLint x, y, z;
3656 glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 0, &x);
3657 EXPECT_LE(65535, x);
3658 EXPECT_GE(std::numeric_limits<GLint>::max(), x);
3659
3660 glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 1, &y);
3661 EXPECT_LE(65535, y);
3662 EXPECT_GE(std::numeric_limits<GLint>::max(), y);
3663
3664 glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 2, &z);
3665 EXPECT_LE(65535, z);
3666 EXPECT_GE(std::numeric_limits<GLint>::max(), z);
3667
3668 glDeleteProgram(program);
3669 EXPECT_GL_NO_ERROR();
3670 }
3671
3672 // Validate that on Vulkan, compute pipeline driver uniforms descriptor set is updated after an
3673 // internal compute-based UtilsVk function is used. The latter is achieved through a draw with a
3674 // vertex buffer whose format is not natively supported. Atomic counters are used to make sure the
3675 // compute pipeline uses the driver uniforms descriptor set.
TEST_P(ComputeShaderTest,DispatchConvertVertexDispatch)3676 TEST_P(ComputeShaderTest, DispatchConvertVertexDispatch)
3677 {
3678 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_vertex_type_10_10_10_2"));
3679
3680 // Skipping due to a bug on the Qualcomm Vulkan Android driver.
3681 // http://anglebug.com/3726
3682 ANGLE_SKIP_TEST_IF(IsAndroid() && IsVulkan());
3683
3684 constexpr uint32_t kVertexCount = 6;
3685
3686 constexpr char kCS[] = R"(#version 310 es
3687 layout(local_size_x=6, local_size_y=1, local_size_z=1) in;
3688
3689 layout(binding = 0) uniform atomic_uint ac;
3690
3691 layout(binding=0, std140) buffer VertexData
3692 {
3693 uint data[];
3694 };
3695
3696 void main()
3697 {
3698 atomicCounterIncrement(ac);
3699 data[gl_GlobalInvocationID.x] = gl_GlobalInvocationID.x;
3700 })";
3701
3702 constexpr char kVS[] = R"(#version 310 es
3703 precision mediump float;
3704
3705 layout(location = 0) in vec4 position;
3706 layout(location = 1) in uvec4 data;
3707
3708 out vec4 color;
3709
3710 void main() {
3711 color = data.x < 6u && data.y == 0u && data.z == 0u && data.w == 0u
3712 ? vec4(0.0, 1.0, 0.0, 1.0) : vec4(1.0, 0.0, 0.0, 1.0);
3713 gl_Position = position;
3714 })";
3715
3716 constexpr char kFS[] = R"(#version 310 es
3717 precision mediump float;
3718 in vec4 color;
3719 out vec4 colorOut;
3720 void main() {
3721 colorOut = color;
3722 })";
3723
3724 ANGLE_GL_COMPUTE_PROGRAM(programCS, kCS);
3725 ANGLE_GL_PROGRAM(programVSFS, kVS, kFS);
3726 EXPECT_GL_NO_ERROR();
3727
3728 // Create atomic counter buffer
3729 GLBuffer atomicCounterBuffer;
3730 constexpr GLuint kInitialAcbData = 0;
3731 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicCounterBuffer);
3732 glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(kInitialAcbData), &kInitialAcbData,
3733 GL_STATIC_DRAW);
3734 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, atomicCounterBuffer);
3735 EXPECT_GL_NO_ERROR();
3736
3737 // Create vertex buffer
3738 constexpr unsigned kVertexBufferInitData[kVertexCount] = {};
3739 GLBuffer vertexBuffer;
3740 glBindBuffer(GL_SHADER_STORAGE_BUFFER, vertexBuffer);
3741 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(kVertexBufferInitData), kVertexBufferInitData,
3742 GL_STATIC_DRAW);
3743 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, vertexBuffer);
3744 EXPECT_GL_NO_ERROR();
3745
3746 // Create position buffer
3747 constexpr GLfloat positions[kVertexCount * 2] = {1.0, 1.0, -1.0, 1.0, -1.0, -1.0,
3748 1.0, 1.0, -1.0, -1.0, 1.0, -1.0};
3749 GLBuffer positionBuffer;
3750 glBindBuffer(GL_ARRAY_BUFFER, positionBuffer);
3751 glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, GL_STATIC_DRAW);
3752 EXPECT_GL_NO_ERROR();
3753
3754 // Create vertex array
3755 GLVertexArray vao;
3756 glBindVertexArray(vao);
3757
3758 glBindBuffer(GL_ARRAY_BUFFER, positionBuffer);
3759 glEnableVertexAttribArray(0);
3760 glVertexAttribPointer(0, 2, GL_FLOAT, false, 0, 0);
3761
3762 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
3763 glEnableVertexAttribArray(1);
3764 glVertexAttribPointer(1, 4, GL_UNSIGNED_INT_10_10_10_2_OES, false, 0, 0);
3765 EXPECT_GL_NO_ERROR();
3766
3767 // Fill the vertex buffer with a dispatch call
3768 glUseProgram(programCS);
3769 glDispatchCompute(1, 1, 1);
3770 EXPECT_GL_NO_ERROR();
3771
3772 glMemoryBarrier(GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT);
3773
3774 // Draw using the vertex buffer, causing vertex format conversion in compute (in the Vulkan
3775 // backend)
3776 glUseProgram(programVSFS);
3777 glBindVertexArray(vao);
3778 glDrawArrays(GL_TRIANGLES, 0, kVertexCount);
3779 EXPECT_GL_NO_ERROR();
3780
3781 // Issue another dispatch call. The driver uniforms descriptor set must be rebound.
3782 glUseProgram(programCS);
3783 glDispatchCompute(1, 1, 1);
3784 EXPECT_GL_NO_ERROR();
3785
3786 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
3787
3788 // Verify that the atomic counter has the expected value.
3789 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicCounterBuffer);
3790 GLuint *mappedBuffer = static_cast<GLuint *>(
3791 glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint), GL_MAP_READ_BIT));
3792 EXPECT_EQ(kVertexCount * 2, mappedBuffer[0]);
3793 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
3794 }
3795
3796 ANGLE_INSTANTIATE_TEST_ES31(ComputeShaderTest);
3797 ANGLE_INSTANTIATE_TEST_ES3(ComputeShaderTestES3);
3798 ANGLE_INSTANTIATE_TEST_ES31(WebGL2ComputeTest);
3799 } // namespace
3800