blob: 4f46e3f17926ca851eda658ef7384cced9ff2834 [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
9#include "test_utils/ANGLETest.h"
10#include "test_utils/gl_raii.h"
11#include <vector>
12
13using namespace angle;
14
15namespace
16{
17
18class ComputeShaderTest : public ANGLETest
19{
20 protected:
21 ComputeShaderTest() {}
22};
23
24class ComputeShaderTestES3 : public ANGLETest
25{
26 protected:
27 ComputeShaderTestES3() {}
28};
29
30// link a simple compute program. It should be successful.
31TEST_P(ComputeShaderTest, LinkComputeProgram)
32{
33 const std::string csSource =
34 "#version 310 es\n"
35 "layout(local_size_x=1) in;\n"
36 "void main()\n"
37 "{\n"
38 "}\n";
39
40 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
41
42 EXPECT_GL_NO_ERROR();
43}
44
Yunchao He85072e82017-11-14 15:43:28 +080045// Link a simple compute program. Then detach the shader and dispatch compute.
46// It should be successful.
47TEST_P(ComputeShaderTest, DetachShaderAfterLinkSuccess)
48{
49 const std::string csSource =
50 R"(#version 310 es
51 layout(local_size_x=1) in;
52 void main()
53 {
54 })";
55
56 GLuint program = glCreateProgram();
57
58 GLuint cs = CompileShader(GL_COMPUTE_SHADER, csSource);
59 EXPECT_NE(0u, cs);
60
61 glAttachShader(program, cs);
62 glDeleteShader(cs);
63
64 glLinkProgram(program);
65 GLint linkStatus;
66 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
67 EXPECT_EQ(GL_TRUE, linkStatus);
68
69 glDetachShader(program, cs);
70 EXPECT_GL_NO_ERROR();
71
72 glUseProgram(program);
73 glDispatchCompute(8, 4, 2);
74 EXPECT_GL_NO_ERROR();
75}
76
Martin Radev4c4c8e72016-08-04 12:25:34 +030077// link a simple compute program. There is no local size and linking should fail.
78TEST_P(ComputeShaderTest, LinkComputeProgramNoLocalSizeLinkError)
79{
80 const std::string csSource =
81 "#version 310 es\n"
82 "void main()\n"
83 "{\n"
84 "}\n";
85
86 GLuint program = CompileComputeProgram(csSource, false);
87 EXPECT_EQ(0u, program);
88
89 glDeleteProgram(program);
90
91 EXPECT_GL_NO_ERROR();
92}
93
94// link a simple compute program.
95// make sure that uniforms and uniform samplers get recorded
96TEST_P(ComputeShaderTest, LinkComputeProgramWithUniforms)
97{
98 const std::string csSource =
Olli Etuaho7caa80e2017-11-14 15:03:14 +020099 R"(#version 310 es
100 precision mediump sampler2D;
101 layout(local_size_x=1) in;
102 uniform int myUniformInt;
103 uniform sampler2D myUniformSampler;
104 layout(rgba32i) uniform highp writeonly iimage2D imageOut;
105 void main()
106 {
107 int q = myUniformInt;
108 vec4 v = textureLod(myUniformSampler, vec2(0.0), 0.0);
109 imageStore(imageOut, ivec2(0), ivec4(v) * q);
110 })";
Martin Radev4c4c8e72016-08-04 12:25:34 +0300111
112 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
113
Olli Etuaho7caa80e2017-11-14 15:03:14 +0200114 GLint uniformLoc = glGetUniformLocation(program.get(), "myUniformInt");
115 EXPECT_NE(-1, uniformLoc);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300116
Olli Etuaho7caa80e2017-11-14 15:03:14 +0200117 uniformLoc = glGetUniformLocation(program.get(), "myUniformSampler");
118 EXPECT_NE(-1, uniformLoc);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300119
120 EXPECT_GL_NO_ERROR();
121}
122
123// Attach both compute and non-compute shaders. A link time error should occur.
124// OpenGL ES 3.10, 7.3 Program Objects
125TEST_P(ComputeShaderTest, AttachMultipleShaders)
126{
127 const std::string csSource =
128 "#version 310 es\n"
129 "layout(local_size_x=1) in;\n"
130 "void main()\n"
131 "{\n"
132 "}\n";
133
134 const std::string vsSource =
135 "#version 310 es\n"
136 "void main()\n"
137 "{\n"
138 "}\n";
139
140 const std::string fsSource =
141 "#version 310 es\n"
142 "void main()\n"
143 "{\n"
144 "}\n";
145
146 GLuint program = glCreateProgram();
147
148 GLuint vs = CompileShader(GL_VERTEX_SHADER, vsSource);
149 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fsSource);
150 GLuint cs = CompileShader(GL_COMPUTE_SHADER, csSource);
151
152 EXPECT_NE(0u, vs);
153 EXPECT_NE(0u, fs);
154 EXPECT_NE(0u, cs);
155
156 glAttachShader(program, vs);
157 glDeleteShader(vs);
158
159 glAttachShader(program, fs);
160 glDeleteShader(fs);
161
162 glAttachShader(program, cs);
163 glDeleteShader(cs);
164
165 glLinkProgram(program);
166
167 GLint linkStatus;
168 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
169
Yunchao He70b715c2017-11-07 14:59:15 +0800170 EXPECT_EQ(GL_FALSE, linkStatus);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300171
172 EXPECT_GL_NO_ERROR();
173}
174
175// Attach a vertex, fragment and compute shader.
176// Query for the number of attached shaders and check the count.
177TEST_P(ComputeShaderTest, AttachmentCount)
178{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300179 const std::string csSource =
180 "#version 310 es\n"
181 "layout(local_size_x=1) in;\n"
182 "void main()\n"
183 "{\n"
184 "}\n";
185
186 const std::string vsSource =
187 "#version 310 es\n"
188 "void main()\n"
189 "{\n"
190 "}\n";
191
192 const std::string fsSource =
193 "#version 310 es\n"
194 "void main()\n"
195 "{\n"
196 "}\n";
197
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 GLint numAttachedShaders;
218 glGetProgramiv(program, GL_ATTACHED_SHADERS, &numAttachedShaders);
219
220 EXPECT_EQ(3, numAttachedShaders);
221
222 glDeleteProgram(program);
223
224 EXPECT_GL_NO_ERROR();
225}
226
Yunchao He70b715c2017-11-07 14:59:15 +0800227// Attach a vertex and fragment shader and link, but dispatch compute.
228TEST_P(ComputeShaderTest, DispatchComputeWithRenderingProgram)
229{
230 const std::string vsSource =
231 "#version 310 es\n"
232 "void main()\n"
233 "{\n"
234 "}\n";
235
236 const std::string fsSource =
237 "#version 310 es\n"
238 "void main()\n"
239 "{\n"
240 "}\n";
241
242 GLuint program = glCreateProgram();
243
244 GLuint vs = CompileShader(GL_VERTEX_SHADER, vsSource);
245 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fsSource);
246
247 EXPECT_NE(0u, vs);
248 EXPECT_NE(0u, fs);
249
250 glAttachShader(program, vs);
251 glDeleteShader(vs);
252
253 glAttachShader(program, fs);
254 glDeleteShader(fs);
255
256 glLinkProgram(program);
257
258 GLint linkStatus;
259 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
260 EXPECT_EQ(GL_TRUE, linkStatus);
261
262 EXPECT_GL_NO_ERROR();
263
264 glUseProgram(program);
265 glDispatchCompute(8, 4, 2);
266 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
267}
268
Xinghua Caob1239382016-12-13 15:07:05 +0800269// Access all compute shader special variables.
270TEST_P(ComputeShaderTest, AccessAllSpecialVariables)
271{
272 const std::string csSource =
Olli Etuaho7caa80e2017-11-14 15:03:14 +0200273 R"(#version 310 es
274 layout(local_size_x=4, local_size_y=3, local_size_z=2) in;
275 layout(rgba32ui) uniform highp writeonly uimage2D imageOut;
276 void main()
277 {
278 uvec3 temp1 = gl_NumWorkGroups;
279 uvec3 temp2 = gl_WorkGroupSize;
280 uvec3 temp3 = gl_WorkGroupID;
281 uvec3 temp4 = gl_LocalInvocationID;
282 uvec3 temp5 = gl_GlobalInvocationID;
283 uint temp6 = gl_LocalInvocationIndex;
284 imageStore(imageOut, ivec2(gl_LocalInvocationIndex, 0), uvec4(temp1 + temp2 + temp3 + temp4 + temp5, temp6));
285 })";
Xinghua Caob1239382016-12-13 15:07:05 +0800286
287 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
288}
289
290// Access part compute shader special variables.
291TEST_P(ComputeShaderTest, AccessPartSpecialVariables)
292{
293 const std::string csSource =
Olli Etuaho7caa80e2017-11-14 15:03:14 +0200294 R"(#version 310 es
295 layout(local_size_x=4, local_size_y=3, local_size_z=2) in;
296 layout(rgba32ui) uniform highp writeonly uimage2D imageOut;
297 void main()
298 {
299 uvec3 temp1 = gl_WorkGroupSize;
300 uvec3 temp2 = gl_WorkGroupID;
301 uint temp3 = gl_LocalInvocationIndex;
302 imageStore(imageOut, ivec2(gl_LocalInvocationIndex, 0), uvec4(temp1 + temp2, temp3));
303 })";
Xinghua Caob1239382016-12-13 15:07:05 +0800304
305 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
306}
307
Xinghua Cao73badc02017-03-29 19:14:53 +0800308// Use glDispatchCompute to define work group count.
309TEST_P(ComputeShaderTest, DispatchCompute)
Xinghua Cao2b396592017-03-29 15:36:04 +0800310{
311 const std::string csSource =
Olli Etuaho7caa80e2017-11-14 15:03:14 +0200312 R"(#version 310 es
313 layout(local_size_x=4, local_size_y=3, local_size_z=2) in;
314 layout(rgba32ui) uniform highp writeonly uimage2D imageOut;
315 void main()
316 {
317 uvec3 temp = gl_NumWorkGroups;
318 imageStore(imageOut, ivec2(0), uvec4(temp, 0u));
319 })";
Xinghua Cao2b396592017-03-29 15:36:04 +0800320
321 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
322
323 glUseProgram(program.get());
324 glDispatchCompute(8, 4, 2);
325 EXPECT_GL_NO_ERROR();
326}
327
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800328// Use image uniform to write texture in compute shader, and verify the content is expected.
329TEST_P(ComputeShaderTest, BindImageTexture)
330{
Xinghua Cao0328b572017-06-26 15:51:36 +0800331 ANGLE_SKIP_TEST_IF(IsD3D11());
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800332
333 GLTexture mTexture[2];
334 GLFramebuffer mFramebuffer;
335 const std::string csSource =
336 "#version 310 es\n"
337 "layout(local_size_x=2, local_size_y=2, local_size_z=1) in;\n"
338 "layout(r32ui, binding = 0) writeonly uniform highp uimage2D uImage[2];"
339 "void main()\n"
340 "{\n"
341 " imageStore(uImage[0], ivec2(gl_LocalInvocationIndex, gl_WorkGroupID.x), uvec4(100, 0, "
342 "0, 0));"
343 " imageStore(uImage[1], ivec2(gl_LocalInvocationIndex, gl_WorkGroupID.x), uvec4(100, 0, "
344 "0, 0));"
345 "}\n";
346
347 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
348 glUseProgram(program.get());
349 int width = 4, height = 2;
350 GLuint inputValues[] = {200, 200, 200, 200, 200, 200, 200, 200};
351
352 glBindTexture(GL_TEXTURE_2D, mTexture[0]);
353 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, width, height);
354 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RED_INTEGER, GL_UNSIGNED_INT,
355 inputValues);
356 EXPECT_GL_NO_ERROR();
357
358 glBindImageTexture(0, mTexture[0], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
359 EXPECT_GL_NO_ERROR();
360
361 glBindTexture(GL_TEXTURE_2D, mTexture[1]);
362 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, width, height);
363 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RED_INTEGER, GL_UNSIGNED_INT,
364 inputValues);
365 EXPECT_GL_NO_ERROR();
366
367 glBindImageTexture(1, mTexture[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
368 EXPECT_GL_NO_ERROR();
369
370 glDispatchCompute(2, 1, 1);
371 EXPECT_GL_NO_ERROR();
372
373 glUseProgram(0);
374 GLuint outputValues[2][8];
375 GLuint expectedValue = 100;
376 glBindFramebuffer(GL_READ_FRAMEBUFFER, mFramebuffer);
377
378 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTexture[0],
379 0);
380 EXPECT_GL_NO_ERROR();
381 glReadPixels(0, 0, width, height, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues[0]);
382 EXPECT_GL_NO_ERROR();
383
384 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTexture[1],
385 0);
386 EXPECT_GL_NO_ERROR();
387 glReadPixels(0, 0, width, height, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues[1]);
388 EXPECT_GL_NO_ERROR();
389
390 for (int i = 0; i < width * height; i++)
391 {
392 EXPECT_EQ(expectedValue, outputValues[0][i]);
393 EXPECT_EQ(expectedValue, outputValues[1][i]);
394 }
395}
396
Xinghua Cao0328b572017-06-26 15:51:36 +0800397// When declare a image array without a binding qualifier, all elements are bound to unit zero.
398TEST_P(ComputeShaderTest, ImageArrayWithoutBindingQualifier)
399{
400 ANGLE_SKIP_TEST_IF(IsD3D11());
401
402 // TODO(xinghua.cao@intel.com): On AMD desktop OpenGL, bind two image variables to unit 0,
403 // only one variable is valid.
Corentin Wallez2bde9192017-07-28 14:15:01 -0400404 ANGLE_SKIP_TEST_IF(IsAMD() && IsDesktopOpenGL());
Xinghua Cao0328b572017-06-26 15:51:36 +0800405
406 GLTexture mTexture;
407 GLFramebuffer mFramebuffer;
408 const std::string csSource =
409 "#version 310 es\n"
410 "layout(local_size_x=2, local_size_y=2, local_size_z=1) in;\n"
411 "layout(r32ui) writeonly uniform highp uimage2D uImage[2];"
412 "void main()\n"
413 "{\n"
414 " imageStore(uImage[0], ivec2(gl_LocalInvocationIndex, 0), uvec4(100, 0, 0, 0));"
415 " imageStore(uImage[1], ivec2(gl_LocalInvocationIndex, 1), uvec4(100, 0, 0, 0));"
416 "}\n";
417
418 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
419 glUseProgram(program.get());
420 constexpr int kTextureWidth = 4, kTextureHeight = 2;
421 GLuint inputValues[] = {200, 200, 200, 200, 200, 200, 200, 200};
422
423 glBindTexture(GL_TEXTURE_2D, mTexture);
424 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kTextureWidth, kTextureHeight);
425 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kTextureWidth, kTextureHeight, GL_RED_INTEGER,
426 GL_UNSIGNED_INT, inputValues);
427 EXPECT_GL_NO_ERROR();
428
429 glBindImageTexture(0, mTexture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
430 glDispatchCompute(1, 1, 1);
431 EXPECT_GL_NO_ERROR();
432
433 glUseProgram(0);
434 glBindFramebuffer(GL_READ_FRAMEBUFFER, mFramebuffer);
435
436 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTexture, 0);
437 GLuint outputValues[8];
438 glReadPixels(0, 0, kTextureWidth, kTextureHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
439 outputValues);
440 EXPECT_GL_NO_ERROR();
441
442 GLuint expectedValue = 100;
443 for (int i = 0; i < kTextureWidth * kTextureHeight; i++)
444 {
445 EXPECT_EQ(expectedValue, outputValues[i]);
446 }
447}
448
Xinghua Cao711b7a12017-10-09 13:38:12 +0800449// imageLoad functions
450TEST_P(ComputeShaderTest, ImageLoad)
451{
452 const std::string csSource =
Olli Etuaho7caa80e2017-11-14 15:03:14 +0200453 R"(#version 310 es
454 layout(local_size_x=8) in;
455 layout(rgba8) uniform highp readonly image2D mImage2DInput;
456 layout(rgba16i) uniform highp readonly iimageCube mImageCubeInput;
457 layout(rgba32ui) uniform highp readonly uimage3D mImage3DInput;
458 layout(r32i) uniform highp writeonly iimage2D imageOut;
459 void main()
460 {
461 vec4 result2d = imageLoad(mImage2DInput, ivec2(gl_LocalInvocationID.xy));
462 ivec4 resultCube = imageLoad(mImageCubeInput, ivec3(gl_LocalInvocationID.xyz));
463 uvec4 result3d = imageLoad(mImage3DInput, ivec3(gl_LocalInvocationID.xyz));
464 imageStore(imageOut, ivec2(gl_LocalInvocationIndex, 0), ivec4(result2d) + resultCube + ivec4(result3d));
465 })";
Xinghua Cao711b7a12017-10-09 13:38:12 +0800466
467 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
468 EXPECT_GL_NO_ERROR();
469}
470
471// imageStore functions
472TEST_P(ComputeShaderTest, ImageStore)
473{
474 const std::string csSource =
475 "#version 310 es\n"
476 "layout(local_size_x=8) in;\n"
477 "layout(rgba16f) uniform highp writeonly imageCube mImageCubeOutput;\n"
478 "layout(r32f) uniform highp writeonly image3D mImage3DOutput;\n"
479 "layout(rgba8ui) uniform highp writeonly uimage2DArray mImage2DArrayOutput;\n"
480 "void main()\n"
481 "{\n"
482 " imageStore(mImageCubeOutput, ivec3(gl_LocalInvocationID.xyz), vec4(0.0));\n"
483 " imageStore(mImage3DOutput, ivec3(gl_LocalInvocationID.xyz), vec4(0.0));\n"
484 " imageStore(mImage2DArrayOutput, ivec3(gl_LocalInvocationID.xyz), uvec4(0));\n"
485 "}\n";
486
487 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
488 EXPECT_GL_NO_ERROR();
489}
490
491// imageSize functions
492TEST_P(ComputeShaderTest, ImageSize)
493{
494 const std::string csSource =
Olli Etuaho7caa80e2017-11-14 15:03:14 +0200495 R"(#version 310 es
496 layout(local_size_x=8) in;
497 layout(rgba8) uniform highp readonly imageCube mImageCubeInput;
498 layout(r32i) uniform highp readonly iimage2D mImage2DInput;
499 layout(rgba16ui) uniform highp readonly uimage2DArray mImage2DArrayInput;
500 layout(r32i) uniform highp writeonly iimage2D imageOut;
501 void main()
502 {
503 ivec2 sizeCube = imageSize(mImageCubeInput);
504 ivec2 size2D = imageSize(mImage2DInput);
505 ivec3 size2DArray = imageSize(mImage2DArrayInput);
506 imageStore(imageOut, ivec2(gl_LocalInvocationIndex, 0), ivec4(sizeCube, size2D.x, size2DArray.x));
507 })";
Xinghua Cao711b7a12017-10-09 13:38:12 +0800508
509 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
510 EXPECT_GL_NO_ERROR();
511}
512
Martin Radev4c4c8e72016-08-04 12:25:34 +0300513// Check that it is not possible to create a compute shader when the context does not support ES
514// 3.10
515TEST_P(ComputeShaderTestES3, NotSupported)
516{
517 GLuint computeShaderHandle = glCreateShader(GL_COMPUTE_SHADER);
518 EXPECT_EQ(0u, computeShaderHandle);
519 EXPECT_GL_ERROR(GL_INVALID_ENUM);
520}
521
Xinghua Caob1239382016-12-13 15:07:05 +0800522ANGLE_INSTANTIATE_TEST(ComputeShaderTest, ES31_OPENGL(), ES31_OPENGLES(), ES31_D3D11());
Martin Radev4c4c8e72016-08-04 12:25:34 +0300523ANGLE_INSTANTIATE_TEST(ComputeShaderTestES3, ES3_OPENGL(), ES3_OPENGLES());
524
525} // namespace