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