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