blob: 9e1f4fb5451535f40b011e9b18de59b920b574f0 [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
45// link a simple compute program. There is no local size and linking should fail.
46TEST_P(ComputeShaderTest, LinkComputeProgramNoLocalSizeLinkError)
47{
48 const std::string csSource =
49 "#version 310 es\n"
50 "void main()\n"
51 "{\n"
52 "}\n";
53
54 GLuint program = CompileComputeProgram(csSource, false);
55 EXPECT_EQ(0u, program);
56
57 glDeleteProgram(program);
58
59 EXPECT_GL_NO_ERROR();
60}
61
62// link a simple compute program.
63// make sure that uniforms and uniform samplers get recorded
64TEST_P(ComputeShaderTest, LinkComputeProgramWithUniforms)
65{
66 const std::string csSource =
Olli Etuaho7caa80e2017-11-14 15:03:14 +020067 R"(#version 310 es
68 precision mediump sampler2D;
69 layout(local_size_x=1) in;
70 uniform int myUniformInt;
71 uniform sampler2D myUniformSampler;
72 layout(rgba32i) uniform highp writeonly iimage2D imageOut;
73 void main()
74 {
75 int q = myUniformInt;
76 vec4 v = textureLod(myUniformSampler, vec2(0.0), 0.0);
77 imageStore(imageOut, ivec2(0), ivec4(v) * q);
78 })";
Martin Radev4c4c8e72016-08-04 12:25:34 +030079
80 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
81
Olli Etuaho7caa80e2017-11-14 15:03:14 +020082 GLint uniformLoc = glGetUniformLocation(program.get(), "myUniformInt");
83 EXPECT_NE(-1, uniformLoc);
Martin Radev4c4c8e72016-08-04 12:25:34 +030084
Olli Etuaho7caa80e2017-11-14 15:03:14 +020085 uniformLoc = glGetUniformLocation(program.get(), "myUniformSampler");
86 EXPECT_NE(-1, uniformLoc);
Martin Radev4c4c8e72016-08-04 12:25:34 +030087
88 EXPECT_GL_NO_ERROR();
89}
90
91// Attach both compute and non-compute shaders. A link time error should occur.
92// OpenGL ES 3.10, 7.3 Program Objects
93TEST_P(ComputeShaderTest, AttachMultipleShaders)
94{
95 const std::string csSource =
96 "#version 310 es\n"
97 "layout(local_size_x=1) in;\n"
98 "void main()\n"
99 "{\n"
100 "}\n";
101
102 const std::string vsSource =
103 "#version 310 es\n"
104 "void main()\n"
105 "{\n"
106 "}\n";
107
108 const std::string fsSource =
109 "#version 310 es\n"
110 "void main()\n"
111 "{\n"
112 "}\n";
113
114 GLuint program = glCreateProgram();
115
116 GLuint vs = CompileShader(GL_VERTEX_SHADER, vsSource);
117 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fsSource);
118 GLuint cs = CompileShader(GL_COMPUTE_SHADER, csSource);
119
120 EXPECT_NE(0u, vs);
121 EXPECT_NE(0u, fs);
122 EXPECT_NE(0u, cs);
123
124 glAttachShader(program, vs);
125 glDeleteShader(vs);
126
127 glAttachShader(program, fs);
128 glDeleteShader(fs);
129
130 glAttachShader(program, cs);
131 glDeleteShader(cs);
132
133 glLinkProgram(program);
134
135 GLint linkStatus;
136 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
137
Yunchao He70b715c2017-11-07 14:59:15 +0800138 EXPECT_EQ(GL_FALSE, linkStatus);
Martin Radev4c4c8e72016-08-04 12:25:34 +0300139
140 EXPECT_GL_NO_ERROR();
141}
142
143// Attach a vertex, fragment and compute shader.
144// Query for the number of attached shaders and check the count.
145TEST_P(ComputeShaderTest, AttachmentCount)
146{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300147 const std::string csSource =
148 "#version 310 es\n"
149 "layout(local_size_x=1) in;\n"
150 "void main()\n"
151 "{\n"
152 "}\n";
153
154 const std::string vsSource =
155 "#version 310 es\n"
156 "void main()\n"
157 "{\n"
158 "}\n";
159
160 const std::string fsSource =
161 "#version 310 es\n"
162 "void main()\n"
163 "{\n"
164 "}\n";
165
166 GLuint program = glCreateProgram();
167
168 GLuint vs = CompileShader(GL_VERTEX_SHADER, vsSource);
169 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fsSource);
170 GLuint cs = CompileShader(GL_COMPUTE_SHADER, csSource);
171
172 EXPECT_NE(0u, vs);
173 EXPECT_NE(0u, fs);
174 EXPECT_NE(0u, cs);
175
176 glAttachShader(program, vs);
177 glDeleteShader(vs);
178
179 glAttachShader(program, fs);
180 glDeleteShader(fs);
181
182 glAttachShader(program, cs);
183 glDeleteShader(cs);
184
185 GLint numAttachedShaders;
186 glGetProgramiv(program, GL_ATTACHED_SHADERS, &numAttachedShaders);
187
188 EXPECT_EQ(3, numAttachedShaders);
189
190 glDeleteProgram(program);
191
192 EXPECT_GL_NO_ERROR();
193}
194
Yunchao He70b715c2017-11-07 14:59:15 +0800195// Attach a vertex and fragment shader and link, but dispatch compute.
196TEST_P(ComputeShaderTest, DispatchComputeWithRenderingProgram)
197{
198 const std::string vsSource =
199 "#version 310 es\n"
200 "void main()\n"
201 "{\n"
202 "}\n";
203
204 const std::string fsSource =
205 "#version 310 es\n"
206 "void main()\n"
207 "{\n"
208 "}\n";
209
210 GLuint program = glCreateProgram();
211
212 GLuint vs = CompileShader(GL_VERTEX_SHADER, vsSource);
213 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fsSource);
214
215 EXPECT_NE(0u, vs);
216 EXPECT_NE(0u, fs);
217
218 glAttachShader(program, vs);
219 glDeleteShader(vs);
220
221 glAttachShader(program, fs);
222 glDeleteShader(fs);
223
224 glLinkProgram(program);
225
226 GLint linkStatus;
227 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
228 EXPECT_EQ(GL_TRUE, linkStatus);
229
230 EXPECT_GL_NO_ERROR();
231
232 glUseProgram(program);
233 glDispatchCompute(8, 4, 2);
234 EXPECT_GL_ERROR(GL_INVALID_OPERATION);
235}
236
Xinghua Caob1239382016-12-13 15:07:05 +0800237// Access all compute shader special variables.
238TEST_P(ComputeShaderTest, AccessAllSpecialVariables)
239{
240 const std::string csSource =
Olli Etuaho7caa80e2017-11-14 15:03:14 +0200241 R"(#version 310 es
242 layout(local_size_x=4, local_size_y=3, local_size_z=2) in;
243 layout(rgba32ui) uniform highp writeonly uimage2D imageOut;
244 void main()
245 {
246 uvec3 temp1 = gl_NumWorkGroups;
247 uvec3 temp2 = gl_WorkGroupSize;
248 uvec3 temp3 = gl_WorkGroupID;
249 uvec3 temp4 = gl_LocalInvocationID;
250 uvec3 temp5 = gl_GlobalInvocationID;
251 uint temp6 = gl_LocalInvocationIndex;
252 imageStore(imageOut, ivec2(gl_LocalInvocationIndex, 0), uvec4(temp1 + temp2 + temp3 + temp4 + temp5, temp6));
253 })";
Xinghua Caob1239382016-12-13 15:07:05 +0800254
255 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
256}
257
258// Access part compute shader special variables.
259TEST_P(ComputeShaderTest, AccessPartSpecialVariables)
260{
261 const std::string csSource =
Olli Etuaho7caa80e2017-11-14 15:03:14 +0200262 R"(#version 310 es
263 layout(local_size_x=4, local_size_y=3, local_size_z=2) in;
264 layout(rgba32ui) uniform highp writeonly uimage2D imageOut;
265 void main()
266 {
267 uvec3 temp1 = gl_WorkGroupSize;
268 uvec3 temp2 = gl_WorkGroupID;
269 uint temp3 = gl_LocalInvocationIndex;
270 imageStore(imageOut, ivec2(gl_LocalInvocationIndex, 0), uvec4(temp1 + temp2, temp3));
271 })";
Xinghua Caob1239382016-12-13 15:07:05 +0800272
273 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
274}
275
Xinghua Cao73badc02017-03-29 19:14:53 +0800276// Use glDispatchCompute to define work group count.
277TEST_P(ComputeShaderTest, DispatchCompute)
Xinghua Cao2b396592017-03-29 15:36:04 +0800278{
279 const std::string csSource =
Olli Etuaho7caa80e2017-11-14 15:03:14 +0200280 R"(#version 310 es
281 layout(local_size_x=4, local_size_y=3, local_size_z=2) in;
282 layout(rgba32ui) uniform highp writeonly uimage2D imageOut;
283 void main()
284 {
285 uvec3 temp = gl_NumWorkGroups;
286 imageStore(imageOut, ivec2(0), uvec4(temp, 0u));
287 })";
Xinghua Cao2b396592017-03-29 15:36:04 +0800288
289 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
290
291 glUseProgram(program.get());
292 glDispatchCompute(8, 4, 2);
293 EXPECT_GL_NO_ERROR();
294}
295
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800296// Use image uniform to write texture in compute shader, and verify the content is expected.
297TEST_P(ComputeShaderTest, BindImageTexture)
298{
Xinghua Cao0328b572017-06-26 15:51:36 +0800299 ANGLE_SKIP_TEST_IF(IsD3D11());
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800300
301 GLTexture mTexture[2];
302 GLFramebuffer mFramebuffer;
303 const std::string csSource =
304 "#version 310 es\n"
305 "layout(local_size_x=2, local_size_y=2, local_size_z=1) in;\n"
306 "layout(r32ui, binding = 0) writeonly uniform highp uimage2D uImage[2];"
307 "void main()\n"
308 "{\n"
309 " imageStore(uImage[0], ivec2(gl_LocalInvocationIndex, gl_WorkGroupID.x), uvec4(100, 0, "
310 "0, 0));"
311 " imageStore(uImage[1], ivec2(gl_LocalInvocationIndex, gl_WorkGroupID.x), uvec4(100, 0, "
312 "0, 0));"
313 "}\n";
314
315 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
316 glUseProgram(program.get());
317 int width = 4, height = 2;
318 GLuint inputValues[] = {200, 200, 200, 200, 200, 200, 200, 200};
319
320 glBindTexture(GL_TEXTURE_2D, mTexture[0]);
321 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, width, height);
322 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RED_INTEGER, GL_UNSIGNED_INT,
323 inputValues);
324 EXPECT_GL_NO_ERROR();
325
326 glBindImageTexture(0, mTexture[0], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
327 EXPECT_GL_NO_ERROR();
328
329 glBindTexture(GL_TEXTURE_2D, mTexture[1]);
330 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, width, height);
331 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RED_INTEGER, GL_UNSIGNED_INT,
332 inputValues);
333 EXPECT_GL_NO_ERROR();
334
335 glBindImageTexture(1, mTexture[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
336 EXPECT_GL_NO_ERROR();
337
338 glDispatchCompute(2, 1, 1);
339 EXPECT_GL_NO_ERROR();
340
341 glUseProgram(0);
342 GLuint outputValues[2][8];
343 GLuint expectedValue = 100;
344 glBindFramebuffer(GL_READ_FRAMEBUFFER, mFramebuffer);
345
346 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTexture[0],
347 0);
348 EXPECT_GL_NO_ERROR();
349 glReadPixels(0, 0, width, height, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues[0]);
350 EXPECT_GL_NO_ERROR();
351
352 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTexture[1],
353 0);
354 EXPECT_GL_NO_ERROR();
355 glReadPixels(0, 0, width, height, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues[1]);
356 EXPECT_GL_NO_ERROR();
357
358 for (int i = 0; i < width * height; i++)
359 {
360 EXPECT_EQ(expectedValue, outputValues[0][i]);
361 EXPECT_EQ(expectedValue, outputValues[1][i]);
362 }
363}
364
Xinghua Cao0328b572017-06-26 15:51:36 +0800365// When declare a image array without a binding qualifier, all elements are bound to unit zero.
366TEST_P(ComputeShaderTest, ImageArrayWithoutBindingQualifier)
367{
368 ANGLE_SKIP_TEST_IF(IsD3D11());
369
370 // TODO(xinghua.cao@intel.com): On AMD desktop OpenGL, bind two image variables to unit 0,
371 // only one variable is valid.
Corentin Wallez2bde9192017-07-28 14:15:01 -0400372 ANGLE_SKIP_TEST_IF(IsAMD() && IsDesktopOpenGL());
Xinghua Cao0328b572017-06-26 15:51:36 +0800373
374 GLTexture mTexture;
375 GLFramebuffer mFramebuffer;
376 const std::string csSource =
377 "#version 310 es\n"
378 "layout(local_size_x=2, local_size_y=2, local_size_z=1) in;\n"
379 "layout(r32ui) writeonly uniform highp uimage2D uImage[2];"
380 "void main()\n"
381 "{\n"
382 " imageStore(uImage[0], ivec2(gl_LocalInvocationIndex, 0), uvec4(100, 0, 0, 0));"
383 " imageStore(uImage[1], ivec2(gl_LocalInvocationIndex, 1), uvec4(100, 0, 0, 0));"
384 "}\n";
385
386 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
387 glUseProgram(program.get());
388 constexpr int kTextureWidth = 4, kTextureHeight = 2;
389 GLuint inputValues[] = {200, 200, 200, 200, 200, 200, 200, 200};
390
391 glBindTexture(GL_TEXTURE_2D, mTexture);
392 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kTextureWidth, kTextureHeight);
393 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kTextureWidth, kTextureHeight, GL_RED_INTEGER,
394 GL_UNSIGNED_INT, inputValues);
395 EXPECT_GL_NO_ERROR();
396
397 glBindImageTexture(0, mTexture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
398 glDispatchCompute(1, 1, 1);
399 EXPECT_GL_NO_ERROR();
400
401 glUseProgram(0);
402 glBindFramebuffer(GL_READ_FRAMEBUFFER, mFramebuffer);
403
404 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTexture, 0);
405 GLuint outputValues[8];
406 glReadPixels(0, 0, kTextureWidth, kTextureHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
407 outputValues);
408 EXPECT_GL_NO_ERROR();
409
410 GLuint expectedValue = 100;
411 for (int i = 0; i < kTextureWidth * kTextureHeight; i++)
412 {
413 EXPECT_EQ(expectedValue, outputValues[i]);
414 }
415}
416
Xinghua Cao711b7a12017-10-09 13:38:12 +0800417// imageLoad functions
418TEST_P(ComputeShaderTest, ImageLoad)
419{
420 const std::string csSource =
Olli Etuaho7caa80e2017-11-14 15:03:14 +0200421 R"(#version 310 es
422 layout(local_size_x=8) in;
423 layout(rgba8) uniform highp readonly image2D mImage2DInput;
424 layout(rgba16i) uniform highp readonly iimageCube mImageCubeInput;
425 layout(rgba32ui) uniform highp readonly uimage3D mImage3DInput;
426 layout(r32i) uniform highp writeonly iimage2D imageOut;
427 void main()
428 {
429 vec4 result2d = imageLoad(mImage2DInput, ivec2(gl_LocalInvocationID.xy));
430 ivec4 resultCube = imageLoad(mImageCubeInput, ivec3(gl_LocalInvocationID.xyz));
431 uvec4 result3d = imageLoad(mImage3DInput, ivec3(gl_LocalInvocationID.xyz));
432 imageStore(imageOut, ivec2(gl_LocalInvocationIndex, 0), ivec4(result2d) + resultCube + ivec4(result3d));
433 })";
Xinghua Cao711b7a12017-10-09 13:38:12 +0800434
435 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
436 EXPECT_GL_NO_ERROR();
437}
438
439// imageStore functions
440TEST_P(ComputeShaderTest, ImageStore)
441{
442 const std::string csSource =
443 "#version 310 es\n"
444 "layout(local_size_x=8) in;\n"
445 "layout(rgba16f) uniform highp writeonly imageCube mImageCubeOutput;\n"
446 "layout(r32f) uniform highp writeonly image3D mImage3DOutput;\n"
447 "layout(rgba8ui) uniform highp writeonly uimage2DArray mImage2DArrayOutput;\n"
448 "void main()\n"
449 "{\n"
450 " imageStore(mImageCubeOutput, ivec3(gl_LocalInvocationID.xyz), vec4(0.0));\n"
451 " imageStore(mImage3DOutput, ivec3(gl_LocalInvocationID.xyz), vec4(0.0));\n"
452 " imageStore(mImage2DArrayOutput, ivec3(gl_LocalInvocationID.xyz), uvec4(0));\n"
453 "}\n";
454
455 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
456 EXPECT_GL_NO_ERROR();
457}
458
459// imageSize functions
460TEST_P(ComputeShaderTest, ImageSize)
461{
462 const std::string csSource =
Olli Etuaho7caa80e2017-11-14 15:03:14 +0200463 R"(#version 310 es
464 layout(local_size_x=8) in;
465 layout(rgba8) uniform highp readonly imageCube mImageCubeInput;
466 layout(r32i) uniform highp readonly iimage2D mImage2DInput;
467 layout(rgba16ui) uniform highp readonly uimage2DArray mImage2DArrayInput;
468 layout(r32i) uniform highp writeonly iimage2D imageOut;
469 void main()
470 {
471 ivec2 sizeCube = imageSize(mImageCubeInput);
472 ivec2 size2D = imageSize(mImage2DInput);
473 ivec3 size2DArray = imageSize(mImage2DArrayInput);
474 imageStore(imageOut, ivec2(gl_LocalInvocationIndex, 0), ivec4(sizeCube, size2D.x, size2DArray.x));
475 })";
Xinghua Cao711b7a12017-10-09 13:38:12 +0800476
477 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
478 EXPECT_GL_NO_ERROR();
479}
480
Martin Radev4c4c8e72016-08-04 12:25:34 +0300481// Check that it is not possible to create a compute shader when the context does not support ES
482// 3.10
483TEST_P(ComputeShaderTestES3, NotSupported)
484{
485 GLuint computeShaderHandle = glCreateShader(GL_COMPUTE_SHADER);
486 EXPECT_EQ(0u, computeShaderHandle);
487 EXPECT_GL_ERROR(GL_INVALID_ENUM);
488}
489
Xinghua Caob1239382016-12-13 15:07:05 +0800490ANGLE_INSTANTIATE_TEST(ComputeShaderTest, ES31_OPENGL(), ES31_OPENGLES(), ES31_D3D11());
Martin Radev4c4c8e72016-08-04 12:25:34 +0300491ANGLE_INSTANTIATE_TEST(ComputeShaderTestES3, ES3_OPENGL(), ES3_OPENGLES());
492
493} // namespace