1 //
2 // Copyright 2016 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // ComputeShaderTest:
7 // Compute shader specific tests.
8
9 #include <vector>
10 #include "test_utils/ANGLETest.h"
11 #include "test_utils/gl_raii.h"
12
13 using namespace angle;
14
15 namespace
16 {
17
18 class ComputeShaderTest : public ANGLETest
19 {
20 protected:
ComputeShaderTest()21 ComputeShaderTest() {}
22
createMockOutputImage(GLuint texture,GLenum internalFormat,GLint width,GLint height)23 void createMockOutputImage(GLuint texture, GLenum internalFormat, GLint width, GLint height)
24 {
25 glBindTexture(GL_TEXTURE_2D, texture);
26 glTexStorage2D(GL_TEXTURE_2D, 1, internalFormat, width, height);
27 EXPECT_GL_NO_ERROR();
28
29 glBindImageTexture(0, texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, internalFormat);
30 EXPECT_GL_NO_ERROR();
31 }
32
33 template <class T, GLint kWidth, GLint kHeight>
runSharedMemoryTest(const char * kCS,GLenum internalFormat,GLenum format,const std::array<T,kWidth * kHeight> & inputData,const std::array<T,kWidth * kHeight> & expectedValues)34 void runSharedMemoryTest(const char *kCS,
35 GLenum internalFormat,
36 GLenum format,
37 const std::array<T, kWidth * kHeight> &inputData,
38 const std::array<T, kWidth * kHeight> &expectedValues)
39 {
40 GLTexture texture[2];
41 GLFramebuffer framebuffer;
42
43 glBindTexture(GL_TEXTURE_2D, texture[0]);
44 glTexStorage2D(GL_TEXTURE_2D, 1, internalFormat, kWidth, kHeight);
45 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, format,
46 inputData.data());
47 EXPECT_GL_NO_ERROR();
48
49 constexpr T initData[kWidth * kHeight] = {};
50 glBindTexture(GL_TEXTURE_2D, texture[1]);
51 glTexStorage2D(GL_TEXTURE_2D, 1, internalFormat, kWidth, kHeight);
52 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, format, initData);
53 EXPECT_GL_NO_ERROR();
54
55 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
56 glUseProgram(program.get());
57
58 glBindImageTexture(0, texture[0], 0, GL_FALSE, 0, GL_READ_ONLY, internalFormat);
59 EXPECT_GL_NO_ERROR();
60
61 glBindImageTexture(1, texture[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, internalFormat);
62 EXPECT_GL_NO_ERROR();
63
64 glDispatchCompute(1, 1, 1);
65 EXPECT_GL_NO_ERROR();
66
67 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
68
69 T outputValues[kWidth * kHeight] = {};
70 glUseProgram(0);
71 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
72
73 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture[1],
74 0);
75 EXPECT_GL_NO_ERROR();
76 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, format, outputValues);
77 EXPECT_GL_NO_ERROR();
78
79 for (int i = 0; i < kWidth * kHeight; i++)
80 {
81 EXPECT_EQ(expectedValues[i], outputValues[i]);
82 }
83 }
84 };
85
86 class ComputeShaderTestES3 : public ANGLETest
87 {
88 protected:
ComputeShaderTestES3()89 ComputeShaderTestES3() {}
90 };
91
92 class WebGL2ComputeTest : public ComputeShaderTest
93 {
94 protected:
WebGL2ComputeTest()95 WebGL2ComputeTest() { setWebGLCompatibilityEnabled(true); }
96 };
97
98 // link a simple compute program. It should be successful.
TEST_P(ComputeShaderTest,LinkComputeProgram)99 TEST_P(ComputeShaderTest, LinkComputeProgram)
100 {
101 constexpr char kCS[] = R"(#version 310 es
102 layout(local_size_x=1) in;
103 void main()
104 {
105 })";
106
107 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
108
109 EXPECT_GL_NO_ERROR();
110 }
111
112 // Link a simple compute program. Then detach the shader and dispatch compute.
113 // It should be successful.
TEST_P(ComputeShaderTest,DetachShaderAfterLinkSuccess)114 TEST_P(ComputeShaderTest, DetachShaderAfterLinkSuccess)
115 {
116 constexpr char kCS[] = R"(#version 310 es
117 layout(local_size_x=1) in;
118 void main()
119 {
120 })";
121
122 GLuint program = glCreateProgram();
123
124 GLuint cs = CompileShader(GL_COMPUTE_SHADER, kCS);
125 EXPECT_NE(0u, cs);
126
127 glAttachShader(program, cs);
128 glDeleteShader(cs);
129
130 glLinkProgram(program);
131 GLint linkStatus;
132 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
133 EXPECT_GL_TRUE(linkStatus);
134
135 glDetachShader(program, cs);
136 EXPECT_GL_NO_ERROR();
137
138 glUseProgram(program);
139 glDispatchCompute(8, 4, 2);
140 EXPECT_GL_NO_ERROR();
141 }
142
143 // link a simple compute program. There is no local size and linking should fail.
TEST_P(ComputeShaderTest,LinkComputeProgramNoLocalSizeLinkError)144 TEST_P(ComputeShaderTest, LinkComputeProgramNoLocalSizeLinkError)
145 {
146 constexpr char kCS[] = R"(#version 310 es
147 void main()
148 {
149 })";
150
151 GLuint program = CompileComputeProgram(kCS, false);
152 EXPECT_EQ(0u, program);
153
154 glDeleteProgram(program);
155
156 EXPECT_GL_NO_ERROR();
157 }
158
159 // link a simple compute program.
160 // make sure that uniforms and uniform samplers get recorded
TEST_P(ComputeShaderTest,LinkComputeProgramWithUniforms)161 TEST_P(ComputeShaderTest, LinkComputeProgramWithUniforms)
162 {
163 constexpr char kCS[] = R"(#version 310 es
164 precision mediump sampler2D;
165 layout(local_size_x=1) in;
166 uniform int myUniformInt;
167 uniform sampler2D myUniformSampler;
168 layout(rgba32i) uniform highp writeonly iimage2D imageOut;
169 void main()
170 {
171 int q = myUniformInt;
172 vec4 v = textureLod(myUniformSampler, vec2(0.0), 0.0);
173 imageStore(imageOut, ivec2(0), ivec4(v) * q);
174 })";
175
176 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
177
178 GLint uniformLoc = glGetUniformLocation(program.get(), "myUniformInt");
179 EXPECT_NE(-1, uniformLoc);
180
181 uniformLoc = glGetUniformLocation(program.get(), "myUniformSampler");
182 EXPECT_NE(-1, uniformLoc);
183
184 EXPECT_GL_NO_ERROR();
185 }
186
187 // Attach both compute and non-compute shaders. A link time error should occur.
188 // OpenGL ES 3.10, 7.3 Program Objects
TEST_P(ComputeShaderTest,AttachMultipleShaders)189 TEST_P(ComputeShaderTest, AttachMultipleShaders)
190 {
191 constexpr char kCS[] = R"(#version 310 es
192 layout(local_size_x=1) in;
193 void main()
194 {
195 })";
196
197 constexpr char kVS[] = R"(#version 310 es
198 void main()
199 {
200 })";
201
202 constexpr char kFS[] = R"(#version 310 es
203 void main()
204 {
205 })";
206
207 GLuint program = glCreateProgram();
208
209 GLuint vs = CompileShader(GL_VERTEX_SHADER, kVS);
210 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, kFS);
211 GLuint cs = CompileShader(GL_COMPUTE_SHADER, kCS);
212
213 EXPECT_NE(0u, vs);
214 EXPECT_NE(0u, fs);
215 EXPECT_NE(0u, cs);
216
217 glAttachShader(program, vs);
218 glDeleteShader(vs);
219
220 glAttachShader(program, fs);
221 glDeleteShader(fs);
222
223 glAttachShader(program, cs);
224 glDeleteShader(cs);
225
226 glLinkProgram(program);
227
228 GLint linkStatus;
229 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
230
231 EXPECT_GL_FALSE(linkStatus);
232
233 EXPECT_GL_NO_ERROR();
234 }
235
236 // Attach a vertex, fragment and compute shader.
237 // Query for the number of attached shaders and check the count.
TEST_P(ComputeShaderTest,AttachmentCount)238 TEST_P(ComputeShaderTest, AttachmentCount)
239 {
240 constexpr char kCS[] = R"(#version 310 es
241 layout(local_size_x=1) in;
242 void main()
243 {
244 })";
245
246 constexpr char kVS[] = R"(#version 310 es
247 void main()
248 {
249 })";
250
251 constexpr char kFS[] = R"(#version 310 es
252 void main()
253 {
254 })";
255
256 GLuint program = glCreateProgram();
257
258 GLuint vs = CompileShader(GL_VERTEX_SHADER, kVS);
259 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, kFS);
260 GLuint cs = CompileShader(GL_COMPUTE_SHADER, kCS);
261
262 EXPECT_NE(0u, vs);
263 EXPECT_NE(0u, fs);
264 EXPECT_NE(0u, cs);
265
266 glAttachShader(program, vs);
267 glDeleteShader(vs);
268
269 glAttachShader(program, fs);
270 glDeleteShader(fs);
271
272 glAttachShader(program, cs);
273 glDeleteShader(cs);
274
275 GLint numAttachedShaders;
276 glGetProgramiv(program, GL_ATTACHED_SHADERS, &numAttachedShaders);
277
278 EXPECT_EQ(3, numAttachedShaders);
279
280 glDeleteProgram(program);
281
282 EXPECT_GL_NO_ERROR();
283 }
284
285 // Attach a compute shader and link, but start rendering.
TEST_P(ComputeShaderTest,StartRenderingWithComputeProgram)286 TEST_P(ComputeShaderTest, StartRenderingWithComputeProgram)
287 {
288 constexpr char kCS[] = R"(#version 310 es
289 layout(local_size_x=1) in;
290 void main()
291 {
292 })";
293
294 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
295 EXPECT_GL_NO_ERROR();
296
297 glUseProgram(program);
298 glDrawArrays(GL_POINTS, 0, 2);
299 EXPECT_GL_NO_ERROR();
300 }
301
302 // Attach a vertex and fragment shader and link, but dispatch compute.
TEST_P(ComputeShaderTest,DispatchComputeWithRenderingProgram)303 TEST_P(ComputeShaderTest, DispatchComputeWithRenderingProgram)
304 {
305 constexpr char kVS[] = R"(#version 310 es
306 void main() {})";
307
308 constexpr char kFS[] = R"(#version 310 es
309 void main() {})";
310
311 GLuint program = glCreateProgram();
312
313 GLuint vs = CompileShader(GL_VERTEX_SHADER, kVS);
314 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, kFS);
315
316 EXPECT_NE(0u, vs);
317 EXPECT_NE(0u, fs);
318
319 glAttachShader(program, vs);
320 glDeleteShader(vs);
321
322 glAttachShader(program, fs);
323 glDeleteShader(fs);
324
325 glLinkProgram(program);
326
327 GLint linkStatus;
328 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
329 EXPECT_GL_TRUE(linkStatus);
330
331 EXPECT_GL_NO_ERROR();
332
333 glUseProgram(program);
334 glDispatchCompute(8, 4, 2);
335 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
336 }
337
338 // Access all compute shader special variables.
TEST_P(ComputeShaderTest,AccessAllSpecialVariables)339 TEST_P(ComputeShaderTest, AccessAllSpecialVariables)
340 {
341 constexpr char kCS[] = R"(#version 310 es
342 layout(local_size_x=4, local_size_y=3, local_size_z=2) in;
343 layout(rgba32ui) uniform highp writeonly uimage2D imageOut;
344 void main()
345 {
346 uvec3 temp1 = gl_NumWorkGroups;
347 uvec3 temp2 = gl_WorkGroupSize;
348 uvec3 temp3 = gl_WorkGroupID;
349 uvec3 temp4 = gl_LocalInvocationID;
350 uvec3 temp5 = gl_GlobalInvocationID;
351 uint temp6 = gl_LocalInvocationIndex;
352 imageStore(imageOut, ivec2(gl_LocalInvocationIndex, 0), uvec4(temp1 + temp2 + temp3 + temp4 + temp5, temp6));
353 })";
354
355 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
356 }
357
358 // Access part compute shader special variables.
TEST_P(ComputeShaderTest,AccessPartSpecialVariables)359 TEST_P(ComputeShaderTest, AccessPartSpecialVariables)
360 {
361 constexpr char kCS[] = R"(#version 310 es
362 layout(local_size_x=4, local_size_y=3, local_size_z=2) in;
363 layout(rgba32ui) uniform highp writeonly uimage2D imageOut;
364 void main()
365 {
366 uvec3 temp1 = gl_WorkGroupSize;
367 uvec3 temp2 = gl_WorkGroupID;
368 uint temp3 = gl_LocalInvocationIndex;
369 imageStore(imageOut, ivec2(gl_LocalInvocationIndex, 0), uvec4(temp1 + temp2, temp3));
370 })";
371
372 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
373 }
374
375 // Use glDispatchCompute to define work group count.
TEST_P(ComputeShaderTest,DispatchCompute)376 TEST_P(ComputeShaderTest, DispatchCompute)
377 {
378 constexpr char kCS[] = R"(#version 310 es
379 layout(local_size_x=4, local_size_y=3, local_size_z=2) in;
380 layout(rgba32ui) uniform highp writeonly uimage2D imageOut;
381 void main()
382 {
383 uvec3 temp = gl_NumWorkGroups;
384 imageStore(imageOut, ivec2(gl_GlobalInvocationID.xy), uvec4(temp, 0u));
385 })";
386
387 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
388
389 GLTexture texture;
390 createMockOutputImage(texture, GL_RGBA32UI, 4, 3);
391
392 glUseProgram(program.get());
393 glDispatchCompute(8, 4, 2);
394 EXPECT_GL_NO_ERROR();
395 }
396
397 // Binds a storage buffer to slot 0, then binds a storage image to slot 0, then buffer again.
TEST_P(ComputeShaderTest,BufferImageBuffer)398 TEST_P(ComputeShaderTest, BufferImageBuffer)
399 {
400 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_READ_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/3636
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/3349
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.get());
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/3349
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.get());
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.get());
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 // When declare a image array without a binding qualifier, all elements are bound to unit zero.
TEST_P(ComputeShaderTest,ImageArrayWithoutBindingQualifier)924 TEST_P(ComputeShaderTest, ImageArrayWithoutBindingQualifier)
925 {
926 ANGLE_SKIP_TEST_IF(IsD3D11());
927
928 // TODO(xinghua.cao@intel.com): On AMD desktop OpenGL, bind two image variables to unit 0,
929 // only one variable is valid.
930 ANGLE_SKIP_TEST_IF(IsAMD() && IsDesktopOpenGL());
931
932 GLTexture mTexture;
933 GLFramebuffer mFramebuffer;
934 constexpr char kCS[] = R"(#version 310 es
935 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
936 layout(r32ui) writeonly uniform highp uimage2D uImage[2];
937 void main()
938 {
939 imageStore(uImage[0], ivec2(gl_LocalInvocationIndex, 0), uvec4(100, 0, 0, 0));
940 imageStore(uImage[1], ivec2(gl_LocalInvocationIndex, 1), uvec4(100, 0, 0, 0));
941 })";
942
943 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
944 glUseProgram(program.get());
945 constexpr int kTextureWidth = 1, kTextureHeight = 2;
946 GLuint inputValues[] = {200, 200};
947
948 glBindTexture(GL_TEXTURE_2D, mTexture);
949 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kTextureWidth, kTextureHeight);
950 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kTextureWidth, kTextureHeight, GL_RED_INTEGER,
951 GL_UNSIGNED_INT, inputValues);
952 EXPECT_GL_NO_ERROR();
953
954 glBindImageTexture(0, mTexture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
955 glDispatchCompute(1, 1, 1);
956 EXPECT_GL_NO_ERROR();
957
958 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
959 glUseProgram(0);
960 glBindFramebuffer(GL_READ_FRAMEBUFFER, mFramebuffer);
961
962 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTexture, 0);
963 GLuint outputValues[kTextureWidth * kTextureHeight];
964 glReadPixels(0, 0, kTextureWidth, kTextureHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
965 outputValues);
966 EXPECT_GL_NO_ERROR();
967
968 GLuint expectedValue = 100;
969 for (int i = 0; i < kTextureWidth * kTextureHeight; i++)
970 {
971 EXPECT_EQ(expectedValue, outputValues[i]);
972 }
973 }
974
975 // When an image array is declared without a binding qualifier, all elements are bound to unit zero.
976 // Check that the unused uniform image array element does not cause any corruption. Checks for a bug
977 // where unused element could make the whole array seem as unused.
TEST_P(ComputeShaderTest,ImageArrayUnusedElement)978 TEST_P(ComputeShaderTest, ImageArrayUnusedElement)
979 {
980 ANGLE_SKIP_TEST_IF(IsD3D11());
981
982 // TODO(xinghua.cao@intel.com): On AMD desktop OpenGL, bind two image variables to unit 0,
983 // only one variable is valid.
984 ANGLE_SKIP_TEST_IF(IsAMD() && IsDesktopOpenGL());
985
986 // Vulkan is currently unable to handle unbound image units in compute shaders.
987 // http://anglebug.com/5026
988 ANGLE_SKIP_TEST_IF(IsVulkan());
989
990 GLFramebuffer framebuffer;
991 constexpr char kCS[] = R"(#version 310 es
992 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
993 layout(r32ui, binding=0) writeonly uniform highp uimage2D uOut;
994 layout(r32ui, binding=1) readonly uniform highp uimage2D uIn[2];
995
996 void main()
997 {
998 uvec4 inValue = imageLoad(uIn[0], ivec2(gl_LocalInvocationID.xy));
999 imageStore(uOut, ivec2(gl_LocalInvocationIndex, 0), inValue);
1000 imageStore(uOut, ivec2(gl_LocalInvocationIndex, 1), inValue);
1001 })";
1002
1003 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
1004 glUseProgram(program.get());
1005 constexpr int kTextureWidth = 1, kTextureHeight = 2;
1006 GLuint inputValues[] = {100, 100};
1007 GLTexture in;
1008 glBindTexture(GL_TEXTURE_2D, in);
1009 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kTextureWidth, kTextureHeight);
1010 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kTextureWidth, kTextureHeight, GL_RED_INTEGER,
1011 GL_UNSIGNED_INT, inputValues);
1012 EXPECT_GL_NO_ERROR();
1013 glBindImageTexture(1, in, 0, GL_FALSE, 0, GL_READ_ONLY, GL_R32UI);
1014
1015 GLuint initValues[] = {111, 111};
1016 GLTexture out;
1017 glBindTexture(GL_TEXTURE_2D, out);
1018 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kTextureWidth, kTextureHeight);
1019 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kTextureWidth, kTextureHeight, GL_RED_INTEGER,
1020 GL_UNSIGNED_INT, initValues);
1021 EXPECT_GL_NO_ERROR();
1022
1023 glBindImageTexture(0, out, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
1024 glDispatchCompute(1, 1, 1);
1025 EXPECT_GL_NO_ERROR();
1026
1027 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
1028 glUseProgram(0);
1029 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
1030
1031 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, out, 0);
1032 GLuint outputValues[kTextureWidth * kTextureHeight];
1033 glReadPixels(0, 0, kTextureWidth, kTextureHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
1034 outputValues);
1035 EXPECT_GL_NO_ERROR();
1036
1037 GLuint expectedValue = 100;
1038 for (int i = 0; i < kTextureWidth * kTextureHeight; i++)
1039 {
1040 EXPECT_EQ(expectedValue, outputValues[i]);
1041 }
1042 }
1043 // imageLoad functions
TEST_P(ComputeShaderTest,ImageLoad)1044 TEST_P(ComputeShaderTest, ImageLoad)
1045 {
1046 constexpr char kCS[] = R"(#version 310 es
1047 layout(local_size_x=8) in;
1048 layout(rgba8) uniform highp readonly image2D mImage2DInput;
1049 layout(rgba16i) uniform highp readonly iimageCube mImageCubeInput;
1050 layout(rgba32ui) uniform highp readonly uimage3D mImage3DInput;
1051 layout(r32i) uniform highp writeonly iimage2D imageOut;
1052 void main()
1053 {
1054 vec4 result2d = imageLoad(mImage2DInput, ivec2(gl_LocalInvocationID.xy));
1055 ivec4 resultCube = imageLoad(mImageCubeInput, ivec3(gl_LocalInvocationID.xyz));
1056 uvec4 result3d = imageLoad(mImage3DInput, ivec3(gl_LocalInvocationID.xyz));
1057 imageStore(imageOut, ivec2(gl_LocalInvocationIndex, 0), ivec4(result2d) + resultCube + ivec4(result3d));
1058 })";
1059
1060 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
1061 EXPECT_GL_NO_ERROR();
1062 }
1063
1064 // imageStore functions
TEST_P(ComputeShaderTest,ImageStore)1065 TEST_P(ComputeShaderTest, ImageStore)
1066 {
1067 constexpr char kCS[] = R"(#version 310 es
1068 layout(local_size_x=8) in;
1069 layout(rgba16f) uniform highp writeonly imageCube mImageCubeOutput;
1070 layout(r32f) uniform highp writeonly image3D mImage3DOutput;
1071 layout(rgba8ui) uniform highp writeonly uimage2DArray mImage2DArrayOutput;
1072 void main()
1073 {
1074 imageStore(mImageCubeOutput, ivec3(gl_LocalInvocationID.xyz), vec4(0.0));
1075 imageStore(mImage3DOutput, ivec3(gl_LocalInvocationID.xyz), vec4(0.0));
1076 imageStore(mImage2DArrayOutput, ivec3(gl_LocalInvocationID.xyz), uvec4(0));
1077 })";
1078
1079 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
1080 EXPECT_GL_NO_ERROR();
1081 }
1082
1083 // imageSize functions
TEST_P(ComputeShaderTest,ImageSize)1084 TEST_P(ComputeShaderTest, ImageSize)
1085 {
1086 constexpr char kCS[] = R"(#version 310 es
1087 layout(local_size_x=8) in;
1088 layout(rgba8) uniform highp readonly imageCube mImageCubeInput;
1089 layout(r32i) uniform highp readonly iimage2D mImage2DInput;
1090 layout(rgba16ui) uniform highp readonly uimage2DArray mImage2DArrayInput;
1091 layout(r32i) uniform highp writeonly iimage2D imageOut;
1092 void main()
1093 {
1094 ivec2 sizeCube = imageSize(mImageCubeInput);
1095 ivec2 size2D = imageSize(mImage2DInput);
1096 ivec3 size2DArray = imageSize(mImage2DArrayInput);
1097 imageStore(imageOut, ivec2(gl_LocalInvocationIndex, 0), ivec4(sizeCube, size2D.x, size2DArray.x));
1098 })";
1099
1100 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
1101 EXPECT_GL_NO_ERROR();
1102 }
1103
1104 // Test that texelFetch works well in compute shader.
TEST_P(ComputeShaderTest,TexelFetchFunction)1105 TEST_P(ComputeShaderTest, TexelFetchFunction)
1106 {
1107 // http://anglebug.com/4092
1108 ANGLE_SKIP_TEST_IF(isSwiftshader());
1109 constexpr char kCS[] = R"(#version 310 es
1110 layout(local_size_x=16, local_size_y=12) in;
1111 precision highp usampler2D;
1112 uniform usampler2D tex;
1113 layout(std140, binding = 0) buffer buf {
1114 uint outData[12][16];
1115 };
1116
1117 void main()
1118 {
1119 uint x = gl_LocalInvocationID.x;
1120 uint y = gl_LocalInvocationID.y;
1121 outData[y][x] = texelFetch(tex, ivec2(x, y), 0).x;
1122 })";
1123
1124 constexpr unsigned int kWidth = 16;
1125 constexpr unsigned int kHeight = 12;
1126 GLTexture tex;
1127 glBindTexture(GL_TEXTURE_2D, tex);
1128 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1129 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1130 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kWidth, kHeight);
1131 GLuint texels[kHeight][kWidth] = {{0}};
1132 for (unsigned int y = 0; y < kHeight; ++y)
1133 {
1134 for (unsigned int x = 0; x < kWidth; ++x)
1135 {
1136 texels[y][x] = x + y * kWidth;
1137 }
1138 }
1139 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1140 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
1141 texels);
1142 glBindTexture(GL_TEXTURE_2D, 0);
1143
1144 // The array stride are rounded up to the base alignment of a vec4 for std140 layout.
1145 constexpr unsigned int kArrayStride = 16;
1146 GLBuffer ssbo;
1147 glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
1148 glBufferData(GL_SHADER_STORAGE_BUFFER, kWidth * kHeight * kArrayStride, nullptr,
1149 GL_STREAM_DRAW);
1150 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
1151 EXPECT_GL_NO_ERROR();
1152
1153 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
1154 glUseProgram(program);
1155
1156 glActiveTexture(GL_TEXTURE0);
1157 glBindTexture(GL_TEXTURE_2D, tex);
1158 glUniform1i(glGetUniformLocation(program, "tex"), 0);
1159 glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
1160 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, ssbo);
1161
1162 glDispatchCompute(1, 1, 1);
1163
1164 glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
1165 const GLuint *ptr = reinterpret_cast<const GLuint *>(glMapBufferRange(
1166 GL_SHADER_STORAGE_BUFFER, 0, kWidth * kHeight * kArrayStride, GL_MAP_READ_BIT));
1167 EXPECT_GL_NO_ERROR();
1168 for (unsigned int idx = 0; idx < kWidth * kHeight; idx++)
1169 {
1170 EXPECT_EQ(idx, *(ptr + idx * kArrayStride / 4));
1171 }
1172 }
1173
1174 // Test that texture function works well in compute shader.
TEST_P(ComputeShaderTest,TextureFunction)1175 TEST_P(ComputeShaderTest, TextureFunction)
1176 {
1177 // http://anglebug.com/4092
1178 ANGLE_SKIP_TEST_IF(isSwiftshader());
1179 constexpr char kCS[] = R"(#version 310 es
1180 layout(local_size_x=16, local_size_y=16) in;
1181 precision highp usampler2D;
1182 uniform usampler2D tex;
1183 layout(std140, binding = 0) buffer buf {
1184 uint outData[16][16];
1185 };
1186
1187 void main()
1188 {
1189 uint x = gl_LocalInvocationID.x;
1190 uint y = gl_LocalInvocationID.y;
1191 float xCoord = float(x) / float(16);
1192 float yCoord = float(y) / float(16);
1193 outData[y][x] = texture(tex, vec2(xCoord, yCoord)).x;
1194 })";
1195
1196 constexpr unsigned int kWidth = 16;
1197 constexpr unsigned int kHeight = 16;
1198 GLTexture tex;
1199 glBindTexture(GL_TEXTURE_2D, tex);
1200 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1201 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1202 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kWidth, kHeight);
1203 GLuint texels[kHeight][kWidth] = {{0}};
1204 for (unsigned int y = 0; y < kHeight; ++y)
1205 {
1206 for (unsigned int x = 0; x < kWidth; ++x)
1207 {
1208 texels[y][x] = x + y * kWidth;
1209 }
1210 }
1211 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1212 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
1213 texels);
1214 glBindTexture(GL_TEXTURE_2D, 0);
1215
1216 // The array stride are rounded up to the base alignment of a vec4 for std140 layout.
1217 constexpr unsigned int kArrayStride = 16;
1218 GLBuffer ssbo;
1219 glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
1220 glBufferData(GL_SHADER_STORAGE_BUFFER, kWidth * kHeight * kArrayStride, nullptr,
1221 GL_STREAM_DRAW);
1222 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
1223 EXPECT_GL_NO_ERROR();
1224
1225 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
1226 glUseProgram(program);
1227
1228 glActiveTexture(GL_TEXTURE0);
1229 glBindTexture(GL_TEXTURE_2D, tex);
1230 glUniform1i(glGetUniformLocation(program, "tex"), 0);
1231 glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
1232 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, ssbo);
1233
1234 glDispatchCompute(1, 1, 1);
1235
1236 glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
1237 const GLuint *ptr = reinterpret_cast<const GLuint *>(glMapBufferRange(
1238 GL_SHADER_STORAGE_BUFFER, 0, kWidth * kHeight * kArrayStride, GL_MAP_READ_BIT));
1239 EXPECT_GL_NO_ERROR();
1240 for (unsigned int idx = 0; idx < kWidth * kHeight; idx++)
1241 {
1242 EXPECT_EQ(idx, *(ptr + idx * kArrayStride / 4));
1243 }
1244 }
1245
1246 // Test mixed use of sampler and image.
TEST_P(ComputeShaderTest,SamplingAndImageReadWrite)1247 TEST_P(ComputeShaderTest, SamplingAndImageReadWrite)
1248 {
1249 GLTexture texture[3];
1250 GLFramebuffer framebuffer;
1251 constexpr char kCS[] = R"(#version 310 es
1252 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
1253 layout(r32ui, binding = 0) readonly uniform highp uimage2D uImage_1;
1254 layout(r32ui, binding = 1) writeonly uniform highp uimage2D uImage_2;
1255 precision highp usampler2D;
1256 uniform usampler2D tex;
1257 void main()
1258 {
1259 uvec4 value_1 = texelFetch(tex, ivec2(gl_LocalInvocationID.xy), 0);
1260 uvec4 value_2 = imageLoad(uImage_1, ivec2(gl_LocalInvocationID.xy));
1261 imageStore(uImage_2, ivec2(gl_LocalInvocationID.xy), value_1 + value_2);
1262 })";
1263
1264 constexpr int kWidth = 1, kHeight = 1;
1265 constexpr GLuint kInputValues[3][1] = {{50}, {100}, {20}};
1266
1267 glBindTexture(GL_TEXTURE_2D, texture[0]);
1268 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kWidth, kHeight);
1269 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
1270 kInputValues[0]);
1271 glBindTexture(GL_TEXTURE_2D, texture[2]);
1272 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kWidth, kHeight);
1273 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
1274 kInputValues[2]);
1275 EXPECT_GL_NO_ERROR();
1276 glBindTexture(GL_TEXTURE_2D, 0);
1277
1278 glBindTexture(GL_TEXTURE_2D, texture[1]);
1279 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1280 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1281 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kWidth, kHeight);
1282 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1283 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
1284 kInputValues[1]);
1285
1286 EXPECT_GL_NO_ERROR();
1287
1288 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
1289 glUseProgram(program.get());
1290
1291 glBindImageTexture(0, texture[0], 0, GL_FALSE, 0, GL_READ_ONLY, GL_R32UI);
1292 glBindImageTexture(1, texture[2], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
1293 EXPECT_GL_NO_ERROR();
1294
1295 glDispatchCompute(1, 1, 1);
1296 EXPECT_GL_NO_ERROR();
1297
1298 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
1299 GLuint outputValues[kWidth * kHeight];
1300 constexpr GLuint expectedValue = 150;
1301 glUseProgram(0);
1302 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
1303
1304 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture[2], 0);
1305 EXPECT_GL_NO_ERROR();
1306 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
1307 EXPECT_GL_NO_ERROR();
1308
1309 for (int i = 0; i < kWidth * kHeight; i++)
1310 {
1311 EXPECT_EQ(expectedValue, outputValues[i]);
1312 }
1313 }
1314
1315 // Use image uniform to read and write Texture2D in compute shader, and verify the contents.
TEST_P(ComputeShaderTest,BindImageTextureWithTexture2D)1316 TEST_P(ComputeShaderTest, BindImageTextureWithTexture2D)
1317 {
1318 GLTexture texture[2];
1319 GLFramebuffer framebuffer;
1320 constexpr char kCS[] = R"(#version 310 es
1321 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
1322 layout(r32ui, binding = 0) readonly uniform highp uimage2D uImage_1;
1323 layout(r32ui, binding = 1) writeonly uniform highp uimage2D uImage_2;
1324 void main()
1325 {
1326 uvec4 value = imageLoad(uImage_1, ivec2(gl_LocalInvocationID.xy));
1327 imageStore(uImage_2, ivec2(gl_LocalInvocationID.xy), value);
1328 })";
1329
1330 constexpr int kWidth = 1, kHeight = 1;
1331 constexpr GLuint kInputValues[2][1] = {{200}, {100}};
1332
1333 glBindTexture(GL_TEXTURE_2D, texture[0]);
1334 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kWidth, kHeight);
1335 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
1336 kInputValues[0]);
1337 EXPECT_GL_NO_ERROR();
1338
1339 glBindTexture(GL_TEXTURE_2D, texture[1]);
1340 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kWidth, kHeight);
1341 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
1342 kInputValues[1]);
1343 EXPECT_GL_NO_ERROR();
1344
1345 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
1346 glUseProgram(program.get());
1347
1348 glBindImageTexture(0, texture[0], 0, GL_FALSE, 0, GL_READ_ONLY, GL_R32UI);
1349 EXPECT_GL_NO_ERROR();
1350
1351 glBindImageTexture(1, texture[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
1352 EXPECT_GL_NO_ERROR();
1353
1354 glDispatchCompute(1, 1, 1);
1355 EXPECT_GL_NO_ERROR();
1356
1357 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
1358 GLuint outputValues[kWidth * kHeight];
1359 constexpr GLuint expectedValue = 200;
1360 glUseProgram(0);
1361 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
1362
1363 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture[1], 0);
1364 EXPECT_GL_NO_ERROR();
1365 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
1366 EXPECT_GL_NO_ERROR();
1367
1368 for (int i = 0; i < kWidth * kHeight; i++)
1369 {
1370 EXPECT_EQ(expectedValue, outputValues[i]);
1371 }
1372 }
1373
1374 // Use image uniform to read and write Texture2D with non-zero base in compute shader, and verify
1375 // the contents.
TEST_P(ComputeShaderTest,BindImageTextureWithNonZeroBaseTexture2D)1376 TEST_P(ComputeShaderTest, BindImageTextureWithNonZeroBaseTexture2D)
1377 {
1378 GLTexture texture[2];
1379 GLFramebuffer framebuffer;
1380 constexpr char kCS[] = R"(#version 310 es
1381 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
1382 layout(r32ui, binding = 0) readonly uniform highp uimage2D uImage_1;
1383 layout(r32ui, binding = 1) writeonly uniform highp uimage2D uImage_2;
1384 void main()
1385 {
1386 uvec4 value = imageLoad(uImage_1, ivec2(gl_LocalInvocationID.xy));
1387 imageStore(uImage_2, ivec2(gl_LocalInvocationID.xy), value);
1388 })";
1389
1390 constexpr int kWidth = 1, kHeight = 1;
1391 constexpr GLuint kInputValues[2][1] = {{200}, {100}};
1392
1393 glBindTexture(GL_TEXTURE_2D, texture[0]);
1394 glTexStorage2D(GL_TEXTURE_2D, 2, GL_R32UI, kWidth * 2, kHeight * 2);
1395 glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
1396 kInputValues[0]);
1397 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1);
1398 EXPECT_GL_NO_ERROR();
1399
1400 glBindTexture(GL_TEXTURE_2D, texture[1]);
1401 glTexStorage2D(GL_TEXTURE_2D, 2, GL_R32UI, kWidth * 2, kHeight * 2);
1402 glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
1403 kInputValues[1]);
1404 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 1);
1405 EXPECT_GL_NO_ERROR();
1406
1407 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
1408 glUseProgram(program.get());
1409
1410 glBindImageTexture(0, texture[0], 1, GL_FALSE, 0, GL_READ_ONLY, GL_R32UI);
1411 EXPECT_GL_NO_ERROR();
1412
1413 glBindImageTexture(1, texture[1], 1, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
1414 EXPECT_GL_NO_ERROR();
1415
1416 glDispatchCompute(1, 1, 1);
1417 EXPECT_GL_NO_ERROR();
1418
1419 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
1420 GLuint outputValues[kWidth * kHeight];
1421 constexpr GLuint expectedValue = 200;
1422 glUseProgram(0);
1423 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
1424
1425 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture[1], 1);
1426 EXPECT_GL_NO_ERROR();
1427 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
1428 EXPECT_GL_NO_ERROR();
1429
1430 for (int i = 0; i < kWidth * kHeight; i++)
1431 {
1432 EXPECT_EQ(expectedValue, outputValues[i]) << " at index: " << i;
1433 }
1434 }
1435
1436 // Use image uniform to read and write Texture2DArray in compute shader, and verify the contents.
TEST_P(ComputeShaderTest,BindImageTextureWithTexture2DArray)1437 TEST_P(ComputeShaderTest, BindImageTextureWithTexture2DArray)
1438 {
1439 GLTexture texture[2];
1440 GLFramebuffer framebuffer;
1441 constexpr char kCS[] = R"(#version 310 es
1442 layout(local_size_x=2, local_size_y=2, local_size_z=2) in;
1443 layout(r32ui, binding = 0) readonly uniform highp uimage2DArray uImage_1;
1444 layout(r32ui, binding = 1) writeonly uniform highp uimage2DArray uImage_2;
1445 void main()
1446 {
1447 uvec4 value = imageLoad(uImage_1, ivec3(gl_LocalInvocationID.xyz));
1448 imageStore(uImage_2, ivec3(gl_LocalInvocationID.xyz), value);
1449 })";
1450
1451 constexpr int kWidth = 1, kHeight = 1, kDepth = 2;
1452 constexpr GLuint kInputValues[2][2] = {{200, 200}, {100, 100}};
1453
1454 glBindTexture(GL_TEXTURE_2D_ARRAY, texture[0]);
1455 glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_R32UI, kWidth, kHeight, kDepth);
1456 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, kWidth, kHeight, kDepth, GL_RED_INTEGER,
1457 GL_UNSIGNED_INT, kInputValues[0]);
1458 EXPECT_GL_NO_ERROR();
1459
1460 glBindTexture(GL_TEXTURE_2D_ARRAY, texture[1]);
1461 glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_R32UI, kWidth, kHeight, kDepth);
1462 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, kWidth, kHeight, kDepth, GL_RED_INTEGER,
1463 GL_UNSIGNED_INT, kInputValues[1]);
1464 EXPECT_GL_NO_ERROR();
1465
1466 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
1467 glUseProgram(program.get());
1468
1469 glBindImageTexture(0, texture[0], 0, GL_TRUE, 0, GL_READ_ONLY, GL_R32UI);
1470 EXPECT_GL_NO_ERROR();
1471
1472 glBindImageTexture(1, texture[1], 0, GL_TRUE, 0, GL_WRITE_ONLY, GL_R32UI);
1473 EXPECT_GL_NO_ERROR();
1474
1475 glDispatchCompute(1, 1, 1);
1476 EXPECT_GL_NO_ERROR();
1477
1478 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
1479 GLuint outputValues[kWidth * kHeight];
1480 constexpr GLuint expectedValue = 200;
1481 glUseProgram(0);
1482 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
1483
1484 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture[1], 0, 0);
1485 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, texture[1], 0, 1);
1486 EXPECT_GL_NO_ERROR();
1487 glReadBuffer(GL_COLOR_ATTACHMENT0);
1488 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
1489 EXPECT_GL_NO_ERROR();
1490 for (int i = 0; i < kWidth * kHeight; i++)
1491 {
1492 EXPECT_EQ(expectedValue, outputValues[i]);
1493 }
1494 glReadBuffer(GL_COLOR_ATTACHMENT1);
1495 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
1496 EXPECT_GL_NO_ERROR();
1497 for (int i = 0; i < kWidth * kHeight; i++)
1498 {
1499 EXPECT_EQ(expectedValue, outputValues[i]);
1500 }
1501 }
1502
1503 // Use image uniform to read and write Texture2DArray with non-zero base in compute shader, and
1504 // verify the contents.
TEST_P(ComputeShaderTest,BindImageTextureWithNonZeroBaseTexture2DArray)1505 TEST_P(ComputeShaderTest, BindImageTextureWithNonZeroBaseTexture2DArray)
1506 {
1507 GLTexture texture[2];
1508 GLFramebuffer framebuffer;
1509 constexpr char kCS[] = R"(#version 310 es
1510 layout(local_size_x=2, local_size_y=2, local_size_z=2) in;
1511 layout(r32ui, binding = 0) readonly uniform highp uimage2DArray uImage_1;
1512 layout(r32ui, binding = 1) writeonly uniform highp uimage2DArray uImage_2;
1513 void main()
1514 {
1515 uvec4 value = imageLoad(uImage_1, ivec3(gl_LocalInvocationID.xyz));
1516 imageStore(uImage_2, ivec3(gl_LocalInvocationID.xyz), value);
1517 })";
1518
1519 constexpr int kWidth = 1, kHeight = 1, kDepth = 2;
1520 constexpr GLuint kInputValues[2][2] = {{200, 200}, {100, 100}};
1521
1522 glBindTexture(GL_TEXTURE_2D_ARRAY, texture[0]);
1523 glTexStorage3D(GL_TEXTURE_2D_ARRAY, 2, GL_R32UI, kWidth * 2, kHeight * 2, kDepth);
1524 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 1, 0, 0, 0, kWidth, kHeight, kDepth, GL_RED_INTEGER,
1525 GL_UNSIGNED_INT, kInputValues[0]);
1526 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_BASE_LEVEL, 1);
1527 EXPECT_GL_NO_ERROR();
1528
1529 glBindTexture(GL_TEXTURE_2D_ARRAY, texture[1]);
1530 glTexStorage3D(GL_TEXTURE_2D_ARRAY, 2, GL_R32UI, kWidth * 2, kHeight * 2, kDepth);
1531 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 1, 0, 0, 0, kWidth, kHeight, kDepth, GL_RED_INTEGER,
1532 GL_UNSIGNED_INT, kInputValues[1]);
1533 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_BASE_LEVEL, 1);
1534 EXPECT_GL_NO_ERROR();
1535
1536 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
1537 glUseProgram(program.get());
1538
1539 glBindImageTexture(0, texture[0], 1, GL_TRUE, 0, GL_READ_ONLY, GL_R32UI);
1540 EXPECT_GL_NO_ERROR();
1541
1542 glBindImageTexture(1, texture[1], 1, GL_TRUE, 0, GL_WRITE_ONLY, GL_R32UI);
1543 EXPECT_GL_NO_ERROR();
1544
1545 glDispatchCompute(1, 1, 1);
1546 EXPECT_GL_NO_ERROR();
1547
1548 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
1549 GLuint outputValues[kWidth * kHeight];
1550 constexpr GLuint expectedValue = 200;
1551 glUseProgram(0);
1552 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
1553
1554 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture[1], 1, 0);
1555 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, texture[1], 1, 1);
1556 EXPECT_GL_NO_ERROR();
1557 glReadBuffer(GL_COLOR_ATTACHMENT0);
1558 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
1559 EXPECT_GL_NO_ERROR();
1560 for (int i = 0; i < kWidth * kHeight; i++)
1561 {
1562 EXPECT_EQ(expectedValue, outputValues[i]);
1563 }
1564 glReadBuffer(GL_COLOR_ATTACHMENT1);
1565 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
1566 EXPECT_GL_NO_ERROR();
1567 for (int i = 0; i < kWidth * kHeight; i++)
1568 {
1569 EXPECT_EQ(expectedValue, outputValues[i]);
1570 }
1571 }
1572
1573 // Use image uniform to read and write Texture3D in compute shader, and verify the contents.
TEST_P(ComputeShaderTest,BindImageTextureWithTexture3D)1574 TEST_P(ComputeShaderTest, BindImageTextureWithTexture3D)
1575 {
1576 GLTexture texture[2];
1577 GLFramebuffer framebuffer;
1578 constexpr char kCS[] = R"(#version 310 es
1579 layout(local_size_x=1, local_size_y=1, local_size_z=2) in;
1580 layout(r32ui, binding = 0) readonly uniform highp uimage3D uImage_1;
1581 layout(r32ui, binding = 1) writeonly uniform highp uimage3D uImage_2;
1582 void main()
1583 {
1584 uvec4 value = imageLoad(uImage_1, ivec3(gl_LocalInvocationID.xyz));
1585 imageStore(uImage_2, ivec3(gl_LocalInvocationID.xyz), value);
1586 })";
1587
1588 constexpr int kWidth = 1, kHeight = 1, kDepth = 2;
1589 constexpr GLuint kInputValues[2][2] = {{200, 200}, {100, 100}};
1590
1591 glBindTexture(GL_TEXTURE_3D, texture[0]);
1592 glTexStorage3D(GL_TEXTURE_3D, 1, GL_R32UI, kWidth, kHeight, kDepth);
1593 glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, kWidth, kHeight, kDepth, GL_RED_INTEGER,
1594 GL_UNSIGNED_INT, kInputValues[0]);
1595 EXPECT_GL_NO_ERROR();
1596
1597 glBindTexture(GL_TEXTURE_3D, texture[1]);
1598 glTexStorage3D(GL_TEXTURE_3D, 1, GL_R32UI, kWidth, kHeight, kDepth);
1599 glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, kWidth, kHeight, kDepth, GL_RED_INTEGER,
1600 GL_UNSIGNED_INT, kInputValues[1]);
1601 EXPECT_GL_NO_ERROR();
1602
1603 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
1604 glUseProgram(program.get());
1605
1606 glBindImageTexture(0, texture[0], 0, GL_TRUE, 0, GL_READ_ONLY, GL_R32UI);
1607 EXPECT_GL_NO_ERROR();
1608
1609 glBindImageTexture(1, texture[1], 0, GL_TRUE, 0, GL_WRITE_ONLY, GL_R32UI);
1610 EXPECT_GL_NO_ERROR();
1611
1612 glDispatchCompute(1, 1, 1);
1613 EXPECT_GL_NO_ERROR();
1614
1615 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
1616 GLuint outputValues[kWidth * kHeight];
1617 constexpr GLuint expectedValue = 200;
1618 glUseProgram(0);
1619 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
1620
1621 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture[1], 0, 0);
1622 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, texture[1], 0, 1);
1623 EXPECT_GL_NO_ERROR();
1624 glReadBuffer(GL_COLOR_ATTACHMENT0);
1625 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
1626 EXPECT_GL_NO_ERROR();
1627 for (int i = 0; i < kWidth * kHeight; i++)
1628 {
1629 EXPECT_EQ(expectedValue, outputValues[i]);
1630 }
1631 glReadBuffer(GL_COLOR_ATTACHMENT1);
1632 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
1633 EXPECT_GL_NO_ERROR();
1634 for (int i = 0; i < kWidth * kHeight; i++)
1635 {
1636 EXPECT_EQ(expectedValue, outputValues[i]);
1637 }
1638 }
1639
1640 // Use image uniform to read and write TextureCube in compute shader, and verify the contents.
TEST_P(ComputeShaderTest,BindImageTextureWithTextureCube)1641 TEST_P(ComputeShaderTest, BindImageTextureWithTextureCube)
1642 {
1643 GLTexture texture[2];
1644 GLFramebuffer framebuffer;
1645 constexpr char kCS[] = R"(#version 310 es
1646 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
1647 layout(r32ui, binding = 0) readonly uniform highp uimageCube uImage_1;
1648 layout(r32ui, binding = 1) writeonly uniform highp uimageCube uImage_2;
1649 void main()
1650 {
1651 for (int i = 0; i < 6; i++)
1652 {
1653 uvec4 value = imageLoad(uImage_1, ivec3(gl_LocalInvocationID.xy, i));
1654 imageStore(uImage_2, ivec3(gl_LocalInvocationID.xy, i), value);
1655 }
1656 })";
1657
1658 constexpr int kWidth = 1, kHeight = 1;
1659 constexpr GLuint kInputValues[2][1] = {{200}, {100}};
1660
1661 glBindTexture(GL_TEXTURE_CUBE_MAP, texture[0]);
1662 glTexStorage2D(GL_TEXTURE_CUBE_MAP, 1, GL_R32UI, kWidth, kHeight);
1663 for (GLenum face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
1664 face++)
1665 {
1666 glTexSubImage2D(face, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
1667 kInputValues[0]);
1668 }
1669 EXPECT_GL_NO_ERROR();
1670
1671 glBindTexture(GL_TEXTURE_CUBE_MAP, texture[1]);
1672 glTexStorage2D(GL_TEXTURE_CUBE_MAP, 1, GL_R32UI, kWidth, kHeight);
1673 for (GLenum face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
1674 face++)
1675 {
1676 glTexSubImage2D(face, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
1677 kInputValues[1]);
1678 }
1679 EXPECT_GL_NO_ERROR();
1680
1681 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
1682 glUseProgram(program.get());
1683
1684 glBindImageTexture(0, texture[0], 0, GL_TRUE, 0, GL_READ_ONLY, GL_R32UI);
1685 EXPECT_GL_NO_ERROR();
1686
1687 glBindImageTexture(1, texture[1], 0, GL_TRUE, 0, GL_WRITE_ONLY, GL_R32UI);
1688 EXPECT_GL_NO_ERROR();
1689
1690 glDispatchCompute(1, 1, 1);
1691 EXPECT_GL_NO_ERROR();
1692
1693 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
1694 GLuint outputValues[kWidth * kHeight];
1695 constexpr GLuint expectedValue = 200;
1696 glUseProgram(0);
1697 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
1698
1699 for (GLenum face = 0; face < 6; face++)
1700 {
1701 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
1702 GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, texture[1], 0);
1703 EXPECT_GL_NO_ERROR();
1704 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
1705 EXPECT_GL_NO_ERROR();
1706
1707 for (int i = 0; i < kWidth * kHeight; i++)
1708 {
1709 EXPECT_EQ(expectedValue, outputValues[i]);
1710 }
1711 }
1712 }
1713
1714 // Use image uniform to read and write one layer of Texture2DArray in compute shader, and verify the
1715 // contents.
TEST_P(ComputeShaderTest,BindImageTextureWithOneLayerTexture2DArray)1716 TEST_P(ComputeShaderTest, BindImageTextureWithOneLayerTexture2DArray)
1717 {
1718 GLTexture texture[2];
1719 GLFramebuffer framebuffer;
1720 constexpr char kCS[] = R"(#version 310 es
1721 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
1722 layout(r32ui, binding = 0) readonly uniform highp uimage2D uImage_1;
1723 layout(r32ui, binding = 1) writeonly uniform highp uimage2D uImage_2;
1724 void main()
1725 {
1726 uvec4 value = imageLoad(uImage_1, ivec2(gl_LocalInvocationID.xy));
1727 imageStore(uImage_2, ivec2(gl_LocalInvocationID.xy), value);
1728 })";
1729
1730 constexpr int kWidth = 1, kHeight = 1, kDepth = 2;
1731 constexpr int kResultSize = kWidth * kHeight;
1732 constexpr GLuint kInputValues[2][2] = {{200, 150}, {100, 50}};
1733 constexpr GLuint expectedValue_1 = 200;
1734 constexpr GLuint expectedValue_2 = 100;
1735 GLuint outputValues[kResultSize];
1736
1737 glBindTexture(GL_TEXTURE_2D_ARRAY, texture[0]);
1738 glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_R32UI, kWidth, kHeight, kDepth);
1739 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, kWidth, kHeight, kDepth, GL_RED_INTEGER,
1740 GL_UNSIGNED_INT, kInputValues[0]);
1741 EXPECT_GL_NO_ERROR();
1742
1743 glBindTexture(GL_TEXTURE_2D_ARRAY, texture[1]);
1744 glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_R32UI, kWidth, kHeight, kDepth);
1745 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, kWidth, kHeight, kDepth, GL_RED_INTEGER,
1746 GL_UNSIGNED_INT, kInputValues[1]);
1747 EXPECT_GL_NO_ERROR();
1748
1749 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
1750 glUseProgram(program.get());
1751
1752 glBindImageTexture(0, texture[0], 0, GL_FALSE, 0, GL_READ_ONLY, GL_R32UI);
1753 EXPECT_GL_NO_ERROR();
1754 glBindImageTexture(1, texture[1], 0, GL_FALSE, 1, GL_WRITE_ONLY, GL_R32UI);
1755 EXPECT_GL_NO_ERROR();
1756 glDispatchCompute(1, 1, 1);
1757 EXPECT_GL_NO_ERROR();
1758
1759 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
1760 glUseProgram(0);
1761 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
1762 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture[1], 0, 0);
1763 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, texture[1], 0, 1);
1764 EXPECT_GL_NO_ERROR();
1765 glReadBuffer(GL_COLOR_ATTACHMENT0);
1766 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
1767 EXPECT_GL_NO_ERROR();
1768 for (int i = 0; i < kResultSize; i++)
1769 {
1770 EXPECT_EQ(expectedValue_2, outputValues[i]);
1771 }
1772 glReadBuffer(GL_COLOR_ATTACHMENT1);
1773 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
1774 EXPECT_GL_NO_ERROR();
1775 for (int i = 0; i < kResultSize; i++)
1776 {
1777 EXPECT_EQ(expectedValue_1, outputValues[i]);
1778 }
1779 }
1780
1781 // Use image uniform to read and write one layer of Texture3D in compute shader, and verify the
1782 // contents.
TEST_P(ComputeShaderTest,BindImageTextureWithOneLayerTexture3D)1783 TEST_P(ComputeShaderTest, BindImageTextureWithOneLayerTexture3D)
1784 {
1785 // Vulkan validation error creating a 2D image view of a 3D image layer.
1786 // http://anglebug.com/3886
1787 ANGLE_SKIP_TEST_IF(IsVulkan());
1788
1789 GLTexture texture[2];
1790 GLFramebuffer framebuffer;
1791 constexpr char kCS[] = R"(#version 310 es
1792 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
1793 layout(r32ui, binding = 0) readonly uniform highp uimage2D uImage_1;
1794 layout(r32ui, binding = 1) writeonly uniform highp uimage2D uImage_2;
1795 void main()
1796 {
1797 uvec4 value = imageLoad(uImage_1, ivec2(gl_LocalInvocationID.xy));
1798 imageStore(uImage_2, ivec2(gl_LocalInvocationID.xy), value);
1799 })";
1800
1801 constexpr int kWidth = 1, kHeight = 1, kDepth = 2;
1802 constexpr int kResultSize = kWidth * kHeight;
1803 constexpr GLuint kInputValues[2][2] = {{200, 150}, {100, 50}};
1804 constexpr GLuint expectedValue_1 = 150;
1805 constexpr GLuint expectedValue_2 = 50;
1806 GLuint outputValues[kResultSize];
1807
1808 glBindTexture(GL_TEXTURE_3D, texture[0]);
1809 glTexStorage3D(GL_TEXTURE_3D, 1, GL_R32UI, kWidth, kHeight, kDepth);
1810 glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, kWidth, kHeight, kDepth, GL_RED_INTEGER,
1811 GL_UNSIGNED_INT, kInputValues[0]);
1812 EXPECT_GL_NO_ERROR();
1813
1814 glBindTexture(GL_TEXTURE_3D, texture[1]);
1815 glTexStorage3D(GL_TEXTURE_3D, 1, GL_R32UI, kWidth, kHeight, kDepth);
1816 glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, kWidth, kHeight, kDepth, GL_RED_INTEGER,
1817 GL_UNSIGNED_INT, kInputValues[1]);
1818 EXPECT_GL_NO_ERROR();
1819
1820 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
1821 glUseProgram(program.get());
1822
1823 glBindImageTexture(0, texture[0], 0, GL_FALSE, 1, GL_READ_ONLY, GL_R32UI);
1824 EXPECT_GL_NO_ERROR();
1825 glBindImageTexture(1, texture[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
1826 EXPECT_GL_NO_ERROR();
1827 glDispatchCompute(1, 1, 1);
1828 EXPECT_GL_NO_ERROR();
1829
1830 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
1831 glUseProgram(0);
1832 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
1833 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture[1], 0, 0);
1834 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, texture[1], 0, 1);
1835 EXPECT_GL_NO_ERROR();
1836 glReadBuffer(GL_COLOR_ATTACHMENT0);
1837 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
1838 EXPECT_GL_NO_ERROR();
1839 for (int i = 0; i < kResultSize; i++)
1840 {
1841 EXPECT_EQ(expectedValue_1, outputValues[i]);
1842 }
1843 glReadBuffer(GL_COLOR_ATTACHMENT1);
1844 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
1845 EXPECT_GL_NO_ERROR();
1846 for (int i = 0; i < kResultSize; i++)
1847 {
1848 EXPECT_EQ(expectedValue_2, outputValues[i]);
1849 }
1850 }
1851
1852 // Use image uniform to read and write one layer of TextureCube in compute shader, and verify the
1853 // contents.
TEST_P(ComputeShaderTest,BindImageTextureWithOneLayerTextureCube)1854 TEST_P(ComputeShaderTest, BindImageTextureWithOneLayerTextureCube)
1855 {
1856 // GL_FRAMEBUFFER_BARRIER_BIT is invalid on Nvidia Linux platform.
1857 // http://anglebug.com/3736
1858 ANGLE_SKIP_TEST_IF(IsNVIDIA() && IsOpenGL() && IsLinux());
1859
1860 GLTexture texture[2];
1861 GLFramebuffer framebuffer;
1862 constexpr char kCS[] = R"(#version 310 es
1863 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
1864 layout(r32ui, binding = 0) readonly uniform highp uimage2D uImage_1;
1865 layout(r32ui, binding = 1) writeonly uniform highp uimage2D uImage_2;
1866 void main()
1867 {
1868 uvec4 value = imageLoad(uImage_1, ivec2(gl_LocalInvocationID.xy));
1869 imageStore(uImage_2, ivec2(gl_LocalInvocationID.xy), value);
1870 })";
1871
1872 constexpr int kWidth = 1, kHeight = 1;
1873 constexpr int kResultSize = kWidth * kHeight;
1874 constexpr GLuint kInputValues[2][1] = {{200}, {100}};
1875 constexpr GLuint expectedValue_1 = 200;
1876 constexpr GLuint expectedValue_2 = 100;
1877 GLuint outputValues[kResultSize];
1878
1879 glBindTexture(GL_TEXTURE_CUBE_MAP, texture[0]);
1880 glTexStorage2D(GL_TEXTURE_CUBE_MAP, 1, GL_R32UI, kWidth, kHeight);
1881 for (GLenum face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
1882 face++)
1883 {
1884 glTexSubImage2D(face, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
1885 kInputValues[0]);
1886 }
1887 EXPECT_GL_NO_ERROR();
1888
1889 glBindTexture(GL_TEXTURE_CUBE_MAP, texture[1]);
1890 glTexStorage2D(GL_TEXTURE_CUBE_MAP, 1, GL_R32UI, kWidth, kHeight);
1891 for (GLenum face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
1892 face++)
1893 {
1894 glTexSubImage2D(face, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
1895 kInputValues[1]);
1896 }
1897 EXPECT_GL_NO_ERROR();
1898
1899 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
1900 glUseProgram(program.get());
1901
1902 glBindImageTexture(0, texture[0], 0, GL_FALSE, 3, GL_READ_ONLY, GL_R32UI);
1903 EXPECT_GL_NO_ERROR();
1904 glBindImageTexture(1, texture[1], 0, GL_FALSE, 4, GL_WRITE_ONLY, GL_R32UI);
1905 EXPECT_GL_NO_ERROR();
1906 glDispatchCompute(1, 1, 1);
1907 EXPECT_GL_NO_ERROR();
1908
1909 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
1910 glUseProgram(0);
1911 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
1912
1913 for (GLenum face = 0; face < 6; face++)
1914 {
1915 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
1916 GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, texture[1], 0);
1917 EXPECT_GL_NO_ERROR();
1918 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
1919 EXPECT_GL_NO_ERROR();
1920
1921 if (face == 4)
1922 {
1923 for (int i = 0; i < kResultSize; i++)
1924 {
1925 EXPECT_EQ(expectedValue_1, outputValues[i]);
1926 }
1927 }
1928 else
1929 {
1930 for (int i = 0; i < kResultSize; i++)
1931 {
1932 EXPECT_EQ(expectedValue_2, outputValues[i]);
1933 }
1934 }
1935 }
1936 }
1937
1938 // Test to bind kinds of texture types, bind either the entire texture
1939 // level or a single layer or face of the face level.
TEST_P(ComputeShaderTest,BindImageTextureWithMixTextureTypes)1940 TEST_P(ComputeShaderTest, BindImageTextureWithMixTextureTypes)
1941 {
1942 // GL_FRAMEBUFFER_BARRIER_BIT is invalid on Nvidia Linux platform.
1943 // http://anglebug.com/3736
1944 ANGLE_SKIP_TEST_IF(IsNVIDIA() && IsOpenGL() && IsLinux());
1945
1946 // http://anglebug.com/5072
1947 ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux() && IsOpenGL());
1948
1949 GLTexture texture[4];
1950 GLFramebuffer framebuffer;
1951 const char csSource[] =
1952 R"(#version 310 es
1953 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
1954 layout(r32ui, binding = 0) readonly uniform highp uimage2D uImage_1;
1955 layout(r32ui, binding = 1) readonly uniform highp uimage2D uImage_2;
1956 layout(r32ui, binding = 2) readonly uniform highp uimage3D uImage_3;
1957 layout(r32ui, binding = 3) writeonly uniform highp uimage2D uImage_4;
1958 void main()
1959 {
1960 uvec4 value_1 = imageLoad(uImage_1, ivec2(gl_LocalInvocationID.xy));
1961 uvec4 value_2 = imageLoad(uImage_2, ivec2(gl_LocalInvocationID.xy));
1962 uvec4 value_3 = imageLoad(uImage_3, ivec3(gl_LocalInvocationID.xyz));
1963 imageStore(uImage_4, ivec2(gl_LocalInvocationID.xy), value_1 + value_2 + value_3);
1964 })";
1965
1966 constexpr int kWidth = 1, kHeight = 1, kDepth = 2;
1967 constexpr int kResultSize = kWidth * kHeight;
1968 constexpr GLuint kInputValues2D[1] = {11};
1969 constexpr GLuint KInputValues2DArray[2] = {23, 35};
1970 constexpr GLuint KInputValues3D[2] = {102, 67};
1971 constexpr GLuint KInputValuesCube[1] = {232};
1972
1973 constexpr GLuint expectedValue_1 = 148;
1974 constexpr GLuint expectedValue_2 = 232;
1975 GLuint outputValues[kResultSize];
1976
1977 glBindTexture(GL_TEXTURE_2D, texture[0]);
1978 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kWidth, kHeight);
1979 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
1980 kInputValues2D);
1981 EXPECT_GL_NO_ERROR();
1982
1983 glBindTexture(GL_TEXTURE_2D_ARRAY, texture[1]);
1984 glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_R32UI, kWidth, kHeight, kDepth);
1985 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, kWidth, kHeight, kDepth, GL_RED_INTEGER,
1986 GL_UNSIGNED_INT, KInputValues2DArray);
1987 EXPECT_GL_NO_ERROR();
1988
1989 glBindTexture(GL_TEXTURE_3D, texture[2]);
1990 glTexStorage3D(GL_TEXTURE_3D, 1, GL_R32UI, kWidth, kHeight, kDepth);
1991 glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, kWidth, kHeight, kDepth, GL_RED_INTEGER,
1992 GL_UNSIGNED_INT, KInputValues3D);
1993 EXPECT_GL_NO_ERROR();
1994
1995 glBindTexture(GL_TEXTURE_CUBE_MAP, texture[3]);
1996 glTexStorage2D(GL_TEXTURE_CUBE_MAP, 1, GL_R32UI, kWidth, kHeight);
1997 for (GLenum face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
1998 face++)
1999 {
2000 glTexSubImage2D(face, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
2001 KInputValuesCube);
2002 }
2003 EXPECT_GL_NO_ERROR();
2004
2005 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
2006 glUseProgram(program.get());
2007
2008 glBindImageTexture(0, texture[0], 0, GL_TRUE, 0, GL_READ_ONLY, GL_R32UI);
2009 EXPECT_GL_NO_ERROR();
2010 glBindImageTexture(1, texture[1], 0, GL_FALSE, 1, GL_READ_ONLY, GL_R32UI);
2011 EXPECT_GL_NO_ERROR();
2012 glBindImageTexture(2, texture[2], 0, GL_TRUE, 0, GL_READ_ONLY, GL_R32UI);
2013 EXPECT_GL_NO_ERROR();
2014 glBindImageTexture(3, texture[3], 0, GL_FALSE, 4, GL_WRITE_ONLY, GL_R32UI);
2015 EXPECT_GL_NO_ERROR();
2016 glDispatchCompute(1, 1, 1);
2017 EXPECT_GL_NO_ERROR();
2018
2019 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
2020 glUseProgram(0);
2021 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
2022
2023 for (GLenum face = 0; face < 6; face++)
2024 {
2025 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
2026 GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, texture[3], 0);
2027 EXPECT_GL_NO_ERROR();
2028 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
2029 EXPECT_GL_NO_ERROR();
2030
2031 if (face == 4)
2032 {
2033 for (int i = 0; i < kResultSize; i++)
2034 {
2035 EXPECT_EQ(expectedValue_1, outputValues[i]);
2036 }
2037 }
2038 else
2039 {
2040 for (int i = 0; i < kResultSize; i++)
2041 {
2042 EXPECT_EQ(expectedValue_2, outputValues[i]);
2043 }
2044 }
2045 }
2046 }
2047
2048 // Verify an INVALID_OPERATION error is reported when querying GL_COMPUTE_WORK_GROUP_SIZE for a
2049 // program which has not been linked successfully or which does not contain objects to form a
2050 // compute shader.
TEST_P(ComputeShaderTest,QueryComputeWorkGroupSize)2051 TEST_P(ComputeShaderTest, QueryComputeWorkGroupSize)
2052 {
2053 constexpr char kVS[] = R"(#version 310 es
2054 void main()
2055 {
2056 })";
2057
2058 constexpr char kFS[] = R"(#version 310 es
2059 void main()
2060 {
2061 })";
2062
2063 GLint workGroupSize[3];
2064
2065 ANGLE_GL_PROGRAM(graphicsProgram, kVS, kFS);
2066 glGetProgramiv(graphicsProgram, GL_COMPUTE_WORK_GROUP_SIZE, workGroupSize);
2067 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2068
2069 GLuint computeProgram = glCreateProgram();
2070 GLShader computeShader(GL_COMPUTE_SHADER);
2071 glAttachShader(computeProgram, computeShader);
2072 glLinkProgram(computeProgram);
2073 glDetachShader(computeProgram, computeShader);
2074
2075 GLint linkStatus;
2076 glGetProgramiv(computeProgram, GL_LINK_STATUS, &linkStatus);
2077 ASSERT_GL_FALSE(linkStatus);
2078
2079 glGetProgramiv(computeProgram, GL_COMPUTE_WORK_GROUP_SIZE, workGroupSize);
2080 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
2081
2082 glDeleteProgram(computeProgram);
2083
2084 ASSERT_GL_NO_ERROR();
2085 }
2086
2087 // Use groupMemoryBarrier and barrier to sync reads/writes order and the execution
2088 // order of multiple shader invocations in compute shader.
TEST_P(ComputeShaderTest,GroupMemoryBarrierAndBarrierTest)2089 TEST_P(ComputeShaderTest, GroupMemoryBarrierAndBarrierTest)
2090 {
2091 // TODO(xinghua.cao@intel.com): Figure out why we get this error message
2092 // that shader uses features not recognized by this D3D version.
2093 ANGLE_SKIP_TEST_IF((IsAMD() || IsNVIDIA()) && IsD3D11());
2094 ANGLE_SKIP_TEST_IF(IsARM64() && IsWindows() && IsD3D());
2095
2096 // http://anglebug.com/5072
2097 ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux() && IsOpenGL());
2098
2099 GLTexture texture;
2100 GLFramebuffer framebuffer;
2101
2102 // Each invocation first stores a single value in an image, then each invocation sums up
2103 // all the values in the image and stores the sum in the image. groupMemoryBarrier is
2104 // used to order reads/writes to variables stored in memory accessible to other shader
2105 // invocations, and barrier is used to control the relative execution order of multiple
2106 // shader invocations used to process a local work group.
2107 constexpr char kCS[] = R"(#version 310 es
2108 layout(local_size_x=2, local_size_y=2, local_size_z=1) in;
2109 layout(r32i, binding = 0) uniform highp iimage2D image;
2110 void main()
2111 {
2112 uint x = gl_LocalInvocationID.x;
2113 uint y = gl_LocalInvocationID.y;
2114 imageStore(image, ivec2(gl_LocalInvocationID.xy), ivec4(x + y));
2115 groupMemoryBarrier();
2116 barrier();
2117 int sum = 0;
2118 for (int i = 0; i < 2; i++)
2119 {
2120 for(int j = 0; j < 2; j++)
2121 {
2122 sum += imageLoad(image, ivec2(i, j)).x;
2123 }
2124 }
2125 groupMemoryBarrier();
2126 barrier();
2127 imageStore(image, ivec2(gl_LocalInvocationID.xy), ivec4(sum));
2128 })";
2129
2130 constexpr int kWidth = 2, kHeight = 2;
2131 glBindTexture(GL_TEXTURE_2D, texture);
2132 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32I, kWidth, kHeight);
2133 EXPECT_GL_NO_ERROR();
2134
2135 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
2136 glUseProgram(program.get());
2137
2138 glBindImageTexture(0, texture, 0, GL_FALSE, 0, GL_READ_WRITE, GL_R32I);
2139 EXPECT_GL_NO_ERROR();
2140
2141 glDispatchCompute(1, 1, 1);
2142 EXPECT_GL_NO_ERROR();
2143
2144 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
2145 GLuint outputValues[kWidth * kHeight];
2146 constexpr GLuint kExpectedValue = 4;
2147 glUseProgram(0);
2148 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
2149
2150 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
2151 EXPECT_GL_NO_ERROR();
2152 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_INT, outputValues);
2153 EXPECT_GL_NO_ERROR();
2154
2155 for (int i = 0; i < kWidth * kHeight; i++)
2156 {
2157 EXPECT_EQ(kExpectedValue, outputValues[i]);
2158 }
2159 }
2160
2161 // Verify that a link error is generated when the sum of the number of active image uniforms and
2162 // active shader storage blocks in a compute shader exceeds GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES.
TEST_P(ComputeShaderTest,ExceedCombinedShaderOutputResourcesInCS)2163 TEST_P(ComputeShaderTest, ExceedCombinedShaderOutputResourcesInCS)
2164 {
2165 GLint maxCombinedShaderOutputResources;
2166 GLint maxComputeShaderStorageBlocks;
2167 GLint maxComputeImageUniforms;
2168
2169 glGetIntegerv(GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES, &maxCombinedShaderOutputResources);
2170 glGetIntegerv(GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS, &maxComputeShaderStorageBlocks);
2171 glGetIntegerv(GL_MAX_COMPUTE_IMAGE_UNIFORMS, &maxComputeImageUniforms);
2172
2173 ANGLE_SKIP_TEST_IF(maxCombinedShaderOutputResources >=
2174 maxComputeShaderStorageBlocks + maxComputeImageUniforms);
2175
2176 std::ostringstream computeShaderStream;
2177 computeShaderStream << "#version 310 es\n"
2178 "layout(local_size_x = 3, local_size_y = 1, local_size_z = 1) in;\n"
2179 "layout(shared, binding = 0) buffer blockName"
2180 "{\n"
2181 " uint data;\n"
2182 "} instance["
2183 << maxComputeShaderStorageBlocks << "];\n";
2184
2185 ASSERT_GE(maxComputeImageUniforms, 4);
2186 int numImagesInArray = maxComputeImageUniforms / 2;
2187 int numImagesNonArray = maxComputeImageUniforms - numImagesInArray;
2188 for (int i = 0; i < numImagesNonArray; ++i)
2189 {
2190 computeShaderStream << "layout(r32f, binding = " << i << ") uniform highp image2D image"
2191 << i << ";\n";
2192 }
2193
2194 computeShaderStream << "layout(r32f, binding = " << numImagesNonArray
2195 << ") uniform highp image2D imageArray[" << numImagesInArray << "];\n";
2196
2197 computeShaderStream << "void main()\n"
2198 "{\n"
2199 " uint val = 0u;\n"
2200 " vec4 val2 = vec4(0.0);\n";
2201
2202 for (int i = 0; i < maxComputeShaderStorageBlocks; ++i)
2203 {
2204 computeShaderStream << " val += instance[" << i << "].data; \n";
2205 }
2206
2207 for (int i = 0; i < numImagesNonArray; ++i)
2208 {
2209 computeShaderStream << " val2 += imageLoad(image" << i
2210 << ", ivec2(gl_LocalInvocationID.xy)); \n";
2211 }
2212
2213 for (int i = 0; i < numImagesInArray; ++i)
2214 {
2215 computeShaderStream << " val2 += imageLoad(imageArray[" << i << "]"
2216 << ", ivec2(gl_LocalInvocationID.xy)); \n";
2217 }
2218
2219 computeShaderStream << " instance[0].data = val + uint(val2.x);\n"
2220 "}\n";
2221
2222 GLuint computeProgram = CompileComputeProgram(computeShaderStream.str().c_str());
2223 EXPECT_EQ(0u, computeProgram);
2224 }
2225
2226 // Test that uniform block with struct member in compute shader is supported.
TEST_P(ComputeShaderTest,UniformBlockWithStructMember)2227 TEST_P(ComputeShaderTest, UniformBlockWithStructMember)
2228 {
2229 constexpr char kCS[] = R"(#version 310 es
2230 layout(local_size_x=8) in;
2231 layout(rgba8) uniform highp readonly image2D mImage2DInput;
2232 layout(rgba8) uniform highp writeonly image2D mImage2DOutput;
2233 struct S {
2234 ivec3 a;
2235 ivec2 b;
2236 };
2237
2238 layout(std140, binding=0) uniform blockName {
2239 S bd;
2240 } instanceName;
2241 void main()
2242 {
2243 ivec2 t1 = instanceName.bd.b;
2244 vec4 result2d = imageLoad(mImage2DInput, t1);
2245 imageStore(mImage2DOutput, ivec2(gl_LocalInvocationID.xy), result2d);
2246 })";
2247
2248 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
2249 EXPECT_GL_NO_ERROR();
2250 }
2251
2252 // Verify shared non-array variables can work correctly.
TEST_P(ComputeShaderTest,NonArraySharedVariable)2253 TEST_P(ComputeShaderTest, NonArraySharedVariable)
2254 {
2255 // http://anglebug.com/5072
2256 ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux() && IsOpenGL());
2257
2258 const char kCSShader[] = R"(#version 310 es
2259 layout (local_size_x = 2, local_size_y = 2, local_size_z = 1) in;
2260 layout (r32ui, binding = 0) readonly uniform highp uimage2D srcImage;
2261 layout (r32ui, binding = 1) writeonly uniform highp uimage2D dstImage;
2262 shared uint temp;
2263 void main()
2264 {
2265 if (gl_LocalInvocationID == uvec3(0, 0, 0))
2266 {
2267 temp = imageLoad(srcImage, ivec2(gl_LocalInvocationID.xy)).x;
2268 }
2269 groupMemoryBarrier();
2270 barrier();
2271 if (gl_LocalInvocationID == uvec3(1, 1, 0))
2272 {
2273 imageStore(dstImage, ivec2(gl_LocalInvocationID.xy), uvec4(temp));
2274 }
2275 else
2276 {
2277 uint inputValue = imageLoad(srcImage, ivec2(gl_LocalInvocationID.xy)).x;
2278 imageStore(dstImage, ivec2(gl_LocalInvocationID.xy), uvec4(inputValue));
2279 }
2280 })";
2281
2282 const std::array<GLuint, 4> inputData = {{250, 200, 150, 100}};
2283 const std::array<GLuint, 4> expectedValues = {{250, 200, 150, 250}};
2284 runSharedMemoryTest<GLuint, 2, 2>(kCSShader, GL_R32UI, GL_UNSIGNED_INT, inputData,
2285 expectedValues);
2286 }
2287
2288 // Verify shared non-struct array variables can work correctly.
TEST_P(ComputeShaderTest,NonStructArrayAsSharedVariable)2289 TEST_P(ComputeShaderTest, NonStructArrayAsSharedVariable)
2290 {
2291 // http://anglebug.com/5072
2292 ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux() && IsOpenGL());
2293
2294 const char kCSShader[] = R"(#version 310 es
2295 layout (local_size_x = 2, local_size_y = 2, local_size_z = 1) in;
2296 layout (r32ui, binding = 0) readonly uniform highp uimage2D srcImage;
2297 layout (r32ui, binding = 1) writeonly uniform highp uimage2D dstImage;
2298 shared uint sharedData[2][2];
2299 void main()
2300 {
2301 uint inputData = imageLoad(srcImage, ivec2(gl_LocalInvocationID.xy)).x;
2302 sharedData[gl_LocalInvocationID.x][gl_LocalInvocationID.y] = inputData;
2303 groupMemoryBarrier();
2304 barrier();
2305 imageStore(dstImage, ivec2(gl_LocalInvocationID.xy),
2306 uvec4(sharedData[gl_LocalInvocationID.y][gl_LocalInvocationID.x]));
2307 })";
2308
2309 const std::array<GLuint, 4> inputData = {{250, 200, 150, 100}};
2310 const std::array<GLuint, 4> expectedValues = {{250, 150, 200, 100}};
2311 runSharedMemoryTest<GLuint, 2, 2>(kCSShader, GL_R32UI, GL_UNSIGNED_INT, inputData,
2312 expectedValues);
2313 }
2314
2315 // Verify shared struct array variables work correctly.
TEST_P(ComputeShaderTest,StructArrayAsSharedVariable)2316 TEST_P(ComputeShaderTest, StructArrayAsSharedVariable)
2317 {
2318 // http://anglebug.com/5072
2319 ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux() && IsOpenGL());
2320
2321 const char kCSShader[] = R"(#version 310 es
2322 layout (local_size_x = 2, local_size_y = 2, local_size_z = 1) in;
2323 layout (r32ui, binding = 0) readonly uniform highp uimage2D srcImage;
2324 layout (r32ui, binding = 1) writeonly uniform highp uimage2D dstImage;
2325 struct SharedStruct
2326 {
2327 uint data;
2328 };
2329 shared SharedStruct sharedData[2][2];
2330 void main()
2331 {
2332 uint inputData = imageLoad(srcImage, ivec2(gl_LocalInvocationID.xy)).x;
2333 sharedData[gl_LocalInvocationID.x][gl_LocalInvocationID.y].data = inputData;
2334 groupMemoryBarrier();
2335 barrier();
2336 imageStore(dstImage, ivec2(gl_LocalInvocationID.xy),
2337 uvec4(sharedData[gl_LocalInvocationID.y][gl_LocalInvocationID.x].data));
2338 })";
2339
2340 const std::array<GLuint, 4> inputData = {{250, 200, 150, 100}};
2341 const std::array<GLuint, 4> expectedValues = {{250, 150, 200, 100}};
2342 runSharedMemoryTest<GLuint, 2, 2>(kCSShader, GL_R32UI, GL_UNSIGNED_INT, inputData,
2343 expectedValues);
2344 }
2345
2346 // Verify using atomic functions without return value can work correctly.
TEST_P(ComputeShaderTest,AtomicFunctionsNoReturnValue)2347 TEST_P(ComputeShaderTest, AtomicFunctionsNoReturnValue)
2348 {
2349 // http://anglebug.com/5072
2350 ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux() && IsOpenGL());
2351
2352 // Fails on AMD windows drivers. http://anglebug.com/3872
2353 ANGLE_SKIP_TEST_IF(IsWindows() && IsAMD() && IsVulkan());
2354
2355 // Fails to link on Android. http://anglebug.com/3874
2356 ANGLE_SKIP_TEST_IF(IsAndroid());
2357
2358 ANGLE_SKIP_TEST_IF(IsARM64() && IsWindows() && IsD3D());
2359
2360 const char kCSShader[] = R"(#version 310 es
2361 layout (local_size_x = 8, local_size_y = 1, local_size_z = 1) in;
2362 layout (r32ui, binding = 0) readonly uniform highp uimage2D srcImage;
2363 layout (r32ui, binding = 1) writeonly uniform highp uimage2D dstImage;
2364
2365 const uint kSumIndex = 0u;
2366 const uint kMinIndex = 1u;
2367 const uint kMaxIndex = 2u;
2368 const uint kOrIndex = 3u;
2369 const uint kAndIndex = 4u;
2370 const uint kXorIndex = 5u;
2371 const uint kExchangeIndex = 6u;
2372 const uint kCompSwapIndex = 7u;
2373
2374 shared highp uint results[8];
2375
2376 void main()
2377 {
2378 if (gl_LocalInvocationID.x == kMinIndex || gl_LocalInvocationID.x == kAndIndex)
2379 {
2380 results[gl_LocalInvocationID.x] = 0xFFFFu;
2381 }
2382 else if (gl_LocalInvocationID.x == kCompSwapIndex)
2383 {
2384 results[gl_LocalInvocationID.x] = 1u;
2385 }
2386 else
2387 {
2388 results[gl_LocalInvocationID.x] = 0u;
2389 }
2390 memoryBarrierShared();
2391 barrier();
2392
2393 uint value = imageLoad(srcImage, ivec2(gl_LocalInvocationID.xy)).x;
2394 atomicAdd(results[kSumIndex], value);
2395 atomicMin(results[kMinIndex], value);
2396 atomicMax(results[kMaxIndex], value);
2397 atomicOr(results[kOrIndex], value);
2398 atomicAnd(results[kAndIndex], value);
2399 atomicXor(results[kXorIndex], value);
2400 atomicExchange(results[kExchangeIndex], value);
2401 atomicCompSwap(results[kCompSwapIndex], value, 256u);
2402 memoryBarrierShared();
2403 barrier();
2404
2405 imageStore(dstImage, ivec2(gl_LocalInvocationID.xy),
2406 uvec4(results[gl_LocalInvocationID.x]));
2407 })";
2408
2409 const std::array<GLuint, 8> inputData = {{1, 2, 4, 8, 16, 32, 64, 128}};
2410 const std::array<GLuint, 8> expectedValues = {{255, 1, 128, 255, 0, 255, 128, 256}};
2411 runSharedMemoryTest<GLuint, 8, 1>(kCSShader, GL_R32UI, GL_UNSIGNED_INT, inputData,
2412 expectedValues);
2413 }
2414
2415 // Verify using atomic functions in a non-initializer single assignment can work correctly.
TEST_P(ComputeShaderTest,AtomicFunctionsInNonInitializerSingleAssignment)2416 TEST_P(ComputeShaderTest, AtomicFunctionsInNonInitializerSingleAssignment)
2417 {
2418 // http://anglebug.com/5072
2419 ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux() && IsOpenGL());
2420
2421 // Fails on AMD windows drivers. http://anglebug.com/3872
2422 ANGLE_SKIP_TEST_IF(IsWindows() && IsAMD() && IsVulkan());
2423
2424 const char kCSShader[] = R"(#version 310 es
2425 layout (local_size_x = 9, local_size_y = 1, local_size_z = 1) in;
2426 layout (r32i, binding = 0) readonly uniform highp iimage2D srcImage;
2427 layout (r32i, binding = 1) writeonly uniform highp iimage2D dstImage;
2428
2429 shared highp int sharedVariable;
2430
2431 shared highp int inputData[9];
2432 shared highp int outputData[9];
2433
2434 void main()
2435 {
2436 int inputValue = imageLoad(srcImage, ivec2(gl_LocalInvocationID.xy)).x;
2437 inputData[gl_LocalInvocationID.x] = inputValue;
2438 memoryBarrierShared();
2439 barrier();
2440
2441 if (gl_LocalInvocationID.x == 0u)
2442 {
2443 sharedVariable = 0;
2444
2445 outputData[0] = atomicAdd(sharedVariable, inputData[0]);
2446 outputData[1] = atomicMin(sharedVariable, inputData[1]);
2447 outputData[2] = atomicMax(sharedVariable, inputData[2]);
2448 outputData[3] = atomicAnd(sharedVariable, inputData[3]);
2449 outputData[4] = atomicOr(sharedVariable, inputData[4]);
2450 outputData[5] = atomicXor(sharedVariable, inputData[5]);
2451 outputData[6] = atomicExchange(sharedVariable, inputData[6]);
2452 outputData[7] = atomicCompSwap(sharedVariable, 64, inputData[7]);
2453 outputData[8] = atomicAdd(sharedVariable, inputData[8]);
2454 }
2455 memoryBarrierShared();
2456 barrier();
2457
2458 imageStore(dstImage, ivec2(gl_LocalInvocationID.xy),
2459 ivec4(outputData[gl_LocalInvocationID.x]));
2460 })";
2461
2462 const std::array<GLint, 9> inputData = {{1, 2, 4, 8, 16, 32, 64, 128, 1}};
2463 const std::array<GLint, 9> expectedValues = {{0, 1, 1, 4, 0, 16, 48, 64, 128}};
2464 runSharedMemoryTest<GLint, 9, 1>(kCSShader, GL_R32I, GL_INT, inputData, expectedValues);
2465 }
2466
2467 // Verify using atomic functions in an initializers and using unsigned int works correctly.
TEST_P(ComputeShaderTest,AtomicFunctionsInitializerWithUnsigned)2468 TEST_P(ComputeShaderTest, AtomicFunctionsInitializerWithUnsigned)
2469 {
2470 // http://anglebug.com/5072
2471 ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux() && IsOpenGL());
2472
2473 // Fails on AMD windows drivers. http://anglebug.com/3872
2474 ANGLE_SKIP_TEST_IF(IsWindows() && IsAMD() && IsVulkan());
2475
2476 constexpr char kCShader[] = R"(#version 310 es
2477 layout (local_size_x = 9, local_size_y = 1, local_size_z = 1) in;
2478 layout (r32ui, binding = 0) readonly uniform highp uimage2D srcImage;
2479 layout (r32ui, binding = 1) writeonly uniform highp uimage2D dstImage;
2480
2481 shared highp uint sharedVariable;
2482
2483 shared highp uint inputData[9];
2484 shared highp uint outputData[9];
2485
2486 void main()
2487 {
2488 uint inputValue = imageLoad(srcImage, ivec2(gl_LocalInvocationID.xy)).x;
2489 inputData[gl_LocalInvocationID.x] = inputValue;
2490 memoryBarrierShared();
2491 barrier();
2492
2493 if (gl_LocalInvocationID.x == 0u)
2494 {
2495 sharedVariable = 0u;
2496
2497 uint addValue = atomicAdd(sharedVariable, inputData[0]);
2498 outputData[0] = addValue;
2499 uint minValue = atomicMin(sharedVariable, inputData[1]);
2500 outputData[1] = minValue;
2501 uint maxValue = atomicMax(sharedVariable, inputData[2]);
2502 outputData[2] = maxValue;
2503 uint andValue = atomicAnd(sharedVariable, inputData[3]);
2504 outputData[3] = andValue;
2505 uint orValue = atomicOr(sharedVariable, inputData[4]);
2506 outputData[4] = orValue;
2507 uint xorValue = atomicXor(sharedVariable, inputData[5]);
2508 outputData[5] = xorValue;
2509 uint exchangeValue = atomicExchange(sharedVariable, inputData[6]);
2510 outputData[6] = exchangeValue;
2511 uint compSwapValue = atomicCompSwap(sharedVariable, 64u, inputData[7]);
2512 outputData[7] = compSwapValue;
2513 uint sharedVariable = atomicAdd(sharedVariable, inputData[8]);
2514 outputData[8] = sharedVariable;
2515
2516 }
2517 memoryBarrierShared();
2518 barrier();
2519
2520 imageStore(dstImage, ivec2(gl_LocalInvocationID.xy),
2521 uvec4(outputData[gl_LocalInvocationID.x]));
2522 })";
2523
2524 constexpr std::array<GLuint, 9> kInputData = {{1, 2, 4, 8, 16, 32, 64, 128, 1}};
2525 constexpr std::array<GLuint, 9> kExpectedValues = {{0, 1, 1, 4, 0, 16, 48, 64, 128}};
2526 runSharedMemoryTest<GLuint, 9, 1>(kCShader, GL_R32UI, GL_UNSIGNED_INT, kInputData,
2527 kExpectedValues);
2528 }
2529
2530 // Verify using atomic functions inside expressions as unsigned int.
TEST_P(ComputeShaderTest,AtomicFunctionsReturnWithUnsigned)2531 TEST_P(ComputeShaderTest, AtomicFunctionsReturnWithUnsigned)
2532 {
2533 // http://anglebug.com/5072
2534 ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux() && IsOpenGL());
2535
2536 // Fails on AMD windows drivers. http://anglebug.com/3872
2537 ANGLE_SKIP_TEST_IF(IsWindows() && IsAMD() && IsVulkan());
2538
2539 constexpr char kCShader[] = R"(#version 310 es
2540 layout (local_size_x = 9, local_size_y = 1, local_size_z = 1) in;
2541 layout (r32ui, binding = 0) readonly uniform highp uimage2D srcImage;
2542 layout (r32ui, binding = 1) writeonly uniform highp uimage2D dstImage;
2543
2544 shared highp uint sharedVariable;
2545
2546 shared highp uint inputData[9];
2547 shared highp uint outputData[9];
2548
2549 void main()
2550 {
2551 uint inputValue = imageLoad(srcImage, ivec2(gl_LocalInvocationID.xy)).x;
2552 inputData[gl_LocalInvocationID.x] = inputValue;
2553 memoryBarrierShared();
2554 barrier();
2555
2556 if (gl_LocalInvocationID.x == 0u)
2557 {
2558 sharedVariable = 0u;
2559
2560 outputData[0] = 1u + atomicAdd(sharedVariable, inputData[0]);
2561 outputData[1] = 1u + atomicMin(sharedVariable, inputData[1]);
2562 outputData[2] = 1u + atomicMax(sharedVariable, inputData[2]);
2563 outputData[3] = 1u + atomicAnd(sharedVariable, inputData[3]);
2564 outputData[4] = 1u + atomicOr(sharedVariable, inputData[4]);
2565 outputData[5] = 1u + atomicXor(sharedVariable, inputData[5]);
2566 outputData[6] = 1u + atomicExchange(sharedVariable, inputData[6]);
2567 outputData[7] = 1u + atomicCompSwap(sharedVariable, 64u, inputData[7]);
2568 outputData[8] = 1u + atomicAdd(sharedVariable, inputData[8]);
2569 }
2570 memoryBarrierShared();
2571 barrier();
2572
2573 imageStore(dstImage, ivec2(gl_LocalInvocationID.xy),
2574 uvec4(outputData[gl_LocalInvocationID.x]));
2575 })";
2576
2577 constexpr std::array<GLuint, 9> kInputData = {{1, 2, 4, 8, 16, 32, 64, 128, 1}};
2578 constexpr std::array<GLuint, 9> kExpectedValues = {{1, 2, 2, 5, 1, 17, 49, 65, 129}};
2579 runSharedMemoryTest<GLuint, 9, 1>(kCShader, GL_R32UI, GL_UNSIGNED_INT, kInputData,
2580 kExpectedValues);
2581 }
2582
2583 // Verify using nested atomic functions in expressions.
TEST_P(ComputeShaderTest,AtomicFunctionsReturnWithMultipleTypes)2584 TEST_P(ComputeShaderTest, AtomicFunctionsReturnWithMultipleTypes)
2585 {
2586 // http://anglebug.com/5072
2587 ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux() && IsOpenGL());
2588
2589 constexpr char kCShader[] = R"(#version 310 es
2590 layout (local_size_x = 4, local_size_y = 1, local_size_z = 1) in;
2591 layout (r32ui, binding = 0) readonly uniform highp uimage2D srcImage;
2592 layout (r32ui, binding = 1) writeonly uniform highp uimage2D dstImage;
2593
2594 shared highp uint sharedVariable;
2595 shared highp int indexVariable;
2596
2597 shared highp uint inputData[4];
2598 shared highp uint outputData[4];
2599
2600 void main()
2601 {
2602 uint inputValue = imageLoad(srcImage, ivec2(gl_LocalInvocationID.xy)).x;
2603 inputData[gl_LocalInvocationID.x] = inputValue;
2604 memoryBarrierShared();
2605 barrier();
2606
2607 if (gl_LocalInvocationID.x == 0u)
2608 {
2609 sharedVariable = 0u;
2610 indexVariable = 2;
2611
2612 outputData[0] = 1u + atomicAdd(sharedVariable, inputData[atomicAdd(indexVariable, -1)]);
2613 outputData[1] = 1u + atomicAdd(sharedVariable, inputData[atomicAdd(indexVariable, -1)]);
2614 outputData[2] = 1u + atomicAdd(sharedVariable, inputData[atomicAdd(indexVariable, -1)]);
2615 outputData[3] = atomicAdd(sharedVariable, 0u);
2616
2617 }
2618 memoryBarrierShared();
2619 barrier();
2620
2621 imageStore(dstImage, ivec2(gl_LocalInvocationID.xy),
2622 uvec4(outputData[gl_LocalInvocationID.x]));
2623 })";
2624
2625 constexpr std::array<GLuint, 4> kInputData = {{1, 2, 3, 0}};
2626 constexpr std::array<GLuint, 4> kExpectedValues = {{1, 4, 6, 6}};
2627 runSharedMemoryTest<GLuint, 4, 1>(kCShader, GL_R32UI, GL_UNSIGNED_INT, kInputData,
2628 kExpectedValues);
2629 }
2630
2631 // Basic uniform buffer functionality.
TEST_P(ComputeShaderTest,UniformBuffer)2632 TEST_P(ComputeShaderTest, UniformBuffer)
2633 {
2634 // http://anglebug.com/5072
2635 ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux() && IsOpenGL());
2636
2637 GLTexture texture;
2638 GLBuffer buffer;
2639 GLFramebuffer framebuffer;
2640 constexpr char kCS[] = R"(#version 310 es
2641 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
2642 uniform uni
2643 {
2644 uvec4 value;
2645 };
2646 layout(rgba32ui, binding = 0) writeonly uniform highp uimage2D uImage;
2647 void main()
2648 {
2649 imageStore(uImage, ivec2(gl_LocalInvocationID.xy), value);
2650 })";
2651
2652 constexpr int kWidth = 1, kHeight = 1;
2653 constexpr GLuint kInputValues[4] = {56, 57, 58, 59};
2654
2655 glBindTexture(GL_TEXTURE_2D, texture);
2656 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32UI, kWidth, kHeight);
2657 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RGBA_INTEGER, GL_UNSIGNED_INT,
2658 kInputValues);
2659 EXPECT_GL_NO_ERROR();
2660
2661 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
2662 glUseProgram(program.get());
2663
2664 GLint uniformBufferIndex = glGetUniformBlockIndex(program, "uni");
2665 EXPECT_NE(uniformBufferIndex, -1);
2666 GLuint data[4] = {201, 202, 203, 204};
2667 glBindBuffer(GL_UNIFORM_BUFFER, buffer);
2668 glBufferData(GL_UNIFORM_BUFFER, sizeof(GLuint) * 4, data, GL_STATIC_DRAW);
2669 glBindBufferBase(GL_UNIFORM_BUFFER, 0, buffer);
2670 glUniformBlockBinding(program, uniformBufferIndex, 0);
2671 EXPECT_GL_NO_ERROR();
2672
2673 glBindImageTexture(0, texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32UI);
2674 EXPECT_GL_NO_ERROR();
2675
2676 glDispatchCompute(1, 1, 1);
2677 EXPECT_GL_NO_ERROR();
2678
2679 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
2680 GLuint outputValues[kWidth * kHeight * 4];
2681 glUseProgram(0);
2682 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
2683
2684 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
2685 EXPECT_GL_NO_ERROR();
2686 glReadPixels(0, 0, kWidth, kHeight, GL_RGBA_INTEGER, GL_UNSIGNED_INT, outputValues);
2687 EXPECT_GL_NO_ERROR();
2688
2689 for (int i = 0; i < kWidth * kHeight * 4; i++)
2690 {
2691 EXPECT_EQ(data[i], outputValues[i]);
2692 }
2693 }
2694
2695 // Test that storing data to image and then loading the same image data works correctly.
TEST_P(ComputeShaderTest,StoreImageThenLoad)2696 TEST_P(ComputeShaderTest, StoreImageThenLoad)
2697 {
2698 // http://anglebug.com/5072
2699 ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux() && IsOpenGL());
2700
2701 const char kCSSource[] = R"(#version 310 es
2702 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
2703 layout(r32ui, binding = 0) readonly uniform highp uimage2D uImage_1;
2704 layout(r32ui, binding = 1) writeonly uniform highp uimage2D uImage_2;
2705 void main()
2706 {
2707 uvec4 value = imageLoad(uImage_1, ivec2(gl_LocalInvocationID.xy));
2708 imageStore(uImage_2, ivec2(gl_LocalInvocationID.xy), value);
2709 })";
2710
2711 constexpr GLuint kInputValues[3][1] = {{300}, {200}, {100}};
2712 GLTexture texture[3];
2713 glBindTexture(GL_TEXTURE_2D, texture[0]);
2714 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, 1, 1);
2715 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RED_INTEGER, GL_UNSIGNED_INT, kInputValues[0]);
2716 EXPECT_GL_NO_ERROR();
2717
2718 glBindTexture(GL_TEXTURE_2D, texture[1]);
2719 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, 1, 1);
2720 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RED_INTEGER, GL_UNSIGNED_INT, kInputValues[1]);
2721 EXPECT_GL_NO_ERROR();
2722
2723 glBindTexture(GL_TEXTURE_2D, texture[2]);
2724 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, 1, 1);
2725 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RED_INTEGER, GL_UNSIGNED_INT, kInputValues[2]);
2726 EXPECT_GL_NO_ERROR();
2727
2728 ANGLE_GL_COMPUTE_PROGRAM(program, kCSSource);
2729 glUseProgram(program.get());
2730
2731 glBindImageTexture(0, texture[0], 0, GL_FALSE, 0, GL_READ_ONLY, GL_R32UI);
2732 glBindImageTexture(1, texture[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
2733
2734 glDispatchCompute(1, 1, 1);
2735 glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
2736 EXPECT_GL_NO_ERROR();
2737
2738 glBindImageTexture(0, texture[1], 0, GL_FALSE, 0, GL_READ_ONLY, GL_R32UI);
2739 glBindImageTexture(1, texture[2], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
2740
2741 glDispatchCompute(1, 1, 1);
2742 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
2743 EXPECT_GL_NO_ERROR();
2744
2745 GLuint outputValue;
2746 GLFramebuffer framebuffer;
2747 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
2748 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture[2], 0);
2749 glReadPixels(0, 0, 1, 1, GL_RED_INTEGER, GL_UNSIGNED_INT, &outputValue);
2750 EXPECT_GL_NO_ERROR();
2751
2752 EXPECT_EQ(300u, outputValue);
2753 }
2754
2755 // Test that loading image data and then storing data to the same image works correctly.
TEST_P(ComputeShaderTest,LoadImageThenStore)2756 TEST_P(ComputeShaderTest, LoadImageThenStore)
2757 {
2758 // http://anglebug.com/5072
2759 ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux() && IsOpenGL());
2760
2761 const char kCSSource[] = R"(#version 310 es
2762 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
2763 layout(r32ui, binding = 0) readonly uniform highp uimage2D uImage_1;
2764 layout(r32ui, binding = 1) writeonly uniform highp uimage2D uImage_2;
2765 void main()
2766 {
2767 uvec4 value = imageLoad(uImage_1, ivec2(gl_LocalInvocationID.xy));
2768 imageStore(uImage_2, ivec2(gl_LocalInvocationID.xy), value);
2769 })";
2770
2771 constexpr GLuint kInputValues[3][1] = {{300}, {200}, {100}};
2772 GLTexture texture[3];
2773 glBindTexture(GL_TEXTURE_2D, texture[0]);
2774 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, 1, 1);
2775 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RED_INTEGER, GL_UNSIGNED_INT, kInputValues[0]);
2776 EXPECT_GL_NO_ERROR();
2777
2778 glBindTexture(GL_TEXTURE_2D, texture[1]);
2779 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, 1, 1);
2780 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RED_INTEGER, GL_UNSIGNED_INT, kInputValues[1]);
2781 EXPECT_GL_NO_ERROR();
2782
2783 glBindTexture(GL_TEXTURE_2D, texture[2]);
2784 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, 1, 1);
2785 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RED_INTEGER, GL_UNSIGNED_INT, kInputValues[2]);
2786 EXPECT_GL_NO_ERROR();
2787
2788 ANGLE_GL_COMPUTE_PROGRAM(program, kCSSource);
2789 glUseProgram(program.get());
2790
2791 glBindImageTexture(0, texture[0], 0, GL_FALSE, 0, GL_READ_ONLY, GL_R32UI);
2792 glBindImageTexture(1, texture[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
2793
2794 glDispatchCompute(1, 1, 1);
2795 glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
2796 EXPECT_GL_NO_ERROR();
2797
2798 glBindImageTexture(0, texture[2], 0, GL_FALSE, 0, GL_READ_ONLY, GL_R32UI);
2799 glBindImageTexture(1, texture[0], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
2800
2801 glDispatchCompute(1, 1, 1);
2802 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
2803 EXPECT_GL_NO_ERROR();
2804
2805 GLuint outputValue;
2806 GLFramebuffer framebuffer;
2807 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
2808 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture[0], 0);
2809 glReadPixels(0, 0, 1, 1, GL_RED_INTEGER, GL_UNSIGNED_INT, &outputValue);
2810 EXPECT_GL_NO_ERROR();
2811
2812 EXPECT_EQ(100u, outputValue);
2813 }
2814
2815 // Test that the length of a struct buffer variable is supported.
TEST_P(ComputeShaderTest,ShaderStorageBlocksStructLength)2816 TEST_P(ComputeShaderTest, ShaderStorageBlocksStructLength)
2817 {
2818 const char kCSSource[] = R"(#version 310 es
2819 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
2820
2821 struct Particle
2822 {
2823 int len;
2824 };
2825
2826 layout(binding = 0, std430) readonly buffer Buf1
2827 {
2828 Particle particlesRead[];
2829 };
2830
2831 layout(binding = 1, std430) buffer Buf2
2832 {
2833 Particle particlesWrite[];
2834 };
2835
2836 void main()
2837 {
2838 int index = int(gl_GlobalInvocationID.x);
2839 particlesWrite[index].len = particlesRead.length();
2840 })";
2841
2842 ANGLE_GL_COMPUTE_PROGRAM(program, kCSSource);
2843 EXPECT_GL_NO_ERROR();
2844 }
2845
2846 // Test that scalar buffer variables are supported.
TEST_P(ComputeShaderTest,ShaderStorageBlocksScalar)2847 TEST_P(ComputeShaderTest, ShaderStorageBlocksScalar)
2848 {
2849 const char kCSSource[] = R"(#version 310 es
2850 layout(local_size_x=1) in;
2851 layout(std140, binding = 0) buffer blockA {
2852 uvec3 uv;
2853 float f;
2854 } instanceA;
2855 layout(std140, binding = 1) buffer blockB {
2856 vec2 v;
2857 uint u[3];
2858 float f;
2859 };
2860 void main()
2861 {
2862 f = instanceA.f;
2863 })";
2864
2865 ANGLE_GL_COMPUTE_PROGRAM(program, kCSSource);
2866 EXPECT_GL_NO_ERROR();
2867 }
2868
2869 // Test that vector buffer variables are supported.
TEST_P(ComputeShaderTest,ShaderStorageBlocksVector)2870 TEST_P(ComputeShaderTest, ShaderStorageBlocksVector)
2871 {
2872 const char kCSSource[] = R"(#version 310 es
2873 layout(local_size_x=1) in;
2874 layout(std140, binding = 0) buffer blockA {
2875 vec2 f;
2876 } instanceA;
2877 layout(std140, binding = 1) buffer blockB {
2878 vec3 f;
2879 };
2880 void main()
2881 {
2882 f[1] = instanceA.f[0];
2883 })";
2884
2885 ANGLE_GL_COMPUTE_PROGRAM(program, kCSSource);
2886 EXPECT_GL_NO_ERROR();
2887 }
2888
2889 // Test that matrix buffer variables are supported.
TEST_P(ComputeShaderTest,ShaderStorageBlocksMatrix)2890 TEST_P(ComputeShaderTest, ShaderStorageBlocksMatrix)
2891 {
2892 const char kCSSource[] = R"(#version 310 es
2893 layout(local_size_x=1) in;
2894 layout(std140, binding = 0) buffer blockA {
2895 mat3x4 m;
2896 } instanceA;
2897 layout(std140, binding = 1) buffer blockB {
2898 mat3x4 m;
2899 };
2900 void main()
2901 {
2902 m[0][1] = instanceA.m[0][1];
2903 })";
2904
2905 ANGLE_GL_COMPUTE_PROGRAM(program, kCSSource);
2906 EXPECT_GL_NO_ERROR();
2907 }
2908
2909 // Test that scalar array buffer variables are supported.
TEST_P(ComputeShaderTest,ShaderStorageBlocksScalarArray)2910 TEST_P(ComputeShaderTest, ShaderStorageBlocksScalarArray)
2911 {
2912 const char kCSSource[] = R"(#version 310 es
2913 layout(local_size_x=8) in;
2914 layout(std140, binding = 0) buffer blockA {
2915 float f[8];
2916 } instanceA;
2917 layout(std140, binding = 1) buffer blockB {
2918 float f[8];
2919 };
2920 void main()
2921 {
2922 f[gl_LocalInvocationIndex] = instanceA.f[gl_LocalInvocationIndex];
2923 })";
2924
2925 ANGLE_GL_COMPUTE_PROGRAM(program, kCSSource);
2926 EXPECT_GL_NO_ERROR();
2927 }
2928
2929 // Test that vector array buffer variables are supported.
TEST_P(ComputeShaderTest,ShaderStorageBlocksVectorArray)2930 TEST_P(ComputeShaderTest, ShaderStorageBlocksVectorArray)
2931 {
2932 const char kCSSource[] = R"(#version 310 es
2933 layout(local_size_x=4) in;
2934 layout(std140, binding = 0) buffer blockA {
2935 vec2 v[4];
2936 } instanceA;
2937 layout(std140, binding = 1) buffer blockB {
2938 vec4 v[4];
2939 };
2940 void main()
2941 {
2942 v[0][gl_LocalInvocationIndex] = instanceA.v[gl_LocalInvocationIndex][1];
2943 })";
2944
2945 ANGLE_GL_COMPUTE_PROGRAM(program, kCSSource);
2946 EXPECT_GL_NO_ERROR();
2947 }
2948
2949 // Test that matrix array buffer variables are supported.
TEST_P(ComputeShaderTest,ShaderStorageBlocksMatrixArray)2950 TEST_P(ComputeShaderTest, ShaderStorageBlocksMatrixArray)
2951 {
2952 const char kCSSource[] = R"(#version 310 es
2953 layout(local_size_x=8) in;
2954 layout(std140, binding = 0) buffer blockA {
2955 float v1[5];
2956 mat4 m[8];
2957 } instanceA;
2958 layout(std140, binding = 1) buffer blockB {
2959 vec2 v1[3];
2960 mat4 m[8];
2961 };
2962 void main()
2963 {
2964 float data = instanceA.m[gl_LocalInvocationIndex][0][0];
2965 m[gl_LocalInvocationIndex][gl_LocalInvocationIndex][gl_LocalInvocationIndex] = data;
2966 })";
2967
2968 ANGLE_GL_COMPUTE_PROGRAM(program, kCSSource);
2969 EXPECT_GL_NO_ERROR();
2970 }
2971
2972 // Test that shader storage blocks only in assignment right is supported.
TEST_P(ComputeShaderTest,ShaderStorageBlocksInAssignmentRight)2973 TEST_P(ComputeShaderTest, ShaderStorageBlocksInAssignmentRight)
2974 {
2975 const char kCSSource[] = R"(#version 310 es
2976 layout(local_size_x=8) in;
2977 layout(std140, binding = 0) buffer blockA {
2978 float data[8];
2979 } instanceA;
2980 layout(r32f, binding = 0) writeonly uniform highp image2D imageOut;
2981
2982 void main()
2983 {
2984 float data = 1.0;
2985 data = instanceA.data[gl_LocalInvocationIndex];
2986 imageStore(imageOut, ivec2(gl_LocalInvocationID.xy), vec4(data));
2987 })";
2988
2989 ANGLE_GL_COMPUTE_PROGRAM(program, kCSSource);
2990 EXPECT_GL_NO_ERROR();
2991 }
2992
2993 // Test that shader storage blocks with unsized array are supported.
TEST_P(ComputeShaderTest,ShaderStorageBlocksWithUnsizedArray)2994 TEST_P(ComputeShaderTest, ShaderStorageBlocksWithUnsizedArray)
2995 {
2996 const char kCSSource[] = R"(#version 310 es
2997 layout(local_size_x=8) in;
2998 layout(std140, binding = 0) buffer blockA {
2999 float v[];
3000 } instanceA;
3001 layout(std140, binding = 0) buffer blockB {
3002 float v[];
3003 } instanceB[1];
3004
3005 void main()
3006 {
3007 float data = instanceA.v[gl_LocalInvocationIndex];
3008 instanceB[0].v[gl_LocalInvocationIndex * 2u + 1u] = data;
3009 }
3010 )";
3011
3012 ANGLE_GL_COMPUTE_PROGRAM(program, kCSSource);
3013 EXPECT_GL_NO_ERROR();
3014 }
3015
3016 // Test that EOpIndexDirect/EOpIndexIndirect/EOpIndexDirectStruct nodes in ssbo EOpIndexInDirect
3017 // don't need to calculate the offset and should be translated by OutputHLSL directly.
TEST_P(ComputeShaderTest,IndexAndDotOperatorsInSSBOIndexIndirectOperator)3018 TEST_P(ComputeShaderTest, IndexAndDotOperatorsInSSBOIndexIndirectOperator)
3019 {
3020 constexpr char kComputeShaderSource[] = R"(#version 310 es
3021 layout(local_size_x=1) in;
3022 layout(std140, binding = 0) buffer blockA {
3023 float v[4];
3024 };
3025 layout(std140, binding = 1) buffer blockB {
3026 float v[4];
3027 } instanceB[1];
3028 struct S
3029 {
3030 uvec4 index[2];
3031 } s;
3032 void main()
3033 {
3034 s.index[0] = uvec4(0u, 1u, 2u, 3u);
3035 float data = v[s.index[0].y];
3036 instanceB[0].v[s.index[0].x] = data;
3037 })";
3038
3039 ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShaderSource);
3040 EXPECT_GL_NO_ERROR();
3041 }
3042
3043 // Test that swizzle node in non-SSBO symbol works well.
TEST_P(ComputeShaderTest,ShaderStorageBlocksWithNonSSBOSwizzle)3044 TEST_P(ComputeShaderTest, ShaderStorageBlocksWithNonSSBOSwizzle)
3045 {
3046 constexpr char kComputeShaderSource[] = R"(#version 310 es
3047 layout(local_size_x=8) in;
3048 layout(std140, binding = 0) buffer blockA {
3049 float v[8];
3050 };
3051 layout(std140, binding = 1) buffer blockB {
3052 float v[8];
3053 } instanceB[1];
3054
3055 void main()
3056 {
3057 float data = v[gl_GlobalInvocationID.x];
3058 instanceB[0].v[gl_GlobalInvocationID.x] = data;
3059 })";
3060
3061 ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShaderSource);
3062 EXPECT_GL_NO_ERROR();
3063 }
3064
3065 // Test that swizzle node in SSBO symbol works well.
TEST_P(ComputeShaderTest,ShaderStorageBlocksWithSSBOSwizzle)3066 TEST_P(ComputeShaderTest, ShaderStorageBlocksWithSSBOSwizzle)
3067 {
3068 constexpr char kComputeShaderSource[] = R"(#version 310 es
3069 layout(local_size_x=1) in;
3070 layout(std140, binding = 0) buffer blockA {
3071 vec2 v;
3072 };
3073 layout(std140, binding = 1) buffer blockB {
3074 float v;
3075 } instanceB[1];
3076
3077 void main()
3078 {
3079 instanceB[0].v = v.x;
3080 })";
3081
3082 ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShaderSource);
3083 EXPECT_GL_NO_ERROR();
3084 }
3085
3086 // Test that a large struct array in std140 uniform block won't consume too much time.
TEST_P(ComputeShaderTest,LargeStructArraySize)3087 TEST_P(ComputeShaderTest, LargeStructArraySize)
3088 {
3089 constexpr char kComputeShaderSource[] = R"(#version 310 es
3090 layout(local_size_x=8) in;
3091 precision mediump float;
3092
3093 struct InstancingData
3094 {
3095 mat4 transformation;
3096 };
3097
3098 #define MAX_INSTANCE_COUNT 800
3099
3100 layout(std140) uniform InstanceBlock
3101 {
3102 InstancingData instances[MAX_INSTANCE_COUNT];
3103 };
3104
3105 layout(std140, binding = 1) buffer blockB {
3106 mat4 v[];
3107 } instanceB;
3108
3109 void main()
3110 {
3111 instanceB.v[gl_GlobalInvocationID.x] = instances[gl_GlobalInvocationID.x].transformation;
3112 })";
3113
3114 ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShaderSource);
3115 EXPECT_GL_NO_ERROR();
3116 }
3117
3118 // Check that it is not possible to create a compute shader when the context does not support ES
3119 // 3.10
TEST_P(ComputeShaderTestES3,NotSupported)3120 TEST_P(ComputeShaderTestES3, NotSupported)
3121 {
3122 GLuint computeShaderHandle = glCreateShader(GL_COMPUTE_SHADER);
3123 EXPECT_EQ(0u, computeShaderHandle);
3124 EXPECT_GL_ERROR(GL_INVALID_ENUM);
3125 }
3126
3127 // The contents of shared variables should be cleared to zero at the beginning of shader execution.
TEST_P(WebGL2ComputeTest,sharedVariablesShouldBeZero)3128 TEST_P(WebGL2ComputeTest, sharedVariablesShouldBeZero)
3129 {
3130 // http://anglebug.com/3226
3131 ANGLE_SKIP_TEST_IF(IsD3D11());
3132
3133 // Fails on Android, AMD/windows and Intel/windows. Probably works by chance on other
3134 // platforms, so suppressing on all platforms to avoid possible flakiness.
3135 // http://anglebug.com/3869
3136 ANGLE_SKIP_TEST_IF(IsVulkan());
3137
3138 // http://anglebug.com/4092
3139 ANGLE_SKIP_TEST_IF(IsAndroid() && IsOpenGLES());
3140 ANGLE_SKIP_TEST_IF(IsOpenGL() &&
3141 ((getClientMajorVersion() == 3) && (getClientMinorVersion() >= 1)));
3142
3143 const char kCSShader[] = R"(#version 310 es
3144 layout (local_size_x = 4, local_size_y = 4, local_size_z = 1) in;
3145 layout (r32ui, binding = 0) readonly uniform highp uimage2D srcImage;
3146 layout (r32ui, binding = 1) writeonly uniform highp uimage2D dstImage;
3147 struct S {
3148 float f;
3149 int i;
3150 uint u;
3151 bool b;
3152 vec4 v[64];
3153 };
3154
3155 shared S vars[16];
3156 void main()
3157 {
3158 S zeroS;
3159 zeroS.f = 0.0f;
3160 zeroS.i = 0;
3161 zeroS.u = 0u;
3162 zeroS.b = false;
3163 for (int i = 0; i < 64; i++)
3164 {
3165 zeroS.v[i] = vec4(0.0f);
3166 }
3167
3168 uint tid = gl_LocalInvocationID.x + gl_LocalInvocationID.y * 4u;
3169 uint value = (zeroS == vars[tid] ? 127u : 0u);
3170 imageStore(dstImage, ivec2(gl_LocalInvocationID.xy), uvec4(value));
3171 })";
3172
3173 const std::array<GLuint, 16> inputData = {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
3174 const std::array<GLuint, 16> expectedValues = {
3175 {127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127}};
3176 runSharedMemoryTest<GLuint, 4, 4>(kCSShader, GL_R32UI, GL_UNSIGNED_INT, inputData,
3177 expectedValues);
3178 }
3179
3180 // Test uniform dirty in compute shader, and verify the contents.
TEST_P(ComputeShaderTest,UniformDirty)3181 TEST_P(ComputeShaderTest, UniformDirty)
3182 {
3183 // http://anglebug.com/5072
3184 ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux() && IsOpenGL());
3185
3186 // glReadPixels is getting the result of the first dispatch call. http://anglebug.com/3879
3187 ANGLE_SKIP_TEST_IF(IsVulkan() && IsWindows() && (IsAMD() || IsNVIDIA()));
3188
3189 GLTexture texture[2];
3190 GLFramebuffer framebuffer;
3191 constexpr char kCS[] = R"(#version 310 es
3192 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
3193 layout(r32ui, binding = 0) readonly uniform highp uimage2D uImage_1;
3194 layout(r32ui, binding = 1) writeonly uniform highp uimage2D uImage_2;
3195 uniform uint factor;
3196 void main()
3197 {
3198 uvec4 value = imageLoad(uImage_1, ivec2(gl_LocalInvocationID.xy));
3199 imageStore(uImage_2, ivec2(gl_LocalInvocationID.xy), value * factor);
3200 })";
3201
3202 constexpr int kWidth = 1, kHeight = 1;
3203 constexpr GLuint kInputValues[2][1] = {{200}, {100}};
3204
3205 glBindTexture(GL_TEXTURE_2D, texture[0]);
3206 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kWidth, kHeight);
3207 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
3208 kInputValues[0]);
3209 EXPECT_GL_NO_ERROR();
3210
3211 glBindTexture(GL_TEXTURE_2D, texture[1]);
3212 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kWidth, kHeight);
3213 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
3214 kInputValues[1]);
3215 EXPECT_GL_NO_ERROR();
3216
3217 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
3218 glUseProgram(program);
3219
3220 glBindImageTexture(0, texture[0], 0, GL_FALSE, 0, GL_READ_ONLY, GL_R32UI);
3221 EXPECT_GL_NO_ERROR();
3222
3223 glBindImageTexture(1, texture[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
3224 EXPECT_GL_NO_ERROR();
3225
3226 glUniform1ui(glGetUniformLocation(program, "factor"), 2);
3227 EXPECT_GL_NO_ERROR();
3228
3229 glDispatchCompute(1, 1, 1);
3230 EXPECT_GL_NO_ERROR();
3231
3232 glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
3233
3234 glUniform1ui(glGetUniformLocation(program, "factor"), 3);
3235 EXPECT_GL_NO_ERROR();
3236
3237 glDispatchCompute(1, 1, 1);
3238 EXPECT_GL_NO_ERROR();
3239
3240 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
3241 GLuint outputValues[kWidth * kHeight];
3242 GLuint expectedValue = 600;
3243 glUseProgram(0);
3244 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
3245
3246 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture[1], 0);
3247 EXPECT_GL_NO_ERROR();
3248 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
3249 EXPECT_GL_NO_ERROR();
3250
3251 for (int i = 0; i < kWidth * kHeight; i++)
3252 {
3253 EXPECT_EQ(expectedValue, outputValues[i]) << " index " << i;
3254 }
3255 }
3256
3257 // Test storage buffer bound is unchanged, shader writes it, buffer content should be updated.
TEST_P(ComputeShaderTest,StorageBufferBoundUnchanged)3258 TEST_P(ComputeShaderTest, StorageBufferBoundUnchanged)
3259 {
3260 // http://anglebug.com/4092
3261 ANGLE_SKIP_TEST_IF(isSwiftshader());
3262 constexpr char kCS[] = R"(#version 310 es
3263 layout(local_size_x=16, local_size_y=16) in;
3264 precision highp usampler2D;
3265 uniform usampler2D tex;
3266 uniform uint factor;
3267 layout(std140, binding = 0) buffer buf {
3268 uint outData[16][16];
3269 };
3270
3271 void main()
3272 {
3273 uint x = gl_LocalInvocationID.x;
3274 uint y = gl_LocalInvocationID.y;
3275 float xCoord = float(x) / float(16);
3276 float yCoord = float(y) / float(16);
3277 outData[y][x] = texture(tex, vec2(xCoord, yCoord)).x + factor;
3278 })";
3279
3280 constexpr unsigned int kWidth = 16;
3281 constexpr unsigned int kHeight = 16;
3282 GLTexture tex;
3283 glBindTexture(GL_TEXTURE_2D, tex);
3284 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3285 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3286 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kWidth, kHeight);
3287 GLuint texels[kHeight][kWidth] = {{0}};
3288 for (unsigned int y = 0; y < kHeight; ++y)
3289 {
3290 for (unsigned int x = 0; x < kWidth; ++x)
3291 {
3292 texels[y][x] = x + y * kWidth;
3293 }
3294 }
3295 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
3296 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
3297 texels);
3298 glBindTexture(GL_TEXTURE_2D, 0);
3299
3300 // The array stride are rounded up to the base alignment of a vec4 for std140 layout.
3301 constexpr unsigned int kArrayStride = 16;
3302 GLBuffer ssbo;
3303 glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
3304 glBufferData(GL_SHADER_STORAGE_BUFFER, kWidth * kHeight * kArrayStride, nullptr,
3305 GL_STREAM_DRAW);
3306 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
3307 EXPECT_GL_NO_ERROR();
3308
3309 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
3310 glUseProgram(program);
3311
3312 glActiveTexture(GL_TEXTURE0);
3313 glBindTexture(GL_TEXTURE_2D, tex);
3314 glUniform1i(glGetUniformLocation(program, "tex"), 0);
3315 glUniform1ui(glGetUniformLocation(program, "factor"), 2);
3316 glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
3317 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, ssbo);
3318
3319 glDispatchCompute(1, 1, 1);
3320
3321 const GLuint *ptr1 = reinterpret_cast<const GLuint *>(glMapBufferRange(
3322 GL_SHADER_STORAGE_BUFFER, 0, kWidth * kHeight * kArrayStride, GL_MAP_READ_BIT));
3323 EXPECT_GL_NO_ERROR();
3324 for (unsigned int idx = 0; idx < kWidth * kHeight; idx++)
3325 {
3326 EXPECT_EQ(idx + 2, *(ptr1 + idx * kArrayStride / 4));
3327 }
3328 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
3329 glUniform1ui(glGetUniformLocation(program, "factor"), 3);
3330 glDispatchCompute(1, 1, 1);
3331
3332 const GLuint *ptr2 = reinterpret_cast<const GLuint *>(glMapBufferRange(
3333 GL_SHADER_STORAGE_BUFFER, 0, kWidth * kHeight * kArrayStride, GL_MAP_READ_BIT));
3334 EXPECT_GL_NO_ERROR();
3335 for (unsigned int idx = 0; idx < kWidth * kHeight; idx++)
3336 {
3337 EXPECT_EQ(idx + 3, *(ptr2 + idx * kArrayStride / 4));
3338 }
3339 }
3340
3341 // Test imageSize to access mipmap slice.
TEST_P(ComputeShaderTest,ImageSizeMipmapSlice)3342 TEST_P(ComputeShaderTest, ImageSizeMipmapSlice)
3343 {
3344 // TODO(xinghua.cao@intel.com): http://anglebug.com/3101
3345 ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux());
3346
3347 // http://anglebug.com/4392
3348 ANGLE_SKIP_TEST_IF(IsWindows() && IsNVIDIA() && IsD3D11());
3349
3350 GLTexture texture[2];
3351 GLFramebuffer framebuffer;
3352 const char kCS[] = R"(#version 310 es
3353 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
3354 layout(r32ui, binding = 0) readonly uniform highp uimage2D uImage_1;
3355 layout(rgba32ui, binding = 1) writeonly uniform highp uimage2D uImage_2;
3356 void main()
3357 {
3358 ivec2 size = imageSize(uImage_1);
3359 imageStore(uImage_2, ivec2(gl_LocalInvocationID.xy), uvec4(size, 0, 0));
3360 })";
3361
3362 constexpr int kWidth1 = 8, kHeight1 = 4, kWidth2 = 1, kHeight2 = 1;
3363 constexpr GLuint kInputValues[] = {0, 0, 0, 0};
3364
3365 glBindTexture(GL_TEXTURE_2D, texture[0]);
3366 glTexStorage2D(GL_TEXTURE_2D, 2, GL_R32UI, kWidth1, kHeight1);
3367 EXPECT_GL_NO_ERROR();
3368
3369 glBindTexture(GL_TEXTURE_2D, texture[1]);
3370 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32UI, kWidth2, kHeight2);
3371 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth2, kHeight2, GL_RGBA_INTEGER, GL_UNSIGNED_INT,
3372 kInputValues);
3373 EXPECT_GL_NO_ERROR();
3374
3375 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
3376 glUseProgram(program);
3377
3378 glBindImageTexture(0, texture[0], 1, GL_FALSE, 0, GL_READ_ONLY, GL_R32UI);
3379 glBindImageTexture(1, texture[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32UI);
3380
3381 glDispatchCompute(1, 1, 1);
3382 EXPECT_GL_NO_ERROR();
3383
3384 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
3385 GLuint outputValues[kWidth2 * kHeight2 * 4];
3386 constexpr GLuint expectedValue[] = {4, 2};
3387 glUseProgram(0);
3388 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
3389
3390 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture[1], 0);
3391 EXPECT_GL_NO_ERROR();
3392 glReadPixels(0, 0, kWidth2, kHeight2, GL_RGBA_INTEGER, GL_UNSIGNED_INT, outputValues);
3393 EXPECT_GL_NO_ERROR();
3394
3395 for (int i = 0; i < kWidth2 * kHeight2; i++)
3396 {
3397 EXPECT_EQ(expectedValue[i], outputValues[i]);
3398 EXPECT_EQ(expectedValue[i + 1], outputValues[i + 1]);
3399 }
3400 }
3401
3402 // Test imageLoad to access mipmap slice.
TEST_P(ComputeShaderTest,ImageLoadMipmapSlice)3403 TEST_P(ComputeShaderTest, ImageLoadMipmapSlice)
3404 {
3405 // TODO(xinghua.cao@intel.com): http://anglebug.com/3101
3406 ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux());
3407
3408 GLTexture texture[2];
3409 GLFramebuffer framebuffer;
3410 constexpr char kCS[] = R"(#version 310 es
3411 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
3412 layout(r32ui, binding = 0) readonly uniform highp uimage2D uImage_1;
3413 layout(r32ui, binding = 1) writeonly uniform highp uimage2D uImage_2;
3414 void main()
3415 {
3416 uvec4 value = imageLoad(uImage_1, ivec2(gl_LocalInvocationID.xy));
3417 imageStore(uImage_2, ivec2(gl_LocalInvocationID.xy), value);
3418 })";
3419
3420 constexpr int kWidth1 = 2, kHeight1 = 2, kWidth2 = 1, kHeight2 = 1;
3421 constexpr GLuint kInputValues11[] = {3, 3, 3, 3};
3422 constexpr GLuint kInputValues12[] = {2};
3423 constexpr GLuint kInputValues2[] = {1};
3424
3425 glBindTexture(GL_TEXTURE_2D, texture[0]);
3426 glTexStorage2D(GL_TEXTURE_2D, 2, GL_R32UI, kWidth1, kHeight1);
3427 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth1, kHeight1, GL_RED_INTEGER, GL_UNSIGNED_INT,
3428 kInputValues11);
3429 glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, kWidth2, kHeight2, GL_RED_INTEGER, GL_UNSIGNED_INT,
3430 kInputValues12);
3431 EXPECT_GL_NO_ERROR();
3432
3433 glBindTexture(GL_TEXTURE_2D, texture[1]);
3434 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kWidth2, kHeight2);
3435 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth2, kHeight2, GL_RED_INTEGER, GL_UNSIGNED_INT,
3436 kInputValues2);
3437 EXPECT_GL_NO_ERROR();
3438
3439 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
3440 glUseProgram(program);
3441
3442 glBindImageTexture(0, texture[0], 1, GL_FALSE, 0, GL_READ_ONLY, GL_R32UI);
3443 glBindImageTexture(1, texture[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
3444
3445 glDispatchCompute(1, 1, 1);
3446 EXPECT_GL_NO_ERROR();
3447
3448 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
3449 GLuint outputValues;
3450 constexpr GLuint expectedValue = 2;
3451 glUseProgram(0);
3452 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
3453
3454 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture[1], 0);
3455 EXPECT_GL_NO_ERROR();
3456 glReadPixels(0, 0, kWidth2, kHeight2, GL_RED_INTEGER, GL_UNSIGNED_INT, &outputValues);
3457 EXPECT_GL_NO_ERROR();
3458 EXPECT_EQ(expectedValue, outputValues);
3459 }
3460
3461 // Test imageStore to access mipmap slice.
TEST_P(ComputeShaderTest,ImageStoreMipmapSlice)3462 TEST_P(ComputeShaderTest, ImageStoreMipmapSlice)
3463 {
3464 // TODO(xinghua.cao@intel.com): http://anglebug.com/3101
3465 ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux() && IsOpenGL());
3466
3467 GLTexture texture[2];
3468 GLFramebuffer framebuffer;
3469 constexpr char kCS[] = R"(#version 310 es
3470 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
3471 layout(r32ui, binding = 0) readonly uniform highp uimage2D uImage_1;
3472 layout(r32ui, binding = 1) writeonly uniform highp uimage2D uImage_2;
3473 void main()
3474 {
3475 uvec4 value = imageLoad(uImage_1, ivec2(gl_LocalInvocationID.xy));
3476 imageStore(uImage_2, ivec2(gl_LocalInvocationID.xy), value);
3477 })";
3478
3479 constexpr int kWidth1 = 1, kHeight1 = 1, kWidth2 = 2, kHeight2 = 2;
3480 constexpr GLuint kInputValues1[] = {3};
3481 constexpr GLuint kInputValues21[] = {2, 2, 2, 2};
3482 constexpr GLuint kInputValues22[] = {1};
3483
3484 glBindTexture(GL_TEXTURE_2D, texture[0]);
3485 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kWidth1, kHeight1);
3486 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth1, kHeight1, GL_RED_INTEGER, GL_UNSIGNED_INT,
3487 kInputValues1);
3488 EXPECT_GL_NO_ERROR();
3489
3490 glBindTexture(GL_TEXTURE_2D, texture[1]);
3491 glTexStorage2D(GL_TEXTURE_2D, 2, GL_R32UI, kWidth2, kHeight2);
3492 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth2, kHeight2, GL_RED_INTEGER, GL_UNSIGNED_INT,
3493 kInputValues21);
3494 glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, kWidth1, kHeight1, GL_RED_INTEGER, GL_UNSIGNED_INT,
3495 kInputValues22);
3496 EXPECT_GL_NO_ERROR();
3497
3498 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
3499 glUseProgram(program);
3500
3501 glBindImageTexture(0, texture[0], 0, GL_FALSE, 0, GL_READ_ONLY, GL_R32UI);
3502 glBindImageTexture(1, texture[1], 1, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
3503
3504 glDispatchCompute(1, 1, 1);
3505 EXPECT_GL_NO_ERROR();
3506
3507 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
3508 GLuint outputValues;
3509 constexpr GLuint expectedValue = 3;
3510 glUseProgram(0);
3511 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
3512
3513 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture[1], 1);
3514 EXPECT_GL_NO_ERROR();
3515 glReadPixels(0, 0, kWidth1, kHeight1, GL_RED_INTEGER, GL_UNSIGNED_INT, &outputValues);
3516 EXPECT_GL_NO_ERROR();
3517 EXPECT_EQ(expectedValue, outputValues);
3518 }
3519
3520 // Test that a resource is bound on render pipeline output, and then it's bound as the compute
3521 // pipeline input. It works well. See http://anglebug.com/3658
TEST_P(ComputeShaderTest,DrawTexture1DispatchTexture2)3522 TEST_P(ComputeShaderTest, DrawTexture1DispatchTexture2)
3523 {
3524 // http://anglebug.com/5072
3525 ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux() && IsOpenGL());
3526
3527 ANGLE_SKIP_TEST_IF(!EnsureGLExtensionEnabled("GL_EXT_color_buffer_float"));
3528
3529 const char kCSSource[] = R"(#version 310 es
3530 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
3531 precision highp sampler2D;
3532 uniform sampler2D tex;
3533 layout(rgba32f, binding = 0) writeonly uniform highp image2D image;
3534 void main()
3535 {
3536 vec4 value = texelFetch(tex, ivec2(gl_LocalInvocationID.xy), 0);
3537 imageStore(image, ivec2(gl_LocalInvocationID.xy), vec4(value.x - 1.0, 1.0, 0.0, value.w - 1.0));
3538 })";
3539
3540 const char kVSSource[] = R"(#version 310 es
3541 layout (location = 0) in vec2 pos;
3542 out vec2 texCoord;
3543 void main(void) {
3544 texCoord = 0.5*pos + 0.5;
3545 gl_Position = vec4(pos, 0.0, 1.0);
3546 })";
3547
3548 const char kFSSource[] = R"(#version 310 es
3549 precision highp float;
3550 uniform sampler2D tex;
3551 in vec2 texCoord;
3552 out vec4 fragColor;
3553 void main(void) {
3554 fragColor = texture(tex, texCoord);
3555 })";
3556
3557 GLuint aPosLoc = 0;
3558 ANGLE_GL_PROGRAM(program, kVSSource, kFSSource);
3559 ANGLE_GL_COMPUTE_PROGRAM(csProgram, kCSSource);
3560 glBindAttribLocation(program, aPosLoc, "pos");
3561 GLuint buffer;
3562 glGenBuffers(1, &buffer);
3563 glBindBuffer(GL_ARRAY_BUFFER, buffer);
3564 GLfloat vertices[] = {-1, -1, 1, -1, -1, 1, 1, 1};
3565 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 8, vertices, GL_STATIC_DRAW);
3566 glVertexAttribPointer(aPosLoc, 2, GL_FLOAT, GL_FALSE, 0, 0);
3567 glEnableVertexAttribArray(aPosLoc);
3568
3569 constexpr GLfloat kInputValues[4] = {1.0, 0.0, 0.0, 1.0};
3570 constexpr GLfloat kZero[4] = {0.0, 0.0, 0.0, 0.0};
3571 GLFramebuffer framebuffer;
3572 GLTexture texture[3];
3573 glBindTexture(GL_TEXTURE_2D, texture[0]);
3574 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32F, 1, 1);
3575 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_FLOAT, kInputValues);
3576 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3577 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3578
3579 glBindTexture(GL_TEXTURE_2D, texture[1]);
3580 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32F, 1, 1);
3581 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_FLOAT, kZero);
3582 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3583 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3584
3585 glBindTexture(GL_TEXTURE_2D, texture[2]);
3586 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32F, 1, 1);
3587 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_FLOAT, kZero);
3588 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3589 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3590
3591 glUseProgram(program);
3592 glActiveTexture(GL_TEXTURE0);
3593 glBindTexture(GL_TEXTURE_2D, texture[0]);
3594 glUniform1i(glGetUniformLocation(program, "tex"), 0);
3595 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
3596 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture[1], 0);
3597 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3598 EXPECT_GL_NO_ERROR();
3599 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
3600 GLfloat actual[4];
3601 glReadPixels(0, 0, 1, 1, GL_RGBA, GL_FLOAT, actual);
3602 EXPECT_GL_NO_ERROR();
3603 EXPECT_EQ(1.0, actual[0]);
3604 EXPECT_EQ(0.0, actual[1]);
3605 EXPECT_EQ(0.0, actual[2]);
3606 EXPECT_EQ(1.0, actual[3]);
3607
3608 glUseProgram(csProgram);
3609 glActiveTexture(GL_TEXTURE0);
3610 glBindTexture(GL_TEXTURE_2D, texture[1]);
3611 glUniform1i(glGetUniformLocation(program, "tex"), 0);
3612 glBindImageTexture(0, texture[2], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
3613 glDispatchCompute(1, 1, 1);
3614 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
3615
3616 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
3617 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture[2], 0);
3618 glReadPixels(0, 0, 1, 1, GL_RGBA, GL_FLOAT, actual);
3619 EXPECT_GL_NO_ERROR();
3620 EXPECT_EQ(0.0, actual[0]);
3621 EXPECT_EQ(1.0, actual[1]);
3622 EXPECT_EQ(0.0, actual[2]);
3623 EXPECT_EQ(0.0, actual[3]);
3624 }
3625
3626 // Test that render pipeline and compute pipeline access to the same texture.
3627 // Steps:
3628 // 1. DispatchCompute.
3629 // 2. DrawArrays.
TEST_P(ComputeShaderTest,DispatchDraw)3630 TEST_P(ComputeShaderTest, DispatchDraw)
3631 {
3632 // http://anglebug.com/5072
3633 ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux() && IsOpenGL());
3634
3635 const char kCSSource[] = R"(#version 310 es
3636 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
3637 layout(rgba32f, binding = 0) writeonly uniform highp image2D image;
3638 void main()
3639 {
3640 imageStore(image, ivec2(gl_LocalInvocationID.xy), vec4(0.0, 0.0, 1.0, 1.0));
3641 })";
3642
3643 const char kVSSource[] = R"(#version 310 es
3644 layout (location = 0) in vec2 pos;
3645 out vec2 texCoord;
3646 void main(void) {
3647 texCoord = 0.5*pos + 0.5;
3648 gl_Position = vec4(pos, 0.0, 1.0);
3649 })";
3650
3651 const char kFSSource[] = R"(#version 310 es
3652 precision highp float;
3653 uniform sampler2D tex;
3654 in vec2 texCoord;
3655 out vec4 fragColor;
3656 void main(void) {
3657 fragColor = texture(tex, texCoord);
3658 })";
3659
3660 GLuint aPosLoc = 0;
3661 ANGLE_GL_PROGRAM(program, kVSSource, kFSSource);
3662 glBindAttribLocation(program, aPosLoc, "pos");
3663 GLuint buffer;
3664 glGenBuffers(1, &buffer);
3665 glBindBuffer(GL_ARRAY_BUFFER, buffer);
3666 GLfloat vertices[] = {-1, -1, 1, -1, -1, 1, 1, 1};
3667 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 8, vertices, GL_STATIC_DRAW);
3668 glVertexAttribPointer(aPosLoc, 2, GL_FLOAT, GL_FALSE, 0, 0);
3669 glEnableVertexAttribArray(aPosLoc);
3670
3671 constexpr GLfloat kInputValues[4] = {1.0, 0.0, 0.0, 1.0};
3672 GLTexture texture;
3673 glBindTexture(GL_TEXTURE_2D, texture);
3674 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32F, 1, 1);
3675 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_FLOAT, kInputValues);
3676 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3677 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3678 EXPECT_GL_NO_ERROR();
3679
3680 ANGLE_GL_COMPUTE_PROGRAM(csProgram, kCSSource);
3681 glUseProgram(csProgram);
3682
3683 glBindImageTexture(0, texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
3684
3685 glDispatchCompute(1, 1, 1);
3686 EXPECT_GL_NO_ERROR();
3687
3688 glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT);
3689 glUseProgram(program);
3690 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3691 EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::blue);
3692 }
3693
3694 // Test that render pipeline and compute pipeline access to the same texture.
3695 // Steps:
3696 // 1. DrawArrays.
3697 // 2. DispatchCompute.
3698 // 3. DispatchCompute.
3699 // 4. DrawArrays.
TEST_P(ComputeShaderTest,DrawDispatchDispatchDraw)3700 TEST_P(ComputeShaderTest, DrawDispatchDispatchDraw)
3701 {
3702 // http://anglebug.com/5072
3703 ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux() && IsOpenGL());
3704
3705 // Fails on AMD windows drivers. http://anglebug.com/3871
3706 ANGLE_SKIP_TEST_IF(IsWindows() && IsAMD() && IsVulkan());
3707
3708 const char kCSSource[] = R"(#version 310 es
3709 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
3710 layout(rgba32f, binding = 0) writeonly uniform highp image2D image;
3711 uniform float factor;
3712 void main()
3713 {
3714 imageStore(image, ivec2(gl_LocalInvocationID.xy), vec4(factor, 0.0, 1.0, 1.0));
3715 })";
3716
3717 const char kVSSource[] = R"(#version 310 es
3718 layout (location = 0) in vec2 pos;
3719 out vec2 texCoord;
3720 void main(void) {
3721 texCoord = 0.5*pos + 0.5;
3722 gl_Position = vec4(pos, 0.0, 1.0);
3723 })";
3724
3725 const char kFSSource[] = R"(#version 310 es
3726 precision highp float;
3727 uniform sampler2D tex;
3728 in vec2 texCoord;
3729 out vec4 fragColor;
3730 void main(void) {
3731 fragColor = texture(tex, texCoord);
3732 })";
3733
3734 GLuint aPosLoc = 0;
3735 ANGLE_GL_PROGRAM(program, kVSSource, kFSSource);
3736 glBindAttribLocation(program, aPosLoc, "pos");
3737 GLuint buffer;
3738 glGenBuffers(1, &buffer);
3739 glBindBuffer(GL_ARRAY_BUFFER, buffer);
3740 GLfloat vertices[] = {-1, -1, 1, -1, -1, 1, 1, 1};
3741 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 8, vertices, GL_STATIC_DRAW);
3742 glVertexAttribPointer(aPosLoc, 2, GL_FLOAT, GL_FALSE, 0, 0);
3743 glEnableVertexAttribArray(aPosLoc);
3744
3745 constexpr GLfloat kInputValues[4] = {1.0, 0.0, 0.0, 1.0};
3746 GLTexture texture;
3747 glBindTexture(GL_TEXTURE_2D, texture);
3748 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32F, 1, 1);
3749 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_FLOAT, kInputValues);
3750 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3751 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3752 glUseProgram(program);
3753 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3754 EXPECT_GL_NO_ERROR();
3755
3756 ANGLE_GL_COMPUTE_PROGRAM(csProgram, kCSSource);
3757 glUseProgram(csProgram);
3758 glUniform1f(glGetUniformLocation(csProgram, "factor"), 0.0);
3759 glBindImageTexture(0, texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
3760 EXPECT_GL_NO_ERROR();
3761
3762 glDispatchCompute(1, 1, 1);
3763 glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
3764 EXPECT_GL_NO_ERROR();
3765
3766 glUniform1f(glGetUniformLocation(csProgram, "factor"), 1.0);
3767 glDispatchCompute(1, 1, 1);
3768 glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT);
3769 EXPECT_GL_NO_ERROR();
3770
3771 glUseProgram(program);
3772 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3773 EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::magenta);
3774 }
3775
3776 // Test that render pipeline and compute pipeline access to the same texture.
3777 // Steps:
3778 // 1. DispatchCompute.
3779 // 2. DrawArrays.
3780 // 3. DrawArrays.
3781 // 4. DispatchCompute.
TEST_P(ComputeShaderTest,DispatchDrawDrawDispatch)3782 TEST_P(ComputeShaderTest, DispatchDrawDrawDispatch)
3783 {
3784 // http://anglebug.com/5072
3785 ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux() && IsOpenGL());
3786
3787 const char kCSSource[] = R"(#version 310 es
3788 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
3789 layout(rgba32f, binding = 0) writeonly uniform highp image2D image;
3790
3791 void main()
3792 {
3793 imageStore(image, ivec2(gl_LocalInvocationID.xy), vec4(0.0, 0.0, 1.0, 1.0));
3794 })";
3795
3796 const char kVSSource[] = R"(#version 310 es
3797 layout (location = 0) in vec2 pos;
3798 out vec2 texCoord;
3799 void main(void) {
3800 texCoord = 0.5*pos + 0.5;
3801 gl_Position = vec4(pos, 0.0, 1.0);
3802 })";
3803
3804 const char kFSSource[] = R"(#version 310 es
3805 precision highp float;
3806 uniform sampler2D tex;
3807 in vec2 texCoord;
3808 uniform float factor;
3809 out vec4 fragColor;
3810 void main(void) {
3811 fragColor = texture(tex, texCoord) + vec4(factor, 0.0, 0.0, 0.0);
3812 })";
3813
3814 GLuint aPosLoc = 0;
3815 ANGLE_GL_PROGRAM(program, kVSSource, kFSSource);
3816 glBindAttribLocation(program, aPosLoc, "pos");
3817 GLuint buffer;
3818 glGenBuffers(1, &buffer);
3819 glBindBuffer(GL_ARRAY_BUFFER, buffer);
3820 GLfloat vertices[] = {-1, -1, 1, -1, -1, 1, 1, 1};
3821 glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 8, vertices, GL_STATIC_DRAW);
3822 glVertexAttribPointer(aPosLoc, 2, GL_FLOAT, GL_FALSE, 0, 0);
3823 glEnableVertexAttribArray(aPosLoc);
3824
3825 constexpr GLfloat kInputValues[4] = {1.0, 0.0, 0.0, 1.0};
3826 GLTexture texture;
3827 glBindTexture(GL_TEXTURE_2D, texture);
3828 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32F, 1, 1);
3829 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_FLOAT, kInputValues);
3830 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3831 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3832
3833 ANGLE_GL_COMPUTE_PROGRAM(csProgram, kCSSource);
3834 glUseProgram(csProgram);
3835 glBindImageTexture(0, texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
3836
3837 glDispatchCompute(1, 1, 1);
3838 glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT);
3839 EXPECT_GL_NO_ERROR();
3840
3841 glUseProgram(program);
3842 glUniform1f(glGetUniformLocation(program, "factor"), 0.0);
3843 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3844 EXPECT_GL_NO_ERROR();
3845
3846 glUniform1f(glGetUniformLocation(program, "factor"), 1.0);
3847 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3848 EXPECT_GL_NO_ERROR();
3849
3850 glUseProgram(csProgram);
3851 glDispatchCompute(1, 1, 1);
3852 glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT);
3853 EXPECT_GL_NO_ERROR();
3854
3855 glUseProgram(program);
3856 glUniform1f(glGetUniformLocation(program, "factor"), 0.0);
3857 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3858 EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::blue);
3859 }
3860
3861 // Test that invalid memory barrier will produce an error.
TEST_P(ComputeShaderTest,InvalidMemoryBarrier)3862 TEST_P(ComputeShaderTest, InvalidMemoryBarrier)
3863 {
3864 GLbitfield barriers = 0;
3865 glMemoryBarrier(barriers);
3866 EXPECT_GL_ERROR(GL_INVALID_VALUE);
3867 }
3868
3869 // test atomic counter increment
3870 // http://anglebug.com/3246
TEST_P(ComputeShaderTest,AtomicCounterIncrement)3871 TEST_P(ComputeShaderTest, AtomicCounterIncrement)
3872 {
3873 constexpr char kComputeShader[] = R"(#version 310 es
3874 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
3875 layout(binding = 1, std430) buffer Output {
3876 uint preGet[1];
3877 uint increment[1];
3878 uint postGet[1];
3879 } sb_in;
3880 layout(binding=0) uniform atomic_uint counter0;
3881
3882 void main(void)
3883 {
3884 uint id = (gl_GlobalInvocationID.x);
3885 sb_in.preGet[0u] = atomicCounter(counter0);
3886 sb_in.increment[0u] = atomicCounterIncrement(counter0);
3887 sb_in.postGet[0u] = atomicCounter(counter0);
3888 }
3889 )";
3890 ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShader);
3891 EXPECT_GL_NO_ERROR();
3892
3893 glUseProgram(program);
3894
3895 constexpr unsigned int kBytesPerComponent = sizeof(GLuint);
3896
3897 GLBuffer shaderStorageBuffer;
3898 glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer);
3899 glBufferData(GL_SHADER_STORAGE_BUFFER, 3 * kBytesPerComponent, nullptr, GL_STATIC_DRAW);
3900 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, shaderStorageBuffer);
3901 EXPECT_GL_NO_ERROR();
3902
3903 constexpr GLuint atomicBufferInitialData[] = {2u};
3904 GLuint atomicBuffer;
3905 glGenBuffers(1, &atomicBuffer);
3906 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicBuffer);
3907 glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(atomicBufferInitialData), atomicBufferInitialData,
3908 GL_DYNAMIC_DRAW);
3909 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, atomicBuffer);
3910 EXPECT_GL_NO_ERROR();
3911
3912 glDispatchCompute(1, 1, 1);
3913 glFinish();
3914 EXPECT_GL_NO_ERROR();
3915
3916 // read back
3917 const GLuint *ptr = reinterpret_cast<const GLuint *>(
3918 glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 3 * kBytesPerComponent, GL_MAP_READ_BIT));
3919 EXPECT_EQ(2u, ptr[0]);
3920 EXPECT_EQ(2u, ptr[1]);
3921 EXPECT_EQ(3u, ptr[2]);
3922
3923 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
3924 }
3925
3926 // Create a 'very large' array inside of a function in a compute shader.
TEST_P(ComputeShaderTest,VeryLargeArrayInsideFunction)3927 TEST_P(ComputeShaderTest, VeryLargeArrayInsideFunction)
3928 {
3929 constexpr char kComputeShader[] = R"(#version 310 es
3930 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
3931 layout(binding = 0, std430) buffer Output {
3932 int value[1];
3933 } output_data;
3934
3935 void main()
3936 {
3937 int values[1000];
3938 for (int i = 0; i < values.length(); i++)
3939 {
3940 values[i] = 0;
3941 }
3942
3943 int total = 0;
3944 for (int i = 0; i < values.length(); i++)
3945 {
3946 total += i;
3947 values[i] = total;
3948 }
3949 output_data.value[0u] = values[1000-1];
3950 })";
3951
3952 ANGLE_GL_COMPUTE_PROGRAM(program, kComputeShader);
3953 EXPECT_GL_NO_ERROR();
3954
3955 glUseProgram(program);
3956
3957 constexpr unsigned int kBytesPerComponent = sizeof(GLint);
3958
3959 GLBuffer shaderStorageBuffer;
3960 glBindBuffer(GL_SHADER_STORAGE_BUFFER, shaderStorageBuffer);
3961 glBufferData(GL_SHADER_STORAGE_BUFFER, 1 * kBytesPerComponent, nullptr, GL_STATIC_DRAW);
3962 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, shaderStorageBuffer);
3963 EXPECT_GL_NO_ERROR();
3964
3965 glDispatchCompute(1, 1, 1);
3966 glFinish();
3967 EXPECT_GL_NO_ERROR();
3968
3969 // read back
3970 const GLint *ptr = reinterpret_cast<const GLint *>(
3971 glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 1 * kBytesPerComponent, GL_MAP_READ_BIT));
3972 EXPECT_EQ(499500, ptr[0]);
3973
3974 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
3975 }
3976
3977 // Test that render pipeline and compute pipeline access to the same texture.
3978 // Steps:
3979 // 1. Clear the texture and DrawArrays.
3980 // 2. DispatchCompute to set the image's first pixel to a specific color.
3981 // 3. DrawArrays and check data.
TEST_P(ComputeShaderTest,DrawDispatchDrawPreserve)3982 TEST_P(ComputeShaderTest, DrawDispatchDrawPreserve)
3983 {
3984 // http://anglebug.com/5072
3985 ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux() && IsOpenGL());
3986
3987 const char kCSSource[] = R"(#version 310 es
3988 layout(local_size_x=1, local_size_y=1) in;
3989 layout(rgba8, binding = 0) writeonly uniform highp image2D image;
3990 void main()
3991 {
3992 imageStore(image, ivec2(0, 0), vec4(0.0, 0.0, 1.0, 1.0));
3993 })";
3994
3995 const char kVSSource[] = R"(#version 310 es
3996 layout (location = 0) in vec2 pos;
3997 in vec4 inTex;
3998 out vec4 texCoord;
3999 void main(void) {
4000 texCoord = inTex;
4001 gl_Position = vec4(pos, 0.0, 1.0);
4002 })";
4003
4004 const char kFSSource[] = R"(#version 310 es
4005 precision highp float;
4006 uniform sampler2D tex;
4007 in vec4 texCoord;
4008 out vec4 fragColor;
4009 void main(void) {
4010 fragColor = texture(tex, texCoord.xy);
4011 })";
4012 GLuint aPosLoc = 0;
4013 ANGLE_GL_PROGRAM(program, kVSSource, kFSSource);
4014 glBindAttribLocation(program, aPosLoc, "pos");
4015
4016 unsigned char *data = new unsigned char[4 * getWindowWidth() * getWindowHeight()];
4017 for (int i = 0; i < getWindowWidth() * getWindowHeight(); i++)
4018 {
4019 data[i * 4] = 0xff;
4020 data[i * 4 + 1] = 0;
4021 data[i * 4 + 2] = 0;
4022 data[i * 4 + 3] = 0xff;
4023 }
4024 GLTexture texture;
4025 glBindTexture(GL_TEXTURE_2D, texture);
4026 glTexStorage2D(GL_TEXTURE_2D, 2, GL_RGBA8, getWindowWidth(), getWindowHeight());
4027 // Clear the texture level 0 to Red.
4028 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, getWindowWidth(), getWindowHeight(), GL_RGBA,
4029 GL_UNSIGNED_BYTE, data);
4030 for (int i = 0; i < getWindowWidth() * getWindowHeight(); i++)
4031 {
4032 data[i * 4] = 0;
4033 data[i * 4 + 1] = 0xff;
4034 data[i * 4 + 2] = 0;
4035 data[i * 4 + 3] = 0xff;
4036 }
4037 // Clear the texture level 1 to Green.
4038 glTexSubImage2D(GL_TEXTURE_2D, 1, 0, 0, getWindowWidth() / 2, getWindowHeight() / 2, GL_RGBA,
4039 GL_UNSIGNED_BYTE, data);
4040 delete[] data;
4041 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
4042 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
4043 glUseProgram(program);
4044 GLfloat vertices[] = {-1, -1, 1, -1, -1, 1, 1, 1};
4045 GLfloat texCoords[] = {0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f};
4046 GLint pos = glGetAttribLocation(program, "pos");
4047 glEnableVertexAttribArray(pos);
4048 glVertexAttribPointer(pos, 2, GL_FLOAT, GL_FALSE, 0, vertices);
4049 GLint posTex = glGetAttribLocation(program, "inTex");
4050 glEnableVertexAttribArray(posTex);
4051 glVertexAttribPointer(posTex, 2, GL_FLOAT, GL_FALSE, 0, texCoords);
4052
4053 // Draw with level 0, the whole framebuffer should be Red.
4054 glViewport(0, 0, getWindowWidth(), getWindowHeight());
4055 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
4056 EXPECT_GL_NO_ERROR();
4057 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
4058 EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::red);
4059 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() - 1, getWindowHeight() - 1, GLColor::red);
4060 // Draw with level 1, a quarter of the framebuffer should be Green.
4061 glViewport(0, 0, getWindowWidth() / 2, getWindowHeight() / 2);
4062 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
4063 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
4064 EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::green);
4065 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2 - 1, getWindowHeight() / 2 - 1, GLColor::green);
4066
4067 // Clear the texture level 0's (0, 0) position to Blue.
4068 glBindImageTexture(0, texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA8);
4069 ANGLE_GL_COMPUTE_PROGRAM(csProgram, kCSSource);
4070 glUseProgram(csProgram);
4071 glDispatchCompute(1, 1, 1);
4072 glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT);
4073 EXPECT_GL_NO_ERROR();
4074 glFinish();
4075
4076 glUseProgram(program);
4077 // Draw with level 0, the first position should be Blue.
4078 glViewport(0, 0, getWindowWidth(), getWindowHeight());
4079 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
4080 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
4081 EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::red);
4082 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() - 1, getWindowHeight() - 1, GLColor::red);
4083 // Draw with level 1, a quarter of the framebuffer should be Green.
4084 glViewport(0, 0, getWindowWidth() / 2, getWindowHeight() / 2);
4085 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
4086 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
4087 EXPECT_PIXEL_COLOR_EQ(1, 1, GLColor::green);
4088 EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2 - 1, getWindowHeight() / 2 - 1, GLColor::green);
4089 }
4090
4091 // Test that maxComputeWorkGroupCount is valid number.
TEST_P(ComputeShaderTest,ValidateMaxComputeWorkGroupCount)4092 TEST_P(ComputeShaderTest, ValidateMaxComputeWorkGroupCount)
4093 {
4094 constexpr char kCS[] = R"(#version 310 es
4095 layout(local_size_x=1) in;
4096 void main()
4097 {
4098 })";
4099
4100 GLuint program = glCreateProgram();
4101 GLuint cs = CompileShader(GL_COMPUTE_SHADER, kCS);
4102 EXPECT_NE(0u, cs);
4103
4104 glAttachShader(program, cs);
4105 glDeleteShader(cs);
4106
4107 GLint x, y, z;
4108 glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 0, &x);
4109 EXPECT_LE(65535, x);
4110 EXPECT_GE(std::numeric_limits<GLint>::max(), x);
4111
4112 glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 1, &y);
4113 EXPECT_LE(65535, y);
4114 EXPECT_GE(std::numeric_limits<GLint>::max(), y);
4115
4116 glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 2, &z);
4117 EXPECT_LE(65535, z);
4118 EXPECT_GE(std::numeric_limits<GLint>::max(), z);
4119
4120 glDeleteProgram(program);
4121 EXPECT_GL_NO_ERROR();
4122 }
4123
4124 // Validate that on Vulkan, compute pipeline driver uniforms descriptor set is updated after an
4125 // internal compute-based UtilsVk function is used. The latter is achieved through a draw with a
4126 // vertex buffer whose format is not natively supported. Atomic counters are used to make sure the
4127 // compute pipeline uses the driver uniforms descriptor set.
TEST_P(ComputeShaderTest,DispatchConvertVertexDispatch)4128 TEST_P(ComputeShaderTest, DispatchConvertVertexDispatch)
4129 {
4130 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_vertex_type_10_10_10_2"));
4131
4132 constexpr uint32_t kVertexCount = 6;
4133
4134 constexpr char kCS[] = R"(#version 310 es
4135 layout(local_size_x=6, local_size_y=1, local_size_z=1) in;
4136
4137 layout(binding = 0) uniform atomic_uint ac;
4138
4139 layout(binding=0, std140) buffer VertexData
4140 {
4141 uint data[];
4142 };
4143
4144 void main()
4145 {
4146 atomicCounterIncrement(ac);
4147 data[gl_GlobalInvocationID.x] = gl_GlobalInvocationID.x;
4148 })";
4149
4150 constexpr char kVS[] = R"(#version 310 es
4151 precision mediump float;
4152
4153 layout(location = 0) in vec4 position;
4154 layout(location = 1) in uvec4 data;
4155
4156 out vec4 color;
4157
4158 void main() {
4159 color = data.x < 6u && data.y == 0u && data.z == 0u && data.w == 0u
4160 ? vec4(0.0, 1.0, 0.0, 1.0) : vec4(1.0, 0.0, 0.0, 1.0);
4161 gl_Position = position;
4162 })";
4163
4164 constexpr char kFS[] = R"(#version 310 es
4165 precision mediump float;
4166 in vec4 color;
4167 out vec4 colorOut;
4168 void main() {
4169 colorOut = color;
4170 })";
4171
4172 ANGLE_GL_COMPUTE_PROGRAM(programCS, kCS);
4173 ANGLE_GL_PROGRAM(programVSFS, kVS, kFS);
4174 EXPECT_GL_NO_ERROR();
4175
4176 // Create atomic counter buffer
4177 GLBuffer atomicCounterBuffer;
4178 constexpr GLuint kInitialAcbData = 0;
4179 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicCounterBuffer);
4180 glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(kInitialAcbData), &kInitialAcbData,
4181 GL_STATIC_DRAW);
4182 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, atomicCounterBuffer);
4183 EXPECT_GL_NO_ERROR();
4184
4185 // Create vertex buffer
4186 constexpr unsigned kVertexBufferInitData[kVertexCount] = {};
4187 GLBuffer vertexBuffer;
4188 glBindBuffer(GL_SHADER_STORAGE_BUFFER, vertexBuffer);
4189 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(kVertexBufferInitData), kVertexBufferInitData,
4190 GL_STATIC_DRAW);
4191 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, vertexBuffer);
4192 EXPECT_GL_NO_ERROR();
4193
4194 // Create position buffer
4195 constexpr GLfloat positions[kVertexCount * 2] = {1.0, 1.0, -1.0, 1.0, -1.0, -1.0,
4196 1.0, 1.0, -1.0, -1.0, 1.0, -1.0};
4197 GLBuffer positionBuffer;
4198 glBindBuffer(GL_ARRAY_BUFFER, positionBuffer);
4199 glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, GL_STATIC_DRAW);
4200 EXPECT_GL_NO_ERROR();
4201
4202 // Create vertex array
4203 GLVertexArray vao;
4204 glBindVertexArray(vao);
4205
4206 glBindBuffer(GL_ARRAY_BUFFER, positionBuffer);
4207 glEnableVertexAttribArray(0);
4208 glVertexAttribPointer(0, 2, GL_FLOAT, false, 0, 0);
4209
4210 glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
4211 glEnableVertexAttribArray(1);
4212 glVertexAttribPointer(1, 4, GL_UNSIGNED_INT_10_10_10_2_OES, false, 0, 0);
4213 EXPECT_GL_NO_ERROR();
4214
4215 // Fill the vertex buffer with a dispatch call
4216 glUseProgram(programCS);
4217 glDispatchCompute(1, 1, 1);
4218 EXPECT_GL_NO_ERROR();
4219
4220 glMemoryBarrier(GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT);
4221
4222 // Draw using the vertex buffer, causing vertex format conversion in compute (in the Vulkan
4223 // backend)
4224 glUseProgram(programVSFS);
4225 glBindVertexArray(vao);
4226 glDrawArrays(GL_TRIANGLES, 0, kVertexCount);
4227 EXPECT_GL_NO_ERROR();
4228
4229 // Issue another dispatch call. The driver uniforms descriptor set must be rebound.
4230 glUseProgram(programCS);
4231 glDispatchCompute(1, 1, 1);
4232 EXPECT_GL_NO_ERROR();
4233
4234 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
4235
4236 // Verify that the atomic counter has the expected value.
4237 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomicCounterBuffer);
4238 GLuint *mappedBuffer = static_cast<GLuint *>(
4239 glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint), GL_MAP_READ_BIT));
4240 EXPECT_EQ(kVertexCount * 2, mappedBuffer[0]);
4241 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
4242 }
4243
4244 // Validate that on Vulkan, compute pipeline is correctly bound after an internal dispatch call is
4245 // made. Blit stencil may issue a dispatch call.
TEST_P(ComputeShaderTest,DispatchBlitStencilDispatch)4246 TEST_P(ComputeShaderTest, DispatchBlitStencilDispatch)
4247 {
4248 // http://anglebug.com/5533
4249 ANGLE_SKIP_TEST_IF(IsQualcomm() && IsOpenGLES());
4250
4251 // http://anglebug.com/5072
4252 ANGLE_SKIP_TEST_IF(IsIntel() && IsLinux() && IsOpenGL());
4253
4254 constexpr GLsizei kSize = 1;
4255
4256 constexpr char kCS[] = R"(#version 310 es
4257 layout(local_size_x=6, local_size_y=1, local_size_z=1) in;
4258
4259 uniform vec4 data;
4260
4261 layout(rgba8, binding = 0) writeonly uniform highp image2D image;
4262
4263 void main()
4264 {
4265 imageStore(image, ivec2(gl_LocalInvocationID.xy), data);
4266 })";
4267
4268 ANGLE_GL_COMPUTE_PROGRAM(programCS, kCS);
4269 EXPECT_GL_NO_ERROR();
4270
4271 // Create a framebuffer with stencil buffer. Use multisampled textures so the future blit
4272 // cannot use vkCmdBlitImage.
4273 GLTexture color;
4274 glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, color);
4275 glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA8, kSize, kSize, true);
4276
4277 GLTexture depthStencil;
4278 glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, depthStencil);
4279 glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_DEPTH24_STENCIL8, kSize, kSize,
4280 true);
4281
4282 GLFramebuffer fbo;
4283 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
4284 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, color,
4285 0);
4286 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D_MULTISAMPLE,
4287 depthStencil, 0);
4288 ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
4289 ASSERT_GL_NO_ERROR();
4290
4291 // Clear the stencil and make sure it's done.
4292 glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
4293 glClearStencil(0x55);
4294 glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
4295
4296 glEnable(GL_STENCIL_TEST);
4297 glStencilFunc(GL_EQUAL, 0x55, 0xFF);
4298 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
4299 glStencilMask(0xFF);
4300
4301 ANGLE_GL_PROGRAM(drawRed, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red());
4302 drawQuad(drawRed, essl1_shaders::PositionAttrib(), 0.0f);
4303 ASSERT_GL_NO_ERROR();
4304
4305 GLTexture colorCopy;
4306 glBindTexture(GL_TEXTURE_2D, colorCopy);
4307 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, kSize, kSize);
4308
4309 GLFramebuffer copyFbo;
4310 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, copyFbo);
4311 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorCopy, 0);
4312 ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_DRAW_FRAMEBUFFER);
4313 glBlitFramebuffer(0, 0, kSize, kSize, 0, 0, kSize, kSize, GL_COLOR_BUFFER_BIT, GL_NEAREST);
4314 ASSERT_GL_NO_ERROR();
4315
4316 glBindFramebuffer(GL_READ_FRAMEBUFFER, copyFbo);
4317 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
4318
4319 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
4320
4321 // Setup image for compute call
4322 GLTexture computeOut;
4323 glBindTexture(GL_TEXTURE_2D, computeOut);
4324 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, kSize, kSize);
4325 glBindImageTexture(0, computeOut, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA8);
4326 ASSERT_GL_NO_ERROR();
4327
4328 // Issue a dispatch call.
4329 glUseProgram(programCS);
4330 GLint uniformLoc = glGetUniformLocation(programCS, "data");
4331 ASSERT_NE(uniformLoc, -1);
4332
4333 glUniform4f(uniformLoc, 0.0f, 0.0f, 1.0f, 1.0f);
4334 glDispatchCompute(1, 1, 1);
4335 glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
4336 ASSERT_GL_NO_ERROR();
4337
4338 // Blit the stencil texture. This may use a compute shader internally.
4339 GLTexture depthStencilCopy;
4340 glBindTexture(GL_TEXTURE_2D, depthStencilCopy);
4341 glTexStorage2D(GL_TEXTURE_2D, 1, GL_DEPTH24_STENCIL8, kSize, kSize);
4342 ASSERT_GL_NO_ERROR();
4343
4344 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, copyFbo);
4345 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
4346 depthStencilCopy, 0);
4347 ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_DRAW_FRAMEBUFFER);
4348 ASSERT_GL_NO_ERROR();
4349
4350 glBlitFramebuffer(0, 0, kSize, kSize, 0, 0, kSize, kSize, GL_STENCIL_BUFFER_BIT, GL_NEAREST);
4351 ASSERT_GL_NO_ERROR();
4352
4353 // Issue another dispatch call.
4354 glUniform4f(uniformLoc, 0.0f, 1.0f, 0.0f, 1.0f);
4355 glDispatchCompute(1, 1, 1);
4356 ASSERT_GL_NO_ERROR();
4357
4358 // Verify the results.
4359 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
4360 glBindFramebuffer(GL_FRAMEBUFFER, copyFbo);
4361 glBindTexture(GL_TEXTURE_2D, computeOut);
4362 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, computeOut, 0);
4363 ASSERT_GL_NO_ERROR();
4364
4365 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
4366
4367 // Verify the blit copy results.
4368 drawQuad(drawRed, essl1_shaders::PositionAttrib(), 0.0f);
4369 ASSERT_GL_NO_ERROR();
4370
4371 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
4372 }
4373
4374 // Validate that on Vulkan, compute pipeline is correctly bound after an internal dispatch call is
4375 // made. Generate mipmap may issue a dispatch call.
TEST_P(ComputeShaderTest,DispatchGenerateMipmapDispatch)4376 TEST_P(ComputeShaderTest, DispatchGenerateMipmapDispatch)
4377 {
4378 constexpr GLsizei kSize = 8;
4379
4380 constexpr char kCS[] = R"(#version 310 es
4381 layout(local_size_x=6, local_size_y=1, local_size_z=1) in;
4382
4383 uniform vec4 data;
4384
4385 layout(rgba8, binding = 0) writeonly uniform highp image2D image;
4386
4387 void main()
4388 {
4389 imageStore(image, ivec2(gl_LocalInvocationID.xy), data);
4390 })";
4391
4392 ANGLE_GL_COMPUTE_PROGRAM(programCS, kCS);
4393 EXPECT_GL_NO_ERROR();
4394
4395 GLTexture color;
4396 glBindTexture(GL_TEXTURE_2D, color);
4397 glTexStorage2D(GL_TEXTURE_2D, 4, GL_RGBA8, kSize, kSize);
4398
4399 const std::vector<GLColor> kInitialColor(kSize * kSize, GLColor::green);
4400 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kSize, kSize, GL_RGBA, GL_UNSIGNED_BYTE,
4401 kInitialColor.data());
4402
4403 // Setup image for compute call
4404 GLTexture computeOut;
4405 glBindTexture(GL_TEXTURE_2D, computeOut);
4406 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, kSize, kSize);
4407 glBindImageTexture(0, computeOut, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA8);
4408 ASSERT_GL_NO_ERROR();
4409
4410 // Issue a dispatch call.
4411 glUseProgram(programCS);
4412 GLint uniformLoc = glGetUniformLocation(programCS, "data");
4413 ASSERT_NE(uniformLoc, -1);
4414
4415 glUniform4f(uniformLoc, 0.0f, 0.0f, 1.0f, 1.0f);
4416 glDispatchCompute(1, 1, 1);
4417 glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
4418 ASSERT_GL_NO_ERROR();
4419
4420 // Generate mipmap on the texture. This may use a compute shader internally.
4421 glBindTexture(GL_TEXTURE_2D, color);
4422 glGenerateMipmap(GL_TEXTURE_2D);
4423
4424 // Issue another dispatch call.
4425 glUniform4f(uniformLoc, 0.0f, 1.0f, 0.0f, 1.0f);
4426 glDispatchCompute(1, 1, 1);
4427 ASSERT_GL_NO_ERROR();
4428
4429 // Verify the results.
4430 GLFramebuffer fbo;
4431 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
4432 glBindTexture(GL_TEXTURE_2D, computeOut);
4433 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, computeOut, 0);
4434 ASSERT_GL_NO_ERROR();
4435
4436 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
4437 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
4438 }
4439
4440 // Write to image array with an aliasing format.
TEST_P(ComputeShaderTest,AliasingFormatForImageArray)4441 TEST_P(ComputeShaderTest, AliasingFormatForImageArray)
4442 {
4443 // http://anglebug.com/5352
4444 ANGLE_SKIP_TEST_IF(IsD3D11());
4445
4446 constexpr char kCS[] = R"(#version 310 es
4447 layout(local_size_x=1, local_size_y=1, local_size_z=2) in;
4448 layout(r32ui, binding = 0) writeonly uniform highp uimage2DArray image;
4449 void main()
4450 {
4451 uint yellow = 0xFF00FFFFu;
4452 imageStore(image, ivec3(gl_LocalInvocationID.xyz), uvec4(yellow, 0, 0, 0));
4453 })";
4454
4455 constexpr int kWidth = 1, kHeight = 1, kDepth = 2;
4456
4457 const std::vector<GLColor> kInitData(kWidth * kHeight * kDepth, GLColor::black);
4458
4459 GLTexture texture;
4460 glBindTexture(GL_TEXTURE_2D_ARRAY, texture);
4461 glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_RGBA8, kWidth, kHeight, kDepth);
4462 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, kWidth, kHeight, kDepth, GL_RGBA,
4463 GL_UNSIGNED_BYTE, kInitData.data());
4464 EXPECT_GL_NO_ERROR();
4465
4466 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
4467 glUseProgram(program);
4468
4469 // Output yellow to both layers.
4470 glBindImageTexture(0, texture, 0, GL_TRUE, 0, GL_WRITE_ONLY, GL_R32UI);
4471 glDispatchCompute(1, 1, 1);
4472 EXPECT_GL_NO_ERROR();
4473
4474 // Verify results.
4475 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
4476 EXPECT_GL_NO_ERROR();
4477
4478 GLFramebuffer framebuffer;
4479 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
4480 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0, 0);
4481 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, texture, 0, 1);
4482 EXPECT_GL_NO_ERROR();
4483
4484 glReadBuffer(GL_COLOR_ATTACHMENT0);
4485 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow);
4486
4487 glReadBuffer(GL_COLOR_ATTACHMENT1);
4488 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow);
4489 }
4490
4491 // Write to one layer of image array with an aliasing format.
TEST_P(ComputeShaderTest,AliasingFormatForOneLayerOfImageArray)4492 TEST_P(ComputeShaderTest, AliasingFormatForOneLayerOfImageArray)
4493 {
4494 // http://anglebug.com/5352
4495 ANGLE_SKIP_TEST_IF(IsD3D11());
4496
4497 constexpr char kCS[] = R"(#version 310 es
4498 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
4499 layout(r32ui, binding = 0) writeonly uniform highp uimage2D image;
4500 void main()
4501 {
4502 uint yellow = 0xFF00FFFFu;
4503 imageStore(image, ivec2(gl_LocalInvocationID.xy), uvec4(yellow, 0, 0, 0));
4504 })";
4505
4506 constexpr int kWidth = 1, kHeight = 1, kDepth = 2;
4507
4508 const std::vector<GLColor> kInitData(kWidth * kHeight * kDepth, GLColor::black);
4509
4510 GLTexture texture;
4511 glBindTexture(GL_TEXTURE_2D_ARRAY, texture);
4512 glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_RGBA8, kWidth, kHeight, kDepth);
4513 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, kWidth, kHeight, kDepth, GL_RGBA,
4514 GL_UNSIGNED_BYTE, kInitData.data());
4515 EXPECT_GL_NO_ERROR();
4516
4517 GLFramebuffer framebuffer;
4518 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
4519 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0, 0);
4520 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, texture, 0, 1);
4521 EXPECT_GL_NO_ERROR();
4522
4523 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
4524 glUseProgram(program);
4525
4526 // Output yellow to layer 0.
4527 glBindImageTexture(0, texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
4528 glDispatchCompute(1, 1, 1);
4529 EXPECT_GL_NO_ERROR();
4530
4531 // Verify that only layer 0 was changed.
4532 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
4533 EXPECT_GL_NO_ERROR();
4534
4535 glReadBuffer(GL_COLOR_ATTACHMENT0);
4536 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow);
4537
4538 glReadBuffer(GL_COLOR_ATTACHMENT1);
4539 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
4540
4541 // Reset texture back to black.
4542 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, kWidth, kHeight, kDepth, GL_RGBA,
4543 GL_UNSIGNED_BYTE, kInitData.data());
4544
4545 // Output yellow to layer 1.
4546 glBindImageTexture(0, texture, 0, GL_FALSE, 1, GL_WRITE_ONLY, GL_R32UI);
4547 glDispatchCompute(1, 1, 1);
4548 EXPECT_GL_NO_ERROR();
4549
4550 // Verify that only layer 1 was changed.
4551 glMemoryBarrier(GL_FRAMEBUFFER_BARRIER_BIT);
4552 EXPECT_GL_NO_ERROR();
4553
4554 glReadBuffer(GL_COLOR_ATTACHMENT0);
4555 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
4556
4557 glReadBuffer(GL_COLOR_ATTACHMENT1);
4558 EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::yellow);
4559 }
4560
4561 // Test glMemoryBarrier(CLIENT_MAPPED_BUFFER_BARRIER_BIT_EXT) by writing to persistenly mapped
4562 // buffer from a compute shader.
TEST_P(ComputeShaderTest,WriteToPersistentBuffer)4563 TEST_P(ComputeShaderTest, WriteToPersistentBuffer)
4564 {
4565 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_buffer_storage"));
4566
4567 constexpr char kCS[] = R"(#version 310 es
4568 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
4569 layout(std140, binding = 0) buffer block {
4570 uvec4 data;
4571 } outBlock;
4572 void main()
4573 {
4574 outBlock.data += uvec4(1);
4575 })";
4576
4577 ANGLE_GL_COMPUTE_PROGRAM(program, kCS);
4578 glUseProgram(program);
4579
4580 constexpr std::array<uint32_t, 4> kInitData = {};
4581
4582 GLBuffer coherentBuffer;
4583 glBindBuffer(GL_SHADER_STORAGE_BUFFER, coherentBuffer);
4584 glBufferStorageEXT(
4585 GL_SHADER_STORAGE_BUFFER, sizeof(kInitData), kInitData.data(),
4586 GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT_EXT | GL_MAP_COHERENT_BIT_EXT);
4587
4588 GLBuffer nonCoherentBuffer;
4589 glBindBuffer(GL_SHADER_STORAGE_BUFFER, nonCoherentBuffer);
4590 glBufferStorageEXT(GL_SHADER_STORAGE_BUFFER, sizeof(kInitData), kInitData.data(),
4591 GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT_EXT);
4592
4593 // Map the buffers for read and write.
4594 glBindBuffer(GL_SHADER_STORAGE_BUFFER, coherentBuffer);
4595 uint32_t *coherentMapped = reinterpret_cast<uint32_t *>(glMapBufferRange(
4596 GL_SHADER_STORAGE_BUFFER, 0, sizeof(kInitData),
4597 GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT_EXT | GL_MAP_COHERENT_BIT_EXT));
4598 ASSERT_GL_NO_ERROR();
4599
4600 glBindBuffer(GL_SHADER_STORAGE_BUFFER, nonCoherentBuffer);
4601 uint32_t *nonCoherentMapped = reinterpret_cast<uint32_t *>(
4602 glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(kInitData),
4603 GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT_EXT));
4604 ASSERT_GL_NO_ERROR();
4605
4606 constexpr std::array<uint32_t, 4> kCoherentExpectedData = {
4607 0x12354678u,
4608 0x2468ACE0u,
4609 0x13579BDFu,
4610 0x76543210u,
4611 };
4612
4613 constexpr std::array<uint32_t, 4> kNonCoherentExpectedData = {
4614 0x9ABCDEF0u,
4615 0xFDB97531u,
4616 0x1F2E3D4Bu,
4617 0x5A697887u,
4618 };
4619
4620 coherentMapped[0] = kCoherentExpectedData[0] - 1;
4621 coherentMapped[1] = kCoherentExpectedData[1] - 1;
4622 coherentMapped[2] = kCoherentExpectedData[2] - 1;
4623 coherentMapped[3] = kCoherentExpectedData[3] - 1;
4624
4625 nonCoherentMapped[0] = kNonCoherentExpectedData[0] - 1;
4626 nonCoherentMapped[1] = kNonCoherentExpectedData[1] - 1;
4627 nonCoherentMapped[2] = kNonCoherentExpectedData[2] - 1;
4628 nonCoherentMapped[3] = kNonCoherentExpectedData[3] - 1;
4629
4630 // Test coherent write
4631 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, coherentBuffer);
4632 glDispatchCompute(1, 1, 1);
4633 EXPECT_GL_NO_ERROR();
4634
4635 glFinish();
4636 EXPECT_EQ(coherentMapped[0], kCoherentExpectedData[0]);
4637 EXPECT_EQ(coherentMapped[1], kCoherentExpectedData[1]);
4638 EXPECT_EQ(coherentMapped[2], kCoherentExpectedData[2]);
4639 EXPECT_EQ(coherentMapped[3], kCoherentExpectedData[3]);
4640
4641 // Test non-coherent write
4642 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, nonCoherentBuffer);
4643 glDispatchCompute(1, 1, 1);
4644
4645 glMemoryBarrier(GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT_EXT);
4646 EXPECT_GL_NO_ERROR();
4647
4648 glFinish();
4649 EXPECT_EQ(nonCoherentMapped[0], kNonCoherentExpectedData[0]);
4650 EXPECT_EQ(nonCoherentMapped[1], kNonCoherentExpectedData[1]);
4651 EXPECT_EQ(nonCoherentMapped[2], kNonCoherentExpectedData[2]);
4652 EXPECT_EQ(nonCoherentMapped[3], kNonCoherentExpectedData[3]);
4653
4654 glBindBuffer(GL_SHADER_STORAGE_BUFFER, coherentBuffer);
4655 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
4656 glBindBuffer(GL_SHADER_STORAGE_BUFFER, nonCoherentBuffer);
4657 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
4658 EXPECT_GL_NO_ERROR();
4659 }
4660
4661 // Verify the CS doesn't overwrite the mapped buffer data.
TEST_P(ComputeShaderTest,ImageBufferMapWrite)4662 TEST_P(ComputeShaderTest, ImageBufferMapWrite)
4663 {
4664 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_texture_buffer"));
4665
4666 // Claims to support GL_OES_texture_buffer, but fails compilation of shader because "extension
4667 // 'GL_OES_texture_buffer' is not supported". http://anglebug.com/5832
4668 ANGLE_SKIP_TEST_IF(IsQualcomm() && IsOpenGLES());
4669
4670 constexpr char kComputeImageBuffer[] = R"(#version 310 es
4671 #extension GL_OES_texture_buffer : require
4672 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
4673 layout(rgba32f, binding = 0) uniform highp writeonly imageBuffer dst;
4674 uniform vec4 uniformData;
4675 void main()
4676 {
4677 imageStore(dst, int(gl_GlobalInvocationID.x), uniformData);
4678 })";
4679
4680 GLProgram program;
4681 program.makeCompute(kComputeImageBuffer);
4682 glUseProgram(program);
4683
4684 GLBuffer textureBufferStorage;
4685 GLTexture texture;
4686 constexpr std::array<float, 4> kInitData = {1.0, 0.0, 0.0, 1.0};
4687
4688 glBindBuffer(GL_TEXTURE_BUFFER, textureBufferStorage);
4689 glBufferData(GL_TEXTURE_BUFFER, sizeof(kInitData), kInitData.data(), GL_STATIC_DRAW);
4690 EXPECT_GL_NO_ERROR();
4691
4692 glBindTexture(GL_TEXTURE_BUFFER, texture);
4693 glTexBufferEXT(GL_TEXTURE_BUFFER, GL_RGBA32F, textureBufferStorage);
4694 glBindImageTexture(0, texture, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32F);
4695 EXPECT_GL_NO_ERROR();
4696
4697 constexpr std::array<float, 4> kComputeShaderData = {0.0, 1.0, 0.0, 1.0};
4698 GLint uniformLocation = glGetUniformLocation(program, "uniformData");
4699 ASSERT_NE(uniformLocation, -1);
4700 glUniform4f(uniformLocation, kComputeShaderData[0], kComputeShaderData[1],
4701 kComputeShaderData[2], kComputeShaderData[3]);
4702 EXPECT_GL_NO_ERROR();
4703
4704 // Write to the buffer with the CS.
4705 glDispatchCompute(1, 1, 1);
4706
4707 // Issue the appropriate memory barrier before mapping the buffer.
4708 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
4709
4710 // Map the buffer and write to it.
4711 constexpr std::array<float, 4> kMapData = {0.0, 0.0, 1.0, 1.0};
4712 void *mappedBuffer =
4713 glMapBufferRange(GL_TEXTURE_BUFFER, 0, sizeof(GLuint) * 3, GL_MAP_WRITE_BIT);
4714 memcpy(mappedBuffer, kMapData.data(), sizeof(kMapData));
4715 glUnmapBuffer(GL_TEXTURE_BUFFER);
4716
4717 glFinish();
4718
4719 // Read back and verify buffer data.
4720 std::array<float, 4> bufferData = {0};
4721 mappedBuffer = glMapBufferRange(GL_TEXTURE_BUFFER, 0, sizeof(GLuint) * 3, GL_MAP_READ_BIT);
4722 memcpy(bufferData.data(), mappedBuffer, sizeof(bufferData));
4723 glUnmapBuffer(GL_TEXTURE_BUFFER);
4724
4725 EXPECT_EQ(bufferData[0], kMapData[0]);
4726 EXPECT_EQ(bufferData[1], kMapData[1]);
4727 EXPECT_EQ(bufferData[2], kMapData[2]);
4728 EXPECT_EQ(bufferData[3], kMapData[3]);
4729 }
4730
4731 // Test compute shader write to texture buffer followed by texSubData and followed by compute shader
4732 // write to texture buffer again.
TEST_P(ComputeShaderTest,ImageBufferMapWriteAndBufferSubData)4733 TEST_P(ComputeShaderTest, ImageBufferMapWriteAndBufferSubData)
4734 {
4735 ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_texture_buffer"));
4736
4737 // Claims to support GL_OES_texture_buffer, but fails compilation of shader because "extension
4738 // 'GL_OES_texture_buffer' is not supported". http://anglebug.com/5832
4739 ANGLE_SKIP_TEST_IF(IsQualcomm() && IsOpenGLES());
4740
4741 // angleporject:6545. Known bug.
4742 ANGLE_SKIP_TEST_IF(IsVulkan());
4743
4744 constexpr char kComputeImageBuffer[] = R"(#version 310 es
4745 #extension GL_OES_texture_buffer : require
4746 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
4747 layout(rgba32f, binding = 0) uniform highp writeonly imageBuffer dst;
4748 uniform vec4 uniformData;
4749 uniform int uniformOffset;
4750 void main()
4751 {
4752 imageStore(dst, uniformOffset, uniformData);
4753 })";
4754
4755 GLProgram program;
4756 program.makeCompute(kComputeImageBuffer);
4757 glUseProgram(program);
4758
4759 for (int loop = 0; loop < 2; loop++)
4760 {
4761 GLBuffer textureBufferStorage;
4762 GLTexture texture;
4763 constexpr unsigned int kShaderUsedSize = sizeof(float) * 4;
4764 constexpr unsigned int kMiddlePaddingSize = 1024;
4765 constexpr unsigned int kBufferSize = kShaderUsedSize + kMiddlePaddingSize + kShaderUsedSize;
4766 constexpr unsigned int kOffset0 = 0;
4767 constexpr unsigned int kOffset1 = kShaderUsedSize;
4768 constexpr unsigned int kOffset2 = kShaderUsedSize + kMiddlePaddingSize;
4769
4770 glBindBuffer(GL_TEXTURE_BUFFER, textureBufferStorage);
4771 glBufferData(GL_TEXTURE_BUFFER, kBufferSize, nullptr, GL_STATIC_DRAW);
4772
4773 glBindTexture(GL_TEXTURE_BUFFER, texture);
4774 glTexBufferEXT(GL_TEXTURE_BUFFER, GL_RGBA32F, textureBufferStorage);
4775 glBindImageTexture(0, texture, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32F);
4776
4777 // Write to the buffer with the CS.
4778 constexpr std::array<float, 4> kComputeShaderData1 = {0.0, 1.0, 0.0, 1.0};
4779 GLint uniformDataLocation = glGetUniformLocation(program, "uniformData");
4780 ASSERT_NE(uniformDataLocation, -1);
4781 glUniform4f(uniformDataLocation, kComputeShaderData1[0], kComputeShaderData1[1],
4782 kComputeShaderData1[2], kComputeShaderData1[3]);
4783 GLint uniformOffsetLocation = glGetUniformLocation(program, "uniformOffset");
4784 ASSERT_NE(uniformOffsetLocation, -1);
4785 glUniform1i(uniformOffsetLocation, kOffset0 / (sizeof(float) * 4));
4786 glDispatchCompute(1, 1, 1);
4787 // Issue the appropriate memory barrier before mapping the buffer.
4788 glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
4789
4790 // Write to the buffer with the CS.
4791 constexpr std::array<float, 4> kComputeShaderData2 = {1.0, 0.0, 1.0, 1.0};
4792 glUniform4f(uniformDataLocation, kComputeShaderData2[0], kComputeShaderData2[1],
4793 kComputeShaderData2[2], kComputeShaderData2[3]);
4794 glUniform1i(uniformOffsetLocation, kOffset2 / (sizeof(float) * 4));
4795 glDispatchCompute(1, 1, 1);
4796
4797 if (loop == 1)
4798 {
4799 // Make write operation finished but read operation pending. We don't care actual
4800 // rendering result but just to have a unflushed rendering using the buffer so that it
4801 // will appears as pending.
4802 glFinish();
4803 constexpr char kVS[] = R"(attribute vec4 in_attrib;
4804 varying vec4 v_attrib;
4805 void main()
4806 {
4807 v_attrib = in_attrib;
4808 gl_Position = vec4(0.0, 0.0, 0.5, 1.0);
4809 gl_PointSize = 100.0;
4810 })";
4811 constexpr char kFS[] = R"(precision mediump float;
4812 varying vec4 v_attrib;
4813 void main()
4814 {
4815 gl_FragColor = v_attrib;
4816 })";
4817 GLuint readProgram = CompileProgram(kVS, kFS);
4818 ASSERT_NE(readProgram, 0U);
4819 GLint attribLocation = glGetAttribLocation(readProgram, "in_attrib");
4820 ASSERT_NE(attribLocation, -1);
4821 glUseProgram(readProgram);
4822 ASSERT_GL_NO_ERROR();
4823 glMemoryBarrier(GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT | GL_ELEMENT_ARRAY_BARRIER_BIT);
4824 glBindBuffer(GL_ARRAY_BUFFER, textureBufferStorage);
4825 glVertexAttribPointer(attribLocation, 4, GL_UNSIGNED_BYTE, GL_TRUE, 4, nullptr);
4826 glEnableVertexAttribArray(attribLocation);
4827 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, textureBufferStorage);
4828 glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
4829 glDrawElements(GL_POINTS, 1, GL_UNSIGNED_INT, nullptr);
4830 ASSERT_GL_NO_ERROR();
4831 }
4832
4833 // Use subData to update middle portion of data to trigger acquireAndUpdate code path in
4834 // ANGLE
4835 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
4836 glBindBuffer(GL_TEXTURE_BUFFER, textureBufferStorage);
4837 constexpr unsigned int kMiddlePaddingValue = 0x55555555u;
4838 std::vector<unsigned int> kPaddingValues(kMiddlePaddingSize / sizeof(unsigned int),
4839 kMiddlePaddingValue);
4840 glBufferSubData(GL_TEXTURE_BUFFER, kOffset1, kMiddlePaddingSize, kPaddingValues.data());
4841
4842 // Read back and verify buffer data.
4843 const GLbyte *mappedBuffer = reinterpret_cast<const GLbyte *>(
4844 glMapBufferRange(GL_TEXTURE_BUFFER, 0, kBufferSize, GL_MAP_READ_BIT));
4845
4846 const GLfloat *ptr0 = reinterpret_cast<const GLfloat *>(mappedBuffer);
4847 EXPECT_EQ(ptr0[0], kComputeShaderData1[0]);
4848 EXPECT_EQ(ptr0[1], kComputeShaderData1[1]);
4849 EXPECT_EQ(ptr0[2], kComputeShaderData1[2]);
4850 EXPECT_EQ(ptr0[3], kComputeShaderData1[3]);
4851
4852 const GLuint *ptr1 = reinterpret_cast<const GLuint *>(mappedBuffer + kOffset1);
4853 for (unsigned int idx = 0; idx < kMiddlePaddingSize / sizeof(unsigned int); idx++)
4854 {
4855 EXPECT_EQ(ptr1[idx], kMiddlePaddingValue);
4856 }
4857
4858 const GLfloat *ptr2 = reinterpret_cast<const GLfloat *>(mappedBuffer + kOffset2);
4859 EXPECT_EQ(ptr2[0], kComputeShaderData2[0]);
4860 EXPECT_EQ(ptr2[1], kComputeShaderData2[1]);
4861 EXPECT_EQ(ptr2[2], kComputeShaderData2[2]);
4862 EXPECT_EQ(ptr2[3], kComputeShaderData2[3]);
4863
4864 glUnmapBuffer(GL_TEXTURE_BUFFER);
4865 EXPECT_GL_NO_ERROR();
4866 }
4867 }
4868
4869 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ComputeShaderTest);
4870 ANGLE_INSTANTIATE_TEST_ES31(ComputeShaderTest);
4871
4872 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ComputeShaderTestES3);
4873 ANGLE_INSTANTIATE_TEST_ES3(ComputeShaderTestES3);
4874
4875 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WebGL2ComputeTest);
4876 ANGLE_INSTANTIATE_TEST_ES31(WebGL2ComputeTest);
4877 } // namespace
4878