blob: a22eaad9ee88122721ee43ac8d4fce0a7ec4032b [file] [log] [blame]
Martin Radev4c4c8e72016-08-04 12:25:34 +03001//
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
Xinghua Cao08a8ec82017-12-27 13:31:11 +08009#include <vector>
Martin Radev4c4c8e72016-08-04 12:25:34 +030010#include "test_utils/ANGLETest.h"
11#include "test_utils/gl_raii.h"
Martin Radev4c4c8e72016-08-04 12:25:34 +030012
13using namespace angle;
14
15namespace
16{
17
18class ComputeShaderTest : public ANGLETest
19{
20 protected:
21 ComputeShaderTest() {}
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +080022
Jiawei Shaoa6a78422018-06-28 08:32:54 +080023 template <class T, GLint kWidth, GLint kHeight>
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +080024 void runSharedMemoryTest(const char *csSource,
Jiawei Shaoa6a78422018-06-28 08:32:54 +080025 GLenum internalFormat,
26 GLenum format,
27 const std::array<T, kWidth * kHeight> &inputData,
28 const std::array<T, kWidth * kHeight> &expectedValues)
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +080029 {
30 GLTexture texture[2];
31 GLFramebuffer framebuffer;
32
33 glBindTexture(GL_TEXTURE_2D, texture[0]);
Jiawei Shaoa6a78422018-06-28 08:32:54 +080034 glTexStorage2D(GL_TEXTURE_2D, 1, internalFormat, kWidth, kHeight);
35 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, format,
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +080036 inputData.data());
37 EXPECT_GL_NO_ERROR();
38
Jiawei Shaoa6a78422018-06-28 08:32:54 +080039 constexpr T initData[kWidth * kHeight] = {};
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +080040 glBindTexture(GL_TEXTURE_2D, texture[1]);
Jiawei Shaoa6a78422018-06-28 08:32:54 +080041 glTexStorage2D(GL_TEXTURE_2D, 1, internalFormat, kWidth, kHeight);
42 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, format, initData);
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +080043 EXPECT_GL_NO_ERROR();
44
45 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
46 glUseProgram(program.get());
47
Jiawei Shaoa6a78422018-06-28 08:32:54 +080048 glBindImageTexture(0, texture[0], 0, GL_FALSE, 0, GL_READ_ONLY, internalFormat);
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +080049 EXPECT_GL_NO_ERROR();
50
Jiawei Shaoa6a78422018-06-28 08:32:54 +080051 glBindImageTexture(1, texture[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, internalFormat);
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +080052 EXPECT_GL_NO_ERROR();
53
54 glDispatchCompute(1, 1, 1);
55 EXPECT_GL_NO_ERROR();
56
57 glMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT);
58
Jiawei Shaoa6a78422018-06-28 08:32:54 +080059 T outputValues[kWidth * kHeight] = {};
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +080060 glUseProgram(0);
61 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
62
63 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture[1],
64 0);
65 EXPECT_GL_NO_ERROR();
Jiawei Shaoa6a78422018-06-28 08:32:54 +080066 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, format, outputValues);
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +080067 EXPECT_GL_NO_ERROR();
68
69 for (int i = 0; i < kWidth * kHeight; i++)
70 {
71 EXPECT_EQ(expectedValues[i], outputValues[i]);
72 }
73 }
Martin Radev4c4c8e72016-08-04 12:25:34 +030074};
75
76class ComputeShaderTestES3 : public ANGLETest
77{
78 protected:
79 ComputeShaderTestES3() {}
80};
81
82// link a simple compute program. It should be successful.
83TEST_P(ComputeShaderTest, LinkComputeProgram)
84{
85 const std::string csSource =
Yunchao Hecddcb592017-11-13 15:27:35 +080086 R"(#version 310 es
87 layout(local_size_x=1) in;
88 void main()
89 {\
90 })";
Martin Radev4c4c8e72016-08-04 12:25:34 +030091
92 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
93
94 EXPECT_GL_NO_ERROR();
95}
96
Yunchao He85072e82017-11-14 15:43:28 +080097// Link a simple compute program. Then detach the shader and dispatch compute.
98// It should be successful.
99TEST_P(ComputeShaderTest, DetachShaderAfterLinkSuccess)
100{
101 const std::string csSource =
102 R"(#version 310 es
103 layout(local_size_x=1) in;
104 void main()
105 {
106 })";
107
108 GLuint program = glCreateProgram();
109
110 GLuint cs = CompileShader(GL_COMPUTE_SHADER, csSource);
111 EXPECT_NE(0u, cs);
112
113 glAttachShader(program, cs);
114 glDeleteShader(cs);
115
116 glLinkProgram(program);
117 GLint linkStatus;
118 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
Yunchao He1f679cc2017-11-29 18:06:00 +0800119 EXPECT_GL_TRUE(linkStatus);
Yunchao He85072e82017-11-14 15:43:28 +0800120
121 glDetachShader(program, cs);
122 EXPECT_GL_NO_ERROR();
123
124 glUseProgram(program);
125 glDispatchCompute(8, 4, 2);
126 EXPECT_GL_NO_ERROR();
127}
128
Martin Radev4c4c8e72016-08-04 12:25:34 +0300129// link a simple compute program. There is no local size and linking should fail.
130TEST_P(ComputeShaderTest, LinkComputeProgramNoLocalSizeLinkError)
131{
132 const std::string csSource =
Yunchao Hecddcb592017-11-13 15:27:35 +0800133 R"(#version 310 es
134 void main()
135 {
136 })";
Martin Radev4c4c8e72016-08-04 12:25:34 +0300137
138 GLuint program = CompileComputeProgram(csSource, false);
139 EXPECT_EQ(0u, program);
140
141 glDeleteProgram(program);
142
143 EXPECT_GL_NO_ERROR();
144}
145
146// link a simple compute program.
147// make sure that uniforms and uniform samplers get recorded
148TEST_P(ComputeShaderTest, LinkComputeProgramWithUniforms)
149{
150 const std::string csSource =
Olli Etuaho7caa80e2017-11-14 15:03:14 +0200151 R"(#version 310 es
152 precision mediump sampler2D;
153 layout(local_size_x=1) in;
154 uniform int myUniformInt;
155 uniform sampler2D myUniformSampler;
156 layout(rgba32i) uniform highp writeonly iimage2D imageOut;
157 void main()
158 {
159 int q = myUniformInt;
160 vec4 v = textureLod(myUniformSampler, vec2(0.0), 0.0);
161 imageStore(imageOut, ivec2(0), ivec4(v) * q);
162 })";
Martin Radev4c4c8e72016-08-04 12:25:34 +0300163
164 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
165
Olli Etuaho7caa80e2017-11-14 15:03:14 +0200166 GLint uniformLoc = glGetUniformLocation(program.get(), "myUniformInt");
167 EXPECT_NE(-1, uniformLoc);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300168
Olli Etuaho7caa80e2017-11-14 15:03:14 +0200169 uniformLoc = glGetUniformLocation(program.get(), "myUniformSampler");
170 EXPECT_NE(-1, uniformLoc);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300171
172 EXPECT_GL_NO_ERROR();
173}
174
175// Attach both compute and non-compute shaders. A link time error should occur.
176// OpenGL ES 3.10, 7.3 Program Objects
177TEST_P(ComputeShaderTest, AttachMultipleShaders)
178{
179 const std::string csSource =
Yunchao Hecddcb592017-11-13 15:27:35 +0800180 R"(#version 310 es
181 layout(local_size_x=1) in;
182 void main()
183 {
184 })";
Martin Radev4c4c8e72016-08-04 12:25:34 +0300185
186 const std::string vsSource =
Yunchao Hecddcb592017-11-13 15:27:35 +0800187 R"(#version 310 es
188 void main()
189 {
190 })";
Martin Radev4c4c8e72016-08-04 12:25:34 +0300191
192 const std::string fsSource =
Yunchao Hecddcb592017-11-13 15:27:35 +0800193 R"(#version 310 es
194 void main()
195 {
196 })";
Martin Radev4c4c8e72016-08-04 12:25:34 +0300197
198 GLuint program = glCreateProgram();
199
200 GLuint vs = CompileShader(GL_VERTEX_SHADER, vsSource);
201 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fsSource);
202 GLuint cs = CompileShader(GL_COMPUTE_SHADER, csSource);
203
204 EXPECT_NE(0u, vs);
205 EXPECT_NE(0u, fs);
206 EXPECT_NE(0u, cs);
207
208 glAttachShader(program, vs);
209 glDeleteShader(vs);
210
211 glAttachShader(program, fs);
212 glDeleteShader(fs);
213
214 glAttachShader(program, cs);
215 glDeleteShader(cs);
216
217 glLinkProgram(program);
218
219 GLint linkStatus;
220 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
221
Yunchao He1f679cc2017-11-29 18:06:00 +0800222 EXPECT_GL_FALSE(linkStatus);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300223
224 EXPECT_GL_NO_ERROR();
225}
226
227// Attach a vertex, fragment and compute shader.
228// Query for the number of attached shaders and check the count.
229TEST_P(ComputeShaderTest, AttachmentCount)
230{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300231 const std::string csSource =
Yunchao Hecddcb592017-11-13 15:27:35 +0800232 R"(#version 310 es
233 layout(local_size_x=1) in;
234 void main()
235 {
236 })";
Martin Radev4c4c8e72016-08-04 12:25:34 +0300237
238 const std::string vsSource =
Yunchao Hecddcb592017-11-13 15:27:35 +0800239 R"(#version 310 es
240 void main()
241 {
242 })";
Martin Radev4c4c8e72016-08-04 12:25:34 +0300243
244 const std::string fsSource =
Yunchao Hecddcb592017-11-13 15:27:35 +0800245 R"(#version 310 es
246 void main()
247 {
248 })";
Martin Radev4c4c8e72016-08-04 12:25:34 +0300249
250 GLuint program = glCreateProgram();
251
252 GLuint vs = CompileShader(GL_VERTEX_SHADER, vsSource);
253 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fsSource);
254 GLuint cs = CompileShader(GL_COMPUTE_SHADER, csSource);
255
256 EXPECT_NE(0u, vs);
257 EXPECT_NE(0u, fs);
258 EXPECT_NE(0u, cs);
259
260 glAttachShader(program, vs);
261 glDeleteShader(vs);
262
263 glAttachShader(program, fs);
264 glDeleteShader(fs);
265
266 glAttachShader(program, cs);
267 glDeleteShader(cs);
268
269 GLint numAttachedShaders;
270 glGetProgramiv(program, GL_ATTACHED_SHADERS, &numAttachedShaders);
271
272 EXPECT_EQ(3, numAttachedShaders);
273
274 glDeleteProgram(program);
275
276 EXPECT_GL_NO_ERROR();
277}
278
Yunchao Hecddcb592017-11-13 15:27:35 +0800279// Attach a compute shader and link, but start rendering.
280TEST_P(ComputeShaderTest, StartRenderingWithComputeProgram)
281{
282 const std::string csSource =
283 R"(#version 310 es
284 layout(local_size_x=1) in;
285 void main()
286 {
287 })";
288
289 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
290 EXPECT_GL_NO_ERROR();
291
292 glUseProgram(program);
293 glDrawArrays(GL_POINTS, 0, 2);
294 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
295}
296
Yunchao He70b715c2017-11-07 14:59:15 +0800297// Attach a vertex and fragment shader and link, but dispatch compute.
298TEST_P(ComputeShaderTest, DispatchComputeWithRenderingProgram)
299{
300 const std::string vsSource =
Yunchao Hecddcb592017-11-13 15:27:35 +0800301 R"(#version 310 es
302 void main()
303 {
304 })";
Yunchao He70b715c2017-11-07 14:59:15 +0800305
306 const std::string fsSource =
Yunchao Hecddcb592017-11-13 15:27:35 +0800307 R"(#version 310 es
308 void main()
309 {
310 })";
Yunchao He70b715c2017-11-07 14:59:15 +0800311
312 GLuint program = glCreateProgram();
313
314 GLuint vs = CompileShader(GL_VERTEX_SHADER, vsSource);
315 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fsSource);
316
317 EXPECT_NE(0u, vs);
318 EXPECT_NE(0u, fs);
319
320 glAttachShader(program, vs);
321 glDeleteShader(vs);
322
323 glAttachShader(program, fs);
324 glDeleteShader(fs);
325
326 glLinkProgram(program);
327
328 GLint linkStatus;
329 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
Yunchao He1f679cc2017-11-29 18:06:00 +0800330 EXPECT_GL_TRUE(linkStatus);
Yunchao He70b715c2017-11-07 14:59:15 +0800331
332 EXPECT_GL_NO_ERROR();
333
334 glUseProgram(program);
335 glDispatchCompute(8, 4, 2);
336 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
337}
338
Xinghua Caob1239382016-12-13 15:07:05 +0800339// Access all compute shader special variables.
340TEST_P(ComputeShaderTest, AccessAllSpecialVariables)
341{
342 const std::string csSource =
Olli Etuaho7caa80e2017-11-14 15:03:14 +0200343 R"(#version 310 es
344 layout(local_size_x=4, local_size_y=3, local_size_z=2) in;
345 layout(rgba32ui) uniform highp writeonly uimage2D imageOut;
346 void main()
347 {
348 uvec3 temp1 = gl_NumWorkGroups;
349 uvec3 temp2 = gl_WorkGroupSize;
350 uvec3 temp3 = gl_WorkGroupID;
351 uvec3 temp4 = gl_LocalInvocationID;
352 uvec3 temp5 = gl_GlobalInvocationID;
353 uint temp6 = gl_LocalInvocationIndex;
354 imageStore(imageOut, ivec2(gl_LocalInvocationIndex, 0), uvec4(temp1 + temp2 + temp3 + temp4 + temp5, temp6));
355 })";
Xinghua Caob1239382016-12-13 15:07:05 +0800356
357 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
358}
359
360// Access part compute shader special variables.
361TEST_P(ComputeShaderTest, AccessPartSpecialVariables)
362{
363 const std::string csSource =
Olli Etuaho7caa80e2017-11-14 15:03:14 +0200364 R"(#version 310 es
365 layout(local_size_x=4, local_size_y=3, local_size_z=2) in;
366 layout(rgba32ui) uniform highp writeonly uimage2D imageOut;
367 void main()
368 {
369 uvec3 temp1 = gl_WorkGroupSize;
370 uvec3 temp2 = gl_WorkGroupID;
371 uint temp3 = gl_LocalInvocationIndex;
372 imageStore(imageOut, ivec2(gl_LocalInvocationIndex, 0), uvec4(temp1 + temp2, temp3));
373 })";
Xinghua Caob1239382016-12-13 15:07:05 +0800374
375 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
376}
377
Xinghua Cao73badc02017-03-29 19:14:53 +0800378// Use glDispatchCompute to define work group count.
379TEST_P(ComputeShaderTest, DispatchCompute)
Xinghua Cao2b396592017-03-29 15:36:04 +0800380{
381 const std::string csSource =
Olli Etuaho7caa80e2017-11-14 15:03:14 +0200382 R"(#version 310 es
383 layout(local_size_x=4, local_size_y=3, local_size_z=2) in;
384 layout(rgba32ui) uniform highp writeonly uimage2D imageOut;
385 void main()
386 {
387 uvec3 temp = gl_NumWorkGroups;
388 imageStore(imageOut, ivec2(0), uvec4(temp, 0u));
389 })";
Xinghua Cao2b396592017-03-29 15:36:04 +0800390
391 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
392
393 glUseProgram(program.get());
394 glDispatchCompute(8, 4, 2);
395 EXPECT_GL_NO_ERROR();
396}
397
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800398// Use image uniform to write texture in compute shader, and verify the content is expected.
399TEST_P(ComputeShaderTest, BindImageTexture)
400{
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800401 GLTexture mTexture[2];
402 GLFramebuffer mFramebuffer;
403 const std::string csSource =
Yunchao Hecddcb592017-11-13 15:27:35 +0800404 R"(#version 310 es
Xinghua Cao27f43212018-02-26 11:05:53 +0800405 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
Yunchao Hecddcb592017-11-13 15:27:35 +0800406 layout(r32ui, binding = 0) writeonly uniform highp uimage2D uImage[2];
407 void main()
408 {
409 imageStore(uImage[0], ivec2(gl_LocalInvocationIndex, gl_WorkGroupID.x), uvec4(100, 0,
410 0, 0));
411 imageStore(uImage[1], ivec2(gl_LocalInvocationIndex, gl_WorkGroupID.x), uvec4(100, 0,
412 0, 0));
413 })";
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800414
415 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
416 glUseProgram(program.get());
Xinghua Cao27f43212018-02-26 11:05:53 +0800417 int width = 1, height = 1;
418 GLuint inputValues[] = {200};
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800419
420 glBindTexture(GL_TEXTURE_2D, mTexture[0]);
421 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, width, height);
422 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RED_INTEGER, GL_UNSIGNED_INT,
423 inputValues);
424 EXPECT_GL_NO_ERROR();
425
426 glBindImageTexture(0, mTexture[0], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
427 EXPECT_GL_NO_ERROR();
428
429 glBindTexture(GL_TEXTURE_2D, mTexture[1]);
430 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, width, height);
431 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RED_INTEGER, GL_UNSIGNED_INT,
432 inputValues);
433 EXPECT_GL_NO_ERROR();
434
435 glBindImageTexture(1, mTexture[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
436 EXPECT_GL_NO_ERROR();
437
Xinghua Cao27f43212018-02-26 11:05:53 +0800438 glDispatchCompute(1, 1, 1);
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800439 EXPECT_GL_NO_ERROR();
440
Xinghua Cao27f43212018-02-26 11:05:53 +0800441 glMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT);
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800442 glUseProgram(0);
Xinghua Cao27f43212018-02-26 11:05:53 +0800443 GLuint outputValues[2][1];
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800444 GLuint expectedValue = 100;
445 glBindFramebuffer(GL_READ_FRAMEBUFFER, mFramebuffer);
446
447 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTexture[0],
448 0);
449 EXPECT_GL_NO_ERROR();
450 glReadPixels(0, 0, width, height, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues[0]);
451 EXPECT_GL_NO_ERROR();
452
453 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTexture[1],
454 0);
455 EXPECT_GL_NO_ERROR();
456 glReadPixels(0, 0, width, height, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues[1]);
457 EXPECT_GL_NO_ERROR();
458
459 for (int i = 0; i < width * height; i++)
460 {
461 EXPECT_EQ(expectedValue, outputValues[0][i]);
462 EXPECT_EQ(expectedValue, outputValues[1][i]);
463 }
464}
465
Xinghua Cao0328b572017-06-26 15:51:36 +0800466// When declare a image array without a binding qualifier, all elements are bound to unit zero.
467TEST_P(ComputeShaderTest, ImageArrayWithoutBindingQualifier)
468{
469 ANGLE_SKIP_TEST_IF(IsD3D11());
470
471 // TODO(xinghua.cao@intel.com): On AMD desktop OpenGL, bind two image variables to unit 0,
472 // only one variable is valid.
Corentin Wallez2bde9192017-07-28 14:15:01 -0400473 ANGLE_SKIP_TEST_IF(IsAMD() && IsDesktopOpenGL());
Xinghua Cao0328b572017-06-26 15:51:36 +0800474
475 GLTexture mTexture;
476 GLFramebuffer mFramebuffer;
477 const std::string csSource =
Yunchao Hecddcb592017-11-13 15:27:35 +0800478 R"(#version 310 es
Xinghua Cao27f43212018-02-26 11:05:53 +0800479 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
Yunchao Hecddcb592017-11-13 15:27:35 +0800480 layout(r32ui) writeonly uniform highp uimage2D uImage[2];
481 void main()
482 {
483 imageStore(uImage[0], ivec2(gl_LocalInvocationIndex, 0), uvec4(100, 0, 0, 0));
484 imageStore(uImage[1], ivec2(gl_LocalInvocationIndex, 1), uvec4(100, 0, 0, 0));
485 })";
Xinghua Cao0328b572017-06-26 15:51:36 +0800486
487 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
488 glUseProgram(program.get());
Xinghua Cao27f43212018-02-26 11:05:53 +0800489 constexpr int kTextureWidth = 1, kTextureHeight = 2;
490 GLuint inputValues[] = {200, 200};
Xinghua Cao0328b572017-06-26 15:51:36 +0800491
492 glBindTexture(GL_TEXTURE_2D, mTexture);
493 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kTextureWidth, kTextureHeight);
494 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kTextureWidth, kTextureHeight, GL_RED_INTEGER,
495 GL_UNSIGNED_INT, inputValues);
496 EXPECT_GL_NO_ERROR();
497
498 glBindImageTexture(0, mTexture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
499 glDispatchCompute(1, 1, 1);
500 EXPECT_GL_NO_ERROR();
501
Xinghua Cao27f43212018-02-26 11:05:53 +0800502 glMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT);
Xinghua Cao0328b572017-06-26 15:51:36 +0800503 glUseProgram(0);
504 glBindFramebuffer(GL_READ_FRAMEBUFFER, mFramebuffer);
505
506 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTexture, 0);
Xinghua Cao27f43212018-02-26 11:05:53 +0800507 GLuint outputValues[kTextureWidth * kTextureHeight];
Xinghua Cao0328b572017-06-26 15:51:36 +0800508 glReadPixels(0, 0, kTextureWidth, kTextureHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
509 outputValues);
510 EXPECT_GL_NO_ERROR();
511
512 GLuint expectedValue = 100;
513 for (int i = 0; i < kTextureWidth * kTextureHeight; i++)
514 {
515 EXPECT_EQ(expectedValue, outputValues[i]);
516 }
517}
518
Xinghua Cao711b7a12017-10-09 13:38:12 +0800519// imageLoad functions
520TEST_P(ComputeShaderTest, ImageLoad)
521{
522 const std::string csSource =
Olli Etuaho7caa80e2017-11-14 15:03:14 +0200523 R"(#version 310 es
524 layout(local_size_x=8) in;
525 layout(rgba8) uniform highp readonly image2D mImage2DInput;
526 layout(rgba16i) uniform highp readonly iimageCube mImageCubeInput;
527 layout(rgba32ui) uniform highp readonly uimage3D mImage3DInput;
528 layout(r32i) uniform highp writeonly iimage2D imageOut;
529 void main()
530 {
531 vec4 result2d = imageLoad(mImage2DInput, ivec2(gl_LocalInvocationID.xy));
532 ivec4 resultCube = imageLoad(mImageCubeInput, ivec3(gl_LocalInvocationID.xyz));
533 uvec4 result3d = imageLoad(mImage3DInput, ivec3(gl_LocalInvocationID.xyz));
534 imageStore(imageOut, ivec2(gl_LocalInvocationIndex, 0), ivec4(result2d) + resultCube + ivec4(result3d));
535 })";
Xinghua Cao711b7a12017-10-09 13:38:12 +0800536
537 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
538 EXPECT_GL_NO_ERROR();
539}
540
541// imageStore functions
542TEST_P(ComputeShaderTest, ImageStore)
543{
544 const std::string csSource =
Yunchao Hecddcb592017-11-13 15:27:35 +0800545 R"(#version 310 es
546 layout(local_size_x=8) in;
547 layout(rgba16f) uniform highp writeonly imageCube mImageCubeOutput;
548 layout(r32f) uniform highp writeonly image3D mImage3DOutput;
549 layout(rgba8ui) uniform highp writeonly uimage2DArray mImage2DArrayOutput;
550 void main()
551 {
552 imageStore(mImageCubeOutput, ivec3(gl_LocalInvocationID.xyz), vec4(0.0));
553 imageStore(mImage3DOutput, ivec3(gl_LocalInvocationID.xyz), vec4(0.0));
554 imageStore(mImage2DArrayOutput, ivec3(gl_LocalInvocationID.xyz), uvec4(0));
555 })";
Xinghua Cao711b7a12017-10-09 13:38:12 +0800556
557 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
558 EXPECT_GL_NO_ERROR();
559}
560
561// imageSize functions
562TEST_P(ComputeShaderTest, ImageSize)
563{
564 const std::string csSource =
Olli Etuaho7caa80e2017-11-14 15:03:14 +0200565 R"(#version 310 es
566 layout(local_size_x=8) in;
567 layout(rgba8) uniform highp readonly imageCube mImageCubeInput;
568 layout(r32i) uniform highp readonly iimage2D mImage2DInput;
569 layout(rgba16ui) uniform highp readonly uimage2DArray mImage2DArrayInput;
570 layout(r32i) uniform highp writeonly iimage2D imageOut;
571 void main()
572 {
573 ivec2 sizeCube = imageSize(mImageCubeInput);
574 ivec2 size2D = imageSize(mImage2DInput);
575 ivec3 size2DArray = imageSize(mImage2DArrayInput);
576 imageStore(imageOut, ivec2(gl_LocalInvocationIndex, 0), ivec4(sizeCube, size2D.x, size2DArray.x));
577 })";
Xinghua Cao711b7a12017-10-09 13:38:12 +0800578
579 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
580 EXPECT_GL_NO_ERROR();
581}
582
Jiajia Qin5ae6ee42018-03-06 17:39:42 +0800583// Test that sampling texture works well in compute shader.
584TEST_P(ComputeShaderTest, TextureSampling)
585{
586 ANGLE_SKIP_TEST_IF(IsD3D11());
587
588 const std::string &csSource =
589 R"(#version 310 es
590 layout(local_size_x=16, local_size_y=16) in;
591 precision highp usampler2D;
592 uniform usampler2D tex;
593 layout(std140, binding = 0) buffer buf {
594 uint outData[16][16];
595 };
596
597 void main()
598 {
599 uint x = gl_LocalInvocationID.x;
600 uint y = gl_LocalInvocationID.y;
601 outData[y][x] = texelFetch(tex, ivec2(x, y), 0).x;
602 })";
603
604 constexpr unsigned int kWidth = 16;
605 constexpr unsigned int kHeight = 16;
606 GLTexture tex;
607 glBindTexture(GL_TEXTURE_2D, tex);
608 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
609 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
610 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kWidth, kHeight);
611 GLuint texels[kHeight][kWidth] = {{0}};
612 for (unsigned int y = 0; y < kHeight; ++y)
613 {
614 for (unsigned int x = 0; x < kWidth; ++x)
615 {
616 texels[y][x] = x + y * kWidth;
617 }
618 }
619 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
620 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
621 texels);
622 glBindTexture(GL_TEXTURE_2D, 0);
623
624 // The array stride are rounded up to the base alignment of a vec4 for std140 layout.
625 constexpr unsigned int kArrayStride = 16;
626 GLBuffer ssbo;
627 glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
628 glBufferData(GL_SHADER_STORAGE_BUFFER, kWidth * kHeight * kArrayStride, nullptr,
629 GL_STREAM_DRAW);
630 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
631 EXPECT_GL_NO_ERROR();
632
633 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
634 glUseProgram(program.get());
635
636 glActiveTexture(GL_TEXTURE0);
637 glBindTexture(GL_TEXTURE_2D, tex);
638 glUniform1i(glGetUniformLocation(program, "tex"), 0);
639 glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
640 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, ssbo);
641
642 glDispatchCompute(1, 1, 1);
643
644 glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
645 void *ptr = glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, kWidth * kHeight * kArrayStride,
646 GL_MAP_READ_BIT);
647 for (unsigned int idx = 0; idx < kWidth * kHeight; idx++)
648 {
649 EXPECT_EQ(idx, *(reinterpret_cast<const GLuint *>(reinterpret_cast<const GLbyte *>(ptr) +
650 idx * kArrayStride)));
651 }
652 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
653 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
654 EXPECT_GL_NO_ERROR();
655}
656
Xinghua Cao08a8ec82017-12-27 13:31:11 +0800657// Use image uniform to read and write Texture2D in compute shader, and verify the contents.
Xinghua Cao26143fd2017-11-01 18:19:05 +0800658TEST_P(ComputeShaderTest, BindImageTextureWithTexture2D)
659{
660 GLTexture texture[2];
661 GLFramebuffer framebuffer;
662 const std::string csSource =
663 R"(#version 310 es
Xinghua Cao27f43212018-02-26 11:05:53 +0800664 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
Xinghua Cao26143fd2017-11-01 18:19:05 +0800665 layout(r32ui, binding = 0) readonly uniform highp uimage2D uImage_1;
666 layout(r32ui, binding = 1) writeonly uniform highp uimage2D uImage_2;
667 void main()
668 {
669 uvec4 value = imageLoad(uImage_1, ivec2(gl_LocalInvocationID.xy));
670 imageStore(uImage_2, ivec2(gl_LocalInvocationID.xy), value);
671 })";
672
Xinghua Cao27f43212018-02-26 11:05:53 +0800673 constexpr int kWidth = 1, kHeight = 1;
674 constexpr GLuint kInputValues[2][1] = {{200}, {100}};
Xinghua Cao26143fd2017-11-01 18:19:05 +0800675
676 glBindTexture(GL_TEXTURE_2D, texture[0]);
677 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kWidth, kHeight);
678 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
679 kInputValues[0]);
680 EXPECT_GL_NO_ERROR();
681
682 glBindTexture(GL_TEXTURE_2D, texture[1]);
683 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kWidth, kHeight);
684 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
685 kInputValues[1]);
686 EXPECT_GL_NO_ERROR();
687
Xinghua Cao26143fd2017-11-01 18:19:05 +0800688 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
689 glUseProgram(program.get());
690
691 glBindImageTexture(0, texture[0], 0, GL_FALSE, 0, GL_READ_ONLY, GL_R32UI);
692 EXPECT_GL_NO_ERROR();
693
694 glBindImageTexture(1, texture[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
695 EXPECT_GL_NO_ERROR();
696
697 glDispatchCompute(1, 1, 1);
698 EXPECT_GL_NO_ERROR();
699
Xinghua Cao27f43212018-02-26 11:05:53 +0800700 glMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT);
701 GLuint outputValues[kWidth * kHeight];
702 constexpr GLuint expectedValue = 200;
Xinghua Cao26143fd2017-11-01 18:19:05 +0800703 glUseProgram(0);
704 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
705
706 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture[1], 0);
707 EXPECT_GL_NO_ERROR();
708 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
709 EXPECT_GL_NO_ERROR();
710
711 for (int i = 0; i < kWidth * kHeight; i++)
712 {
Xinghua Cao27f43212018-02-26 11:05:53 +0800713 EXPECT_EQ(expectedValue, outputValues[i]);
Xinghua Cao26143fd2017-11-01 18:19:05 +0800714 }
715}
716
Xinghua Cao08a8ec82017-12-27 13:31:11 +0800717// Use image uniform to read and write Texture2DArray in compute shader, and verify the contents.
718TEST_P(ComputeShaderTest, BindImageTextureWithTexture2DArray)
719{
720 GLTexture texture[2];
721 GLFramebuffer framebuffer;
722 const std::string csSource =
723 R"(#version 310 es
724 layout(local_size_x=2, local_size_y=2, local_size_z=2) in;
725 layout(r32ui, binding = 0) readonly uniform highp uimage2DArray uImage_1;
726 layout(r32ui, binding = 1) writeonly uniform highp uimage2DArray uImage_2;
727 void main()
728 {
729 uvec4 value = imageLoad(uImage_1, ivec3(gl_LocalInvocationID.xyz));
730 imageStore(uImage_2, ivec3(gl_LocalInvocationID.xyz), value);
731 })";
732
Xinghua Cao27f43212018-02-26 11:05:53 +0800733 constexpr int kWidth = 1, kHeight = 1, kDepth = 2;
734 constexpr GLuint kInputValues[2][2] = {{200, 200}, {100, 100}};
Xinghua Cao08a8ec82017-12-27 13:31:11 +0800735
736 glBindTexture(GL_TEXTURE_2D_ARRAY, texture[0]);
737 glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_R32UI, kWidth, kHeight, kDepth);
738 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, kWidth, kHeight, kDepth, GL_RED_INTEGER,
739 GL_UNSIGNED_INT, kInputValues[0]);
740 EXPECT_GL_NO_ERROR();
741
742 glBindTexture(GL_TEXTURE_2D_ARRAY, texture[1]);
743 glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_R32UI, kWidth, kHeight, kDepth);
744 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, kWidth, kHeight, kDepth, GL_RED_INTEGER,
745 GL_UNSIGNED_INT, kInputValues[1]);
746 EXPECT_GL_NO_ERROR();
747
Xinghua Cao08a8ec82017-12-27 13:31:11 +0800748 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
749 glUseProgram(program.get());
750
751 glBindImageTexture(0, texture[0], 0, GL_TRUE, 0, GL_READ_ONLY, GL_R32UI);
752 EXPECT_GL_NO_ERROR();
753
754 glBindImageTexture(1, texture[1], 0, GL_TRUE, 0, GL_WRITE_ONLY, GL_R32UI);
755 EXPECT_GL_NO_ERROR();
756
757 glDispatchCompute(1, 1, 1);
758 EXPECT_GL_NO_ERROR();
759
Xinghua Cao27f43212018-02-26 11:05:53 +0800760 glMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT);
761 GLuint outputValues[kWidth * kHeight];
762 constexpr GLuint expectedValue = 200;
Xinghua Cao08a8ec82017-12-27 13:31:11 +0800763 glUseProgram(0);
764 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
765
766 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture[1], 0, 0);
767 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, texture[1], 0, 1);
768 EXPECT_GL_NO_ERROR();
769 glReadBuffer(GL_COLOR_ATTACHMENT0);
770 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
771 EXPECT_GL_NO_ERROR();
772 for (int i = 0; i < kWidth * kHeight; i++)
773 {
Xinghua Cao27f43212018-02-26 11:05:53 +0800774 EXPECT_EQ(expectedValue, outputValues[i]);
Xinghua Cao08a8ec82017-12-27 13:31:11 +0800775 }
776 glReadBuffer(GL_COLOR_ATTACHMENT1);
777 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
778 EXPECT_GL_NO_ERROR();
779 for (int i = 0; i < kWidth * kHeight; i++)
780 {
Xinghua Cao27f43212018-02-26 11:05:53 +0800781 EXPECT_EQ(expectedValue, outputValues[i]);
Xinghua Cao08a8ec82017-12-27 13:31:11 +0800782 }
783}
784
785// Use image uniform to read and write Texture3D in compute shader, and verify the contents.
786TEST_P(ComputeShaderTest, BindImageTextureWithTexture3D)
787{
788 GLTexture texture[2];
789 GLFramebuffer framebuffer;
790 const std::string csSource =
791 R"(#version 310 es
Xinghua Cao27f43212018-02-26 11:05:53 +0800792 layout(local_size_x=1, local_size_y=1, local_size_z=2) in;
Xinghua Cao08a8ec82017-12-27 13:31:11 +0800793 layout(r32ui, binding = 0) readonly uniform highp uimage3D uImage_1;
794 layout(r32ui, binding = 1) writeonly uniform highp uimage3D uImage_2;
795 void main()
796 {
797 uvec4 value = imageLoad(uImage_1, ivec3(gl_LocalInvocationID.xyz));
798 imageStore(uImage_2, ivec3(gl_LocalInvocationID.xyz), value);
799 })";
800
Xinghua Cao27f43212018-02-26 11:05:53 +0800801 constexpr int kWidth = 1, kHeight = 1, kDepth = 2;
802 constexpr GLuint kInputValues[2][2] = {{200, 200}, {100, 100}};
Xinghua Cao08a8ec82017-12-27 13:31:11 +0800803
804 glBindTexture(GL_TEXTURE_3D, texture[0]);
805 glTexStorage3D(GL_TEXTURE_3D, 1, GL_R32UI, kWidth, kHeight, kDepth);
806 glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, kWidth, kHeight, kDepth, GL_RED_INTEGER,
807 GL_UNSIGNED_INT, kInputValues[0]);
808 EXPECT_GL_NO_ERROR();
809
810 glBindTexture(GL_TEXTURE_3D, texture[1]);
811 glTexStorage3D(GL_TEXTURE_3D, 1, GL_R32UI, kWidth, kHeight, kDepth);
812 glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, kWidth, kHeight, kDepth, GL_RED_INTEGER,
813 GL_UNSIGNED_INT, kInputValues[1]);
814 EXPECT_GL_NO_ERROR();
815
Xinghua Cao08a8ec82017-12-27 13:31:11 +0800816 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
817 glUseProgram(program.get());
818
819 glBindImageTexture(0, texture[0], 0, GL_TRUE, 0, GL_READ_ONLY, GL_R32UI);
820 EXPECT_GL_NO_ERROR();
821
822 glBindImageTexture(1, texture[1], 0, GL_TRUE, 0, GL_WRITE_ONLY, GL_R32UI);
823 EXPECT_GL_NO_ERROR();
824
825 glDispatchCompute(1, 1, 1);
826 EXPECT_GL_NO_ERROR();
827
Xinghua Cao27f43212018-02-26 11:05:53 +0800828 glMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT);
829 GLuint outputValues[kWidth * kHeight];
830 constexpr GLuint expectedValue = 200;
Xinghua Cao08a8ec82017-12-27 13:31:11 +0800831 glUseProgram(0);
832 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
833
834 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture[1], 0, 0);
835 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, texture[1], 0, 1);
836 EXPECT_GL_NO_ERROR();
837 glReadBuffer(GL_COLOR_ATTACHMENT0);
838 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
839 EXPECT_GL_NO_ERROR();
840 for (int i = 0; i < kWidth * kHeight; i++)
841 {
Xinghua Cao27f43212018-02-26 11:05:53 +0800842 EXPECT_EQ(expectedValue, outputValues[i]);
Xinghua Cao08a8ec82017-12-27 13:31:11 +0800843 }
844 glReadBuffer(GL_COLOR_ATTACHMENT1);
845 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
846 EXPECT_GL_NO_ERROR();
847 for (int i = 0; i < kWidth * kHeight; i++)
848 {
Xinghua Cao27f43212018-02-26 11:05:53 +0800849 EXPECT_EQ(expectedValue, outputValues[i]);
Xinghua Cao08a8ec82017-12-27 13:31:11 +0800850 }
851}
852
853// Use image uniform to read and write TextureCube in compute shader, and verify the contents.
854TEST_P(ComputeShaderTest, BindImageTextureWithTextureCube)
855{
856 GLTexture texture[2];
857 GLFramebuffer framebuffer;
858 const std::string csSource =
859 R"(#version 310 es
Xinghua Cao27f43212018-02-26 11:05:53 +0800860 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
Xinghua Cao08a8ec82017-12-27 13:31:11 +0800861 layout(r32ui, binding = 0) readonly uniform highp uimageCube uImage_1;
862 layout(r32ui, binding = 1) writeonly uniform highp uimageCube uImage_2;
863 void main()
864 {
865 for (int i = 0; i < 6; i++)
866 {
867 uvec4 value = imageLoad(uImage_1, ivec3(gl_LocalInvocationID.xy, i));
868 imageStore(uImage_2, ivec3(gl_LocalInvocationID.xy, i), value);
869 }
870 })";
871
Xinghua Cao27f43212018-02-26 11:05:53 +0800872 constexpr int kWidth = 1, kHeight = 1;
873 constexpr GLuint kInputValues[2][1] = {{200}, {100}};
Xinghua Cao08a8ec82017-12-27 13:31:11 +0800874
875 glBindTexture(GL_TEXTURE_CUBE_MAP, texture[0]);
876 glTexStorage2D(GL_TEXTURE_CUBE_MAP, 1, GL_R32UI, kWidth, kHeight);
877 for (GLenum face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
878 face++)
879 {
880 glTexSubImage2D(face, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
881 kInputValues[0]);
882 }
883 EXPECT_GL_NO_ERROR();
884
885 glBindTexture(GL_TEXTURE_CUBE_MAP, texture[1]);
886 glTexStorage2D(GL_TEXTURE_CUBE_MAP, 1, GL_R32UI, kWidth, kHeight);
887 for (GLenum face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
888 face++)
889 {
890 glTexSubImage2D(face, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
891 kInputValues[1]);
892 }
893 EXPECT_GL_NO_ERROR();
894
Xinghua Cao08a8ec82017-12-27 13:31:11 +0800895 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
896 glUseProgram(program.get());
897
898 glBindImageTexture(0, texture[0], 0, GL_TRUE, 0, GL_READ_ONLY, GL_R32UI);
899 EXPECT_GL_NO_ERROR();
900
901 glBindImageTexture(1, texture[1], 0, GL_TRUE, 0, GL_WRITE_ONLY, GL_R32UI);
902 EXPECT_GL_NO_ERROR();
903
904 glDispatchCompute(1, 1, 1);
905 EXPECT_GL_NO_ERROR();
906
Xinghua Cao27f43212018-02-26 11:05:53 +0800907 glMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT);
908 GLuint outputValues[kWidth * kHeight];
909 constexpr GLuint expectedValue = 200;
Xinghua Cao08a8ec82017-12-27 13:31:11 +0800910 glUseProgram(0);
911 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
912
913 for (GLenum face = 0; face < 6; face++)
914 {
915 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
916 GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, texture[1], 0);
917 EXPECT_GL_NO_ERROR();
918 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
919 EXPECT_GL_NO_ERROR();
920
921 for (int i = 0; i < kWidth * kHeight; i++)
922 {
Xinghua Cao27f43212018-02-26 11:05:53 +0800923 EXPECT_EQ(expectedValue, outputValues[i]);
Xinghua Cao08a8ec82017-12-27 13:31:11 +0800924 }
925 }
926}
927
Xinghua Caob745f172018-01-09 16:10:02 +0800928// Use image uniform to read and write one layer of Texture2DArray in compute shader, and verify the
929// contents.
930TEST_P(ComputeShaderTest, BindImageTextureWithOneLayerTexture2DArray)
931{
932 ANGLE_SKIP_TEST_IF(IsD3D11());
933
934 GLTexture texture[2];
935 GLFramebuffer framebuffer;
936 const std::string csSource =
937 R"(#version 310 es
938 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
939 layout(r32ui, binding = 0) readonly uniform highp uimage2D uImage_1;
940 layout(r32ui, binding = 1) writeonly uniform highp uimage2D uImage_2;
941 void main()
942 {
943 uvec4 value = imageLoad(uImage_1, ivec2(gl_LocalInvocationID.xy));
944 imageStore(uImage_2, ivec2(gl_LocalInvocationID.xy), value);
945 })";
946
947 constexpr int kWidth = 1, kHeight = 1, kDepth = 2;
948 constexpr int kResultSize = kWidth * kHeight;
949 constexpr GLuint kInputValues[2][2] = {{200, 150}, {100, 50}};
950 constexpr GLuint expectedValue_1 = 200;
951 constexpr GLuint expectedValue_2 = 100;
952 GLuint outputValues[kResultSize];
953
954 glBindTexture(GL_TEXTURE_2D_ARRAY, texture[0]);
955 glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_R32UI, kWidth, kHeight, kDepth);
956 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, kWidth, kHeight, kDepth, GL_RED_INTEGER,
957 GL_UNSIGNED_INT, kInputValues[0]);
958 EXPECT_GL_NO_ERROR();
959
960 glBindTexture(GL_TEXTURE_2D_ARRAY, texture[1]);
961 glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_R32UI, kWidth, kHeight, kDepth);
962 glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, kWidth, kHeight, kDepth, GL_RED_INTEGER,
963 GL_UNSIGNED_INT, kInputValues[1]);
964 EXPECT_GL_NO_ERROR();
965
966 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
967 glUseProgram(program.get());
968
969 glBindImageTexture(0, texture[0], 0, GL_FALSE, 0, GL_READ_ONLY, GL_R32UI);
970 EXPECT_GL_NO_ERROR();
971 glBindImageTexture(1, texture[1], 0, GL_FALSE, 1, GL_WRITE_ONLY, GL_R32UI);
972 EXPECT_GL_NO_ERROR();
973 glDispatchCompute(1, 1, 1);
974 EXPECT_GL_NO_ERROR();
975
976 glMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT);
977 glUseProgram(0);
978 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
979 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture[1], 0, 0);
980 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, texture[1], 0, 1);
981 EXPECT_GL_NO_ERROR();
982 glReadBuffer(GL_COLOR_ATTACHMENT0);
983 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
984 EXPECT_GL_NO_ERROR();
985 for (int i = 0; i < kResultSize; i++)
986 {
987 EXPECT_EQ(expectedValue_2, outputValues[i]);
988 }
989 glReadBuffer(GL_COLOR_ATTACHMENT1);
990 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
991 EXPECT_GL_NO_ERROR();
992 for (int i = 0; i < kResultSize; i++)
993 {
994 EXPECT_EQ(expectedValue_1, outputValues[i]);
995 }
996}
997
998// Use image uniform to read and write one layer of Texture3D in compute shader, and verify the
999// contents.
1000TEST_P(ComputeShaderTest, BindImageTextureWithOneLayerTexture3D)
1001{
1002 ANGLE_SKIP_TEST_IF(IsD3D11());
1003 GLTexture texture[2];
1004 GLFramebuffer framebuffer;
1005 const std::string csSource =
1006 R"(#version 310 es
1007 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
1008 layout(r32ui, binding = 0) readonly uniform highp uimage2D uImage_1;
1009 layout(r32ui, binding = 1) writeonly uniform highp uimage2D uImage_2;
1010 void main()
1011 {
1012 uvec4 value = imageLoad(uImage_1, ivec2(gl_LocalInvocationID.xy));
1013 imageStore(uImage_2, ivec2(gl_LocalInvocationID.xy), value);
1014 })";
1015
1016 constexpr int kWidth = 1, kHeight = 1, kDepth = 2;
1017 constexpr int kResultSize = kWidth * kHeight;
1018 constexpr GLuint kInputValues[2][2] = {{200, 150}, {100, 50}};
1019 constexpr GLuint expectedValue_1 = 150;
1020 constexpr GLuint expectedValue_2 = 50;
1021 GLuint outputValues[kResultSize];
1022
1023 glBindTexture(GL_TEXTURE_3D, texture[0]);
1024 glTexStorage3D(GL_TEXTURE_3D, 1, GL_R32UI, kWidth, kHeight, kDepth);
1025 glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, kWidth, kHeight, kDepth, GL_RED_INTEGER,
1026 GL_UNSIGNED_INT, kInputValues[0]);
1027 EXPECT_GL_NO_ERROR();
1028
1029 glBindTexture(GL_TEXTURE_3D, texture[1]);
1030 glTexStorage3D(GL_TEXTURE_3D, 1, GL_R32UI, kWidth, kHeight, kDepth);
1031 glTexSubImage3D(GL_TEXTURE_3D, 0, 0, 0, 0, kWidth, kHeight, kDepth, GL_RED_INTEGER,
1032 GL_UNSIGNED_INT, kInputValues[1]);
1033 EXPECT_GL_NO_ERROR();
1034
1035 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
1036 glUseProgram(program.get());
1037
1038 glBindImageTexture(0, texture[0], 0, GL_FALSE, 1, GL_READ_ONLY, GL_R32UI);
1039 EXPECT_GL_NO_ERROR();
1040 glBindImageTexture(1, texture[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
1041 EXPECT_GL_NO_ERROR();
1042 glDispatchCompute(1, 1, 1);
1043 EXPECT_GL_NO_ERROR();
1044
1045 glMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT);
1046 glUseProgram(0);
1047 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
1048 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture[1], 0, 0);
1049 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, texture[1], 0, 1);
1050 EXPECT_GL_NO_ERROR();
1051 glReadBuffer(GL_COLOR_ATTACHMENT0);
1052 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
1053 EXPECT_GL_NO_ERROR();
1054 for (int i = 0; i < kResultSize; i++)
1055 {
1056 EXPECT_EQ(expectedValue_1, outputValues[i]);
1057 }
1058 glReadBuffer(GL_COLOR_ATTACHMENT1);
1059 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
1060 EXPECT_GL_NO_ERROR();
1061 for (int i = 0; i < kResultSize; i++)
1062 {
1063 EXPECT_EQ(expectedValue_2, outputValues[i]);
1064 }
1065}
1066
1067// Use image uniform to read and write one layer of TextureCube in compute shader, and verify the
1068// contents.
1069TEST_P(ComputeShaderTest, BindImageTextureWithOneLayerTextureCube)
1070{
1071 ANGLE_SKIP_TEST_IF(IsD3D11());
1072
1073 GLTexture texture[2];
1074 GLFramebuffer framebuffer;
1075 const std::string csSource =
1076 R"(#version 310 es
1077 layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
1078 layout(r32ui, binding = 0) readonly uniform highp uimage2D uImage_1;
1079 layout(r32ui, binding = 1) writeonly uniform highp uimage2D uImage_2;
1080 void main()
1081 {
1082 uvec4 value = imageLoad(uImage_1, ivec2(gl_LocalInvocationID.xy));
1083 imageStore(uImage_2, ivec2(gl_LocalInvocationID.xy), value);
1084 })";
1085
1086 constexpr int kWidth = 1, kHeight = 1;
1087 constexpr int kResultSize = kWidth * kHeight;
1088 constexpr GLuint kInputValues[2][1] = {{200}, {100}};
1089 constexpr GLuint expectedValue_1 = 200;
1090 constexpr GLuint expectedValue_2 = 100;
1091 GLuint outputValues[kResultSize];
1092
1093 glBindTexture(GL_TEXTURE_CUBE_MAP, texture[0]);
1094 glTexStorage2D(GL_TEXTURE_CUBE_MAP, 1, GL_R32UI, kWidth, kHeight);
1095 for (GLenum face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
1096 face++)
1097 {
1098 glTexSubImage2D(face, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
1099 kInputValues[0]);
1100 }
1101 EXPECT_GL_NO_ERROR();
1102
1103 glBindTexture(GL_TEXTURE_CUBE_MAP, texture[1]);
1104 glTexStorage2D(GL_TEXTURE_CUBE_MAP, 1, GL_R32UI, kWidth, kHeight);
1105 for (GLenum face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
1106 face++)
1107 {
1108 glTexSubImage2D(face, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
1109 kInputValues[1]);
1110 }
1111 EXPECT_GL_NO_ERROR();
1112
1113 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
1114 glUseProgram(program.get());
1115
1116 glBindImageTexture(0, texture[0], 0, GL_FALSE, 3, GL_READ_ONLY, GL_R32UI);
1117 EXPECT_GL_NO_ERROR();
1118 glBindImageTexture(1, texture[1], 0, GL_FALSE, 4, GL_WRITE_ONLY, GL_R32UI);
1119 EXPECT_GL_NO_ERROR();
1120 glDispatchCompute(1, 1, 1);
1121 EXPECT_GL_NO_ERROR();
1122
1123 glMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT);
1124 glUseProgram(0);
1125 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
1126
1127 for (GLenum face = 0; face < 6; face++)
1128 {
1129 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
1130 GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, texture[1], 0);
1131 EXPECT_GL_NO_ERROR();
1132 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues);
1133 EXPECT_GL_NO_ERROR();
1134
1135 if (face == 4)
1136 {
1137 for (int i = 0; i < kResultSize; i++)
1138 {
1139 EXPECT_EQ(expectedValue_1, outputValues[i]);
1140 }
1141 }
1142 else
1143 {
1144 for (int i = 0; i < kResultSize; i++)
1145 {
1146 EXPECT_EQ(expectedValue_2, outputValues[i]);
1147 }
1148 }
1149 }
1150}
1151
Jiawei Shao6ae51612018-02-23 14:03:25 +08001152// Verify an INVALID_OPERATION error is reported when querying GL_COMPUTE_WORK_GROUP_SIZE for a
1153// program which has not been linked successfully or which does not contain objects to form a
1154// compute shader.
1155TEST_P(ComputeShaderTest, QueryComputeWorkGroupSize)
1156{
1157 const std::string vsSource =
1158 R"(#version 310 es
1159 void main()
1160 {
1161 })";
1162
1163 const std::string fsSource =
1164 R"(#version 310 es
1165 void main()
1166 {
1167 })";
1168
1169 GLint workGroupSize[3];
1170
1171 ANGLE_GL_PROGRAM(graphicsProgram, vsSource, fsSource);
1172 glGetProgramiv(graphicsProgram, GL_COMPUTE_WORK_GROUP_SIZE, workGroupSize);
1173 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1174
1175 GLuint computeProgram = glCreateProgram();
1176 GLShader computeShader(GL_COMPUTE_SHADER);
1177 glAttachShader(computeProgram, computeShader);
1178 glLinkProgram(computeProgram);
1179 glDetachShader(computeProgram, computeShader);
1180
1181 GLint linkStatus;
1182 glGetProgramiv(computeProgram, GL_LINK_STATUS, &linkStatus);
1183 ASSERT_GL_FALSE(linkStatus);
1184
1185 glGetProgramiv(computeProgram, GL_COMPUTE_WORK_GROUP_SIZE, workGroupSize);
1186 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
1187
1188 glDeleteProgram(computeProgram);
1189
1190 ASSERT_GL_NO_ERROR();
1191}
1192
Xinghua Cao47335852018-02-12 15:41:55 +08001193// Use groupMemoryBarrier and barrier to sync reads/writes order and the execution
1194// order of multiple shader invocations in compute shader.
1195TEST_P(ComputeShaderTest, groupMemoryBarrierAndBarrierTest)
1196{
1197 // TODO(xinghua.cao@intel.com): Figure out why we get this error message
1198 // that shader uses features not recognized by this D3D version.
Yuly Novikovbeafe1a2018-03-29 18:23:50 -04001199 ANGLE_SKIP_TEST_IF((IsAMD() || IsNVIDIA()) && IsD3D11());
Xinghua Cao47335852018-02-12 15:41:55 +08001200
1201 GLTexture texture;
1202 GLFramebuffer framebuffer;
1203
1204 // Each invocation first stores a single value in an image, then each invocation sums up
1205 // all the values in the image and stores the sum in the image. groupMemoryBarrier is
1206 // used to order reads/writes to variables stored in memory accessible to other shader
1207 // invocations, and barrier is used to control the relative execution order of multiple
1208 // shader invocations used to process a local work group.
1209 const std::string csSource =
1210 R"(#version 310 es
1211 layout(local_size_x=2, local_size_y=2, local_size_z=1) in;
1212 layout(r32i, binding = 0) uniform highp iimage2D image;
1213 void main()
1214 {
1215 uint x = gl_LocalInvocationID.x;
1216 uint y = gl_LocalInvocationID.y;
1217 imageStore(image, ivec2(gl_LocalInvocationID.xy), ivec4(x + y));
1218 groupMemoryBarrier();
1219 barrier();
1220 int sum = 0;
1221 for (int i = 0; i < 2; i++)
1222 {
1223 for(int j = 0; j < 2; j++)
1224 {
1225 sum += imageLoad(image, ivec2(i, j)).x;
1226 }
1227 }
1228 groupMemoryBarrier();
1229 barrier();
1230 imageStore(image, ivec2(gl_LocalInvocationID.xy), ivec4(sum));
1231 })";
1232
1233 constexpr int kWidth = 2, kHeight = 2;
1234 glBindTexture(GL_TEXTURE_2D, texture);
1235 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32I, kWidth, kHeight);
1236 EXPECT_GL_NO_ERROR();
1237
1238 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
1239 glUseProgram(program.get());
1240
1241 glBindImageTexture(0, texture, 0, GL_FALSE, 0, GL_READ_WRITE, GL_R32I);
1242 EXPECT_GL_NO_ERROR();
1243
1244 glDispatchCompute(1, 1, 1);
1245 EXPECT_GL_NO_ERROR();
1246
1247 glMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT);
1248 GLuint outputValues[kWidth * kHeight];
1249 constexpr GLuint kExpectedValue = 4;
1250 glUseProgram(0);
1251 glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
1252
1253 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
1254 EXPECT_GL_NO_ERROR();
1255 glReadPixels(0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_INT, outputValues);
1256 EXPECT_GL_NO_ERROR();
1257
1258 for (int i = 0; i < kWidth * kHeight; i++)
1259 {
1260 EXPECT_EQ(kExpectedValue, outputValues[i]);
1261 }
1262}
1263
Jiawei Shao7a8fe152018-04-28 12:59:58 +08001264// Verify that a link error is generated when the sum of the number of active image uniforms and
1265// active shader storage blocks in a compute shader exceeds GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES.
1266TEST_P(ComputeShaderTest, ExceedCombinedShaderOutputResourcesInCS)
1267{
1268 // TODO(jiawei.shao@intel.com): enable this test when shader storage buffer is supported on
1269 // D3D11 back-ends.
1270 ANGLE_SKIP_TEST_IF(IsD3D11());
1271
1272 GLint maxCombinedShaderOutputResources;
1273 GLint maxComputeShaderStorageBlocks;
1274 GLint maxComputeImageUniforms;
1275
1276 glGetIntegerv(GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES, &maxCombinedShaderOutputResources);
1277 glGetIntegerv(GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS, &maxComputeShaderStorageBlocks);
1278 glGetIntegerv(GL_MAX_COMPUTE_IMAGE_UNIFORMS, &maxComputeImageUniforms);
1279
1280 ANGLE_SKIP_TEST_IF(maxCombinedShaderOutputResources >=
1281 maxComputeShaderStorageBlocks + maxComputeImageUniforms);
1282
1283 std::ostringstream computeShaderStream;
1284 computeShaderStream << "#version 310 es\n"
1285 "layout(local_size_x = 3, local_size_y = 1, local_size_z = 1) in;\n"
1286 "layout(shared, binding = 0) buffer blockName"
1287 "{\n"
1288 " uint data;\n"
1289 "} instance["
1290 << maxComputeShaderStorageBlocks << "];\n";
1291
1292 ASSERT_GE(maxComputeImageUniforms, 4);
1293 int numImagesInArray = maxComputeImageUniforms / 2;
1294 int numImagesNonArray = maxComputeImageUniforms - numImagesInArray;
1295 for (int i = 0; i < numImagesNonArray; ++i)
1296 {
1297 computeShaderStream << "layout(r32f, binding = " << i << ") uniform highp image2D image"
1298 << i << ";\n";
1299 }
1300
1301 computeShaderStream << "layout(r32f, binding = " << numImagesNonArray
1302 << ") uniform highp image2D imageArray[" << numImagesInArray << "];\n";
1303
1304 computeShaderStream << "void main()\n"
1305 "{\n"
1306 " uint val = 0u;\n"
1307 " vec4 val2 = vec4(0.0);\n";
1308
1309 for (int i = 0; i < maxComputeShaderStorageBlocks; ++i)
1310 {
1311 computeShaderStream << " val += instance[" << i << "].data; \n";
1312 }
1313
1314 for (int i = 0; i < numImagesNonArray; ++i)
1315 {
1316 computeShaderStream << " val2 += imageLoad(image" << i
1317 << ", ivec2(gl_LocalInvocationID.xy)); \n";
1318 }
1319
1320 for (int i = 0; i < numImagesInArray; ++i)
1321 {
1322 computeShaderStream << " val2 += imageLoad(imageArray[" << i << "]"
1323 << ", ivec2(gl_LocalInvocationID.xy)); \n";
1324 }
1325
1326 computeShaderStream << " instance[0].data = val + uint(val2.x);\n"
1327 "}\n";
1328
1329 GLuint computeProgram = CompileComputeProgram(computeShaderStream.str());
1330 EXPECT_EQ(0u, computeProgram);
1331}
1332
Qin Jiajia2a12b3d2018-05-23 13:42:13 +08001333// Test that uniform block with struct member in compute shader is supported.
1334TEST_P(ComputeShaderTest, UniformBlockWithStructMember)
1335{
1336 const std::string csSource =
1337 R"(#version 310 es
1338 layout(local_size_x=8) in;
1339 layout(rgba8) uniform highp readonly image2D mImage2DInput;
1340 layout(rgba8) uniform highp writeonly image2D mImage2DOutput;
1341 struct S {
1342 ivec3 a;
1343 ivec2 b;
1344 };
1345
1346 layout(std140, binding=0) uniform blockName {
1347 S bd;
1348 } instanceName;
1349 void main()
1350 {
1351 ivec2 t1 = instanceName.bd.b;
1352 vec4 result2d = imageLoad(mImage2DInput, t1);
1353 imageStore(mImage2DOutput, ivec2(gl_LocalInvocationID.xy), result2d);
1354 })";
1355
1356 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
1357 EXPECT_GL_NO_ERROR();
1358}
1359
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +08001360// Verify shared non-array variables can work correctly.
1361TEST_P(ComputeShaderTest, NonArraySharedVariable)
1362{
1363 const char kCSShader[] =
1364 R"(#version 310 es
1365 layout (local_size_x = 2, local_size_y = 2, local_size_z = 1) in;
1366 layout (r32ui, binding = 0) readonly uniform highp uimage2D srcImage;
1367 layout (r32ui, binding = 1) writeonly uniform highp uimage2D dstImage;
1368 shared uint temp;
1369 void main()
1370 {
1371 if (gl_LocalInvocationID == uvec3(0, 0, 0))
1372 {
1373 temp = imageLoad(srcImage, ivec2(gl_LocalInvocationID.xy)).x;
1374 }
1375 groupMemoryBarrier();
1376 barrier();
1377 if (gl_LocalInvocationID == uvec3(1, 1, 0))
1378 {
1379 imageStore(dstImage, ivec2(gl_LocalInvocationID.xy), uvec4(temp));
1380 }
1381 else
1382 {
1383 uint inputValue = imageLoad(srcImage, ivec2(gl_LocalInvocationID.xy)).x;
1384 imageStore(dstImage, ivec2(gl_LocalInvocationID.xy), uvec4(inputValue));
1385 }
1386 })";
1387
1388 const std::array<GLuint, 4> inputData = {{250, 200, 150, 100}};
1389 const std::array<GLuint, 4> expectedValues = {{250, 200, 150, 250}};
Jiawei Shaoa6a78422018-06-28 08:32:54 +08001390 runSharedMemoryTest<GLuint, 2, 2>(kCSShader, GL_R32UI, GL_UNSIGNED_INT, inputData,
1391 expectedValues);
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +08001392}
1393
1394// Verify shared non-struct array variables can work correctly.
1395TEST_P(ComputeShaderTest, NonStructArrayAsSharedVariable)
1396{
1397 const char kCSShader[] =
1398 R"(#version 310 es
1399 layout (local_size_x = 2, local_size_y = 2, local_size_z = 1) in;
1400 layout (r32ui, binding = 0) readonly uniform highp uimage2D srcImage;
1401 layout (r32ui, binding = 1) writeonly uniform highp uimage2D dstImage;
1402 shared uint sharedData[2][2];
1403 void main()
1404 {
1405 uint inputData = imageLoad(srcImage, ivec2(gl_LocalInvocationID.xy)).x;
1406 sharedData[gl_LocalInvocationID.x][gl_LocalInvocationID.y] = inputData;
1407 groupMemoryBarrier();
1408 barrier();
1409 imageStore(dstImage, ivec2(gl_LocalInvocationID.xy),
1410 uvec4(sharedData[gl_LocalInvocationID.y][gl_LocalInvocationID.x]));
1411 })";
1412
1413 const std::array<GLuint, 4> inputData = {{250, 200, 150, 100}};
1414 const std::array<GLuint, 4> expectedValues = {{250, 150, 200, 100}};
Jiawei Shaoa6a78422018-06-28 08:32:54 +08001415 runSharedMemoryTest<GLuint, 2, 2>(kCSShader, GL_R32UI, GL_UNSIGNED_INT, inputData,
1416 expectedValues);
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +08001417}
1418
1419// Verify shared struct array variables work correctly.
1420TEST_P(ComputeShaderTest, StructArrayAsSharedVariable)
1421{
1422 const char kCSShader[] =
1423 R"(#version 310 es
1424 layout (local_size_x = 2, local_size_y = 2, local_size_z = 1) in;
1425 layout (r32ui, binding = 0) readonly uniform highp uimage2D srcImage;
1426 layout (r32ui, binding = 1) writeonly uniform highp uimage2D dstImage;
1427 struct SharedStruct
1428 {
1429 uint data;
1430 };
1431 shared SharedStruct sharedData[2][2];
1432 void main()
1433 {
1434 uint inputData = imageLoad(srcImage, ivec2(gl_LocalInvocationID.xy)).x;
1435 sharedData[gl_LocalInvocationID.x][gl_LocalInvocationID.y].data = inputData;
1436 groupMemoryBarrier();
1437 barrier();
1438 imageStore(dstImage, ivec2(gl_LocalInvocationID.xy),
1439 uvec4(sharedData[gl_LocalInvocationID.y][gl_LocalInvocationID.x].data));
1440 })";
1441
1442 const std::array<GLuint, 4> inputData = {{250, 200, 150, 100}};
1443 const std::array<GLuint, 4> expectedValues = {{250, 150, 200, 100}};
Jiawei Shaoa6a78422018-06-28 08:32:54 +08001444 runSharedMemoryTest<GLuint, 2, 2>(kCSShader, GL_R32UI, GL_UNSIGNED_INT, inputData,
1445 expectedValues);
1446}
1447
1448// Verify using atomic functions without return value can work correctly.
1449// TODO(jiawei.shao@intel.com): add test on atomicExchange and atomicCompSwap.
1450TEST_P(ComputeShaderTest, AtomicFunctionsNoReturnValue)
1451{
1452 // TODO(jiawei.shao@intel.com): find out why this shader causes a link error on Android Nexus 5
1453 // bot.
1454 ANGLE_SKIP_TEST_IF(IsAndroid());
1455
1456 const char kCSShader[] =
1457 R"(#version 310 es
1458 layout (local_size_x = 6, local_size_y = 1, local_size_z = 1) in;
1459 layout (r32ui, binding = 0) readonly uniform highp uimage2D srcImage;
1460 layout (r32ui, binding = 1) writeonly uniform highp uimage2D dstImage;
1461
1462 const uint kSumIndex = 0u;
1463 const uint kMinIndex = 1u;
1464 const uint kMaxIndex = 2u;
1465 const uint kOrIndex = 3u;
1466 const uint kAndIndex = 4u;
1467 const uint kXorIndex = 5u;
1468
1469 shared highp uint results[6];
1470
1471 void main()
1472 {
1473 if (gl_LocalInvocationID.x == kMinIndex || gl_LocalInvocationID.x == kAndIndex)
1474 {
1475 results[gl_LocalInvocationID.x] = 0xFFFFu;
1476 }
1477 else
1478 {
1479 results[gl_LocalInvocationID.x] = 0u;
1480 }
1481 memoryBarrierShared();
1482 barrier();
1483
1484 uint value = imageLoad(srcImage, ivec2(gl_LocalInvocationID.xy)).x;
1485 atomicAdd(results[kSumIndex], value);
1486 atomicMin(results[kMinIndex], value);
1487 atomicMax(results[kMaxIndex], value);
1488 atomicOr(results[kOrIndex], value);
1489 atomicAnd(results[kAndIndex], value);
1490 atomicXor(results[kXorIndex], value);
1491 memoryBarrierShared();
1492 barrier();
1493
1494 imageStore(dstImage, ivec2(gl_LocalInvocationID.xy),
1495 uvec4(results[gl_LocalInvocationID.x]));
1496 })";
1497
1498 const std::array<GLuint, 6> inputData = {{1, 2, 4, 8, 16, 32}};
1499 const std::array<GLuint, 6> expectedValues = {{63, 1, 32, 63, 0, 63}};
1500 runSharedMemoryTest<GLuint, 6, 1>(kCSShader, GL_R32UI, GL_UNSIGNED_INT, inputData,
1501 expectedValues);
1502}
1503
1504// Verify using atomic functions in a non-initializer single assignment can work correctly.
1505TEST_P(ComputeShaderTest, AtomicFunctionsInNonInitializerSingleAssignment)
1506{
1507 const char kCSShader[] =
1508 R"(#version 310 es
1509 layout (local_size_x = 9, local_size_y = 1, local_size_z = 1) in;
1510 layout (r32i, binding = 0) readonly uniform highp iimage2D srcImage;
1511 layout (r32i, binding = 1) writeonly uniform highp iimage2D dstImage;
1512
1513 shared highp int sharedVariable;
1514
1515 shared highp int inputData[9];
1516 shared highp int outputData[9];
1517
1518 void main()
1519 {
1520 int inputValue = imageLoad(srcImage, ivec2(gl_LocalInvocationID.xy)).x;
1521 inputData[gl_LocalInvocationID.x] = inputValue;
1522 memoryBarrierShared();
1523 barrier();
1524
1525 if (gl_LocalInvocationID.x == 0u)
1526 {
1527 sharedVariable = 0;
1528
1529 outputData[0] = atomicAdd(sharedVariable, inputData[0]);
1530 outputData[1] = atomicMin(sharedVariable, inputData[1]);
1531 outputData[2] = atomicMax(sharedVariable, inputData[2]);
1532 outputData[3] = atomicAnd(sharedVariable, inputData[3]);
1533 outputData[4] = atomicOr(sharedVariable, inputData[4]);
1534 outputData[5] = atomicXor(sharedVariable, inputData[5]);
1535 outputData[6] = atomicExchange(sharedVariable, inputData[6]);
1536 outputData[7] = atomicCompSwap(sharedVariable, 64, inputData[7]);
1537 outputData[8] = atomicAdd(sharedVariable, inputData[8]);
1538 }
1539 memoryBarrierShared();
1540 barrier();
1541
1542 imageStore(dstImage, ivec2(gl_LocalInvocationID.xy),
1543 ivec4(outputData[gl_LocalInvocationID.x]));
1544 })";
1545
1546 const std::array<GLint, 9> inputData = {{1, 2, 4, 8, 16, 32, 64, 128, 1}};
1547 const std::array<GLint, 9> expectedValues = {{0, 1, 1, 4, 0, 16, 48, 64, 128}};
1548 runSharedMemoryTest<GLint, 9, 1>(kCSShader, GL_R32I, GL_INT, inputData, expectedValues);
Jiawei Shaoa75aa3b2018-06-21 10:38:28 +08001549}
1550
Martin Radev4c4c8e72016-08-04 12:25:34 +03001551// Check that it is not possible to create a compute shader when the context does not support ES
1552// 3.10
1553TEST_P(ComputeShaderTestES3, NotSupported)
1554{
1555 GLuint computeShaderHandle = glCreateShader(GL_COMPUTE_SHADER);
1556 EXPECT_EQ(0u, computeShaderHandle);
1557 EXPECT_GL_ERROR(GL_INVALID_ENUM);
1558}
1559
Xinghua Caob1239382016-12-13 15:07:05 +08001560ANGLE_INSTANTIATE_TEST(ComputeShaderTest, ES31_OPENGL(), ES31_OPENGLES(), ES31_D3D11());
Martin Radev4c4c8e72016-08-04 12:25:34 +03001561ANGLE_INSTANTIATE_TEST(ComputeShaderTestES3, ES3_OPENGL(), ES3_OPENGLES());
1562
1563} // namespace