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
createMockOutputImage(GLuint texture,GLenum internalFormat,GLint width,GLint height)23 void createMockOutputImage(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 createMockOutputImage(texture, GL_RGBA32UI, 4, 3);
391
392 glUseProgram(program.get());
393 glDispatchCompute(8, 4, 2);
394 EXPECT_GL_NO_ERROR();
395 }
396
397 // Binds a storage buffer to slot 0, then binds a storage image to slot 0, then buffer again.
TEST_P(ComputeShaderTest,BufferImageBuffer)398 TEST_P(ComputeShaderTest, BufferImageBuffer)
399 {
400 // See http://anglebug.com/3536
401 ANGLE_SKIP_TEST_IF(IsOpenGL() && IsIntel() && IsWindows());
402
403 constexpr char kCS0[] = R"(#version 310 es
404 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
405 layout(binding = 0, offset = 4) uniform atomic_uint ac[2];
406 void main()
407 {
408 atomicCounterIncrement(ac[0]);
409 atomicCounterDecrement(ac[1]);
410 })";
411
412 ANGLE_GL_COMPUTE_PROGRAM(program0, kCS0);
413 glUseProgram(program0);
414
415 unsigned int bufferData[3] = {11u, 4u, 4u};
416 GLBuffer atomicCounterBuffer;
417 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicCounterBuffer);
418 glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(bufferData), bufferData, GL_STATIC_DRAW);
419
420 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, atomicCounterBuffer);
421
422 glDispatchCompute(1, 1, 1);
423 EXPECT_GL_NO_ERROR();
424
425 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
426 void *mappedBuffer =
427 glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint) * 3, GL_MAP_READ_BIT);
428 memcpy(bufferData, mappedBuffer, sizeof(bufferData));
429 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
430
431 EXPECT_EQ(11u, bufferData[0]);
432 EXPECT_EQ(5u, bufferData[1]);
433 EXPECT_EQ(3u, bufferData[2]);
434
435 constexpr char kCS1[] = R"(#version 310 es
436 layout(local_size_x=4, local_size_y=3, local_size_z=2) in;
437 layout(rgba32ui) uniform highp writeonly uimage2D imageOut;
438 void main()
439 {
440 uvec3 temp = gl_NumWorkGroups;
441 imageStore(imageOut, ivec2(gl_GlobalInvocationID.xy), uvec4(temp, 0u));
442 })";
443
444 ANGLE_GL_COMPUTE_PROGRAM(program1, kCS1);
445
446 GLTexture texture;
447 createMockOutputImage(texture, GL_RGBA32UI, 4, 3);
448
449 glUseProgram(program1);
450 glDispatchCompute(8, 4, 2);
451
452 glMemoryBarrier(GL_ATOMIC_COUNTER_BARRIER_BIT);
453 glUseProgram(program0);
454 glDispatchCompute(1, 1, 1);
455 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
456 mappedBuffer =
457 glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint) * 3, GL_MAP_READ_BIT);
458 memcpy(bufferData, mappedBuffer, sizeof(bufferData));
459 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
460
461 EXPECT_EQ(11u, bufferData[0]);
462 EXPECT_EQ(6u, bufferData[1]);
463 EXPECT_EQ(2u, bufferData[2]);
464
465 EXPECT_GL_NO_ERROR();
466 }
467
468 // Test that binds UAV with type image to slot 0, then binds UAV with type buffer to slot 0.
TEST_P(ComputeShaderTest,ImageAtomicCounterBuffer)469 TEST_P(ComputeShaderTest, ImageAtomicCounterBuffer)
470 {
471 // Flaky hang. http://anglebug.com/3636
472 ANGLE_SKIP_TEST_IF(IsWindows() && IsNVIDIA() && IsDesktopOpenGL());
473
474 constexpr char kCS0[] = R"(#version 310 es
475 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
476 layout(r32ui, binding = 0) writeonly uniform highp uimage2D uImage[2];
477 void main()
478 {
479 imageStore(uImage[0], ivec2(gl_LocalInvocationIndex, gl_WorkGroupID.x), uvec4(100, 0,
480 0, 0));
481 imageStore(uImage[1], ivec2(gl_LocalInvocationIndex, gl_WorkGroupID.x), uvec4(100, 0,
482 0, 0));
483 })";
484
485 ANGLE_GL_COMPUTE_PROGRAM(program0, kCS0);
486 glUseProgram(program0);
487 int width = 1, height = 1;
488 GLuint inputValues[] = {200};
489 GLTexture mTexture[2];
490 glBindTexture(GL_TEXTURE_2D, mTexture[0]);
491 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, width, height);
492 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RED_INTEGER, GL_UNSIGNED_INT,
493 inputValues);
494
495 glBindTexture(GL_TEXTURE_2D, mTexture[1]);
496 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, width, height);
497 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RED_INTEGER, GL_UNSIGNED_INT,
498 inputValues);
499
500 glBindImageTexture(0, mTexture[0], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
501 glBindImageTexture(1, mTexture[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
502
503 glDispatchCompute(1, 1, 1);
504 EXPECT_GL_NO_ERROR();
505
506 constexpr char kCS1[] = R"(#version 310 es
507 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
508 layout(binding = 0, offset = 4) uniform atomic_uint ac[2];
509 void main()
510 {
511 atomicCounterIncrement(ac[0]);
512 atomicCounterDecrement(ac[1]);
513 })";
514
515 ANGLE_GL_COMPUTE_PROGRAM(program1, kCS1);
516
517 unsigned int bufferData[3] = {11u, 4u, 4u};
518 GLBuffer atomicCounterBuffer;
519 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicCounterBuffer);
520 glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(bufferData), bufferData, GL_STATIC_DRAW);
521
522 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, atomicCounterBuffer);
523
524 glUseProgram(program1);
525 glDispatchCompute(1, 1, 1);
526 EXPECT_GL_NO_ERROR();
527
528 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
529 void *mappedBuffer =
530 glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint) * 3, GL_MAP_READ_BIT);
531 memcpy(bufferData, mappedBuffer, sizeof(bufferData));
532 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
533
534 EXPECT_EQ(11u, bufferData[0]);
535 EXPECT_EQ(5u, bufferData[1]);
536 EXPECT_EQ(3u, bufferData[2]);
537
538 EXPECT_GL_NO_ERROR();
539 }
540
541 // Test that binds UAV with type image to slot 0, then binds UAV with type buffer to slot 0.
TEST_P(ComputeShaderTest,ImageShaderStorageBuffer)542 TEST_P(ComputeShaderTest, ImageShaderStorageBuffer)
543 {
544 constexpr char kCS0[] = R"(#version 310 es
545 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
546 layout(r32ui, binding = 0) writeonly uniform highp uimage2D uImage[2];
547 void main()
548 {
549 imageStore(uImage[0], ivec2(gl_LocalInvocationIndex, gl_WorkGroupID.x), uvec4(100, 0,
550 0, 0));
551 imageStore(uImage[1], ivec2(gl_LocalInvocationIndex, gl_WorkGroupID.x), uvec4(100, 0,
552 0, 0));
553 })";
554
555 ANGLE_GL_COMPUTE_PROGRAM(program0, kCS0);
556 glUseProgram(program0);
557 int width = 1, height = 1;
558 GLuint inputValues[] = {200};
559 GLTexture mTexture[2];
560 glBindTexture(GL_TEXTURE_2D, mTexture[0]);
561 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, width, height);
562 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RED_INTEGER, GL_UNSIGNED_INT,
563 inputValues);
564
565 glBindTexture(GL_TEXTURE_2D, mTexture[1]);
566 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, width, height);
567 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RED_INTEGER, GL_UNSIGNED_INT,
568 inputValues);
569
570 glBindImageTexture(0, mTexture[0], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
571 glBindImageTexture(1, mTexture[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
572
573 glDispatchCompute(1, 1, 1);
574 EXPECT_GL_NO_ERROR();
575
576 constexpr char kCS1[] =
577 R"(#version 310 es
578 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
579 layout(std140, binding = 0) buffer blockOut {
580 uvec2 data;
581 } instanceOut;
582 layout(std140, binding = 1) buffer blockIn {
583 uvec2 data;
584 } instanceIn;
585 void main()
586 {
587 instanceOut.data = instanceIn.data;
588 }
589 )";
590
591 ANGLE_GL_COMPUTE_PROGRAM(program1, kCS1);
592
593 constexpr unsigned int kBufferSize = 2;
594 constexpr unsigned int kBufferData[kBufferSize] = {10, 20};
595
596 GLBuffer blockIn;
597 glBindBuffer(GL_SHADER_STORAGE_BUFFER, blockIn);
598 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(kBufferData), kBufferData, GL_STATIC_DRAW);
599 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, blockIn);
600
601 GLBuffer blockOut;
602 glBindBuffer(GL_SHADER_STORAGE_BUFFER, blockOut);
603 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(kBufferData), nullptr, GL_STATIC_DRAW);
604 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, blockOut);
605
606 glUseProgram(program1);
607 glDispatchCompute(1, 1, 1);
608 EXPECT_GL_NO_ERROR();
609
610 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
611
612 glBindBuffer(GL_SHADER_STORAGE_BUFFER, blockOut);
613 unsigned int bufferDataOut[kBufferSize] = {};
614 const GLColor *ptr = reinterpret_cast<GLColor *>(
615 glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(kBufferData), GL_MAP_READ_BIT));
616 memcpy(bufferDataOut, ptr, sizeof(kBufferData));
617 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
618
619 for (unsigned int index = 0; index < kBufferSize; ++index)
620 {
621 EXPECT_EQ(bufferDataOut[index], kBufferData[index]) << " index " << index;
622 }
623 }
624
625 // Basic test for DispatchComputeIndirect.
TEST_P(ComputeShaderTest,DispatchComputeIndirect)626 TEST_P(ComputeShaderTest, DispatchComputeIndirect)
627 {
628 // Flaky crash on teardown, see http://anglebug.com/3349
629 ANGLE_SKIP_TEST_IF(IsD3D11() && IsIntel() && IsWindows());
630
631 const char kCSSource[] = R"(#version 310 es
632 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
633 layout(r32ui, binding = 0) uniform highp uimage2D uImage;
634 void main()
635 {
636 imageStore(uImage, ivec2(gl_WorkGroupID.x, gl_WorkGroupID.y), uvec4(100, 0, 0, 0));
637 })";
638
639 ANGLE_GL_COMPUTE_PROGRAM(program, kCSSource);
640 glUseProgram(program.get());
641 const int kWidth = 4, kHeight = 6;
642 GLuint inputValues[kWidth][kHeight] = {};
643
644 GLBuffer buffer;
645 glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, buffer);
646 GLuint params[] = {kWidth, kHeight, 1};
647 glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(params), params, GL_STATIC_DRAW);
648
649 GLTexture texture;
650 glBindTexture(GL_TEXTURE_2D, texture);
651 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kWidth, kHeight);
652 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
653 inputValues);
654 EXPECT_GL_NO_ERROR();
655
656 glBindImageTexture(0, texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
657 EXPECT_GL_NO_ERROR();
658
659 glDispatchComputeIndirect(0);
660 EXPECT_GL_NO_ERROR();
661
662 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
663
664 GLuint outputValues[kWidth][kHeight];
665
666 GLFramebuffer framebuffer;
667 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
668 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
669 EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_READ_FRAMEBUFFER);
670 EXPECT_GL_NO_ERROR();
671
672 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
673 EXPECT_GL_NO_ERROR();
674
675 constexpr GLuint kExpectedValue = 100u;
676 for (int x = 0; x < kWidth; x++)
677 {
678 for (int y = 0; y < kHeight; y++)
679 {
680 EXPECT_EQ(kExpectedValue, outputValues[x][y]);
681 }
682 }
683 }
684
685 // Test that uploading data to buffer that's in use then using it as indirect buffer works.
TEST_P(ComputeShaderTest,UseAsUBOThenUpdateThenDispatchComputeIndirect)686 TEST_P(ComputeShaderTest, UseAsUBOThenUpdateThenDispatchComputeIndirect)
687 {
688 // Flaky crash on teardown, see http://anglebug.com/3349
689 ANGLE_SKIP_TEST_IF(IsD3D11() && IsIntel() && IsWindows());
690
691 constexpr GLsizei kWidth = 4, kHeight = 6;
692
693 const std::array<uint32_t, 4> kInitialData = {1, 2, 3, 4};
694 const std::array<uint32_t, 4> kUpdateData = {kWidth, kHeight, 1, 0};
695
696 GLBuffer buffer;
697 glBindBuffer(GL_UNIFORM_BUFFER, buffer);
698 glBufferData(GL_UNIFORM_BUFFER, sizeof(kInitialData), kInitialData.data(), GL_DYNAMIC_DRAW);
699 glBindBufferBase(GL_UNIFORM_BUFFER, 0, buffer);
700 EXPECT_GL_NO_ERROR();
701
702 constexpr char kVerifyUBO[] = R"(#version 310 es
703 precision mediump float;
704 layout(binding = 0) uniform block {
705 uvec4 data;
706 } ubo;
707 out vec4 colorOut;
708 void main()
709 {
710 if (all(equal(ubo.data, uvec4(1, 2, 3, 4))))
711 colorOut = vec4(0, 1.0, 0, 1.0);
712 else
713 colorOut = vec4(1.0, 0, 0, 1.0);
714 })";
715
716 ANGLE_GL_PROGRAM(verifyUbo, essl31_shaders::vs::Simple(), kVerifyUBO);
717 drawQuad(verifyUbo, essl31_shaders::PositionAttrib(), 0.5);
718 EXPECT_GL_NO_ERROR();
719
720 // Update buffer data
721 glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(kInitialData), kUpdateData.data());
722 EXPECT_GL_NO_ERROR();
723
724 const char kCS[] = R"(#version 310 es
725 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
726 layout(r32ui, binding = 0) uniform highp uimage2D uImage;
727 void main()
728 {
729 imageStore(uImage, ivec2(gl_WorkGroupID.x, gl_WorkGroupID.y), uvec4(100, 0, 0, 0));
730 })";
731
732 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
733 glUseProgram(program.get());
734
735 glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, buffer);
736
737 const std::vector<GLuint> inputValues(kWidth * kHeight, 0);
738
739 GLTexture texture;
740 glBindTexture(GL_TEXTURE_2D, texture);
741 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kWidth, kHeight);
742 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
743 inputValues.data());
744 EXPECT_GL_NO_ERROR();
745
746 glBindImageTexture(0, texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
747 EXPECT_GL_NO_ERROR();
748
749 glDispatchComputeIndirect(0);
750 EXPECT_GL_NO_ERROR();
751
752 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
753
754 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
755
756 GLuint outputValues[kWidth][kHeight];
757
758 GLFramebuffer framebuffer;
759 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
760 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
761 EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_READ_FRAMEBUFFER);
762 EXPECT_GL_NO_ERROR();
763
764 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
765 EXPECT_GL_NO_ERROR();
766
767 constexpr GLuint kExpectedValue = 100u;
768 for (int x = 0; x < kWidth; x++)
769 {
770 for (int y = 0; y < kHeight; y++)
771 {
772 EXPECT_EQ(kExpectedValue, outputValues[x][y]);
773 }
774 }
775 }
776
777 // Use image uniform to write texture in compute shader, and verify the content is expected.
TEST_P(ComputeShaderTest,BindImageTexture)778 TEST_P(ComputeShaderTest, BindImageTexture)
779 {
780 GLTexture mTexture[2];
781 GLFramebuffer mFramebuffer;
782 constexpr char kCS[] = R"(#version 310 es
783 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
784 layout(r32ui, binding = 0) writeonly uniform highp uimage2D uImage[2];
785 void main()
786 {
787 imageStore(uImage[0], ivec2(gl_LocalInvocationIndex, gl_WorkGroupID.x), uvec4(100, 0,
788 0, 0));
789 imageStore(uImage[1], ivec2(gl_LocalInvocationIndex, gl_WorkGroupID.x), uvec4(100, 0,
790 0, 0));
791 })";
792
793 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
794 glUseProgram(program.get());
795 int width = 1, height = 1;
796 GLuint inputValues[] = {200};
797
798 glBindTexture(GL_TEXTURE_2D, mTexture[0]);
799 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, width, height);
800 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RED_INTEGER, GL_UNSIGNED_INT,
801 inputValues);
802 EXPECT_GL_NO_ERROR();
803
804 glBindImageTexture(0, mTexture[0], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
805 EXPECT_GL_NO_ERROR();
806
807 glBindTexture(GL_TEXTURE_2D, mTexture[1]);
808 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, width, height);
809 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RED_INTEGER, GL_UNSIGNED_INT,
810 inputValues);
811 EXPECT_GL_NO_ERROR();
812
813 glBindImageTexture(1, mTexture[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
814 EXPECT_GL_NO_ERROR();
815
816 glDispatchCompute(1, 1, 1);
817 EXPECT_GL_NO_ERROR();
818
819 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
820 glUseProgram(0);
821 GLuint outputValues[2][1];
822 GLuint expectedValue = 100;
823 glBindFramebuffer(GL_READ_FRAMEBUFFER, mFramebuffer);
824
825 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTexture[0],
826 0);
827 EXPECT_GL_NO_ERROR();
828 glReadPixels(0, 0, width, height, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues[0]);
829 EXPECT_GL_NO_ERROR();
830
831 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTexture[1],
832 0);
833 EXPECT_GL_NO_ERROR();
834 glReadPixels(0, 0, width, height, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues[1]);
835 EXPECT_GL_NO_ERROR();
836
837 for (int i = 0; i < width * height; i++)
838 {
839 EXPECT_EQ(expectedValue, outputValues[0][i]);
840 EXPECT_EQ(expectedValue, outputValues[1][i]);
841 }
842 }
843
844 // When declare a image array without a binding qualifier, all elements are bound to unit zero.
TEST_P(ComputeShaderTest,ImageArrayWithoutBindingQualifier)845 TEST_P(ComputeShaderTest, ImageArrayWithoutBindingQualifier)
846 {
847 ANGLE_SKIP_TEST_IF(IsD3D11());
848
849 // TODO(xinghua.cao@intel.com): On AMD desktop OpenGL, bind two image variables to unit 0,
850 // only one variable is valid.
851 ANGLE_SKIP_TEST_IF(IsAMD() && IsDesktopOpenGL());
852
853 GLTexture mTexture;
854 GLFramebuffer mFramebuffer;
855 constexpr char kCS[] = R"(#version 310 es
856 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
857 layout(r32ui) writeonly uniform highp uimage2D uImage[2];
858 void main()
859 {
860 imageStore(uImage[0], ivec2(gl_LocalInvocationIndex, 0), uvec4(100, 0, 0, 0));
861 imageStore(uImage[1], ivec2(gl_LocalInvocationIndex, 1), uvec4(100, 0, 0, 0));
862 })";
863
864 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
865 glUseProgram(program.get());
866 constexpr int kTextureWidth = 1, kTextureHeight = 2;
867 GLuint inputValues[] = {200, 200};
868
869 glBindTexture(GL_TEXTURE_2D, mTexture);
870 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kTextureWidth, kTextureHeight);
871 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kTextureWidth, kTextureHeight, GL_RED_INTEGER,
872 GL_UNSIGNED_INT, inputValues);
873 EXPECT_GL_NO_ERROR();
874
875 glBindImageTexture(0, mTexture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
876 glDispatchCompute(1, 1, 1);
877 EXPECT_GL_NO_ERROR();
878
879 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
880 glUseProgram(0);
881 glBindFramebuffer(GL_READ_FRAMEBUFFER, mFramebuffer);
882
883 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTexture, 0);
884 GLuint outputValues[kTextureWidth * kTextureHeight];
885 glReadPixels(0, 0, kTextureWidth, kTextureHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
886 outputValues);
887 EXPECT_GL_NO_ERROR();
888
889 GLuint expectedValue = 100;
890 for (int i = 0; i < kTextureWidth * kTextureHeight; i++)
891 {
892 EXPECT_EQ(expectedValue, outputValues[i]);
893 }
894 }
895
896 // When an image array is declared without a binding qualifier, all elements are bound to unit zero.
897 // Check that the unused uniform image array element does not cause any corruption. Checks for a bug
898 // where unused element could make the whole array seem as unused.
TEST_P(ComputeShaderTest,ImageArrayUnusedElement)899 TEST_P(ComputeShaderTest, ImageArrayUnusedElement)
900 {
901 ANGLE_SKIP_TEST_IF(IsD3D11());
902
903 // TODO(xinghua.cao@intel.com): On AMD desktop OpenGL, bind two image variables to unit 0,
904 // only one variable is valid.
905 ANGLE_SKIP_TEST_IF(IsAMD() && IsDesktopOpenGL());
906
907 // Vulkan is currently unable to handle unbound image units in compute shaders.
908 // http://anglebug.com/5026
909 ANGLE_SKIP_TEST_IF(IsVulkan());
910
911 GLFramebuffer framebuffer;
912 constexpr char kCS[] = R"(#version 310 es
913 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
914 layout(r32ui, binding=0) writeonly uniform highp uimage2D uOut;
915 layout(r32ui, binding=1) readonly uniform highp uimage2D uIn[2];
916
917 void main()
918 {
919 uvec4 inValue = imageLoad(uIn[0], ivec2(gl_LocalInvocationID.xy));
920 imageStore(uOut, ivec2(gl_LocalInvocationIndex, 0), inValue);
921 imageStore(uOut, ivec2(gl_LocalInvocationIndex, 1), inValue);
922 })";
923
924 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
925 glUseProgram(program.get());
926 constexpr int kTextureWidth = 1, kTextureHeight = 2;
927 GLuint inputValues[] = {100, 100};
928 GLTexture in;
929 glBindTexture(GL_TEXTURE_2D, in);
930 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kTextureWidth, kTextureHeight);
931 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kTextureWidth, kTextureHeight, GL_RED_INTEGER,
932 GL_UNSIGNED_INT, inputValues);
933 EXPECT_GL_NO_ERROR();
934 glBindImageTexture(1, in, 0, GL_FALSE, 0, GL_READ_ONLY, GL_R32UI);
935
936 GLuint initValues[] = {111, 111};
937 GLTexture out;
938 glBindTexture(GL_TEXTURE_2D, out);
939 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kTextureWidth, kTextureHeight);
940 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kTextureWidth, kTextureHeight, GL_RED_INTEGER,
941 GL_UNSIGNED_INT, initValues);
942 EXPECT_GL_NO_ERROR();
943
944 glBindImageTexture(0, out, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
945 glDispatchCompute(1, 1, 1);
946 EXPECT_GL_NO_ERROR();
947
948 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
949 glUseProgram(0);
950 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
951
952 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, out, 0);
953 GLuint outputValues[kTextureWidth * kTextureHeight];
954 glReadPixels(0, 0, kTextureWidth, kTextureHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
955 outputValues);
956 EXPECT_GL_NO_ERROR();
957
958 GLuint expectedValue = 100;
959 for (int i = 0; i < kTextureWidth * kTextureHeight; i++)
960 {
961 EXPECT_EQ(expectedValue, outputValues[i]);
962 }
963 }
964 // imageLoad functions
TEST_P(ComputeShaderTest,ImageLoad)965 TEST_P(ComputeShaderTest, ImageLoad)
966 {
967 constexpr char kCS[] = R"(#version 310 es
968 layout(local_size_x=8) in;
969 layout(rgba8) uniform highp readonly image2D mImage2DInput;
970 layout(rgba16i) uniform highp readonly iimageCube mImageCubeInput;
971 layout(rgba32ui) uniform highp readonly uimage3D mImage3DInput;
972 layout(r32i) uniform highp writeonly iimage2D imageOut;
973 void main()
974 {
975 vec4 result2d = imageLoad(mImage2DInput, ivec2(gl_LocalInvocationID.xy));
976 ivec4 resultCube = imageLoad(mImageCubeInput, ivec3(gl_LocalInvocationID.xyz));
977 uvec4 result3d = imageLoad(mImage3DInput, ivec3(gl_LocalInvocationID.xyz));
978 imageStore(imageOut, ivec2(gl_LocalInvocationIndex, 0), ivec4(result2d) + resultCube + ivec4(result3d));
979 })";
980
981 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
982 EXPECT_GL_NO_ERROR();
983 }
984
985 // imageStore functions
TEST_P(ComputeShaderTest,ImageStore)986 TEST_P(ComputeShaderTest, ImageStore)
987 {
988 constexpr char kCS[] = R"(#version 310 es
989 layout(local_size_x=8) in;
990 layout(rgba16f) uniform highp writeonly imageCube mImageCubeOutput;
991 layout(r32f) uniform highp writeonly image3D mImage3DOutput;
992 layout(rgba8ui) uniform highp writeonly uimage2DArray mImage2DArrayOutput;
993 void main()
994 {
995 imageStore(mImageCubeOutput, ivec3(gl_LocalInvocationID.xyz), vec4(0.0));
996 imageStore(mImage3DOutput, ivec3(gl_LocalInvocationID.xyz), vec4(0.0));
997 imageStore(mImage2DArrayOutput, ivec3(gl_LocalInvocationID.xyz), uvec4(0));
998 })";
999
1000 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
1001 EXPECT_GL_NO_ERROR();
1002 }
1003
1004 // imageSize functions
TEST_P(ComputeShaderTest,ImageSize)1005 TEST_P(ComputeShaderTest, ImageSize)
1006 {
1007 constexpr char kCS[] = R"(#version 310 es
1008 layout(local_size_x=8) in;
1009 layout(rgba8) uniform highp readonly imageCube mImageCubeInput;
1010 layout(r32i) uniform highp readonly iimage2D mImage2DInput;
1011 layout(rgba16ui) uniform highp readonly uimage2DArray mImage2DArrayInput;
1012 layout(r32i) uniform highp writeonly iimage2D imageOut;
1013 void main()
1014 {
1015 ivec2 sizeCube = imageSize(mImageCubeInput);
1016 ivec2 size2D = imageSize(mImage2DInput);
1017 ivec3 size2DArray = imageSize(mImage2DArrayInput);
1018 imageStore(imageOut, ivec2(gl_LocalInvocationIndex, 0), ivec4(sizeCube, size2D.x, size2DArray.x));
1019 })";
1020
1021 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
1022 EXPECT_GL_NO_ERROR();
1023 }
1024
1025 // Test that texelFetch works well in compute shader.
TEST_P(ComputeShaderTest,TexelFetchFunction)1026 TEST_P(ComputeShaderTest, TexelFetchFunction)
1027 {
1028 // http://anglebug.com/4092
1029 ANGLE_SKIP_TEST_IF(isSwiftshader());
1030 constexpr char kCS[] = R"(#version 310 es
1031 layout(local_size_x=16, local_size_y=12) in;
1032 precision highp usampler2D;
1033 uniform usampler2D tex;
1034 layout(std140, binding = 0) buffer buf {
1035 uint outData[12][16];
1036 };
1037
1038 void main()
1039 {
1040 uint x = gl_LocalInvocationID.x;
1041 uint y = gl_LocalInvocationID.y;
1042 outData[y][x] = texelFetch(tex, ivec2(x, y), 0).x;
1043 })";
1044
1045 constexpr unsigned int kWidth = 16;
1046 constexpr unsigned int kHeight = 12;
1047 GLTexture tex;
1048 glBindTexture(GL_TEXTURE_2D, tex);
1049 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1050 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1051 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kWidth, kHeight);
1052 GLuint texels[kHeight][kWidth] = {{0}};
1053 for (unsigned int y = 0; y < kHeight; ++y)
1054 {
1055 for (unsigned int x = 0; x < kWidth; ++x)
1056 {
1057 texels[y][x] = x + y * kWidth;
1058 }
1059 }
1060 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1061 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
1062 texels);
1063 glBindTexture(GL_TEXTURE_2D, 0);
1064
1065 // The array stride are rounded up to the base alignment of a vec4 for std140 layout.
1066 constexpr unsigned int kArrayStride = 16;
1067 GLBuffer ssbo;
1068 glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
1069 glBufferData(GL_SHADER_STORAGE_BUFFER, kWidth * kHeight * kArrayStride, nullptr,
1070 GL_STREAM_DRAW);
1071 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
1072 EXPECT_GL_NO_ERROR();
1073
1074 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
1075 glUseProgram(program);
1076
1077 glActiveTexture(GL_TEXTURE0);
1078 glBindTexture(GL_TEXTURE_2D, tex);
1079 glUniform1i(glGetUniformLocation(program, "tex"), 0);
1080 glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
1081 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, ssbo);
1082
1083 glDispatchCompute(1, 1, 1);
1084
1085 glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
1086 const GLuint *ptr = reinterpret_cast<const GLuint *>(glMapBufferRange(
1087 GL_SHADER_STORAGE_BUFFER, 0, kWidth * kHeight * kArrayStride, GL_MAP_READ_BIT));
1088 EXPECT_GL_NO_ERROR();
1089 for (unsigned int idx = 0; idx < kWidth * kHeight; idx++)
1090 {
1091 EXPECT_EQ(idx, *(ptr + idx * kArrayStride / 4));
1092 }
1093 }
1094
1095 // Test that texture function works well in compute shader.
TEST_P(ComputeShaderTest,TextureFunction)1096 TEST_P(ComputeShaderTest, TextureFunction)
1097 {
1098 // http://anglebug.com/4092
1099 ANGLE_SKIP_TEST_IF(isSwiftshader());
1100 constexpr char kCS[] = R"(#version 310 es
1101 layout(local_size_x=16, local_size_y=16) in;
1102 precision highp usampler2D;
1103 uniform usampler2D tex;
1104 layout(std140, binding = 0) buffer buf {
1105 uint outData[16][16];
1106 };
1107
1108 void main()
1109 {
1110 uint x = gl_LocalInvocationID.x;
1111 uint y = gl_LocalInvocationID.y;
1112 float xCoord = float(x) / float(16);
1113 float yCoord = float(y) / float(16);
1114 outData[y][x] = texture(tex, vec2(xCoord, yCoord)).x;
1115 })";
1116
1117 constexpr unsigned int kWidth = 16;
1118 constexpr unsigned int kHeight = 16;
1119 GLTexture tex;
1120 glBindTexture(GL_TEXTURE_2D, tex);
1121 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1122 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1123 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kWidth, kHeight);
1124 GLuint texels[kHeight][kWidth] = {{0}};
1125 for (unsigned int y = 0; y < kHeight; ++y)
1126 {
1127 for (unsigned int x = 0; x < kWidth; ++x)
1128 {
1129 texels[y][x] = x + y * kWidth;
1130 }
1131 }
1132 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1133 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
1134 texels);
1135 glBindTexture(GL_TEXTURE_2D, 0);
1136
1137 // The array stride are rounded up to the base alignment of a vec4 for std140 layout.
1138 constexpr unsigned int kArrayStride = 16;
1139 GLBuffer ssbo;
1140 glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
1141 glBufferData(GL_SHADER_STORAGE_BUFFER, kWidth * kHeight * kArrayStride, nullptr,
1142 GL_STREAM_DRAW);
1143 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
1144 EXPECT_GL_NO_ERROR();
1145
1146 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
1147 glUseProgram(program);
1148
1149 glActiveTexture(GL_TEXTURE0);
1150 glBindTexture(GL_TEXTURE_2D, tex);
1151 glUniform1i(glGetUniformLocation(program, "tex"), 0);
1152 glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
1153 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, ssbo);
1154
1155 glDispatchCompute(1, 1, 1);
1156
1157 glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
1158 const GLuint *ptr = reinterpret_cast<const GLuint *>(glMapBufferRange(
1159 GL_SHADER_STORAGE_BUFFER, 0, kWidth * kHeight * kArrayStride, GL_MAP_READ_BIT));
1160 EXPECT_GL_NO_ERROR();
1161 for (unsigned int idx = 0; idx < kWidth * kHeight; idx++)
1162 {
1163 EXPECT_EQ(idx, *(ptr + idx * kArrayStride / 4));
1164 }
1165 }
1166
1167 // Test mixed use of sampler and image.
TEST_P(ComputeShaderTest,SamplingAndImageReadWrite)1168 TEST_P(ComputeShaderTest, SamplingAndImageReadWrite)
1169 {
1170 GLTexture texture[3];
1171 GLFramebuffer framebuffer;
1172 constexpr char kCS[] = R"(#version 310 es
1173 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
1174 layout(r32ui, binding = 0) readonly uniform highp uimage2D uImage_1;
1175 layout(r32ui, binding = 1) writeonly uniform highp uimage2D uImage_2;
1176 precision highp usampler2D;
1177 uniform usampler2D tex;
1178 void main()
1179 {
1180 uvec4 value_1 = texelFetch(tex, ivec2(gl_LocalInvocationID.xy), 0);
1181 uvec4 value_2 = imageLoad(uImage_1, ivec2(gl_LocalInvocationID.xy));
1182 imageStore(uImage_2, ivec2(gl_LocalInvocationID.xy), value_1 + value_2);
1183 })";
1184
1185 constexpr int kWidth = 1, kHeight = 1;
1186 constexpr GLuint kInputValues[3][1] = {{50}, {100}, {20}};
1187
1188 glBindTexture(GL_TEXTURE_2D, texture[0]);
1189 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kWidth, kHeight);
1190 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
1191 kInputValues[0]);
1192 glBindTexture(GL_TEXTURE_2D, texture[2]);
1193 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kWidth, kHeight);
1194 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
1195 kInputValues[2]);
1196 EXPECT_GL_NO_ERROR();
1197 glBindTexture(GL_TEXTURE_2D, 0);
1198
1199 glBindTexture(GL_TEXTURE_2D, texture[1]);
1200 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1201 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1202 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kWidth, kHeight);
1203 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1204 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
1205 kInputValues[1]);
1206
1207 EXPECT_GL_NO_ERROR();
1208
1209 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
1210 glUseProgram(program.get());
1211
1212 glBindImageTexture(0, texture[0], 0, GL_FALSE, 0, GL_READ_ONLY, GL_R32UI);
1213 glBindImageTexture(1, texture[2], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
1214 EXPECT_GL_NO_ERROR();
1215
1216 glDispatchCompute(1, 1, 1);
1217 EXPECT_GL_NO_ERROR();
1218
1219 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
1220 GLuint outputValues[kWidth * kHeight];
1221 constexpr GLuint expectedValue = 150;
1222 glUseProgram(0);
1223 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
1224
1225 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture[2], 0);
1226 EXPECT_GL_NO_ERROR();
1227 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
1228 EXPECT_GL_NO_ERROR();
1229
1230 for (int i = 0; i < kWidth * kHeight; i++)
1231 {
1232 EXPECT_EQ(expectedValue, outputValues[i]);
1233 }
1234 }
1235
1236 // Use image uniform to read and write Texture2D in compute shader, and verify the contents.
TEST_P(ComputeShaderTest,BindImageTextureWithTexture2D)1237 TEST_P(ComputeShaderTest, BindImageTextureWithTexture2D)
1238 {
1239 GLTexture texture[2];
1240 GLFramebuffer framebuffer;
1241 constexpr char kCS[] = R"(#version 310 es
1242 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
1243 layout(r32ui, binding = 0) readonly uniform highp uimage2D uImage_1;
1244 layout(r32ui, binding = 1) writeonly uniform highp uimage2D uImage_2;
1245 void main()
1246 {
1247 uvec4 value = imageLoad(uImage_1, ivec2(gl_LocalInvocationID.xy));
1248 imageStore(uImage_2, ivec2(gl_LocalInvocationID.xy), value);
1249 })";
1250
1251 constexpr int kWidth = 1, kHeight = 1;
1252 constexpr GLuint kInputValues[2][1] = {{200}, {100}};
1253
1254 glBindTexture(GL_TEXTURE_2D, texture[0]);
1255 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kWidth, kHeight);
1256 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
1257 kInputValues[0]);
1258 EXPECT_GL_NO_ERROR();
1259
1260 glBindTexture(GL_TEXTURE_2D, texture[1]);
1261 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kWidth, kHeight);
1262 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
1263 kInputValues[1]);
1264 EXPECT_GL_NO_ERROR();
1265
1266 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
1267 glUseProgram(program.get());
1268
1269 glBindImageTexture(0, texture[0], 0, GL_FALSE, 0, GL_READ_ONLY, GL_R32UI);
1270 EXPECT_GL_NO_ERROR();
1271
1272 glBindImageTexture(1, texture[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
1273 EXPECT_GL_NO_ERROR();
1274
1275 glDispatchCompute(1, 1, 1);
1276 EXPECT_GL_NO_ERROR();
1277
1278 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
1279 GLuint outputValues[kWidth * kHeight];
1280 constexpr GLuint expectedValue = 200;
1281 glUseProgram(0);
1282 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
1283
1284 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture[1], 0);
1285 EXPECT_GL_NO_ERROR();
1286 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
1287 EXPECT_GL_NO_ERROR();
1288
1289 for (int i = 0; i < kWidth * kHeight; i++)
1290 {
1291 EXPECT_EQ(expectedValue, outputValues[i]);
1292 }
1293 }
1294
1295 // Use image uniform to read and write Texture2D with non-zero base in compute shader, and verify
1296 // the contents.
TEST_P(ComputeShaderTest,BindImageTextureWithNonZeroBaseTexture2D)1297 TEST_P(ComputeShaderTest, BindImageTextureWithNonZeroBaseTexture2D)
1298 {
1299 GLTexture texture[2];
1300 GLFramebuffer framebuffer;
1301 constexpr char kCS[] = R"(#version 310 es
1302 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
1303 layout(r32ui, binding = 0) readonly uniform highp uimage2D uImage_1;
1304 layout(r32ui, binding = 1) writeonly uniform highp uimage2D uImage_2;
1305 void main()
1306 {
1307 uvec4 value = imageLoad(uImage_1, ivec2(gl_LocalInvocationID.xy));
1308 imageStore(uImage_2, ivec2(gl_LocalInvocationID.xy), value);
1309 })";
1310
1311 constexpr int kWidth = 1, kHeight = 1;
1312 constexpr GLuint kInputValues[2][1] = {{200}, {100}};
1313
1314 glBindTexture(GL_TEXTURE_2D, texture[0]);
1315 glTexStorage2D(GL_TEXTURE_2D, 2, GL_R32UI, kWidth * 2, kHeight * 2);
1316 glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
1317 kInputValues[0]);
1318 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1);
1319 EXPECT_GL_NO_ERROR();
1320
1321 glBindTexture(GL_TEXTURE_2D, texture[1]);
1322 glTexStorage2D(GL_TEXTURE_2D, 2, GL_R32UI, kWidth * 2, kHeight * 2);
1323 glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
1324 kInputValues[1]);
1325 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1);
1326 EXPECT_GL_NO_ERROR();
1327
1328 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
1329 glUseProgram(program.get());
1330
1331 glBindImageTexture(0, texture[0], 1, GL_FALSE, 0, GL_READ_ONLY, GL_R32UI);
1332 EXPECT_GL_NO_ERROR();
1333
1334 glBindImageTexture(1, texture[1], 1, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
1335 EXPECT_GL_NO_ERROR();
1336
1337 glDispatchCompute(1, 1, 1);
1338 EXPECT_GL_NO_ERROR();
1339
1340 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
1341 GLuint outputValues[kWidth * kHeight];
1342 constexpr GLuint expectedValue = 200;
1343 glUseProgram(0);
1344 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
1345
1346 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture[1], 1);
1347 EXPECT_GL_NO_ERROR();
1348 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
1349 EXPECT_GL_NO_ERROR();
1350
1351 for (int i = 0; i < kWidth * kHeight; i++)
1352 {
1353 EXPECT_EQ(expectedValue, outputValues[i]) << " at index: " << i;
1354 }
1355 }
1356
1357 // Use image uniform to read and write Texture2DArray in compute shader, and verify the contents.
TEST_P(ComputeShaderTest,BindImageTextureWithTexture2DArray)1358 TEST_P(ComputeShaderTest, BindImageTextureWithTexture2DArray)
1359 {
1360 GLTexture texture[2];
1361 GLFramebuffer framebuffer;
1362 constexpr char kCS[] = R"(#version 310 es
1363 layout(local_size_x=2, local_size_y=2, local_size_z=2) in;
1364 layout(r32ui, binding = 0) readonly uniform highp uimage2DArray uImage_1;
1365 layout(r32ui, binding = 1) writeonly uniform highp uimage2DArray uImage_2;
1366 void main()
1367 {
1368 uvec4 value = imageLoad(uImage_1, ivec3(gl_LocalInvocationID.xyz));
1369 imageStore(uImage_2, ivec3(gl_LocalInvocationID.xyz), value);
1370 })";
1371
1372 constexpr int kWidth = 1, kHeight = 1, kDepth = 2;
1373 constexpr GLuint kInputValues[2][2] = {{200, 200}, {100, 100}};
1374
1375 glBindTexture(GL_TEXTURE_2D_ARRAY, texture[0]);
1376 glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_R32UI, kWidth, kHeight, kDepth);
1377 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, kWidth, kHeight, kDepth, GL_RED_INTEGER,
1378 GL_UNSIGNED_INT, kInputValues[0]);
1379 EXPECT_GL_NO_ERROR();
1380
1381 glBindTexture(GL_TEXTURE_2D_ARRAY, texture[1]);
1382 glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_R32UI, kWidth, kHeight, kDepth);
1383 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, kWidth, kHeight, kDepth, GL_RED_INTEGER,
1384 GL_UNSIGNED_INT, kInputValues[1]);
1385 EXPECT_GL_NO_ERROR();
1386
1387 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
1388 glUseProgram(program.get());
1389
1390 glBindImageTexture(0, texture[0], 0, GL_TRUE, 0, GL_READ_ONLY, GL_R32UI);
1391 EXPECT_GL_NO_ERROR();
1392
1393 glBindImageTexture(1, texture[1], 0, GL_TRUE, 0, GL_WRITE_ONLY, GL_R32UI);
1394 EXPECT_GL_NO_ERROR();
1395
1396 glDispatchCompute(1, 1, 1);
1397 EXPECT_GL_NO_ERROR();
1398
1399 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
1400 GLuint outputValues[kWidth * kHeight];
1401 constexpr GLuint expectedValue = 200;
1402 glUseProgram(0);
1403 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
1404
1405 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture[1], 0, 0);
1406 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, texture[1], 0, 1);
1407 EXPECT_GL_NO_ERROR();
1408 glReadBuffer(GL_COLOR_ATTACHMENT0);
1409 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
1410 EXPECT_GL_NO_ERROR();
1411 for (int i = 0; i < kWidth * kHeight; i++)
1412 {
1413 EXPECT_EQ(expectedValue, outputValues[i]);
1414 }
1415 glReadBuffer(GL_COLOR_ATTACHMENT1);
1416 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
1417 EXPECT_GL_NO_ERROR();
1418 for (int i = 0; i < kWidth * kHeight; i++)
1419 {
1420 EXPECT_EQ(expectedValue, outputValues[i]);
1421 }
1422 }
1423
1424 // Use image uniform to read and write Texture2DArray with non-zero base in compute shader, and
1425 // verify the contents.
TEST_P(ComputeShaderTest,BindImageTextureWithNonZeroBaseTexture2DArray)1426 TEST_P(ComputeShaderTest, BindImageTextureWithNonZeroBaseTexture2DArray)
1427 {
1428 GLTexture texture[2];
1429 GLFramebuffer framebuffer;
1430 constexpr char kCS[] = R"(#version 310 es
1431 layout(local_size_x=2, local_size_y=2, local_size_z=2) in;
1432 layout(r32ui, binding = 0) readonly uniform highp uimage2DArray uImage_1;
1433 layout(r32ui, binding = 1) writeonly uniform highp uimage2DArray uImage_2;
1434 void main()
1435 {
1436 uvec4 value = imageLoad(uImage_1, ivec3(gl_LocalInvocationID.xyz));
1437 imageStore(uImage_2, ivec3(gl_LocalInvocationID.xyz), value);
1438 })";
1439
1440 constexpr int kWidth = 1, kHeight = 1, kDepth = 2;
1441 constexpr GLuint kInputValues[2][2] = {{200, 200}, {100, 100}};
1442
1443 glBindTexture(GL_TEXTURE_2D_ARRAY, texture[0]);
1444 glTexStorage3D(GL_TEXTURE_2D_ARRAY, 2, GL_R32UI, kWidth * 2, kHeight * 2, kDepth);
1445 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 1, 0, 0, 0, kWidth, kHeight, kDepth, GL_RED_INTEGER,
1446 GL_UNSIGNED_INT, kInputValues[0]);
1447 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_BASE_LEVEL, 1);
1448 EXPECT_GL_NO_ERROR();
1449
1450 glBindTexture(GL_TEXTURE_2D_ARRAY, texture[1]);
1451 glTexStorage3D(GL_TEXTURE_2D_ARRAY, 2, GL_R32UI, kWidth * 2, kHeight * 2, kDepth);
1452 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 1, 0, 0, 0, kWidth, kHeight, kDepth, GL_RED_INTEGER,
1453 GL_UNSIGNED_INT, kInputValues[1]);
1454 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_BASE_LEVEL, 1);
1455 EXPECT_GL_NO_ERROR();
1456
1457 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
1458 glUseProgram(program.get());
1459
1460 glBindImageTexture(0, texture[0], 1, GL_TRUE, 0, GL_READ_ONLY, GL_R32UI);
1461 EXPECT_GL_NO_ERROR();
1462
1463 glBindImageTexture(1, texture[1], 1, GL_TRUE, 0, GL_WRITE_ONLY, GL_R32UI);
1464 EXPECT_GL_NO_ERROR();
1465
1466 glDispatchCompute(1, 1, 1);
1467 EXPECT_GL_NO_ERROR();
1468
1469 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
1470 GLuint outputValues[kWidth * kHeight];
1471 constexpr GLuint expectedValue = 200;
1472 glUseProgram(0);
1473 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
1474
1475 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture[1], 1, 0);
1476 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, texture[1], 1, 1);
1477 EXPECT_GL_NO_ERROR();
1478 glReadBuffer(GL_COLOR_ATTACHMENT0);
1479 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
1480 EXPECT_GL_NO_ERROR();
1481 for (int i = 0; i < kWidth * kHeight; i++)
1482 {
1483 EXPECT_EQ(expectedValue, outputValues[i]);
1484 }
1485 glReadBuffer(GL_COLOR_ATTACHMENT1);
1486 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
1487 EXPECT_GL_NO_ERROR();
1488 for (int i = 0; i < kWidth * kHeight; i++)
1489 {
1490 EXPECT_EQ(expectedValue, outputValues[i]);
1491 }
1492 }
1493
1494 // Use image uniform to read and write Texture3D in compute shader, and verify the contents.
TEST_P(ComputeShaderTest,BindImageTextureWithTexture3D)1495 TEST_P(ComputeShaderTest, BindImageTextureWithTexture3D)
1496 {
1497 GLTexture texture[2];
1498 GLFramebuffer framebuffer;
1499 constexpr char kCS[] = R"(#version 310 es
1500 layout(local_size_x=1, local_size_y=1, local_size_z=2) in;
1501 layout(r32ui, binding = 0) readonly uniform highp uimage3D uImage_1;
1502 layout(r32ui, binding = 1) writeonly uniform highp uimage3D uImage_2;
1503 void main()
1504 {
1505 uvec4 value = imageLoad(uImage_1, ivec3(gl_LocalInvocationID.xyz));
1506 imageStore(uImage_2, ivec3(gl_LocalInvocationID.xyz), value);
1507 })";
1508
1509 constexpr int kWidth = 1, kHeight = 1, kDepth = 2;
1510 constexpr GLuint kInputValues[2][2] = {{200, 200}, {100, 100}};
1511
1512 glBindTexture(GL_TEXTURE_3D, texture[0]);
1513 glTexStorage3D(GL_TEXTURE_3D, 1, GL_R32UI, kWidth, kHeight, kDepth);
1514 glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, kWidth, kHeight, kDepth, GL_RED_INTEGER,
1515 GL_UNSIGNED_INT, kInputValues[0]);
1516 EXPECT_GL_NO_ERROR();
1517
1518 glBindTexture(GL_TEXTURE_3D, texture[1]);
1519 glTexStorage3D(GL_TEXTURE_3D, 1, GL_R32UI, kWidth, kHeight, kDepth);
1520 glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, kWidth, kHeight, kDepth, GL_RED_INTEGER,
1521 GL_UNSIGNED_INT, kInputValues[1]);
1522 EXPECT_GL_NO_ERROR();
1523
1524 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
1525 glUseProgram(program.get());
1526
1527 glBindImageTexture(0, texture[0], 0, GL_TRUE, 0, GL_READ_ONLY, GL_R32UI);
1528 EXPECT_GL_NO_ERROR();
1529
1530 glBindImageTexture(1, texture[1], 0, GL_TRUE, 0, GL_WRITE_ONLY, GL_R32UI);
1531 EXPECT_GL_NO_ERROR();
1532
1533 glDispatchCompute(1, 1, 1);
1534 EXPECT_GL_NO_ERROR();
1535
1536 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
1537 GLuint outputValues[kWidth * kHeight];
1538 constexpr GLuint expectedValue = 200;
1539 glUseProgram(0);
1540 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
1541
1542 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture[1], 0, 0);
1543 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, texture[1], 0, 1);
1544 EXPECT_GL_NO_ERROR();
1545 glReadBuffer(GL_COLOR_ATTACHMENT0);
1546 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
1547 EXPECT_GL_NO_ERROR();
1548 for (int i = 0; i < kWidth * kHeight; i++)
1549 {
1550 EXPECT_EQ(expectedValue, outputValues[i]);
1551 }
1552 glReadBuffer(GL_COLOR_ATTACHMENT1);
1553 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
1554 EXPECT_GL_NO_ERROR();
1555 for (int i = 0; i < kWidth * kHeight; i++)
1556 {
1557 EXPECT_EQ(expectedValue, outputValues[i]);
1558 }
1559 }
1560
1561 // Use image uniform to read and write TextureCube in compute shader, and verify the contents.
TEST_P(ComputeShaderTest,BindImageTextureWithTextureCube)1562 TEST_P(ComputeShaderTest, BindImageTextureWithTextureCube)
1563 {
1564 GLTexture texture[2];
1565 GLFramebuffer framebuffer;
1566 constexpr char kCS[] = R"(#version 310 es
1567 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
1568 layout(r32ui, binding = 0) readonly uniform highp uimageCube uImage_1;
1569 layout(r32ui, binding = 1) writeonly uniform highp uimageCube uImage_2;
1570 void main()
1571 {
1572 for (int i = 0; i < 6; i++)
1573 {
1574 uvec4 value = imageLoad(uImage_1, ivec3(gl_LocalInvocationID.xy, i));
1575 imageStore(uImage_2, ivec3(gl_LocalInvocationID.xy, i), value);
1576 }
1577 })";
1578
1579 constexpr int kWidth = 1, kHeight = 1;
1580 constexpr GLuint kInputValues[2][1] = {{200}, {100}};
1581
1582 glBindTexture(GL_TEXTURE_CUBE_MAP, texture[0]);
1583 glTexStorage2D(GL_TEXTURE_CUBE_MAP, 1, GL_R32UI, kWidth, kHeight);
1584 for (GLenum face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
1585 face++)
1586 {
1587 glTexSubImage2D(face, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
1588 kInputValues[0]);
1589 }
1590 EXPECT_GL_NO_ERROR();
1591
1592 glBindTexture(GL_TEXTURE_CUBE_MAP, texture[1]);
1593 glTexStorage2D(GL_TEXTURE_CUBE_MAP, 1, GL_R32UI, kWidth, kHeight);
1594 for (GLenum face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
1595 face++)
1596 {
1597 glTexSubImage2D(face, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
1598 kInputValues[1]);
1599 }
1600 EXPECT_GL_NO_ERROR();
1601
1602 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
1603 glUseProgram(program.get());
1604
1605 glBindImageTexture(0, texture[0], 0, GL_TRUE, 0, GL_READ_ONLY, GL_R32UI);
1606 EXPECT_GL_NO_ERROR();
1607
1608 glBindImageTexture(1, texture[1], 0, GL_TRUE, 0, GL_WRITE_ONLY, GL_R32UI);
1609 EXPECT_GL_NO_ERROR();
1610
1611 glDispatchCompute(1, 1, 1);
1612 EXPECT_GL_NO_ERROR();
1613
1614 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
1615 GLuint outputValues[kWidth * kHeight];
1616 constexpr GLuint expectedValue = 200;
1617 glUseProgram(0);
1618 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
1619
1620 for (GLenum face = 0; face < 6; face++)
1621 {
1622 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
1623 GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, texture[1], 0);
1624 EXPECT_GL_NO_ERROR();
1625 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
1626 EXPECT_GL_NO_ERROR();
1627
1628 for (int i = 0; i < kWidth * kHeight; i++)
1629 {
1630 EXPECT_EQ(expectedValue, outputValues[i]);
1631 }
1632 }
1633 }
1634
1635 // Use image uniform to read and write one layer of Texture2DArray in compute shader, and verify the
1636 // contents.
TEST_P(ComputeShaderTest,BindImageTextureWithOneLayerTexture2DArray)1637 TEST_P(ComputeShaderTest, BindImageTextureWithOneLayerTexture2DArray)
1638 {
1639 GLTexture texture[2];
1640 GLFramebuffer framebuffer;
1641 constexpr char kCS[] = R"(#version 310 es
1642 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
1643 layout(r32ui, binding = 0) readonly uniform highp uimage2D uImage_1;
1644 layout(r32ui, binding = 1) writeonly uniform highp uimage2D uImage_2;
1645 void main()
1646 {
1647 uvec4 value = imageLoad(uImage_1, ivec2(gl_LocalInvocationID.xy));
1648 imageStore(uImage_2, ivec2(gl_LocalInvocationID.xy), value);
1649 })";
1650
1651 constexpr int kWidth = 1, kHeight = 1, kDepth = 2;
1652 constexpr int kResultSize = kWidth * kHeight;
1653 constexpr GLuint kInputValues[2][2] = {{200, 150}, {100, 50}};
1654 constexpr GLuint expectedValue_1 = 200;
1655 constexpr GLuint expectedValue_2 = 100;
1656 GLuint outputValues[kResultSize];
1657
1658 glBindTexture(GL_TEXTURE_2D_ARRAY, texture[0]);
1659 glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_R32UI, kWidth, kHeight, kDepth);
1660 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, kWidth, kHeight, kDepth, GL_RED_INTEGER,
1661 GL_UNSIGNED_INT, kInputValues[0]);
1662 EXPECT_GL_NO_ERROR();
1663
1664 glBindTexture(GL_TEXTURE_2D_ARRAY, texture[1]);
1665 glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_R32UI, kWidth, kHeight, kDepth);
1666 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, kWidth, kHeight, kDepth, GL_RED_INTEGER,
1667 GL_UNSIGNED_INT, kInputValues[1]);
1668 EXPECT_GL_NO_ERROR();
1669
1670 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
1671 glUseProgram(program.get());
1672
1673 glBindImageTexture(0, texture[0], 0, GL_FALSE, 0, GL_READ_ONLY, GL_R32UI);
1674 EXPECT_GL_NO_ERROR();
1675 glBindImageTexture(1, texture[1], 0, GL_FALSE, 1, GL_WRITE_ONLY, GL_R32UI);
1676 EXPECT_GL_NO_ERROR();
1677 glDispatchCompute(1, 1, 1);
1678 EXPECT_GL_NO_ERROR();
1679
1680 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
1681 glUseProgram(0);
1682 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
1683 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture[1], 0, 0);
1684 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, texture[1], 0, 1);
1685 EXPECT_GL_NO_ERROR();
1686 glReadBuffer(GL_COLOR_ATTACHMENT0);
1687 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
1688 EXPECT_GL_NO_ERROR();
1689 for (int i = 0; i < kResultSize; i++)
1690 {
1691 EXPECT_EQ(expectedValue_2, outputValues[i]);
1692 }
1693 glReadBuffer(GL_COLOR_ATTACHMENT1);
1694 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
1695 EXPECT_GL_NO_ERROR();
1696 for (int i = 0; i < kResultSize; i++)
1697 {
1698 EXPECT_EQ(expectedValue_1, outputValues[i]);
1699 }
1700 }
1701
1702 // Use image uniform to read and write one layer of Texture3D in compute shader, and verify the
1703 // contents.
TEST_P(ComputeShaderTest,BindImageTextureWithOneLayerTexture3D)1704 TEST_P(ComputeShaderTest, BindImageTextureWithOneLayerTexture3D)
1705 {
1706 // Vulkan validation error creating a 2D image view of a 3D image layer.
1707 // http://anglebug.com/3886
1708 ANGLE_SKIP_TEST_IF(IsVulkan());
1709
1710 GLTexture texture[2];
1711 GLFramebuffer framebuffer;
1712 constexpr char kCS[] = R"(#version 310 es
1713 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
1714 layout(r32ui, binding = 0) readonly uniform highp uimage2D uImage_1;
1715 layout(r32ui, binding = 1) writeonly uniform highp uimage2D uImage_2;
1716 void main()
1717 {
1718 uvec4 value = imageLoad(uImage_1, ivec2(gl_LocalInvocationID.xy));
1719 imageStore(uImage_2, ivec2(gl_LocalInvocationID.xy), value);
1720 })";
1721
1722 constexpr int kWidth = 1, kHeight = 1, kDepth = 2;
1723 constexpr int kResultSize = kWidth * kHeight;
1724 constexpr GLuint kInputValues[2][2] = {{200, 150}, {100, 50}};
1725 constexpr GLuint expectedValue_1 = 150;
1726 constexpr GLuint expectedValue_2 = 50;
1727 GLuint outputValues[kResultSize];
1728
1729 glBindTexture(GL_TEXTURE_3D, texture[0]);
1730 glTexStorage3D(GL_TEXTURE_3D, 1, GL_R32UI, kWidth, kHeight, kDepth);
1731 glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, kWidth, kHeight, kDepth, GL_RED_INTEGER,
1732 GL_UNSIGNED_INT, kInputValues[0]);
1733 EXPECT_GL_NO_ERROR();
1734
1735 glBindTexture(GL_TEXTURE_3D, texture[1]);
1736 glTexStorage3D(GL_TEXTURE_3D, 1, GL_R32UI, kWidth, kHeight, kDepth);
1737 glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, kWidth, kHeight, kDepth, GL_RED_INTEGER,
1738 GL_UNSIGNED_INT, kInputValues[1]);
1739 EXPECT_GL_NO_ERROR();
1740
1741 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
1742 glUseProgram(program.get());
1743
1744 glBindImageTexture(0, texture[0], 0, GL_FALSE, 1, GL_READ_ONLY, GL_R32UI);
1745 EXPECT_GL_NO_ERROR();
1746 glBindImageTexture(1, texture[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
1747 EXPECT_GL_NO_ERROR();
1748 glDispatchCompute(1, 1, 1);
1749 EXPECT_GL_NO_ERROR();
1750
1751 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
1752 glUseProgram(0);
1753 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
1754 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture[1], 0, 0);
1755 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, texture[1], 0, 1);
1756 EXPECT_GL_NO_ERROR();
1757 glReadBuffer(GL_COLOR_ATTACHMENT0);
1758 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
1759 EXPECT_GL_NO_ERROR();
1760 for (int i = 0; i < kResultSize; i++)
1761 {
1762 EXPECT_EQ(expectedValue_1, outputValues[i]);
1763 }
1764 glReadBuffer(GL_COLOR_ATTACHMENT1);
1765 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
1766 EXPECT_GL_NO_ERROR();
1767 for (int i = 0; i < kResultSize; i++)
1768 {
1769 EXPECT_EQ(expectedValue_2, outputValues[i]);
1770 }
1771 }
1772
1773 // Use image uniform to read and write one layer of TextureCube in compute shader, and verify the
1774 // contents.
TEST_P(ComputeShaderTest,BindImageTextureWithOneLayerTextureCube)1775 TEST_P(ComputeShaderTest, BindImageTextureWithOneLayerTextureCube)
1776 {
1777 // GL_FRAMEBUFFER_BARRIER_BIT is invalid on Nvidia Linux platform.
1778 // http://anglebug.com/3736
1779 ANGLE_SKIP_TEST_IF(IsNVIDIA() && IsOpenGL() && IsLinux());
1780
1781 GLTexture texture[2];
1782 GLFramebuffer framebuffer;
1783 constexpr char kCS[] = R"(#version 310 es
1784 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
1785 layout(r32ui, binding = 0) readonly uniform highp uimage2D uImage_1;
1786 layout(r32ui, binding = 1) writeonly uniform highp uimage2D uImage_2;
1787 void main()
1788 {
1789 uvec4 value = imageLoad(uImage_1, ivec2(gl_LocalInvocationID.xy));
1790 imageStore(uImage_2, ivec2(gl_LocalInvocationID.xy), value);
1791 })";
1792
1793 constexpr int kWidth = 1, kHeight = 1;
1794 constexpr int kResultSize = kWidth * kHeight;
1795 constexpr GLuint kInputValues[2][1] = {{200}, {100}};
1796 constexpr GLuint expectedValue_1 = 200;
1797 constexpr GLuint expectedValue_2 = 100;
1798 GLuint outputValues[kResultSize];
1799
1800 glBindTexture(GL_TEXTURE_CUBE_MAP, texture[0]);
1801 glTexStorage2D(GL_TEXTURE_CUBE_MAP, 1, GL_R32UI, kWidth, kHeight);
1802 for (GLenum face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
1803 face++)
1804 {
1805 glTexSubImage2D(face, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
1806 kInputValues[0]);
1807 }
1808 EXPECT_GL_NO_ERROR();
1809
1810 glBindTexture(GL_TEXTURE_CUBE_MAP, texture[1]);
1811 glTexStorage2D(GL_TEXTURE_CUBE_MAP, 1, GL_R32UI, kWidth, kHeight);
1812 for (GLenum face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
1813 face++)
1814 {
1815 glTexSubImage2D(face, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
1816 kInputValues[1]);
1817 }
1818 EXPECT_GL_NO_ERROR();
1819
1820 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
1821 glUseProgram(program.get());
1822
1823 glBindImageTexture(0, texture[0], 0, GL_FALSE, 3, GL_READ_ONLY, GL_R32UI);
1824 EXPECT_GL_NO_ERROR();
1825 glBindImageTexture(1, texture[1], 0, GL_FALSE, 4, GL_WRITE_ONLY, GL_R32UI);
1826 EXPECT_GL_NO_ERROR();
1827 glDispatchCompute(1, 1, 1);
1828 EXPECT_GL_NO_ERROR();
1829
1830 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
1831 glUseProgram(0);
1832 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
1833
1834 for (GLenum face = 0; face < 6; face++)
1835 {
1836 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
1837 GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, texture[1], 0);
1838 EXPECT_GL_NO_ERROR();
1839 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
1840 EXPECT_GL_NO_ERROR();
1841
1842 if (face == 4)
1843 {
1844 for (int i = 0; i < kResultSize; i++)
1845 {
1846 EXPECT_EQ(expectedValue_1, outputValues[i]);
1847 }
1848 }
1849 else
1850 {
1851 for (int i = 0; i < kResultSize; i++)
1852 {
1853 EXPECT_EQ(expectedValue_2, outputValues[i]);
1854 }
1855 }
1856 }
1857 }
1858
1859 // Test to bind kinds of texture types, bind either the entire texture
1860 // level or a single layer or face of the face level.
TEST_P(ComputeShaderTest,BindImageTextureWithMixTextureTypes)1861 TEST_P(ComputeShaderTest, BindImageTextureWithMixTextureTypes)
1862 {
1863 // GL_FRAMEBUFFER_BARRIER_BIT is invalid on Nvidia Linux platform.
1864 // http://anglebug.com/3736
1865 ANGLE_SKIP_TEST_IF(IsNVIDIA() && IsOpenGL() && IsLinux());
1866
1867 // http://anglebug.com/5072
1868 ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux() && IsOpenGL());
1869
1870 GLTexture texture[4];
1871 GLFramebuffer framebuffer;
1872 const char csSource[] =
1873 R"(#version 310 es
1874 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
1875 layout(r32ui, binding = 0) readonly uniform highp uimage2D uImage_1;
1876 layout(r32ui, binding = 1) readonly uniform highp uimage2D uImage_2;
1877 layout(r32ui, binding = 2) readonly uniform highp uimage3D uImage_3;
1878 layout(r32ui, binding = 3) writeonly uniform highp uimage2D uImage_4;
1879 void main()
1880 {
1881 uvec4 value_1 = imageLoad(uImage_1, ivec2(gl_LocalInvocationID.xy));
1882 uvec4 value_2 = imageLoad(uImage_2, ivec2(gl_LocalInvocationID.xy));
1883 uvec4 value_3 = imageLoad(uImage_3, ivec3(gl_LocalInvocationID.xyz));
1884 imageStore(uImage_4, ivec2(gl_LocalInvocationID.xy), value_1 + value_2 + value_3);
1885 })";
1886
1887 constexpr int kWidth = 1, kHeight = 1, kDepth = 2;
1888 constexpr int kResultSize = kWidth * kHeight;
1889 constexpr GLuint kInputValues2D[1] = {11};
1890 constexpr GLuint KInputValues2DArray[2] = {23, 35};
1891 constexpr GLuint KInputValues3D[2] = {102, 67};
1892 constexpr GLuint KInputValuesCube[1] = {232};
1893
1894 constexpr GLuint expectedValue_1 = 148;
1895 constexpr GLuint expectedValue_2 = 232;
1896 GLuint outputValues[kResultSize];
1897
1898 glBindTexture(GL_TEXTURE_2D, texture[0]);
1899 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kWidth, kHeight);
1900 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
1901 kInputValues2D);
1902 EXPECT_GL_NO_ERROR();
1903
1904 glBindTexture(GL_TEXTURE_2D_ARRAY, texture[1]);
1905 glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_R32UI, kWidth, kHeight, kDepth);
1906 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, kWidth, kHeight, kDepth, GL_RED_INTEGER,
1907 GL_UNSIGNED_INT, KInputValues2DArray);
1908 EXPECT_GL_NO_ERROR();
1909
1910 glBindTexture(GL_TEXTURE_3D, texture[2]);
1911 glTexStorage3D(GL_TEXTURE_3D, 1, GL_R32UI, kWidth, kHeight, kDepth);
1912 glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, kWidth, kHeight, kDepth, GL_RED_INTEGER,
1913 GL_UNSIGNED_INT, KInputValues3D);
1914 EXPECT_GL_NO_ERROR();
1915
1916 glBindTexture(GL_TEXTURE_CUBE_MAP, texture[3]);
1917 glTexStorage2D(GL_TEXTURE_CUBE_MAP, 1, GL_R32UI, kWidth, kHeight);
1918 for (GLenum face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
1919 face++)
1920 {
1921 glTexSubImage2D(face, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
1922 KInputValuesCube);
1923 }
1924 EXPECT_GL_NO_ERROR();
1925
1926 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
1927 glUseProgram(program.get());
1928
1929 glBindImageTexture(0, texture[0], 0, GL_TRUE, 0, GL_READ_ONLY, GL_R32UI);
1930 EXPECT_GL_NO_ERROR();
1931 glBindImageTexture(1, texture[1], 0, GL_FALSE, 1, GL_READ_ONLY, GL_R32UI);
1932 EXPECT_GL_NO_ERROR();
1933 glBindImageTexture(2, texture[2], 0, GL_TRUE, 0, GL_READ_ONLY, GL_R32UI);
1934 EXPECT_GL_NO_ERROR();
1935 glBindImageTexture(3, texture[3], 0, GL_FALSE, 4, GL_WRITE_ONLY, GL_R32UI);
1936 EXPECT_GL_NO_ERROR();
1937 glDispatchCompute(1, 1, 1);
1938 EXPECT_GL_NO_ERROR();
1939
1940 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
1941 glUseProgram(0);
1942 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
1943
1944 for (GLenum face = 0; face < 6; face++)
1945 {
1946 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
1947 GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, texture[3], 0);
1948 EXPECT_GL_NO_ERROR();
1949 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
1950 EXPECT_GL_NO_ERROR();
1951
1952 if (face == 4)
1953 {
1954 for (int i = 0; i < kResultSize; i++)
1955 {
1956 EXPECT_EQ(expectedValue_1, outputValues[i]);
1957 }
1958 }
1959 else
1960 {
1961 for (int i = 0; i < kResultSize; i++)
1962 {
1963 EXPECT_EQ(expectedValue_2, outputValues[i]);
1964 }
1965 }
1966 }
1967 }
1968
1969 // Verify an INVALID_OPERATION error is reported when querying GL_COMPUTE_WORK_GROUP_SIZE for a
1970 // program which has not been linked successfully or which does not contain objects to form a
1971 // compute shader.
TEST_P(ComputeShaderTest,QueryComputeWorkGroupSize)1972 TEST_P(ComputeShaderTest, QueryComputeWorkGroupSize)
1973 {
1974 constexpr char kVS[] = R"(#version 310 es
1975 void main()
1976 {
1977 })";
1978
1979 constexpr char kFS[] = R"(#version 310 es
1980 void main()
1981 {
1982 })";
1983
1984 GLint workGroupSize[3];
1985
1986 ANGLE_GL_PROGRAM(graphicsProgram, kVS, kFS);
1987 glGetProgramiv(graphicsProgram, GL_COMPUTE_WORK_GROUP_SIZE, workGroupSize);
1988 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1989
1990 GLuint computeProgram = glCreateProgram();
1991 GLShader computeShader(GL_COMPUTE_SHADER);
1992 glAttachShader(computeProgram, computeShader);
1993 glLinkProgram(computeProgram);
1994 glDetachShader(computeProgram, computeShader);
1995
1996 GLint linkStatus;
1997 glGetProgramiv(computeProgram, GL_LINK_STATUS, &linkStatus);
1998 ASSERT_GL_FALSE(linkStatus);
1999
2000 glGetProgramiv(computeProgram, GL_COMPUTE_WORK_GROUP_SIZE, workGroupSize);
2001 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2002
2003 glDeleteProgram(computeProgram);
2004
2005 ASSERT_GL_NO_ERROR();
2006 }
2007
2008 // Use groupMemoryBarrier and barrier to sync reads/writes order and the execution
2009 // order of multiple shader invocations in compute shader.
TEST_P(ComputeShaderTest,GroupMemoryBarrierAndBarrierTest)2010 TEST_P(ComputeShaderTest, GroupMemoryBarrierAndBarrierTest)
2011 {
2012 // TODO(xinghua.cao@intel.com): Figure out why we get this error message
2013 // that shader uses features not recognized by this D3D version.
2014 ANGLE_SKIP_TEST_IF((IsAMD() || IsNVIDIA()) && IsD3D11());
2015 ANGLE_SKIP_TEST_IF(IsARM64() && IsWindows() && IsD3D());
2016
2017 // http://anglebug.com/5072
2018 ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux() && IsOpenGL());
2019
2020 GLTexture texture;
2021 GLFramebuffer framebuffer;
2022
2023 // Each invocation first stores a single value in an image, then each invocation sums up
2024 // all the values in the image and stores the sum in the image. groupMemoryBarrier is
2025 // used to order reads/writes to variables stored in memory accessible to other shader
2026 // invocations, and barrier is used to control the relative execution order of multiple
2027 // shader invocations used to process a local work group.
2028 constexpr char kCS[] = R"(#version 310 es
2029 layout(local_size_x=2, local_size_y=2, local_size_z=1) in;
2030 layout(r32i, binding = 0) uniform highp iimage2D image;
2031 void main()
2032 {
2033 uint x = gl_LocalInvocationID.x;
2034 uint y = gl_LocalInvocationID.y;
2035 imageStore(image, ivec2(gl_LocalInvocationID.xy), ivec4(x + y));
2036 groupMemoryBarrier();
2037 barrier();
2038 int sum = 0;
2039 for (int i = 0; i < 2; i++)
2040 {
2041 for(int j = 0; j < 2; j++)
2042 {
2043 sum += imageLoad(image, ivec2(i, j)).x;
2044 }
2045 }
2046 groupMemoryBarrier();
2047 barrier();
2048 imageStore(image, ivec2(gl_LocalInvocationID.xy), ivec4(sum));
2049 })";
2050
2051 constexpr int kWidth = 2, kHeight = 2;
2052 glBindTexture(GL_TEXTURE_2D, texture);
2053 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32I, kWidth, kHeight);
2054 EXPECT_GL_NO_ERROR();
2055
2056 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
2057 glUseProgram(program.get());
2058
2059 glBindImageTexture(0, texture, 0, GL_FALSE, 0, GL_READ_WRITE, GL_R32I);
2060 EXPECT_GL_NO_ERROR();
2061
2062 glDispatchCompute(1, 1, 1);
2063 EXPECT_GL_NO_ERROR();
2064
2065 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
2066 GLuint outputValues[kWidth * kHeight];
2067 constexpr GLuint kExpectedValue = 4;
2068 glUseProgram(0);
2069 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
2070
2071 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
2072 EXPECT_GL_NO_ERROR();
2073 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_INT, outputValues);
2074 EXPECT_GL_NO_ERROR();
2075
2076 for (int i = 0; i < kWidth * kHeight; i++)
2077 {
2078 EXPECT_EQ(kExpectedValue, outputValues[i]);
2079 }
2080 }
2081
2082 // Verify that a link error is generated when the sum of the number of active image uniforms and
2083 // active shader storage blocks in a compute shader exceeds GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES.
TEST_P(ComputeShaderTest,ExceedCombinedShaderOutputResourcesInCS)2084 TEST_P(ComputeShaderTest, ExceedCombinedShaderOutputResourcesInCS)
2085 {
2086 GLint maxCombinedShaderOutputResources;
2087 GLint maxComputeShaderStorageBlocks;
2088 GLint maxComputeImageUniforms;
2089
2090 glGetIntegerv(GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES, &maxCombinedShaderOutputResources);
2091 glGetIntegerv(GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS, &maxComputeShaderStorageBlocks);
2092 glGetIntegerv(GL_MAX_COMPUTE_IMAGE_UNIFORMS, &maxComputeImageUniforms);
2093
2094 ANGLE_SKIP_TEST_IF(maxCombinedShaderOutputResources >=
2095 maxComputeShaderStorageBlocks + maxComputeImageUniforms);
2096
2097 std::ostringstream computeShaderStream;
2098 computeShaderStream << "#version 310 es\n"
2099 "layout(local_size_x = 3, local_size_y = 1, local_size_z = 1) in;\n"
2100 "layout(shared, binding = 0) buffer blockName"
2101 "{\n"
2102 " uint data;\n"
2103 "} instance["
2104 << maxComputeShaderStorageBlocks << "];\n";
2105
2106 ASSERT_GE(maxComputeImageUniforms, 4);
2107 int numImagesInArray = maxComputeImageUniforms / 2;
2108 int numImagesNonArray = maxComputeImageUniforms - numImagesInArray;
2109 for (int i = 0; i < numImagesNonArray; ++i)
2110 {
2111 computeShaderStream << "layout(r32f, binding = " << i << ") uniform highp image2D image"
2112 << i << ";\n";
2113 }
2114
2115 computeShaderStream << "layout(r32f, binding = " << numImagesNonArray
2116 << ") uniform highp image2D imageArray[" << numImagesInArray << "];\n";
2117
2118 computeShaderStream << "void main()\n"
2119 "{\n"
2120 " uint val = 0u;\n"
2121 " vec4 val2 = vec4(0.0);\n";
2122
2123 for (int i = 0; i < maxComputeShaderStorageBlocks; ++i)
2124 {
2125 computeShaderStream << " val += instance[" << i << "].data; \n";
2126 }
2127
2128 for (int i = 0; i < numImagesNonArray; ++i)
2129 {
2130 computeShaderStream << " val2 += imageLoad(image" << i
2131 << ", ivec2(gl_LocalInvocationID.xy)); \n";
2132 }
2133
2134 for (int i = 0; i < numImagesInArray; ++i)
2135 {
2136 computeShaderStream << " val2 += imageLoad(imageArray[" << i << "]"
2137 << ", ivec2(gl_LocalInvocationID.xy)); \n";
2138 }
2139
2140 computeShaderStream << " instance[0].data = val + uint(val2.x);\n"
2141 "}\n";
2142
2143 GLuint computeProgram = CompileComputeProgram(computeShaderStream.str().c_str());
2144 EXPECT_EQ(0u, computeProgram);
2145 }
2146
2147 // Test that uniform block with struct member in compute shader is supported.
TEST_P(ComputeShaderTest,UniformBlockWithStructMember)2148 TEST_P(ComputeShaderTest, UniformBlockWithStructMember)
2149 {
2150 constexpr char kCS[] = R"(#version 310 es
2151 layout(local_size_x=8) in;
2152 layout(rgba8) uniform highp readonly image2D mImage2DInput;
2153 layout(rgba8) uniform highp writeonly image2D mImage2DOutput;
2154 struct S {
2155 ivec3 a;
2156 ivec2 b;
2157 };
2158
2159 layout(std140, binding=0) uniform blockName {
2160 S bd;
2161 } instanceName;
2162 void main()
2163 {
2164 ivec2 t1 = instanceName.bd.b;
2165 vec4 result2d = imageLoad(mImage2DInput, t1);
2166 imageStore(mImage2DOutput, ivec2(gl_LocalInvocationID.xy), result2d);
2167 })";
2168
2169 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
2170 EXPECT_GL_NO_ERROR();
2171 }
2172
2173 // Verify shared non-array variables can work correctly.
TEST_P(ComputeShaderTest,NonArraySharedVariable)2174 TEST_P(ComputeShaderTest, NonArraySharedVariable)
2175 {
2176 // http://anglebug.com/5072
2177 ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux() && IsOpenGL());
2178
2179 const char kCSShader[] = R"(#version 310 es
2180 layout (local_size_x = 2, local_size_y = 2, local_size_z = 1) in;
2181 layout (r32ui, binding = 0) readonly uniform highp uimage2D srcImage;
2182 layout (r32ui, binding = 1) writeonly uniform highp uimage2D dstImage;
2183 shared uint temp;
2184 void main()
2185 {
2186 if (gl_LocalInvocationID == uvec3(0, 0, 0))
2187 {
2188 temp = imageLoad(srcImage, ivec2(gl_LocalInvocationID.xy)).x;
2189 }
2190 groupMemoryBarrier();
2191 barrier();
2192 if (gl_LocalInvocationID == uvec3(1, 1, 0))
2193 {
2194 imageStore(dstImage, ivec2(gl_LocalInvocationID.xy), uvec4(temp));
2195 }
2196 else
2197 {
2198 uint inputValue = imageLoad(srcImage, ivec2(gl_LocalInvocationID.xy)).x;
2199 imageStore(dstImage, ivec2(gl_LocalInvocationID.xy), uvec4(inputValue));
2200 }
2201 })";
2202
2203 const std::array<GLuint, 4> inputData = {{250, 200, 150, 100}};
2204 const std::array<GLuint, 4> expectedValues = {{250, 200, 150, 250}};
2205 runSharedMemoryTest<GLuint, 2, 2>(kCSShader, GL_R32UI, GL_UNSIGNED_INT, inputData,
2206 expectedValues);
2207 }
2208
2209 // Verify shared non-struct array variables can work correctly.
TEST_P(ComputeShaderTest,NonStructArrayAsSharedVariable)2210 TEST_P(ComputeShaderTest, NonStructArrayAsSharedVariable)
2211 {
2212 // http://anglebug.com/5072
2213 ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux() && IsOpenGL());
2214
2215 const char kCSShader[] = R"(#version 310 es
2216 layout (local_size_x = 2, local_size_y = 2, local_size_z = 1) in;
2217 layout (r32ui, binding = 0) readonly uniform highp uimage2D srcImage;
2218 layout (r32ui, binding = 1) writeonly uniform highp uimage2D dstImage;
2219 shared uint sharedData[2][2];
2220 void main()
2221 {
2222 uint inputData = imageLoad(srcImage, ivec2(gl_LocalInvocationID.xy)).x;
2223 sharedData[gl_LocalInvocationID.x][gl_LocalInvocationID.y] = inputData;
2224 groupMemoryBarrier();
2225 barrier();
2226 imageStore(dstImage, ivec2(gl_LocalInvocationID.xy),
2227 uvec4(sharedData[gl_LocalInvocationID.y][gl_LocalInvocationID.x]));
2228 })";
2229
2230 const std::array<GLuint, 4> inputData = {{250, 200, 150, 100}};
2231 const std::array<GLuint, 4> expectedValues = {{250, 150, 200, 100}};
2232 runSharedMemoryTest<GLuint, 2, 2>(kCSShader, GL_R32UI, GL_UNSIGNED_INT, inputData,
2233 expectedValues);
2234 }
2235
2236 // Verify shared struct array variables work correctly.
TEST_P(ComputeShaderTest,StructArrayAsSharedVariable)2237 TEST_P(ComputeShaderTest, StructArrayAsSharedVariable)
2238 {
2239 // http://anglebug.com/5072
2240 ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux() && IsOpenGL());
2241
2242 const char kCSShader[] = R"(#version 310 es
2243 layout (local_size_x = 2, local_size_y = 2, local_size_z = 1) in;
2244 layout (r32ui, binding = 0) readonly uniform highp uimage2D srcImage;
2245 layout (r32ui, binding = 1) writeonly uniform highp uimage2D dstImage;
2246 struct SharedStruct
2247 {
2248 uint data;
2249 };
2250 shared SharedStruct sharedData[2][2];
2251 void main()
2252 {
2253 uint inputData = imageLoad(srcImage, ivec2(gl_LocalInvocationID.xy)).x;
2254 sharedData[gl_LocalInvocationID.x][gl_LocalInvocationID.y].data = inputData;
2255 groupMemoryBarrier();
2256 barrier();
2257 imageStore(dstImage, ivec2(gl_LocalInvocationID.xy),
2258 uvec4(sharedData[gl_LocalInvocationID.y][gl_LocalInvocationID.x].data));
2259 })";
2260
2261 const std::array<GLuint, 4> inputData = {{250, 200, 150, 100}};
2262 const std::array<GLuint, 4> expectedValues = {{250, 150, 200, 100}};
2263 runSharedMemoryTest<GLuint, 2, 2>(kCSShader, GL_R32UI, GL_UNSIGNED_INT, inputData,
2264 expectedValues);
2265 }
2266
2267 // Verify using atomic functions without return value can work correctly.
TEST_P(ComputeShaderTest,AtomicFunctionsNoReturnValue)2268 TEST_P(ComputeShaderTest, AtomicFunctionsNoReturnValue)
2269 {
2270 // http://anglebug.com/5072
2271 ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux() && IsOpenGL());
2272
2273 // Fails on AMD windows drivers. http://anglebug.com/3872
2274 ANGLE_SKIP_TEST_IF(IsWindows() && IsAMD() && IsVulkan());
2275
2276 // Fails to link on Android. http://anglebug.com/3874
2277 ANGLE_SKIP_TEST_IF(IsAndroid());
2278
2279 ANGLE_SKIP_TEST_IF(IsARM64() && IsWindows() && IsD3D());
2280
2281 const char kCSShader[] = R"(#version 310 es
2282 layout (local_size_x = 8, local_size_y = 1, local_size_z = 1) in;
2283 layout (r32ui, binding = 0) readonly uniform highp uimage2D srcImage;
2284 layout (r32ui, binding = 1) writeonly uniform highp uimage2D dstImage;
2285
2286 const uint kSumIndex = 0u;
2287 const uint kMinIndex = 1u;
2288 const uint kMaxIndex = 2u;
2289 const uint kOrIndex = 3u;
2290 const uint kAndIndex = 4u;
2291 const uint kXorIndex = 5u;
2292 const uint kExchangeIndex = 6u;
2293 const uint kCompSwapIndex = 7u;
2294
2295 shared highp uint results[8];
2296
2297 void main()
2298 {
2299 if (gl_LocalInvocationID.x == kMinIndex || gl_LocalInvocationID.x == kAndIndex)
2300 {
2301 results[gl_LocalInvocationID.x] = 0xFFFFu;
2302 }
2303 else if (gl_LocalInvocationID.x == kCompSwapIndex)
2304 {
2305 results[gl_LocalInvocationID.x] = 1u;
2306 }
2307 else
2308 {
2309 results[gl_LocalInvocationID.x] = 0u;
2310 }
2311 memoryBarrierShared();
2312 barrier();
2313
2314 uint value = imageLoad(srcImage, ivec2(gl_LocalInvocationID.xy)).x;
2315 atomicAdd(results[kSumIndex], value);
2316 atomicMin(results[kMinIndex], value);
2317 atomicMax(results[kMaxIndex], value);
2318 atomicOr(results[kOrIndex], value);
2319 atomicAnd(results[kAndIndex], value);
2320 atomicXor(results[kXorIndex], value);
2321 atomicExchange(results[kExchangeIndex], value);
2322 atomicCompSwap(results[kCompSwapIndex], value, 256u);
2323 memoryBarrierShared();
2324 barrier();
2325
2326 imageStore(dstImage, ivec2(gl_LocalInvocationID.xy),
2327 uvec4(results[gl_LocalInvocationID.x]));
2328 })";
2329
2330 const std::array<GLuint, 8> inputData = {{1, 2, 4, 8, 16, 32, 64, 128}};
2331 const std::array<GLuint, 8> expectedValues = {{255, 1, 128, 255, 0, 255, 128, 256}};
2332 runSharedMemoryTest<GLuint, 8, 1>(kCSShader, GL_R32UI, GL_UNSIGNED_INT, inputData,
2333 expectedValues);
2334 }
2335
2336 // Verify using atomic functions in a non-initializer single assignment can work correctly.
TEST_P(ComputeShaderTest,AtomicFunctionsInNonInitializerSingleAssignment)2337 TEST_P(ComputeShaderTest, AtomicFunctionsInNonInitializerSingleAssignment)
2338 {
2339 // http://anglebug.com/5072
2340 ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux() && IsOpenGL());
2341
2342 // Fails on AMD windows drivers. http://anglebug.com/3872
2343 ANGLE_SKIP_TEST_IF(IsWindows() && IsAMD() && IsVulkan());
2344
2345 const char kCSShader[] = R"(#version 310 es
2346 layout (local_size_x = 9, local_size_y = 1, local_size_z = 1) in;
2347 layout (r32i, binding = 0) readonly uniform highp iimage2D srcImage;
2348 layout (r32i, binding = 1) writeonly uniform highp iimage2D dstImage;
2349
2350 shared highp int sharedVariable;
2351
2352 shared highp int inputData[9];
2353 shared highp int outputData[9];
2354
2355 void main()
2356 {
2357 int inputValue = imageLoad(srcImage, ivec2(gl_LocalInvocationID.xy)).x;
2358 inputData[gl_LocalInvocationID.x] = inputValue;
2359 memoryBarrierShared();
2360 barrier();
2361
2362 if (gl_LocalInvocationID.x == 0u)
2363 {
2364 sharedVariable = 0;
2365
2366 outputData[0] = atomicAdd(sharedVariable, inputData[0]);
2367 outputData[1] = atomicMin(sharedVariable, inputData[1]);
2368 outputData[2] = atomicMax(sharedVariable, inputData[2]);
2369 outputData[3] = atomicAnd(sharedVariable, inputData[3]);
2370 outputData[4] = atomicOr(sharedVariable, inputData[4]);
2371 outputData[5] = atomicXor(sharedVariable, inputData[5]);
2372 outputData[6] = atomicExchange(sharedVariable, inputData[6]);
2373 outputData[7] = atomicCompSwap(sharedVariable, 64, inputData[7]);
2374 outputData[8] = atomicAdd(sharedVariable, inputData[8]);
2375 }
2376 memoryBarrierShared();
2377 barrier();
2378
2379 imageStore(dstImage, ivec2(gl_LocalInvocationID.xy),
2380 ivec4(outputData[gl_LocalInvocationID.x]));
2381 })";
2382
2383 const std::array<GLint, 9> inputData = {{1, 2, 4, 8, 16, 32, 64, 128, 1}};
2384 const std::array<GLint, 9> expectedValues = {{0, 1, 1, 4, 0, 16, 48, 64, 128}};
2385 runSharedMemoryTest<GLint, 9, 1>(kCSShader, GL_R32I, GL_INT, inputData, expectedValues);
2386 }
2387
2388 // Verify using atomic functions in an initializers and using unsigned int works correctly.
TEST_P(ComputeShaderTest,AtomicFunctionsInitializerWithUnsigned)2389 TEST_P(ComputeShaderTest, AtomicFunctionsInitializerWithUnsigned)
2390 {
2391 // http://anglebug.com/5072
2392 ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux() && IsOpenGL());
2393
2394 // Fails on AMD windows drivers. http://anglebug.com/3872
2395 ANGLE_SKIP_TEST_IF(IsWindows() && IsAMD() && IsVulkan());
2396
2397 constexpr char kCShader[] = R"(#version 310 es
2398 layout (local_size_x = 9, local_size_y = 1, local_size_z = 1) in;
2399 layout (r32ui, binding = 0) readonly uniform highp uimage2D srcImage;
2400 layout (r32ui, binding = 1) writeonly uniform highp uimage2D dstImage;
2401
2402 shared highp uint sharedVariable;
2403
2404 shared highp uint inputData[9];
2405 shared highp uint outputData[9];
2406
2407 void main()
2408 {
2409 uint inputValue = imageLoad(srcImage, ivec2(gl_LocalInvocationID.xy)).x;
2410 inputData[gl_LocalInvocationID.x] = inputValue;
2411 memoryBarrierShared();
2412 barrier();
2413
2414 if (gl_LocalInvocationID.x == 0u)
2415 {
2416 sharedVariable = 0u;
2417
2418 uint addValue = atomicAdd(sharedVariable, inputData[0]);
2419 outputData[0] = addValue;
2420 uint minValue = atomicMin(sharedVariable, inputData[1]);
2421 outputData[1] = minValue;
2422 uint maxValue = atomicMax(sharedVariable, inputData[2]);
2423 outputData[2] = maxValue;
2424 uint andValue = atomicAnd(sharedVariable, inputData[3]);
2425 outputData[3] = andValue;
2426 uint orValue = atomicOr(sharedVariable, inputData[4]);
2427 outputData[4] = orValue;
2428 uint xorValue = atomicXor(sharedVariable, inputData[5]);
2429 outputData[5] = xorValue;
2430 uint exchangeValue = atomicExchange(sharedVariable, inputData[6]);
2431 outputData[6] = exchangeValue;
2432 uint compSwapValue = atomicCompSwap(sharedVariable, 64u, inputData[7]);
2433 outputData[7] = compSwapValue;
2434 uint sharedVariable = atomicAdd(sharedVariable, inputData[8]);
2435 outputData[8] = sharedVariable;
2436
2437 }
2438 memoryBarrierShared();
2439 barrier();
2440
2441 imageStore(dstImage, ivec2(gl_LocalInvocationID.xy),
2442 uvec4(outputData[gl_LocalInvocationID.x]));
2443 })";
2444
2445 constexpr std::array<GLuint, 9> kInputData = {{1, 2, 4, 8, 16, 32, 64, 128, 1}};
2446 constexpr std::array<GLuint, 9> kExpectedValues = {{0, 1, 1, 4, 0, 16, 48, 64, 128}};
2447 runSharedMemoryTest<GLuint, 9, 1>(kCShader, GL_R32UI, GL_UNSIGNED_INT, kInputData,
2448 kExpectedValues);
2449 }
2450
2451 // Verify using atomic functions inside expressions as unsigned int.
TEST_P(ComputeShaderTest,AtomicFunctionsReturnWithUnsigned)2452 TEST_P(ComputeShaderTest, AtomicFunctionsReturnWithUnsigned)
2453 {
2454 // http://anglebug.com/5072
2455 ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux() && IsOpenGL());
2456
2457 // Fails on AMD windows drivers. http://anglebug.com/3872
2458 ANGLE_SKIP_TEST_IF(IsWindows() && IsAMD() && IsVulkan());
2459
2460 constexpr char kCShader[] = R"(#version 310 es
2461 layout (local_size_x = 9, local_size_y = 1, local_size_z = 1) in;
2462 layout (r32ui, binding = 0) readonly uniform highp uimage2D srcImage;
2463 layout (r32ui, binding = 1) writeonly uniform highp uimage2D dstImage;
2464
2465 shared highp uint sharedVariable;
2466
2467 shared highp uint inputData[9];
2468 shared highp uint outputData[9];
2469
2470 void main()
2471 {
2472 uint inputValue = imageLoad(srcImage, ivec2(gl_LocalInvocationID.xy)).x;
2473 inputData[gl_LocalInvocationID.x] = inputValue;
2474 memoryBarrierShared();
2475 barrier();
2476
2477 if (gl_LocalInvocationID.x == 0u)
2478 {
2479 sharedVariable = 0u;
2480
2481 outputData[0] = 1u + atomicAdd(sharedVariable, inputData[0]);
2482 outputData[1] = 1u + atomicMin(sharedVariable, inputData[1]);
2483 outputData[2] = 1u + atomicMax(sharedVariable, inputData[2]);
2484 outputData[3] = 1u + atomicAnd(sharedVariable, inputData[3]);
2485 outputData[4] = 1u + atomicOr(sharedVariable, inputData[4]);
2486 outputData[5] = 1u + atomicXor(sharedVariable, inputData[5]);
2487 outputData[6] = 1u + atomicExchange(sharedVariable, inputData[6]);
2488 outputData[7] = 1u + atomicCompSwap(sharedVariable, 64u, inputData[7]);
2489 outputData[8] = 1u + atomicAdd(sharedVariable, inputData[8]);
2490 }
2491 memoryBarrierShared();
2492 barrier();
2493
2494 imageStore(dstImage, ivec2(gl_LocalInvocationID.xy),
2495 uvec4(outputData[gl_LocalInvocationID.x]));
2496 })";
2497
2498 constexpr std::array<GLuint, 9> kInputData = {{1, 2, 4, 8, 16, 32, 64, 128, 1}};
2499 constexpr std::array<GLuint, 9> kExpectedValues = {{1, 2, 2, 5, 1, 17, 49, 65, 129}};
2500 runSharedMemoryTest<GLuint, 9, 1>(kCShader, GL_R32UI, GL_UNSIGNED_INT, kInputData,
2501 kExpectedValues);
2502 }
2503
2504 // Verify using nested atomic functions in expressions.
TEST_P(ComputeShaderTest,AtomicFunctionsReturnWithMultipleTypes)2505 TEST_P(ComputeShaderTest, AtomicFunctionsReturnWithMultipleTypes)
2506 {
2507 // http://anglebug.com/5072
2508 ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux() && IsOpenGL());
2509
2510 constexpr char kCShader[] = R"(#version 310 es
2511 layout (local_size_x = 4, local_size_y = 1, local_size_z = 1) in;
2512 layout (r32ui, binding = 0) readonly uniform highp uimage2D srcImage;
2513 layout (r32ui, binding = 1) writeonly uniform highp uimage2D dstImage;
2514
2515 shared highp uint sharedVariable;
2516 shared highp int indexVariable;
2517
2518 shared highp uint inputData[4];
2519 shared highp uint outputData[4];
2520
2521 void main()
2522 {
2523 uint inputValue = imageLoad(srcImage, ivec2(gl_LocalInvocationID.xy)).x;
2524 inputData[gl_LocalInvocationID.x] = inputValue;
2525 memoryBarrierShared();
2526 barrier();
2527
2528 if (gl_LocalInvocationID.x == 0u)
2529 {
2530 sharedVariable = 0u;
2531 indexVariable = 2;
2532
2533 outputData[0] = 1u + atomicAdd(sharedVariable, inputData[atomicAdd(indexVariable, -1)]);
2534 outputData[1] = 1u + atomicAdd(sharedVariable, inputData[atomicAdd(indexVariable, -1)]);
2535 outputData[2] = 1u + atomicAdd(sharedVariable, inputData[atomicAdd(indexVariable, -1)]);
2536 outputData[3] = atomicAdd(sharedVariable, 0u);
2537
2538 }
2539 memoryBarrierShared();
2540 barrier();
2541
2542 imageStore(dstImage, ivec2(gl_LocalInvocationID.xy),
2543 uvec4(outputData[gl_LocalInvocationID.x]));
2544 })";
2545
2546 constexpr std::array<GLuint, 4> kInputData = {{1, 2, 3, 0}};
2547 constexpr std::array<GLuint, 4> kExpectedValues = {{1, 4, 6, 6}};
2548 runSharedMemoryTest<GLuint, 4, 1>(kCShader, GL_R32UI, GL_UNSIGNED_INT, kInputData,
2549 kExpectedValues);
2550 }
2551
2552 // Basic uniform buffer functionality.
TEST_P(ComputeShaderTest,UniformBuffer)2553 TEST_P(ComputeShaderTest, UniformBuffer)
2554 {
2555 // http://anglebug.com/5072
2556 ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux() && IsOpenGL());
2557
2558 GLTexture texture;
2559 GLBuffer buffer;
2560 GLFramebuffer framebuffer;
2561 constexpr char kCS[] = R"(#version 310 es
2562 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
2563 uniform uni
2564 {
2565 uvec4 value;
2566 };
2567 layout(rgba32ui, binding = 0) writeonly uniform highp uimage2D uImage;
2568 void main()
2569 {
2570 imageStore(uImage, ivec2(gl_LocalInvocationID.xy), value);
2571 })";
2572
2573 constexpr int kWidth = 1, kHeight = 1;
2574 constexpr GLuint kInputValues[4] = {56, 57, 58, 59};
2575
2576 glBindTexture(GL_TEXTURE_2D, texture);
2577 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32UI, kWidth, kHeight);
2578 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RGBA_INTEGER, GL_UNSIGNED_INT,
2579 kInputValues);
2580 EXPECT_GL_NO_ERROR();
2581
2582 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
2583 glUseProgram(program.get());
2584
2585 GLint uniformBufferIndex = glGetUniformBlockIndex(program, "uni");
2586 EXPECT_NE(uniformBufferIndex, -1);
2587 GLuint data[4] = {201, 202, 203, 204};
2588 glBindBuffer(GL_UNIFORM_BUFFER, buffer);
2589 glBufferData(GL_UNIFORM_BUFFER, sizeof(GLuint) * 4, data, GL_STATIC_DRAW);
2590 glBindBufferBase(GL_UNIFORM_BUFFER, 0, buffer);
2591 glUniformBlockBinding(program, uniformBufferIndex, 0);
2592 EXPECT_GL_NO_ERROR();
2593
2594 glBindImageTexture(0, texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32UI);
2595 EXPECT_GL_NO_ERROR();
2596
2597 glDispatchCompute(1, 1, 1);
2598 EXPECT_GL_NO_ERROR();
2599
2600 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
2601 GLuint outputValues[kWidth * kHeight * 4];
2602 glUseProgram(0);
2603 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
2604
2605 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
2606 EXPECT_GL_NO_ERROR();
2607 glReadPixels(0, 0, kWidth, kHeight, GL_RGBA_INTEGER, GL_UNSIGNED_INT, outputValues);
2608 EXPECT_GL_NO_ERROR();
2609
2610 for (int i = 0; i < kWidth * kHeight * 4; i++)
2611 {
2612 EXPECT_EQ(data[i], outputValues[i]);
2613 }
2614 }
2615
2616 // Test that storing data to image and then loading the same image data works correctly.
TEST_P(ComputeShaderTest,StoreImageThenLoad)2617 TEST_P(ComputeShaderTest, StoreImageThenLoad)
2618 {
2619 // http://anglebug.com/5072
2620 ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux() && IsOpenGL());
2621
2622 const char kCSSource[] = R"(#version 310 es
2623 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
2624 layout(r32ui, binding = 0) readonly uniform highp uimage2D uImage_1;
2625 layout(r32ui, binding = 1) writeonly uniform highp uimage2D uImage_2;
2626 void main()
2627 {
2628 uvec4 value = imageLoad(uImage_1, ivec2(gl_LocalInvocationID.xy));
2629 imageStore(uImage_2, ivec2(gl_LocalInvocationID.xy), value);
2630 })";
2631
2632 constexpr GLuint kInputValues[3][1] = {{300}, {200}, {100}};
2633 GLTexture texture[3];
2634 glBindTexture(GL_TEXTURE_2D, texture[0]);
2635 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, 1, 1);
2636 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RED_INTEGER, GL_UNSIGNED_INT, kInputValues[0]);
2637 EXPECT_GL_NO_ERROR();
2638
2639 glBindTexture(GL_TEXTURE_2D, texture[1]);
2640 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, 1, 1);
2641 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RED_INTEGER, GL_UNSIGNED_INT, kInputValues[1]);
2642 EXPECT_GL_NO_ERROR();
2643
2644 glBindTexture(GL_TEXTURE_2D, texture[2]);
2645 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, 1, 1);
2646 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RED_INTEGER, GL_UNSIGNED_INT, kInputValues[2]);
2647 EXPECT_GL_NO_ERROR();
2648
2649 ANGLE_GL_COMPUTE_PROGRAM(program, kCSSource);
2650 glUseProgram(program.get());
2651
2652 glBindImageTexture(0, texture[0], 0, GL_FALSE, 0, GL_READ_ONLY, GL_R32UI);
2653 glBindImageTexture(1, texture[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
2654
2655 glDispatchCompute(1, 1, 1);
2656 glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
2657 EXPECT_GL_NO_ERROR();
2658
2659 glBindImageTexture(0, texture[1], 0, GL_FALSE, 0, GL_READ_ONLY, GL_R32UI);
2660 glBindImageTexture(1, texture[2], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
2661
2662 glDispatchCompute(1, 1, 1);
2663 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
2664 EXPECT_GL_NO_ERROR();
2665
2666 GLuint outputValue;
2667 GLFramebuffer framebuffer;
2668 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
2669 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture[2], 0);
2670 glReadPixels(0, 0, 1, 1, GL_RED_INTEGER, GL_UNSIGNED_INT, &outputValue);
2671 EXPECT_GL_NO_ERROR();
2672
2673 EXPECT_EQ(300u, outputValue);
2674 }
2675
2676 // Test that loading image data and then storing data to the same image works correctly.
TEST_P(ComputeShaderTest,LoadImageThenStore)2677 TEST_P(ComputeShaderTest, LoadImageThenStore)
2678 {
2679 // http://anglebug.com/5072
2680 ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux() && IsOpenGL());
2681
2682 const char kCSSource[] = R"(#version 310 es
2683 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
2684 layout(r32ui, binding = 0) readonly uniform highp uimage2D uImage_1;
2685 layout(r32ui, binding = 1) writeonly uniform highp uimage2D uImage_2;
2686 void main()
2687 {
2688 uvec4 value = imageLoad(uImage_1, ivec2(gl_LocalInvocationID.xy));
2689 imageStore(uImage_2, ivec2(gl_LocalInvocationID.xy), value);
2690 })";
2691
2692 constexpr GLuint kInputValues[3][1] = {{300}, {200}, {100}};
2693 GLTexture texture[3];
2694 glBindTexture(GL_TEXTURE_2D, texture[0]);
2695 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, 1, 1);
2696 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RED_INTEGER, GL_UNSIGNED_INT, kInputValues[0]);
2697 EXPECT_GL_NO_ERROR();
2698
2699 glBindTexture(GL_TEXTURE_2D, texture[1]);
2700 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, 1, 1);
2701 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RED_INTEGER, GL_UNSIGNED_INT, kInputValues[1]);
2702 EXPECT_GL_NO_ERROR();
2703
2704 glBindTexture(GL_TEXTURE_2D, texture[2]);
2705 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, 1, 1);
2706 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RED_INTEGER, GL_UNSIGNED_INT, kInputValues[2]);
2707 EXPECT_GL_NO_ERROR();
2708
2709 ANGLE_GL_COMPUTE_PROGRAM(program, kCSSource);
2710 glUseProgram(program.get());
2711
2712 glBindImageTexture(0, texture[0], 0, GL_FALSE, 0, GL_READ_ONLY, GL_R32UI);
2713 glBindImageTexture(1, texture[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
2714
2715 glDispatchCompute(1, 1, 1);
2716 glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
2717 EXPECT_GL_NO_ERROR();
2718
2719 glBindImageTexture(0, texture[2], 0, GL_FALSE, 0, GL_READ_ONLY, GL_R32UI);
2720 glBindImageTexture(1, texture[0], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
2721
2722 glDispatchCompute(1, 1, 1);
2723 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
2724 EXPECT_GL_NO_ERROR();
2725
2726 GLuint outputValue;
2727 GLFramebuffer framebuffer;
2728 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
2729 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture[0], 0);
2730 glReadPixels(0, 0, 1, 1, GL_RED_INTEGER, GL_UNSIGNED_INT, &outputValue);
2731 EXPECT_GL_NO_ERROR();
2732
2733 EXPECT_EQ(100u, outputValue);
2734 }
2735
2736 // Test that the length of a struct buffer variable is supported.
TEST_P(ComputeShaderTest,ShaderStorageBlocksStructLength)2737 TEST_P(ComputeShaderTest, ShaderStorageBlocksStructLength)
2738 {
2739 const char kCSSource[] = R"(#version 310 es
2740 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
2741
2742 struct Particle
2743 {
2744 int len;
2745 };
2746
2747 layout(binding = 0, std430) readonly buffer Buf1
2748 {
2749 Particle particlesRead[];
2750 };
2751
2752 layout(binding = 1, std430) buffer Buf2
2753 {
2754 Particle particlesWrite[];
2755 };
2756
2757 void main()
2758 {
2759 int index = int(gl_GlobalInvocationID.x);
2760 particlesWrite[index].len = particlesRead.length();
2761 })";
2762
2763 ANGLE_GL_COMPUTE_PROGRAM(program, kCSSource);
2764 EXPECT_GL_NO_ERROR();
2765 }
2766
2767 // Test that scalar buffer variables are supported.
TEST_P(ComputeShaderTest,ShaderStorageBlocksScalar)2768 TEST_P(ComputeShaderTest, ShaderStorageBlocksScalar)
2769 {
2770 const char kCSSource[] = R"(#version 310 es
2771 layout(local_size_x=1) in;
2772 layout(std140, binding = 0) buffer blockA {
2773 uvec3 uv;
2774 float f;
2775 } instanceA;
2776 layout(std140, binding = 1) buffer blockB {
2777 vec2 v;
2778 uint u[3];
2779 float f;
2780 };
2781 void main()
2782 {
2783 f = instanceA.f;
2784 })";
2785
2786 ANGLE_GL_COMPUTE_PROGRAM(program, kCSSource);
2787 EXPECT_GL_NO_ERROR();
2788 }
2789
2790 // Test that vector buffer variables are supported.
TEST_P(ComputeShaderTest,ShaderStorageBlocksVector)2791 TEST_P(ComputeShaderTest, ShaderStorageBlocksVector)
2792 {
2793 const char kCSSource[] = R"(#version 310 es
2794 layout(local_size_x=1) in;
2795 layout(std140, binding = 0) buffer blockA {
2796 vec2 f;
2797 } instanceA;
2798 layout(std140, binding = 1) buffer blockB {
2799 vec3 f;
2800 };
2801 void main()
2802 {
2803 f[1] = instanceA.f[0];
2804 })";
2805
2806 ANGLE_GL_COMPUTE_PROGRAM(program, kCSSource);
2807 EXPECT_GL_NO_ERROR();
2808 }
2809
2810 // Test that matrix buffer variables are supported.
TEST_P(ComputeShaderTest,ShaderStorageBlocksMatrix)2811 TEST_P(ComputeShaderTest, ShaderStorageBlocksMatrix)
2812 {
2813 const char kCSSource[] = R"(#version 310 es
2814 layout(local_size_x=1) in;
2815 layout(std140, binding = 0) buffer blockA {
2816 mat3x4 m;
2817 } instanceA;
2818 layout(std140, binding = 1) buffer blockB {
2819 mat3x4 m;
2820 };
2821 void main()
2822 {
2823 m[0][1] = instanceA.m[0][1];
2824 })";
2825
2826 ANGLE_GL_COMPUTE_PROGRAM(program, kCSSource);
2827 EXPECT_GL_NO_ERROR();
2828 }
2829
2830 // Test that scalar array buffer variables are supported.
TEST_P(ComputeShaderTest,ShaderStorageBlocksScalarArray)2831 TEST_P(ComputeShaderTest, ShaderStorageBlocksScalarArray)
2832 {
2833 const char kCSSource[] = R"(#version 310 es
2834 layout(local_size_x=8) in;
2835 layout(std140, binding = 0) buffer blockA {
2836 float f[8];
2837 } instanceA;
2838 layout(std140, binding = 1) buffer blockB {
2839 float f[8];
2840 };
2841 void main()
2842 {
2843 f[gl_LocalInvocationIndex] = instanceA.f[gl_LocalInvocationIndex];
2844 })";
2845
2846 ANGLE_GL_COMPUTE_PROGRAM(program, kCSSource);
2847 EXPECT_GL_NO_ERROR();
2848 }
2849
2850 // Test that vector array buffer variables are supported.
TEST_P(ComputeShaderTest,ShaderStorageBlocksVectorArray)2851 TEST_P(ComputeShaderTest, ShaderStorageBlocksVectorArray)
2852 {
2853 const char kCSSource[] = R"(#version 310 es
2854 layout(local_size_x=4) in;
2855 layout(std140, binding = 0) buffer blockA {
2856 vec2 v[4];
2857 } instanceA;
2858 layout(std140, binding = 1) buffer blockB {
2859 vec4 v[4];
2860 };
2861 void main()
2862 {
2863 v[0][gl_LocalInvocationIndex] = instanceA.v[gl_LocalInvocationIndex][1];
2864 })";
2865
2866 ANGLE_GL_COMPUTE_PROGRAM(program, kCSSource);
2867 EXPECT_GL_NO_ERROR();
2868 }
2869
2870 // Test that matrix array buffer variables are supported.
TEST_P(ComputeShaderTest,ShaderStorageBlocksMatrixArray)2871 TEST_P(ComputeShaderTest, ShaderStorageBlocksMatrixArray)
2872 {
2873 const char kCSSource[] = R"(#version 310 es
2874 layout(local_size_x=8) in;
2875 layout(std140, binding = 0) buffer blockA {
2876 float v1[5];
2877 mat4 m[8];
2878 } instanceA;
2879 layout(std140, binding = 1) buffer blockB {
2880 vec2 v1[3];
2881 mat4 m[8];
2882 };
2883 void main()
2884 {
2885 float data = instanceA.m[gl_LocalInvocationIndex][0][0];
2886 m[gl_LocalInvocationIndex][gl_LocalInvocationIndex][gl_LocalInvocationIndex] = data;
2887 })";
2888
2889 ANGLE_GL_COMPUTE_PROGRAM(program, kCSSource);
2890 EXPECT_GL_NO_ERROR();
2891 }
2892
2893 // Test that shader storage blocks only in assignment right is supported.
TEST_P(ComputeShaderTest,ShaderStorageBlocksInAssignmentRight)2894 TEST_P(ComputeShaderTest, ShaderStorageBlocksInAssignmentRight)
2895 {
2896 const char kCSSource[] = R"(#version 310 es
2897 layout(local_size_x=8) in;
2898 layout(std140, binding = 0) buffer blockA {
2899 float data[8];
2900 } instanceA;
2901 layout(r32f, binding = 0) writeonly uniform highp image2D imageOut;
2902
2903 void main()
2904 {
2905 float data = 1.0;
2906 data = instanceA.data[gl_LocalInvocationIndex];
2907 imageStore(imageOut, ivec2(gl_LocalInvocationID.xy), vec4(data));
2908 })";
2909
2910 ANGLE_GL_COMPUTE_PROGRAM(program, kCSSource);
2911 EXPECT_GL_NO_ERROR();
2912 }
2913
2914 // Test that shader storage blocks with unsized array are supported.
TEST_P(ComputeShaderTest,ShaderStorageBlocksWithUnsizedArray)2915 TEST_P(ComputeShaderTest, ShaderStorageBlocksWithUnsizedArray)
2916 {
2917 const char kCSSource[] = R"(#version 310 es
2918 layout(local_size_x=8) in;
2919 layout(std140, binding = 0) buffer blockA {
2920 float v[];
2921 } instanceA;
2922 layout(std140, binding = 0) buffer blockB {
2923 float v[];
2924 } instanceB[1];
2925
2926 void main()
2927 {
2928 float data = instanceA.v[gl_LocalInvocationIndex];
2929 instanceB[0].v[gl_LocalInvocationIndex * 2u + 1u] = data;
2930 }
2931 )";
2932
2933 ANGLE_GL_COMPUTE_PROGRAM(program, kCSSource);
2934 EXPECT_GL_NO_ERROR();
2935 }
2936
2937 // Test that EOpIndexDirect/EOpIndexIndirect/EOpIndexDirectStruct nodes in ssbo EOpIndexInDirect
2938 // don't need to calculate the offset and should be translated by OutputHLSL directly.
TEST_P(ComputeShaderTest,IndexAndDotOperatorsInSSBOIndexIndirectOperator)2939 TEST_P(ComputeShaderTest, IndexAndDotOperatorsInSSBOIndexIndirectOperator)
2940 {
2941 constexpr char kComputeShaderSource[] = R"(#version 310 es
2942 layout(local_size_x=1) in;
2943 layout(std140, binding = 0) buffer blockA {
2944 float v[4];
2945 };
2946 layout(std140, binding = 1) buffer blockB {
2947 float v[4];
2948 } instanceB[1];
2949 struct S
2950 {
2951 uvec4 index[2];
2952 } s;
2953 void main()
2954 {
2955 s.index[0] = uvec4(0u, 1u, 2u, 3u);
2956 float data = v[s.index[0].y];
2957 instanceB[0].v[s.index[0].x] = data;
2958 })";
2959
2960 ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShaderSource);
2961 EXPECT_GL_NO_ERROR();
2962 }
2963
2964 // Test that swizzle node in non-SSBO symbol works well.
TEST_P(ComputeShaderTest,ShaderStorageBlocksWithNonSSBOSwizzle)2965 TEST_P(ComputeShaderTest, ShaderStorageBlocksWithNonSSBOSwizzle)
2966 {
2967 constexpr char kComputeShaderSource[] = R"(#version 310 es
2968 layout(local_size_x=8) in;
2969 layout(std140, binding = 0) buffer blockA {
2970 float v[8];
2971 };
2972 layout(std140, binding = 1) buffer blockB {
2973 float v[8];
2974 } instanceB[1];
2975
2976 void main()
2977 {
2978 float data = v[gl_GlobalInvocationID.x];
2979 instanceB[0].v[gl_GlobalInvocationID.x] = data;
2980 })";
2981
2982 ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShaderSource);
2983 EXPECT_GL_NO_ERROR();
2984 }
2985
2986 // Test that swizzle node in SSBO symbol works well.
TEST_P(ComputeShaderTest,ShaderStorageBlocksWithSSBOSwizzle)2987 TEST_P(ComputeShaderTest, ShaderStorageBlocksWithSSBOSwizzle)
2988 {
2989 constexpr char kComputeShaderSource[] = R"(#version 310 es
2990 layout(local_size_x=1) in;
2991 layout(std140, binding = 0) buffer blockA {
2992 vec2 v;
2993 };
2994 layout(std140, binding = 1) buffer blockB {
2995 float v;
2996 } instanceB[1];
2997
2998 void main()
2999 {
3000 instanceB[0].v = v.x;
3001 })";
3002
3003 ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShaderSource);
3004 EXPECT_GL_NO_ERROR();
3005 }
3006
3007 // Test that a large struct array in std140 uniform block won't consume too much time.
TEST_P(ComputeShaderTest,LargeStructArraySize)3008 TEST_P(ComputeShaderTest, LargeStructArraySize)
3009 {
3010 constexpr char kComputeShaderSource[] = R"(#version 310 es
3011 layout(local_size_x=8) in;
3012 precision mediump float;
3013
3014 struct InstancingData
3015 {
3016 mat4 transformation;
3017 };
3018
3019 #define MAX_INSTANCE_COUNT 800
3020
3021 layout(std140) uniform InstanceBlock
3022 {
3023 InstancingData instances[MAX_INSTANCE_COUNT];
3024 };
3025
3026 layout(std140, binding = 1) buffer blockB {
3027 mat4 v[];
3028 } instanceB;
3029
3030 void main()
3031 {
3032 instanceB.v[gl_GlobalInvocationID.x] = instances[gl_GlobalInvocationID.x].transformation;
3033 })";
3034
3035 ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShaderSource);
3036 EXPECT_GL_NO_ERROR();
3037 }
3038
3039 // Check that it is not possible to create a compute shader when the context does not support ES
3040 // 3.10
TEST_P(ComputeShaderTestES3,NotSupported)3041 TEST_P(ComputeShaderTestES3, NotSupported)
3042 {
3043 GLuint computeShaderHandle = glCreateShader(GL_COMPUTE_SHADER);
3044 EXPECT_EQ(0u, computeShaderHandle);
3045 EXPECT_GL_ERROR(GL_INVALID_ENUM);
3046 }
3047
3048 // The contents of shared variables should be cleared to zero at the beginning of shader execution.
TEST_P(WebGL2ComputeTest,sharedVariablesShouldBeZero)3049 TEST_P(WebGL2ComputeTest, sharedVariablesShouldBeZero)
3050 {
3051 // http://anglebug.com/3226
3052 ANGLE_SKIP_TEST_IF(IsD3D11());
3053
3054 // Fails on Android, AMD/windows and Intel/windows. Probably works by chance on other
3055 // platforms, so suppressing on all platforms to avoid possible flakiness.
3056 // http://anglebug.com/3869
3057 ANGLE_SKIP_TEST_IF(IsVulkan());
3058
3059 // http://anglebug.com/4092
3060 ANGLE_SKIP_TEST_IF(IsAndroid() && IsOpenGLES());
3061 ANGLE_SKIP_TEST_IF(IsOpenGL() &&
3062 ((getClientMajorVersion() == 3) && (getClientMinorVersion() >= 1)));
3063
3064 const char kCSShader[] = R"(#version 310 es
3065 layout (local_size_x = 4, local_size_y = 4, local_size_z = 1) in;
3066 layout (r32ui, binding = 0) readonly uniform highp uimage2D srcImage;
3067 layout (r32ui, binding = 1) writeonly uniform highp uimage2D dstImage;
3068 struct S {
3069 float f;
3070 int i;
3071 uint u;
3072 bool b;
3073 vec4 v[64];
3074 };
3075
3076 shared S vars[16];
3077 void main()
3078 {
3079 S zeroS;
3080 zeroS.f = 0.0f;
3081 zeroS.i = 0;
3082 zeroS.u = 0u;
3083 zeroS.b = false;
3084 for (int i = 0; i < 64; i++)
3085 {
3086 zeroS.v[i] = vec4(0.0f);
3087 }
3088
3089 uint tid = gl_LocalInvocationID.x + gl_LocalInvocationID.y * 4u;
3090 uint value = (zeroS == vars[tid] ? 127u : 0u);
3091 imageStore(dstImage, ivec2(gl_LocalInvocationID.xy), uvec4(value));
3092 })";
3093
3094 const std::array<GLuint, 16> inputData = {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
3095 const std::array<GLuint, 16> expectedValues = {
3096 {127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127}};
3097 runSharedMemoryTest<GLuint, 4, 4>(kCSShader, GL_R32UI, GL_UNSIGNED_INT, inputData,
3098 expectedValues);
3099 }
3100
3101 // Test uniform dirty in compute shader, and verify the contents.
TEST_P(ComputeShaderTest,UniformDirty)3102 TEST_P(ComputeShaderTest, UniformDirty)
3103 {
3104 // http://anglebug.com/5072
3105 ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux() && IsOpenGL());
3106
3107 // glReadPixels is getting the result of the first dispatch call. http://anglebug.com/3879
3108 ANGLE_SKIP_TEST_IF(IsVulkan() && IsWindows() && (IsAMD() || IsNVIDIA()));
3109
3110 GLTexture texture[2];
3111 GLFramebuffer framebuffer;
3112 constexpr char kCS[] = R"(#version 310 es
3113 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
3114 layout(r32ui, binding = 0) readonly uniform highp uimage2D uImage_1;
3115 layout(r32ui, binding = 1) writeonly uniform highp uimage2D uImage_2;
3116 uniform uint factor;
3117 void main()
3118 {
3119 uvec4 value = imageLoad(uImage_1, ivec2(gl_LocalInvocationID.xy));
3120 imageStore(uImage_2, ivec2(gl_LocalInvocationID.xy), value * factor);
3121 })";
3122
3123 constexpr int kWidth = 1, kHeight = 1;
3124 constexpr GLuint kInputValues[2][1] = {{200}, {100}};
3125
3126 glBindTexture(GL_TEXTURE_2D, texture[0]);
3127 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kWidth, kHeight);
3128 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
3129 kInputValues[0]);
3130 EXPECT_GL_NO_ERROR();
3131
3132 glBindTexture(GL_TEXTURE_2D, texture[1]);
3133 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kWidth, kHeight);
3134 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
3135 kInputValues[1]);
3136 EXPECT_GL_NO_ERROR();
3137
3138 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
3139 glUseProgram(program);
3140
3141 glBindImageTexture(0, texture[0], 0, GL_FALSE, 0, GL_READ_ONLY, GL_R32UI);
3142 EXPECT_GL_NO_ERROR();
3143
3144 glBindImageTexture(1, texture[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
3145 EXPECT_GL_NO_ERROR();
3146
3147 glUniform1ui(glGetUniformLocation(program, "factor"), 2);
3148 EXPECT_GL_NO_ERROR();
3149
3150 glDispatchCompute(1, 1, 1);
3151 EXPECT_GL_NO_ERROR();
3152
3153 glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
3154
3155 glUniform1ui(glGetUniformLocation(program, "factor"), 3);
3156 EXPECT_GL_NO_ERROR();
3157
3158 glDispatchCompute(1, 1, 1);
3159 EXPECT_GL_NO_ERROR();
3160
3161 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
3162 GLuint outputValues[kWidth * kHeight];
3163 GLuint expectedValue = 600;
3164 glUseProgram(0);
3165 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
3166
3167 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture[1], 0);
3168 EXPECT_GL_NO_ERROR();
3169 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
3170 EXPECT_GL_NO_ERROR();
3171
3172 for (int i = 0; i < kWidth * kHeight; i++)
3173 {
3174 EXPECT_EQ(expectedValue, outputValues[i]) << " index " << i;
3175 }
3176 }
3177
3178 // Test storage buffer bound is unchanged, shader writes it, buffer content should be updated.
TEST_P(ComputeShaderTest,StorageBufferBoundUnchanged)3179 TEST_P(ComputeShaderTest, StorageBufferBoundUnchanged)
3180 {
3181 // http://anglebug.com/4092
3182 ANGLE_SKIP_TEST_IF(isSwiftshader());
3183 constexpr char kCS[] = R"(#version 310 es
3184 layout(local_size_x=16, local_size_y=16) in;
3185 precision highp usampler2D;
3186 uniform usampler2D tex;
3187 uniform uint factor;
3188 layout(std140, binding = 0) buffer buf {
3189 uint outData[16][16];
3190 };
3191
3192 void main()
3193 {
3194 uint x = gl_LocalInvocationID.x;
3195 uint y = gl_LocalInvocationID.y;
3196 float xCoord = float(x) / float(16);
3197 float yCoord = float(y) / float(16);
3198 outData[y][x] = texture(tex, vec2(xCoord, yCoord)).x + factor;
3199 })";
3200
3201 constexpr unsigned int kWidth = 16;
3202 constexpr unsigned int kHeight = 16;
3203 GLTexture tex;
3204 glBindTexture(GL_TEXTURE_2D, tex);
3205 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3206 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3207 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kWidth, kHeight);
3208 GLuint texels[kHeight][kWidth] = {{0}};
3209 for (unsigned int y = 0; y < kHeight; ++y)
3210 {
3211 for (unsigned int x = 0; x < kWidth; ++x)
3212 {
3213 texels[y][x] = x + y * kWidth;
3214 }
3215 }
3216 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
3217 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
3218 texels);
3219 glBindTexture(GL_TEXTURE_2D, 0);
3220
3221 // The array stride are rounded up to the base alignment of a vec4 for std140 layout.
3222 constexpr unsigned int kArrayStride = 16;
3223 GLBuffer ssbo;
3224 glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
3225 glBufferData(GL_SHADER_STORAGE_BUFFER, kWidth * kHeight * kArrayStride, nullptr,
3226 GL_STREAM_DRAW);
3227 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
3228 EXPECT_GL_NO_ERROR();
3229
3230 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
3231 glUseProgram(program);
3232
3233 glActiveTexture(GL_TEXTURE0);
3234 glBindTexture(GL_TEXTURE_2D, tex);
3235 glUniform1i(glGetUniformLocation(program, "tex"), 0);
3236 glUniform1ui(glGetUniformLocation(program, "factor"), 2);
3237 glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
3238 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, ssbo);
3239
3240 glDispatchCompute(1, 1, 1);
3241
3242 const GLuint *ptr1 = reinterpret_cast<const GLuint *>(glMapBufferRange(
3243 GL_SHADER_STORAGE_BUFFER, 0, kWidth * kHeight * kArrayStride, GL_MAP_READ_BIT));
3244 EXPECT_GL_NO_ERROR();
3245 for (unsigned int idx = 0; idx < kWidth * kHeight; idx++)
3246 {
3247 EXPECT_EQ(idx + 2, *(ptr1 + idx * kArrayStride / 4));
3248 }
3249 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
3250 glUniform1ui(glGetUniformLocation(program, "factor"), 3);
3251 glDispatchCompute(1, 1, 1);
3252
3253 const GLuint *ptr2 = reinterpret_cast<const GLuint *>(glMapBufferRange(
3254 GL_SHADER_STORAGE_BUFFER, 0, kWidth * kHeight * kArrayStride, GL_MAP_READ_BIT));
3255 EXPECT_GL_NO_ERROR();
3256 for (unsigned int idx = 0; idx < kWidth * kHeight; idx++)
3257 {
3258 EXPECT_EQ(idx + 3, *(ptr2 + idx * kArrayStride / 4));
3259 }
3260 }
3261
3262 // Test imageSize to access mipmap slice.
TEST_P(ComputeShaderTest,ImageSizeMipmapSlice)3263 TEST_P(ComputeShaderTest, ImageSizeMipmapSlice)
3264 {
3265 // TODO(xinghua.cao@intel.com): http://anglebug.com/3101
3266 ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux());
3267
3268 // http://anglebug.com/4392
3269 ANGLE_SKIP_TEST_IF(IsWindows() && IsNVIDIA() && IsD3D11());
3270
3271 GLTexture texture[2];
3272 GLFramebuffer framebuffer;
3273 const char kCS[] = R"(#version 310 es
3274 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
3275 layout(r32ui, binding = 0) readonly uniform highp uimage2D uImage_1;
3276 layout(rgba32ui, binding = 1) writeonly uniform highp uimage2D uImage_2;
3277 void main()
3278 {
3279 ivec2 size = imageSize(uImage_1);
3280 imageStore(uImage_2, ivec2(gl_LocalInvocationID.xy), uvec4(size, 0, 0));
3281 })";
3282
3283 constexpr int kWidth1 = 8, kHeight1 = 4, kWidth2 = 1, kHeight2 = 1;
3284 constexpr GLuint kInputValues[] = {0, 0, 0, 0};
3285
3286 glBindTexture(GL_TEXTURE_2D, texture[0]);
3287 glTexStorage2D(GL_TEXTURE_2D, 2, GL_R32UI, kWidth1, kHeight1);
3288 EXPECT_GL_NO_ERROR();
3289
3290 glBindTexture(GL_TEXTURE_2D, texture[1]);
3291 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32UI, kWidth2, kHeight2);
3292 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth2, kHeight2, GL_RGBA_INTEGER, GL_UNSIGNED_INT,
3293 kInputValues);
3294 EXPECT_GL_NO_ERROR();
3295
3296 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
3297 glUseProgram(program);
3298
3299 glBindImageTexture(0, texture[0], 1, GL_FALSE, 0, GL_READ_ONLY, GL_R32UI);
3300 glBindImageTexture(1, texture[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32UI);
3301
3302 glDispatchCompute(1, 1, 1);
3303 EXPECT_GL_NO_ERROR();
3304
3305 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
3306 GLuint outputValues[kWidth2 * kHeight2 * 4];
3307 constexpr GLuint expectedValue[] = {4, 2};
3308 glUseProgram(0);
3309 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
3310
3311 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture[1], 0);
3312 EXPECT_GL_NO_ERROR();
3313 glReadPixels(0, 0, kWidth2, kHeight2, GL_RGBA_INTEGER, GL_UNSIGNED_INT, outputValues);
3314 EXPECT_GL_NO_ERROR();
3315
3316 for (int i = 0; i < kWidth2 * kHeight2; i++)
3317 {
3318 EXPECT_EQ(expectedValue[i], outputValues[i]);
3319 EXPECT_EQ(expectedValue[i + 1], outputValues[i + 1]);
3320 }
3321 }
3322
3323 // Test imageLoad to access mipmap slice.
TEST_P(ComputeShaderTest,ImageLoadMipmapSlice)3324 TEST_P(ComputeShaderTest, ImageLoadMipmapSlice)
3325 {
3326 // TODO(xinghua.cao@intel.com): http://anglebug.com/3101
3327 ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux());
3328
3329 GLTexture texture[2];
3330 GLFramebuffer framebuffer;
3331 constexpr char kCS[] = R"(#version 310 es
3332 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
3333 layout(r32ui, binding = 0) readonly uniform highp uimage2D uImage_1;
3334 layout(r32ui, binding = 1) writeonly uniform highp uimage2D uImage_2;
3335 void main()
3336 {
3337 uvec4 value = imageLoad(uImage_1, ivec2(gl_LocalInvocationID.xy));
3338 imageStore(uImage_2, ivec2(gl_LocalInvocationID.xy), value);
3339 })";
3340
3341 constexpr int kWidth1 = 2, kHeight1 = 2, kWidth2 = 1, kHeight2 = 1;
3342 constexpr GLuint kInputValues11[] = {3, 3, 3, 3};
3343 constexpr GLuint kInputValues12[] = {2};
3344 constexpr GLuint kInputValues2[] = {1};
3345
3346 glBindTexture(GL_TEXTURE_2D, texture[0]);
3347 glTexStorage2D(GL_TEXTURE_2D, 2, GL_R32UI, kWidth1, kHeight1);
3348 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth1, kHeight1, GL_RED_INTEGER, GL_UNSIGNED_INT,
3349 kInputValues11);
3350 glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, kWidth2, kHeight2, GL_RED_INTEGER, GL_UNSIGNED_INT,
3351 kInputValues12);
3352 EXPECT_GL_NO_ERROR();
3353
3354 glBindTexture(GL_TEXTURE_2D, texture[1]);
3355 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kWidth2, kHeight2);
3356 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth2, kHeight2, GL_RED_INTEGER, GL_UNSIGNED_INT,
3357 kInputValues2);
3358 EXPECT_GL_NO_ERROR();
3359
3360 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
3361 glUseProgram(program);
3362
3363 glBindImageTexture(0, texture[0], 1, GL_FALSE, 0, GL_READ_ONLY, GL_R32UI);
3364 glBindImageTexture(1, texture[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
3365
3366 glDispatchCompute(1, 1, 1);
3367 EXPECT_GL_NO_ERROR();
3368
3369 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
3370 GLuint outputValues;
3371 constexpr GLuint expectedValue = 2;
3372 glUseProgram(0);
3373 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
3374
3375 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture[1], 0);
3376 EXPECT_GL_NO_ERROR();
3377 glReadPixels(0, 0, kWidth2, kHeight2, GL_RED_INTEGER, GL_UNSIGNED_INT, &outputValues);
3378 EXPECT_GL_NO_ERROR();
3379 EXPECT_EQ(expectedValue, outputValues);
3380 }
3381
3382 // Test imageStore to access mipmap slice.
TEST_P(ComputeShaderTest,ImageStoreMipmapSlice)3383 TEST_P(ComputeShaderTest, ImageStoreMipmapSlice)
3384 {
3385 // TODO(xinghua.cao@intel.com): http://anglebug.com/3101
3386 ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux() && IsOpenGL());
3387
3388 GLTexture texture[2];
3389 GLFramebuffer framebuffer;
3390 constexpr char kCS[] = R"(#version 310 es
3391 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
3392 layout(r32ui, binding = 0) readonly uniform highp uimage2D uImage_1;
3393 layout(r32ui, binding = 1) writeonly uniform highp uimage2D uImage_2;
3394 void main()
3395 {
3396 uvec4 value = imageLoad(uImage_1, ivec2(gl_LocalInvocationID.xy));
3397 imageStore(uImage_2, ivec2(gl_LocalInvocationID.xy), value);
3398 })";
3399
3400 constexpr int kWidth1 = 1, kHeight1 = 1, kWidth2 = 2, kHeight2 = 2;
3401 constexpr GLuint kInputValues1[] = {3};
3402 constexpr GLuint kInputValues21[] = {2, 2, 2, 2};
3403 constexpr GLuint kInputValues22[] = {1};
3404
3405 glBindTexture(GL_TEXTURE_2D, texture[0]);
3406 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kWidth1, kHeight1);
3407 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth1, kHeight1, GL_RED_INTEGER, GL_UNSIGNED_INT,
3408 kInputValues1);
3409 EXPECT_GL_NO_ERROR();
3410
3411 glBindTexture(GL_TEXTURE_2D, texture[1]);
3412 glTexStorage2D(GL_TEXTURE_2D, 2, GL_R32UI, kWidth2, kHeight2);
3413 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth2, kHeight2, GL_RED_INTEGER, GL_UNSIGNED_INT,
3414 kInputValues21);
3415 glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, kWidth1, kHeight1, GL_RED_INTEGER, GL_UNSIGNED_INT,
3416 kInputValues22);
3417 EXPECT_GL_NO_ERROR();
3418
3419 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
3420 glUseProgram(program);
3421
3422 glBindImageTexture(0, texture[0], 0, GL_FALSE, 0, GL_READ_ONLY, GL_R32UI);
3423 glBindImageTexture(1, texture[1], 1, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
3424
3425 glDispatchCompute(1, 1, 1);
3426 EXPECT_GL_NO_ERROR();
3427
3428 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
3429 GLuint outputValues;
3430 constexpr GLuint expectedValue = 3;
3431 glUseProgram(0);
3432 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
3433
3434 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture[1], 1);
3435 EXPECT_GL_NO_ERROR();
3436 glReadPixels(0, 0, kWidth1, kHeight1, GL_RED_INTEGER, GL_UNSIGNED_INT, &outputValues);
3437 EXPECT_GL_NO_ERROR();
3438 EXPECT_EQ(expectedValue, outputValues);
3439 }
3440
3441 // Test that a resource is bound on render pipeline output, and then it's bound as the compute
3442 // pipeline input. It works well. See http://anglebug.com/3658
TEST_P(ComputeShaderTest,DrawTexture1DispatchTexture2)3443 TEST_P(ComputeShaderTest, DrawTexture1DispatchTexture2)
3444 {
3445 // http://anglebug.com/5072
3446 ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux() && IsOpenGL());
3447
3448 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_color_buffer_float"));
3449
3450 const char kCSSource[] = R"(#version 310 es
3451 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
3452 precision highp sampler2D;
3453 uniform sampler2D tex;
3454 layout(rgba32f, binding = 0) writeonly uniform highp image2D image;
3455 void main()
3456 {
3457 vec4 value = texelFetch(tex, ivec2(gl_LocalInvocationID.xy), 0);
3458 imageStore(image, ivec2(gl_LocalInvocationID.xy), vec4(value.x - 1.0, 1.0, 0.0, value.w - 1.0));
3459 })";
3460
3461 const char kVSSource[] = R"(#version 310 es
3462 layout (location = 0) in vec2 pos;
3463 out vec2 texCoord;
3464 void main(void) {
3465 texCoord = 0.5*pos + 0.5;
3466 gl_Position = vec4(pos, 0.0, 1.0);
3467 })";
3468
3469 const char kFSSource[] = R"(#version 310 es
3470 precision highp float;
3471 uniform sampler2D tex;
3472 in vec2 texCoord;
3473 out vec4 fragColor;
3474 void main(void) {
3475 fragColor = texture(tex, texCoord);
3476 })";
3477
3478 GLuint aPosLoc = 0;
3479 ANGLE_GL_PROGRAM(program, kVSSource, kFSSource);
3480 ANGLE_GL_COMPUTE_PROGRAM(csProgram, kCSSource);
3481 glBindAttribLocation(program, aPosLoc, "pos");
3482 GLuint buffer;
3483 glGenBuffers(1, &buffer);
3484 glBindBuffer(GL_ARRAY_BUFFER, buffer);
3485 GLfloat vertices[] = {-1, -1, 1, -1, -1, 1, 1, 1};
3486 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 8, vertices, GL_STATIC_DRAW);
3487 glVertexAttribPointer(aPosLoc, 2, GL_FLOAT, GL_FALSE, 0, 0);
3488 glEnableVertexAttribArray(aPosLoc);
3489
3490 constexpr GLfloat kInputValues[4] = {1.0, 0.0, 0.0, 1.0};
3491 constexpr GLfloat kZero[4] = {0.0, 0.0, 0.0, 0.0};
3492 GLFramebuffer framebuffer;
3493 GLTexture texture[3];
3494 glBindTexture(GL_TEXTURE_2D, texture[0]);
3495 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32F, 1, 1);
3496 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_FLOAT, kInputValues);
3497 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3498 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3499
3500 glBindTexture(GL_TEXTURE_2D, texture[1]);
3501 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32F, 1, 1);
3502 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_FLOAT, kZero);
3503 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3504 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3505
3506 glBindTexture(GL_TEXTURE_2D, texture[2]);
3507 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32F, 1, 1);
3508 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_FLOAT, kZero);
3509 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3510 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3511
3512 glUseProgram(program);
3513 glActiveTexture(GL_TEXTURE0);
3514 glBindTexture(GL_TEXTURE_2D, texture[0]);
3515 glUniform1i(glGetUniformLocation(program, "tex"), 0);
3516 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
3517 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture[1], 0);
3518 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3519 EXPECT_GL_NO_ERROR();
3520 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
3521 GLfloat actual[4];
3522 glReadPixels(0, 0, 1, 1, GL_RGBA, GL_FLOAT, actual);
3523 EXPECT_GL_NO_ERROR();
3524 EXPECT_EQ(1.0, actual[0]);
3525 EXPECT_EQ(0.0, actual[1]);
3526 EXPECT_EQ(0.0, actual[2]);
3527 EXPECT_EQ(1.0, actual[3]);
3528
3529 glUseProgram(csProgram);
3530 glActiveTexture(GL_TEXTURE0);
3531 glBindTexture(GL_TEXTURE_2D, texture[1]);
3532 glUniform1i(glGetUniformLocation(program, "tex"), 0);
3533 glBindImageTexture(0, texture[2], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
3534 glDispatchCompute(1, 1, 1);
3535 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
3536
3537 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
3538 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture[2], 0);
3539 glReadPixels(0, 0, 1, 1, GL_RGBA, GL_FLOAT, actual);
3540 EXPECT_GL_NO_ERROR();
3541 EXPECT_EQ(0.0, actual[0]);
3542 EXPECT_EQ(1.0, actual[1]);
3543 EXPECT_EQ(0.0, actual[2]);
3544 EXPECT_EQ(0.0, actual[3]);
3545 }
3546
3547 // Test that render pipeline and compute pipeline access to the same texture.
3548 // Steps:
3549 // 1. DispatchCompute.
3550 // 2. DrawArrays.
TEST_P(ComputeShaderTest,DispatchDraw)3551 TEST_P(ComputeShaderTest, DispatchDraw)
3552 {
3553 // http://anglebug.com/5072
3554 ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux() && IsOpenGL());
3555
3556 const char kCSSource[] = R"(#version 310 es
3557 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
3558 layout(rgba32f, binding = 0) writeonly uniform highp image2D image;
3559 void main()
3560 {
3561 imageStore(image, ivec2(gl_LocalInvocationID.xy), vec4(0.0, 0.0, 1.0, 1.0));
3562 })";
3563
3564 const char kVSSource[] = R"(#version 310 es
3565 layout (location = 0) in vec2 pos;
3566 out vec2 texCoord;
3567 void main(void) {
3568 texCoord = 0.5*pos + 0.5;
3569 gl_Position = vec4(pos, 0.0, 1.0);
3570 })";
3571
3572 const char kFSSource[] = R"(#version 310 es
3573 precision highp float;
3574 uniform sampler2D tex;
3575 in vec2 texCoord;
3576 out vec4 fragColor;
3577 void main(void) {
3578 fragColor = texture(tex, texCoord);
3579 })";
3580
3581 GLuint aPosLoc = 0;
3582 ANGLE_GL_PROGRAM(program, kVSSource, kFSSource);
3583 glBindAttribLocation(program, aPosLoc, "pos");
3584 GLuint buffer;
3585 glGenBuffers(1, &buffer);
3586 glBindBuffer(GL_ARRAY_BUFFER, buffer);
3587 GLfloat vertices[] = {-1, -1, 1, -1, -1, 1, 1, 1};
3588 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 8, vertices, GL_STATIC_DRAW);
3589 glVertexAttribPointer(aPosLoc, 2, GL_FLOAT, GL_FALSE, 0, 0);
3590 glEnableVertexAttribArray(aPosLoc);
3591
3592 constexpr GLfloat kInputValues[4] = {1.0, 0.0, 0.0, 1.0};
3593 GLTexture texture;
3594 glBindTexture(GL_TEXTURE_2D, texture);
3595 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32F, 1, 1);
3596 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_FLOAT, kInputValues);
3597 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3598 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3599 EXPECT_GL_NO_ERROR();
3600
3601 ANGLE_GL_COMPUTE_PROGRAM(csProgram, kCSSource);
3602 glUseProgram(csProgram);
3603
3604 glBindImageTexture(0, texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
3605
3606 glDispatchCompute(1, 1, 1);
3607 EXPECT_GL_NO_ERROR();
3608
3609 glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT);
3610 glUseProgram(program);
3611 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3612 EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::blue);
3613 }
3614
3615 // Test that render pipeline and compute pipeline access to the same texture.
3616 // Steps:
3617 // 1. DrawArrays.
3618 // 2. DispatchCompute.
3619 // 3. DispatchCompute.
3620 // 4. DrawArrays.
TEST_P(ComputeShaderTest,DrawDispatchDispatchDraw)3621 TEST_P(ComputeShaderTest, DrawDispatchDispatchDraw)
3622 {
3623 // http://anglebug.com/5072
3624 ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux() && IsOpenGL());
3625
3626 // Fails on AMD windows drivers. http://anglebug.com/3871
3627 ANGLE_SKIP_TEST_IF(IsWindows() && IsAMD() && IsVulkan());
3628
3629 const char kCSSource[] = R"(#version 310 es
3630 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
3631 layout(rgba32f, binding = 0) writeonly uniform highp image2D image;
3632 uniform float factor;
3633 void main()
3634 {
3635 imageStore(image, ivec2(gl_LocalInvocationID.xy), vec4(factor, 0.0, 1.0, 1.0));
3636 })";
3637
3638 const char kVSSource[] = R"(#version 310 es
3639 layout (location = 0) in vec2 pos;
3640 out vec2 texCoord;
3641 void main(void) {
3642 texCoord = 0.5*pos + 0.5;
3643 gl_Position = vec4(pos, 0.0, 1.0);
3644 })";
3645
3646 const char kFSSource[] = R"(#version 310 es
3647 precision highp float;
3648 uniform sampler2D tex;
3649 in vec2 texCoord;
3650 out vec4 fragColor;
3651 void main(void) {
3652 fragColor = texture(tex, texCoord);
3653 })";
3654
3655 GLuint aPosLoc = 0;
3656 ANGLE_GL_PROGRAM(program, kVSSource, kFSSource);
3657 glBindAttribLocation(program, aPosLoc, "pos");
3658 GLuint buffer;
3659 glGenBuffers(1, &buffer);
3660 glBindBuffer(GL_ARRAY_BUFFER, buffer);
3661 GLfloat vertices[] = {-1, -1, 1, -1, -1, 1, 1, 1};
3662 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 8, vertices, GL_STATIC_DRAW);
3663 glVertexAttribPointer(aPosLoc, 2, GL_FLOAT, GL_FALSE, 0, 0);
3664 glEnableVertexAttribArray(aPosLoc);
3665
3666 constexpr GLfloat kInputValues[4] = {1.0, 0.0, 0.0, 1.0};
3667 GLTexture texture;
3668 glBindTexture(GL_TEXTURE_2D, texture);
3669 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32F, 1, 1);
3670 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_FLOAT, kInputValues);
3671 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3672 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3673 glUseProgram(program);
3674 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3675 EXPECT_GL_NO_ERROR();
3676
3677 ANGLE_GL_COMPUTE_PROGRAM(csProgram, kCSSource);
3678 glUseProgram(csProgram);
3679 glUniform1f(glGetUniformLocation(csProgram, "factor"), 0.0);
3680 glBindImageTexture(0, texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
3681 EXPECT_GL_NO_ERROR();
3682
3683 glDispatchCompute(1, 1, 1);
3684 glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
3685 EXPECT_GL_NO_ERROR();
3686
3687 glUniform1f(glGetUniformLocation(csProgram, "factor"), 1.0);
3688 glDispatchCompute(1, 1, 1);
3689 glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT);
3690 EXPECT_GL_NO_ERROR();
3691
3692 glUseProgram(program);
3693 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3694 EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::magenta);
3695 }
3696
3697 // Test that render pipeline and compute pipeline access to the same texture.
3698 // Steps:
3699 // 1. DispatchCompute.
3700 // 2. DrawArrays.
3701 // 3. DrawArrays.
3702 // 4. DispatchCompute.
TEST_P(ComputeShaderTest,DispatchDrawDrawDispatch)3703 TEST_P(ComputeShaderTest, DispatchDrawDrawDispatch)
3704 {
3705 // http://anglebug.com/5072
3706 ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux() && IsOpenGL());
3707
3708 const char kCSSource[] = R"(#version 310 es
3709 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
3710 layout(rgba32f, binding = 0) writeonly uniform highp image2D image;
3711
3712 void main()
3713 {
3714 imageStore(image, ivec2(gl_LocalInvocationID.xy), vec4(0.0, 0.0, 1.0, 1.0));
3715 })";
3716
3717 const char kVSSource[] = R"(#version 310 es
3718 layout (location = 0) in vec2 pos;
3719 out vec2 texCoord;
3720 void main(void) {
3721 texCoord = 0.5*pos + 0.5;
3722 gl_Position = vec4(pos, 0.0, 1.0);
3723 })";
3724
3725 const char kFSSource[] = R"(#version 310 es
3726 precision highp float;
3727 uniform sampler2D tex;
3728 in vec2 texCoord;
3729 uniform float factor;
3730 out vec4 fragColor;
3731 void main(void) {
3732 fragColor = texture(tex, texCoord) + vec4(factor, 0.0, 0.0, 0.0);
3733 })";
3734
3735 GLuint aPosLoc = 0;
3736 ANGLE_GL_PROGRAM(program, kVSSource, kFSSource);
3737 glBindAttribLocation(program, aPosLoc, "pos");
3738 GLuint buffer;
3739 glGenBuffers(1, &buffer);
3740 glBindBuffer(GL_ARRAY_BUFFER, buffer);
3741 GLfloat vertices[] = {-1, -1, 1, -1, -1, 1, 1, 1};
3742 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 8, vertices, GL_STATIC_DRAW);
3743 glVertexAttribPointer(aPosLoc, 2, GL_FLOAT, GL_FALSE, 0, 0);
3744 glEnableVertexAttribArray(aPosLoc);
3745
3746 constexpr GLfloat kInputValues[4] = {1.0, 0.0, 0.0, 1.0};
3747 GLTexture texture;
3748 glBindTexture(GL_TEXTURE_2D, texture);
3749 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32F, 1, 1);
3750 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_FLOAT, kInputValues);
3751 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3752 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3753
3754 ANGLE_GL_COMPUTE_PROGRAM(csProgram, kCSSource);
3755 glUseProgram(csProgram);
3756 glBindImageTexture(0, texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
3757
3758 glDispatchCompute(1, 1, 1);
3759 glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT);
3760 EXPECT_GL_NO_ERROR();
3761
3762 glUseProgram(program);
3763 glUniform1f(glGetUniformLocation(program, "factor"), 0.0);
3764 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3765 EXPECT_GL_NO_ERROR();
3766
3767 glUniform1f(glGetUniformLocation(program, "factor"), 1.0);
3768 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3769 EXPECT_GL_NO_ERROR();
3770
3771 glUseProgram(csProgram);
3772 glDispatchCompute(1, 1, 1);
3773 glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT);
3774 EXPECT_GL_NO_ERROR();
3775
3776 glUseProgram(program);
3777 glUniform1f(glGetUniformLocation(program, "factor"), 0.0);
3778 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3779 EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::blue);
3780 }
3781
3782 // Test that invalid memory barrier will produce an error.
TEST_P(ComputeShaderTest,InvalidMemoryBarrier)3783 TEST_P(ComputeShaderTest, InvalidMemoryBarrier)
3784 {
3785 GLbitfield barriers = 0;
3786 glMemoryBarrier(barriers);
3787 EXPECT_GL_ERROR(GL_INVALID_VALUE);
3788 }
3789
3790 // test atomic counter increment
3791 // http://anglebug.com/3246
TEST_P(ComputeShaderTest,AtomicCounterIncrement)3792 TEST_P(ComputeShaderTest, AtomicCounterIncrement)
3793 {
3794 constexpr char kComputeShader[] = R"(#version 310 es
3795 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
3796 layout(binding = 1, std430) buffer Output {
3797 uint preGet[1];
3798 uint increment[1];
3799 uint postGet[1];
3800 } sb_in;
3801 layout(binding=0) uniform atomic_uint counter0;
3802
3803 void main(void)
3804 {
3805 uint id = (gl_GlobalInvocationID.x);
3806 sb_in.preGet[0u] = atomicCounter(counter0);
3807 sb_in.increment[0u] = atomicCounterIncrement(counter0);
3808 sb_in.postGet[0u] = atomicCounter(counter0);
3809 }
3810 )";
3811 ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShader);
3812 EXPECT_GL_NO_ERROR();
3813
3814 glUseProgram(program);
3815
3816 constexpr unsigned int kBytesPerComponent = sizeof(GLuint);
3817
3818 GLBuffer shaderStorageBuffer;
3819 glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer);
3820 glBufferData(GL_SHADER_STORAGE_BUFFER, 3 * kBytesPerComponent, nullptr, GL_STATIC_DRAW);
3821 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, shaderStorageBuffer);
3822 EXPECT_GL_NO_ERROR();
3823
3824 constexpr GLuint atomicBufferInitialData[] = {2u};
3825 GLuint atomicBuffer;
3826 glGenBuffers(1, &atomicBuffer);
3827 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicBuffer);
3828 glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(atomicBufferInitialData), atomicBufferInitialData,
3829 GL_DYNAMIC_DRAW);
3830 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, atomicBuffer);
3831 EXPECT_GL_NO_ERROR();
3832
3833 glDispatchCompute(1, 1, 1);
3834 glFinish();
3835 EXPECT_GL_NO_ERROR();
3836
3837 // read back
3838 const GLuint *ptr = reinterpret_cast<const GLuint *>(
3839 glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 3 * kBytesPerComponent, GL_MAP_READ_BIT));
3840 EXPECT_EQ(2u, ptr[0]);
3841 EXPECT_EQ(2u, ptr[1]);
3842 EXPECT_EQ(3u, ptr[2]);
3843
3844 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
3845 }
3846
3847 // Create a 'very large' array inside of a function in a compute shader.
TEST_P(ComputeShaderTest,VeryLargeArrayInsideFunction)3848 TEST_P(ComputeShaderTest, VeryLargeArrayInsideFunction)
3849 {
3850 constexpr char kComputeShader[] = R"(#version 310 es
3851 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
3852 layout(binding = 0, std430) buffer Output {
3853 int value[1];
3854 } output_data;
3855
3856 void main()
3857 {
3858 int values[1000];
3859 for (int i = 0; i < values.length(); i++)
3860 {
3861 values[i] = 0;
3862 }
3863
3864 int total = 0;
3865 for (int i = 0; i < values.length(); i++)
3866 {
3867 total += i;
3868 values[i] = total;
3869 }
3870 output_data.value[0u] = values[1000-1];
3871 })";
3872
3873 ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShader);
3874 EXPECT_GL_NO_ERROR();
3875
3876 glUseProgram(program);
3877
3878 constexpr unsigned int kBytesPerComponent = sizeof(GLint);
3879
3880 GLBuffer shaderStorageBuffer;
3881 glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer);
3882 glBufferData(GL_SHADER_STORAGE_BUFFER, 1 * kBytesPerComponent, nullptr, GL_STATIC_DRAW);
3883 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, shaderStorageBuffer);
3884 EXPECT_GL_NO_ERROR();
3885
3886 glDispatchCompute(1, 1, 1);
3887 glFinish();
3888 EXPECT_GL_NO_ERROR();
3889
3890 // read back
3891 const GLint *ptr = reinterpret_cast<const GLint *>(
3892 glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 1 * kBytesPerComponent, GL_MAP_READ_BIT));
3893 EXPECT_EQ(499500, ptr[0]);
3894
3895 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
3896 }
3897
3898 // Test that render pipeline and compute pipeline access to the same texture.
3899 // Steps:
3900 // 1. Clear the texture and DrawArrays.
3901 // 2. DispatchCompute to set the image's first pixel to a specific color.
3902 // 3. DrawArrays and check data.
TEST_P(ComputeShaderTest,DrawDispatchDrawPreserve)3903 TEST_P(ComputeShaderTest, DrawDispatchDrawPreserve)
3904 {
3905 // http://anglebug.com/5072
3906 ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux() && IsOpenGL());
3907
3908 const char kCSSource[] = R"(#version 310 es
3909 layout(local_size_x=1, local_size_y=1) in;
3910 layout(rgba8, binding = 0) writeonly uniform highp image2D image;
3911 void main()
3912 {
3913 imageStore(image, ivec2(0, 0), vec4(0.0, 0.0, 1.0, 1.0));
3914 })";
3915
3916 const char kVSSource[] = R"(#version 310 es
3917 layout (location = 0) in vec2 pos;
3918 in vec4 inTex;
3919 out vec4 texCoord;
3920 void main(void) {
3921 texCoord = inTex;
3922 gl_Position = vec4(pos, 0.0, 1.0);
3923 })";
3924
3925 const char kFSSource[] = R"(#version 310 es
3926 precision highp float;
3927 uniform sampler2D tex;
3928 in vec4 texCoord;
3929 out vec4 fragColor;
3930 void main(void) {
3931 fragColor = texture(tex, texCoord.xy);
3932 })";
3933 GLuint aPosLoc = 0;
3934 ANGLE_GL_PROGRAM(program, kVSSource, kFSSource);
3935 glBindAttribLocation(program, aPosLoc, "pos");
3936
3937 unsigned char *data = new unsigned char[4 * getWindowWidth() * getWindowHeight()];
3938 for (int i = 0; i < getWindowWidth() * getWindowHeight(); i++)
3939 {
3940 data[i * 4] = 0xff;
3941 data[i * 4 + 1] = 0;
3942 data[i * 4 + 2] = 0;
3943 data[i * 4 + 3] = 0xff;
3944 }
3945 GLTexture texture;
3946 glBindTexture(GL_TEXTURE_2D, texture);
3947 glTexStorage2D(GL_TEXTURE_2D, 2, GL_RGBA8, getWindowWidth(), getWindowHeight());
3948 // Clear the texture level 0 to Red.
3949 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA,
3950 GL_UNSIGNED_BYTE, data);
3951 for (int i = 0; i < getWindowWidth() * getWindowHeight(); i++)
3952 {
3953 data[i * 4] = 0;
3954 data[i * 4 + 1] = 0xff;
3955 data[i * 4 + 2] = 0;
3956 data[i * 4 + 3] = 0xff;
3957 }
3958 // Clear the texture level 1 to Green.
3959 glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, getWindowWidth() / 2, getWindowHeight() / 2, GL_RGBA,
3960 GL_UNSIGNED_BYTE, data);
3961 delete[] data;
3962 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
3963 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3964 glUseProgram(program);
3965 GLfloat vertices[] = {-1, -1, 1, -1, -1, 1, 1, 1};
3966 GLfloat texCoords[] = {0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f};
3967 GLint pos = glGetAttribLocation(program, "pos");
3968 glEnableVertexAttribArray(pos);
3969 glVertexAttribPointer(pos, 2, GL_FLOAT, GL_FALSE, 0, vertices);
3970 GLint posTex = glGetAttribLocation(program, "inTex");
3971 glEnableVertexAttribArray(posTex);
3972 glVertexAttribPointer(posTex, 2, GL_FLOAT, GL_FALSE, 0, texCoords);
3973
3974 // Draw with level 0, the whole framebuffer should be Red.
3975 glViewport(0, 0, getWindowWidth(), getWindowHeight());
3976 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3977 EXPECT_GL_NO_ERROR();
3978 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
3979 EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::red);
3980 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() - 1, getWindowHeight() - 1, GLColor::red);
3981 // Draw with level 1, a quarter of the framebuffer should be Green.
3982 glViewport(0, 0, getWindowWidth() / 2, getWindowHeight() / 2);
3983 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3984 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
3985 EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::green);
3986 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2 - 1, getWindowHeight() / 2 - 1, GLColor::green);
3987
3988 // Clear the texture level 0's (0, 0) position to Blue.
3989 glBindImageTexture(0, texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA8);
3990 ANGLE_GL_COMPUTE_PROGRAM(csProgram, kCSSource);
3991 glUseProgram(csProgram);
3992 glDispatchCompute(1, 1, 1);
3993 glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT);
3994 EXPECT_GL_NO_ERROR();
3995 glFinish();
3996
3997 glUseProgram(program);
3998 // Draw with level 0, the first position should be Blue.
3999 glViewport(0, 0, getWindowWidth(), getWindowHeight());
4000 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
4001 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
4002 EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::red);
4003 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() - 1, getWindowHeight() - 1, GLColor::red);
4004 // Draw with level 1, a quarter of the framebuffer should be Green.
4005 glViewport(0, 0, getWindowWidth() / 2, getWindowHeight() / 2);
4006 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
4007 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
4008 EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::green);
4009 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2 - 1, getWindowHeight() / 2 - 1, GLColor::green);
4010 }
4011
4012 // Test that maxComputeWorkGroupCount is valid number.
TEST_P(ComputeShaderTest,ValidateMaxComputeWorkGroupCount)4013 TEST_P(ComputeShaderTest, ValidateMaxComputeWorkGroupCount)
4014 {
4015 constexpr char kCS[] = R"(#version 310 es
4016 layout(local_size_x=1) in;
4017 void main()
4018 {
4019 })";
4020
4021 GLuint program = glCreateProgram();
4022 GLuint cs = CompileShader(GL_COMPUTE_SHADER, kCS);
4023 EXPECT_NE(0u, cs);
4024
4025 glAttachShader(program, cs);
4026 glDeleteShader(cs);
4027
4028 GLint x, y, z;
4029 glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 0, &x);
4030 EXPECT_LE(65535, x);
4031 EXPECT_GE(std::numeric_limits<GLint>::max(), x);
4032
4033 glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 1, &y);
4034 EXPECT_LE(65535, y);
4035 EXPECT_GE(std::numeric_limits<GLint>::max(), y);
4036
4037 glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 2, &z);
4038 EXPECT_LE(65535, z);
4039 EXPECT_GE(std::numeric_limits<GLint>::max(), z);
4040
4041 glDeleteProgram(program);
4042 EXPECT_GL_NO_ERROR();
4043 }
4044
4045 // Validate that on Vulkan, compute pipeline driver uniforms descriptor set is updated after an
4046 // internal compute-based UtilsVk function is used. The latter is achieved through a draw with a
4047 // vertex buffer whose format is not natively supported. Atomic counters are used to make sure the
4048 // compute pipeline uses the driver uniforms descriptor set.
TEST_P(ComputeShaderTest,DispatchConvertVertexDispatch)4049 TEST_P(ComputeShaderTest, DispatchConvertVertexDispatch)
4050 {
4051 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_vertex_type_10_10_10_2"));
4052
4053 constexpr uint32_t kVertexCount = 6;
4054
4055 constexpr char kCS[] = R"(#version 310 es
4056 layout(local_size_x=6, local_size_y=1, local_size_z=1) in;
4057
4058 layout(binding = 0) uniform atomic_uint ac;
4059
4060 layout(binding=0, std140) buffer VertexData
4061 {
4062 uint data[];
4063 };
4064
4065 void main()
4066 {
4067 atomicCounterIncrement(ac);
4068 data[gl_GlobalInvocationID.x] = gl_GlobalInvocationID.x;
4069 })";
4070
4071 constexpr char kVS[] = R"(#version 310 es
4072 precision mediump float;
4073
4074 layout(location = 0) in vec4 position;
4075 layout(location = 1) in uvec4 data;
4076
4077 out vec4 color;
4078
4079 void main() {
4080 color = data.x < 6u && data.y == 0u && data.z == 0u && data.w == 0u
4081 ? vec4(0.0, 1.0, 0.0, 1.0) : vec4(1.0, 0.0, 0.0, 1.0);
4082 gl_Position = position;
4083 })";
4084
4085 constexpr char kFS[] = R"(#version 310 es
4086 precision mediump float;
4087 in vec4 color;
4088 out vec4 colorOut;
4089 void main() {
4090 colorOut = color;
4091 })";
4092
4093 ANGLE_GL_COMPUTE_PROGRAM(programCS, kCS);
4094 ANGLE_GL_PROGRAM(programVSFS, kVS, kFS);
4095 EXPECT_GL_NO_ERROR();
4096
4097 // Create atomic counter buffer
4098 GLBuffer atomicCounterBuffer;
4099 constexpr GLuint kInitialAcbData = 0;
4100 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicCounterBuffer);
4101 glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(kInitialAcbData), &kInitialAcbData,
4102 GL_STATIC_DRAW);
4103 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, atomicCounterBuffer);
4104 EXPECT_GL_NO_ERROR();
4105
4106 // Create vertex buffer
4107 constexpr unsigned kVertexBufferInitData[kVertexCount] = {};
4108 GLBuffer vertexBuffer;
4109 glBindBuffer(GL_SHADER_STORAGE_BUFFER, vertexBuffer);
4110 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(kVertexBufferInitData), kVertexBufferInitData,
4111 GL_STATIC_DRAW);
4112 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, vertexBuffer);
4113 EXPECT_GL_NO_ERROR();
4114
4115 // Create position buffer
4116 constexpr GLfloat positions[kVertexCount * 2] = {1.0, 1.0, -1.0, 1.0, -1.0, -1.0,
4117 1.0, 1.0, -1.0, -1.0, 1.0, -1.0};
4118 GLBuffer positionBuffer;
4119 glBindBuffer(GL_ARRAY_BUFFER, positionBuffer);
4120 glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, GL_STATIC_DRAW);
4121 EXPECT_GL_NO_ERROR();
4122
4123 // Create vertex array
4124 GLVertexArray vao;
4125 glBindVertexArray(vao);
4126
4127 glBindBuffer(GL_ARRAY_BUFFER, positionBuffer);
4128 glEnableVertexAttribArray(0);
4129 glVertexAttribPointer(0, 2, GL_FLOAT, false, 0, 0);
4130
4131 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
4132 glEnableVertexAttribArray(1);
4133 glVertexAttribPointer(1, 4, GL_UNSIGNED_INT_10_10_10_2_OES, false, 0, 0);
4134 EXPECT_GL_NO_ERROR();
4135
4136 // Fill the vertex buffer with a dispatch call
4137 glUseProgram(programCS);
4138 glDispatchCompute(1, 1, 1);
4139 EXPECT_GL_NO_ERROR();
4140
4141 glMemoryBarrier(GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT);
4142
4143 // Draw using the vertex buffer, causing vertex format conversion in compute (in the Vulkan
4144 // backend)
4145 glUseProgram(programVSFS);
4146 glBindVertexArray(vao);
4147 glDrawArrays(GL_TRIANGLES, 0, kVertexCount);
4148 EXPECT_GL_NO_ERROR();
4149
4150 // Issue another dispatch call. The driver uniforms descriptor set must be rebound.
4151 glUseProgram(programCS);
4152 glDispatchCompute(1, 1, 1);
4153 EXPECT_GL_NO_ERROR();
4154
4155 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
4156
4157 // Verify that the atomic counter has the expected value.
4158 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicCounterBuffer);
4159 GLuint *mappedBuffer = static_cast<GLuint *>(
4160 glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint), GL_MAP_READ_BIT));
4161 EXPECT_EQ(kVertexCount * 2, mappedBuffer[0]);
4162 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
4163 }
4164
4165 // Validate that on Vulkan, compute pipeline is correctly bound after an internal dispatch call is
4166 // made. Blit stencil may issue a dispatch call.
TEST_P(ComputeShaderTest,DispatchBlitStencilDispatch)4167 TEST_P(ComputeShaderTest, DispatchBlitStencilDispatch)
4168 {
4169 // http://anglebug.com/5533
4170 ANGLE_SKIP_TEST_IF(IsQualcomm() && IsOpenGLES());
4171
4172 // http://anglebug.com/5072
4173 ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux() && IsOpenGL());
4174
4175 constexpr GLsizei kSize = 1;
4176
4177 constexpr char kCS[] = R"(#version 310 es
4178 layout(local_size_x=6, local_size_y=1, local_size_z=1) in;
4179
4180 uniform vec4 data;
4181
4182 layout(rgba8, binding = 0) writeonly uniform highp image2D image;
4183
4184 void main()
4185 {
4186 imageStore(image, ivec2(gl_LocalInvocationID.xy), data);
4187 })";
4188
4189 ANGLE_GL_COMPUTE_PROGRAM(programCS, kCS);
4190 EXPECT_GL_NO_ERROR();
4191
4192 // Create a framebuffer with stencil buffer. Use multisampled textures so the future blit
4193 // cannot use vkCmdBlitImage.
4194 GLTexture color;
4195 glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, color);
4196 glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA8, kSize, kSize, true);
4197
4198 GLTexture depthStencil;
4199 glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, depthStencil);
4200 glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_DEPTH24_STENCIL8, kSize, kSize,
4201 true);
4202
4203 GLFramebuffer fbo;
4204 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
4205 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, color,
4206 0);
4207 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D_MULTISAMPLE,
4208 depthStencil, 0);
4209 ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
4210 ASSERT_GL_NO_ERROR();
4211
4212 // Clear the stencil and make sure it's done.
4213 glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
4214 glClearStencil(0x55);
4215 glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
4216
4217 glEnable(GL_STENCIL_TEST);
4218 glStencilFunc(GL_EQUAL, 0x55, 0xFF);
4219 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
4220 glStencilMask(0xFF);
4221
4222 ANGLE_GL_PROGRAM(drawRed, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
4223 drawQuad(drawRed, essl1_shaders::PositionAttrib(), 0.0f);
4224 ASSERT_GL_NO_ERROR();
4225
4226 GLTexture colorCopy;
4227 glBindTexture(GL_TEXTURE_2D, colorCopy);
4228 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, kSize, kSize);
4229
4230 GLFramebuffer copyFbo;
4231 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, copyFbo);
4232 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorCopy, 0);
4233 ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_DRAW_FRAMEBUFFER);
4234 glBlitFramebuffer(0, 0, kSize, kSize, 0, 0, kSize, kSize, GL_COLOR_BUFFER_BIT, GL_NEAREST);
4235 ASSERT_GL_NO_ERROR();
4236
4237 glBindFramebuffer(GL_READ_FRAMEBUFFER, copyFbo);
4238 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
4239
4240 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
4241
4242 // Setup image for compute call
4243 GLTexture computeOut;
4244 glBindTexture(GL_TEXTURE_2D, computeOut);
4245 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, kSize, kSize);
4246 glBindImageTexture(0, computeOut, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA8);
4247 ASSERT_GL_NO_ERROR();
4248
4249 // Issue a dispatch call.
4250 glUseProgram(programCS);
4251 GLint uniformLoc = glGetUniformLocation(programCS, "data");
4252 ASSERT_NE(uniformLoc, -1);
4253
4254 glUniform4f(uniformLoc, 0.0f, 0.0f, 1.0f, 1.0f);
4255 glDispatchCompute(1, 1, 1);
4256 glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
4257 ASSERT_GL_NO_ERROR();
4258
4259 // Blit the stencil texture. This may use a compute shader internally.
4260 GLTexture depthStencilCopy;
4261 glBindTexture(GL_TEXTURE_2D, depthStencilCopy);
4262 glTexStorage2D(GL_TEXTURE_2D, 1, GL_DEPTH24_STENCIL8, kSize, kSize);
4263 ASSERT_GL_NO_ERROR();
4264
4265 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, copyFbo);
4266 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
4267 depthStencilCopy, 0);
4268 ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_DRAW_FRAMEBUFFER);
4269 ASSERT_GL_NO_ERROR();
4270
4271 glBlitFramebuffer(0, 0, kSize, kSize, 0, 0, kSize, kSize, GL_STENCIL_BUFFER_BIT, GL_NEAREST);
4272 ASSERT_GL_NO_ERROR();
4273
4274 // Issue another dispatch call.
4275 glUniform4f(uniformLoc, 0.0f, 1.0f, 0.0f, 1.0f);
4276 glDispatchCompute(1, 1, 1);
4277 ASSERT_GL_NO_ERROR();
4278
4279 // Verify the results.
4280 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
4281 glBindFramebuffer(GL_FRAMEBUFFER, copyFbo);
4282 glBindTexture(GL_TEXTURE_2D, computeOut);
4283 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, computeOut, 0);
4284 ASSERT_GL_NO_ERROR();
4285
4286 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
4287
4288 // Verify the blit copy results.
4289 drawQuad(drawRed, essl1_shaders::PositionAttrib(), 0.0f);
4290 ASSERT_GL_NO_ERROR();
4291
4292 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
4293 }
4294
4295 // Validate that on Vulkan, compute pipeline is correctly bound after an internal dispatch call is
4296 // made. Generate mipmap may issue a dispatch call.
TEST_P(ComputeShaderTest,DispatchGenerateMipmapDispatch)4297 TEST_P(ComputeShaderTest, DispatchGenerateMipmapDispatch)
4298 {
4299 constexpr GLsizei kSize = 8;
4300
4301 constexpr char kCS[] = R"(#version 310 es
4302 layout(local_size_x=6, local_size_y=1, local_size_z=1) in;
4303
4304 uniform vec4 data;
4305
4306 layout(rgba8, binding = 0) writeonly uniform highp image2D image;
4307
4308 void main()
4309 {
4310 imageStore(image, ivec2(gl_LocalInvocationID.xy), data);
4311 })";
4312
4313 ANGLE_GL_COMPUTE_PROGRAM(programCS, kCS);
4314 EXPECT_GL_NO_ERROR();
4315
4316 GLTexture color;
4317 glBindTexture(GL_TEXTURE_2D, color);
4318 glTexStorage2D(GL_TEXTURE_2D, 4, GL_RGBA8, kSize, kSize);
4319
4320 const std::vector<GLColor> kInitialColor(kSize * kSize, GLColor::green);
4321 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kSize, kSize, GL_RGBA, GL_UNSIGNED_BYTE,
4322 kInitialColor.data());
4323
4324 // Setup image for compute call
4325 GLTexture computeOut;
4326 glBindTexture(GL_TEXTURE_2D, computeOut);
4327 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, kSize, kSize);
4328 glBindImageTexture(0, computeOut, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA8);
4329 ASSERT_GL_NO_ERROR();
4330
4331 // Issue a dispatch call.
4332 glUseProgram(programCS);
4333 GLint uniformLoc = glGetUniformLocation(programCS, "data");
4334 ASSERT_NE(uniformLoc, -1);
4335
4336 glUniform4f(uniformLoc, 0.0f, 0.0f, 1.0f, 1.0f);
4337 glDispatchCompute(1, 1, 1);
4338 glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
4339 ASSERT_GL_NO_ERROR();
4340
4341 // Generate mipmap on the texture. This may use a compute shader internally.
4342 glBindTexture(GL_TEXTURE_2D, color);
4343 glGenerateMipmap(GL_TEXTURE_2D);
4344
4345 // Issue another dispatch call.
4346 glUniform4f(uniformLoc, 0.0f, 1.0f, 0.0f, 1.0f);
4347 glDispatchCompute(1, 1, 1);
4348 ASSERT_GL_NO_ERROR();
4349
4350 // Verify the results.
4351 GLFramebuffer fbo;
4352 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
4353 glBindTexture(GL_TEXTURE_2D, computeOut);
4354 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, computeOut, 0);
4355 ASSERT_GL_NO_ERROR();
4356
4357 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
4358 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
4359 }
4360
4361 // Write to image array with an aliasing format.
TEST_P(ComputeShaderTest,AliasingFormatForImageArray)4362 TEST_P(ComputeShaderTest, AliasingFormatForImageArray)
4363 {
4364 // http://anglebug.com/5352
4365 ANGLE_SKIP_TEST_IF(IsD3D11());
4366
4367 constexpr char kCS[] = R"(#version 310 es
4368 layout(local_size_x=1, local_size_y=1, local_size_z=2) in;
4369 layout(r32ui, binding = 0) writeonly uniform highp uimage2DArray image;
4370 void main()
4371 {
4372 uint yellow = 0xFF00FFFFu;
4373 imageStore(image, ivec3(gl_LocalInvocationID.xyz), uvec4(yellow, 0, 0, 0));
4374 })";
4375
4376 constexpr int kWidth = 1, kHeight = 1, kDepth = 2;
4377
4378 const std::vector<GLColor> kInitData(kWidth * kHeight * kDepth, GLColor::black);
4379
4380 GLTexture texture;
4381 glBindTexture(GL_TEXTURE_2D_ARRAY, texture);
4382 glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_RGBA8, kWidth, kHeight, kDepth);
4383 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, kWidth, kHeight, kDepth, GL_RGBA,
4384 GL_UNSIGNED_BYTE, kInitData.data());
4385 EXPECT_GL_NO_ERROR();
4386
4387 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
4388 glUseProgram(program);
4389
4390 // Output yellow to both layers.
4391 glBindImageTexture(0, texture, 0, GL_TRUE, 0, GL_WRITE_ONLY, GL_R32UI);
4392 glDispatchCompute(1, 1, 1);
4393 EXPECT_GL_NO_ERROR();
4394
4395 // Verify results.
4396 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
4397 EXPECT_GL_NO_ERROR();
4398
4399 GLFramebuffer framebuffer;
4400 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
4401 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0, 0);
4402 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, texture, 0, 1);
4403 EXPECT_GL_NO_ERROR();
4404
4405 glReadBuffer(GL_COLOR_ATTACHMENT0);
4406 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow);
4407
4408 glReadBuffer(GL_COLOR_ATTACHMENT1);
4409 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow);
4410 }
4411
4412 // Write to one layer of image array with an aliasing format.
TEST_P(ComputeShaderTest,AliasingFormatForOneLayerOfImageArray)4413 TEST_P(ComputeShaderTest, AliasingFormatForOneLayerOfImageArray)
4414 {
4415 // http://anglebug.com/5352
4416 ANGLE_SKIP_TEST_IF(IsD3D11());
4417
4418 constexpr char kCS[] = R"(#version 310 es
4419 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
4420 layout(r32ui, binding = 0) writeonly uniform highp uimage2D image;
4421 void main()
4422 {
4423 uint yellow = 0xFF00FFFFu;
4424 imageStore(image, ivec2(gl_LocalInvocationID.xy), uvec4(yellow, 0, 0, 0));
4425 })";
4426
4427 constexpr int kWidth = 1, kHeight = 1, kDepth = 2;
4428
4429 const std::vector<GLColor> kInitData(kWidth * kHeight * kDepth, GLColor::black);
4430
4431 GLTexture texture;
4432 glBindTexture(GL_TEXTURE_2D_ARRAY, texture);
4433 glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_RGBA8, kWidth, kHeight, kDepth);
4434 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, kWidth, kHeight, kDepth, GL_RGBA,
4435 GL_UNSIGNED_BYTE, kInitData.data());
4436 EXPECT_GL_NO_ERROR();
4437
4438 GLFramebuffer framebuffer;
4439 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
4440 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0, 0);
4441 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, texture, 0, 1);
4442 EXPECT_GL_NO_ERROR();
4443
4444 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
4445 glUseProgram(program);
4446
4447 // Output yellow to layer 0.
4448 glBindImageTexture(0, texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
4449 glDispatchCompute(1, 1, 1);
4450 EXPECT_GL_NO_ERROR();
4451
4452 // Verify that only layer 0 was changed.
4453 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
4454 EXPECT_GL_NO_ERROR();
4455
4456 glReadBuffer(GL_COLOR_ATTACHMENT0);
4457 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow);
4458
4459 glReadBuffer(GL_COLOR_ATTACHMENT1);
4460 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
4461
4462 // Reset texture back to black.
4463 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, kWidth, kHeight, kDepth, GL_RGBA,
4464 GL_UNSIGNED_BYTE, kInitData.data());
4465
4466 // Output yellow to layer 1.
4467 glBindImageTexture(0, texture, 0, GL_FALSE, 1, GL_WRITE_ONLY, GL_R32UI);
4468 glDispatchCompute(1, 1, 1);
4469 EXPECT_GL_NO_ERROR();
4470
4471 // Verify that only layer 1 was changed.
4472 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
4473 EXPECT_GL_NO_ERROR();
4474
4475 glReadBuffer(GL_COLOR_ATTACHMENT0);
4476 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
4477
4478 glReadBuffer(GL_COLOR_ATTACHMENT1);
4479 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow);
4480 }
4481
4482 // Test glMemoryBarrier(CLIENT_MAPPED_BUFFER_BARRIER_BIT_EXT) by writing to persistenly mapped
4483 // buffer from a compute shader.
TEST_P(ComputeShaderTest,WriteToPersistentBuffer)4484 TEST_P(ComputeShaderTest, WriteToPersistentBuffer)
4485 {
4486 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_buffer_storage"));
4487
4488 constexpr char kCS[] = R"(#version 310 es
4489 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
4490 layout(std140, binding = 0) buffer block {
4491 uvec4 data;
4492 } outBlock;
4493 void main()
4494 {
4495 outBlock.data += uvec4(1);
4496 })";
4497
4498 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
4499 glUseProgram(program);
4500
4501 constexpr std::array<uint32_t, 4> kInitData = {};
4502
4503 GLBuffer coherentBuffer;
4504 glBindBuffer(GL_SHADER_STORAGE_BUFFER, coherentBuffer);
4505 glBufferStorageEXT(
4506 GL_SHADER_STORAGE_BUFFER, sizeof(kInitData), kInitData.data(),
4507 GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT_EXT | GL_MAP_COHERENT_BIT_EXT);
4508
4509 GLBuffer nonCoherentBuffer;
4510 glBindBuffer(GL_SHADER_STORAGE_BUFFER, nonCoherentBuffer);
4511 glBufferStorageEXT(GL_SHADER_STORAGE_BUFFER, sizeof(kInitData), kInitData.data(),
4512 GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT_EXT);
4513
4514 // Map the buffers for read and write.
4515 glBindBuffer(GL_SHADER_STORAGE_BUFFER, coherentBuffer);
4516 uint32_t *coherentMapped = reinterpret_cast<uint32_t *>(glMapBufferRange(
4517 GL_SHADER_STORAGE_BUFFER, 0, sizeof(kInitData),
4518 GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT_EXT | GL_MAP_COHERENT_BIT_EXT));
4519 ASSERT_GL_NO_ERROR();
4520
4521 glBindBuffer(GL_SHADER_STORAGE_BUFFER, nonCoherentBuffer);
4522 uint32_t *nonCoherentMapped = reinterpret_cast<uint32_t *>(
4523 glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(kInitData),
4524 GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT_EXT));
4525 ASSERT_GL_NO_ERROR();
4526
4527 constexpr std::array<uint32_t, 4> kCoherentExpectedData = {
4528 0x12354678u,
4529 0x2468ACE0u,
4530 0x13579BDFu,
4531 0x76543210u,
4532 };
4533
4534 constexpr std::array<uint32_t, 4> kNonCoherentExpectedData = {
4535 0x9ABCDEF0u,
4536 0xFDB97531u,
4537 0x1F2E3D4Bu,
4538 0x5A697887u,
4539 };
4540
4541 coherentMapped[0] = kCoherentExpectedData[0] - 1;
4542 coherentMapped[1] = kCoherentExpectedData[1] - 1;
4543 coherentMapped[2] = kCoherentExpectedData[2] - 1;
4544 coherentMapped[3] = kCoherentExpectedData[3] - 1;
4545
4546 nonCoherentMapped[0] = kNonCoherentExpectedData[0] - 1;
4547 nonCoherentMapped[1] = kNonCoherentExpectedData[1] - 1;
4548 nonCoherentMapped[2] = kNonCoherentExpectedData[2] - 1;
4549 nonCoherentMapped[3] = kNonCoherentExpectedData[3] - 1;
4550
4551 // Test coherent write
4552 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, coherentBuffer);
4553 glDispatchCompute(1, 1, 1);
4554 EXPECT_GL_NO_ERROR();
4555
4556 glFinish();
4557 EXPECT_EQ(coherentMapped[0], kCoherentExpectedData[0]);
4558 EXPECT_EQ(coherentMapped[1], kCoherentExpectedData[1]);
4559 EXPECT_EQ(coherentMapped[2], kCoherentExpectedData[2]);
4560 EXPECT_EQ(coherentMapped[3], kCoherentExpectedData[3]);
4561
4562 // Test non-coherent write
4563 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, nonCoherentBuffer);
4564 glDispatchCompute(1, 1, 1);
4565
4566 glMemoryBarrier(GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT_EXT);
4567 EXPECT_GL_NO_ERROR();
4568
4569 glFinish();
4570 EXPECT_EQ(nonCoherentMapped[0], kNonCoherentExpectedData[0]);
4571 EXPECT_EQ(nonCoherentMapped[1], kNonCoherentExpectedData[1]);
4572 EXPECT_EQ(nonCoherentMapped[2], kNonCoherentExpectedData[2]);
4573 EXPECT_EQ(nonCoherentMapped[3], kNonCoherentExpectedData[3]);
4574
4575 glBindBuffer(GL_SHADER_STORAGE_BUFFER, coherentBuffer);
4576 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
4577 glBindBuffer(GL_SHADER_STORAGE_BUFFER, nonCoherentBuffer);
4578 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
4579 EXPECT_GL_NO_ERROR();
4580 }
4581
4582 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ComputeShaderTest);
4583 ANGLE_INSTANTIATE_TEST_ES31_AND(ComputeShaderTest, WithDirectSPIRVGeneration(ES31_VULKAN()));
4584
4585 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ComputeShaderTestES3);
4586 ANGLE_INSTANTIATE_TEST_ES3(ComputeShaderTestES3);
4587
4588 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WebGL2ComputeTest);
4589 ANGLE_INSTANTIATE_TEST_ES31(WebGL2ComputeTest);
4590 } // namespace
4591