blob: 4d779e3aea31d27e3a92efdeb0f0078ef128b519 [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 =
67 "#version 310 es\n"
68 "precision mediump sampler2D;\n"
69 "layout(local_size_x=1) in;\n"
70 "uniform int myUniformInt;\n"
71 "uniform sampler2D myUniformSampler;\n"
72 "void main()\n"
73 "{\n"
74 "int q = myUniformInt;\n"
75 "texture(myUniformSampler, vec2(0.0));\n"
76 "}\n";
77
78 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
79
Jamie Madill54164b02017-08-28 15:17:37 -040080 // It's not possible to validate uniforms are present since they are unreferenced.
81 // TODO(jmadill): Make uniforms referenced.
82 // GLint uniformLoc = glGetUniformLocation(program.get(), "myUniformInt");
83 // EXPECT_NE(-1, uniformLoc);
Martin Radev4c4c8e72016-08-04 12:25:34 +030084
Jamie Madill54164b02017-08-28 15:17:37 -040085 // 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
138 EXPECT_EQ(0, linkStatus);
139
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
Xinghua Caob1239382016-12-13 15:07:05 +0800195// Access all compute shader special variables.
196TEST_P(ComputeShaderTest, AccessAllSpecialVariables)
197{
198 const std::string csSource =
199 "#version 310 es\n"
200 "layout(local_size_x=4, local_size_y=3, local_size_z=2) in;\n"
201 "void main()\n"
202 "{\n"
203 " uvec3 temp1 = gl_NumWorkGroups;\n"
204 " uvec3 temp2 = gl_WorkGroupSize;\n"
205 " uvec3 temp3 = gl_WorkGroupID;\n"
206 " uvec3 temp4 = gl_LocalInvocationID;\n"
207 " uvec3 temp5 = gl_GlobalInvocationID;\n"
208 " uint temp6 = gl_LocalInvocationIndex;\n"
209 "}\n";
210
211 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
212}
213
214// Access part compute shader special variables.
215TEST_P(ComputeShaderTest, AccessPartSpecialVariables)
216{
217 const std::string csSource =
218 "#version 310 es\n"
219 "layout(local_size_x=4, local_size_y=3, local_size_z=2) in;\n"
220 "void main()\n"
221 "{\n"
222 " uvec3 temp1 = gl_WorkGroupSize;\n"
223 " uvec3 temp2 = gl_WorkGroupID;\n"
224 " uint temp3 = gl_LocalInvocationIndex;\n"
225 "}\n";
226
227 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
228}
229
Xinghua Cao73badc02017-03-29 19:14:53 +0800230// Use glDispatchCompute to define work group count.
231TEST_P(ComputeShaderTest, DispatchCompute)
Xinghua Cao2b396592017-03-29 15:36:04 +0800232{
233 const std::string csSource =
234 "#version 310 es\n"
235 "layout(local_size_x=4, local_size_y=3, local_size_z=2) in;\n"
236 "void main()\n"
237 "{\n"
Xinghua Cao73badc02017-03-29 19:14:53 +0800238 " uvec3 temp = gl_NumWorkGroups;\n"
Xinghua Cao2b396592017-03-29 15:36:04 +0800239 "}\n";
240
241 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
242
243 glUseProgram(program.get());
244 glDispatchCompute(8, 4, 2);
245 EXPECT_GL_NO_ERROR();
246}
247
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800248// Use image uniform to write texture in compute shader, and verify the content is expected.
249TEST_P(ComputeShaderTest, BindImageTexture)
250{
Xinghua Cao0328b572017-06-26 15:51:36 +0800251 ANGLE_SKIP_TEST_IF(IsD3D11());
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800252
253 GLTexture mTexture[2];
254 GLFramebuffer mFramebuffer;
255 const std::string csSource =
256 "#version 310 es\n"
257 "layout(local_size_x=2, local_size_y=2, local_size_z=1) in;\n"
258 "layout(r32ui, binding = 0) writeonly uniform highp uimage2D uImage[2];"
259 "void main()\n"
260 "{\n"
261 " imageStore(uImage[0], ivec2(gl_LocalInvocationIndex, gl_WorkGroupID.x), uvec4(100, 0, "
262 "0, 0));"
263 " imageStore(uImage[1], ivec2(gl_LocalInvocationIndex, gl_WorkGroupID.x), uvec4(100, 0, "
264 "0, 0));"
265 "}\n";
266
267 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
268 glUseProgram(program.get());
269 int width = 4, height = 2;
270 GLuint inputValues[] = {200, 200, 200, 200, 200, 200, 200, 200};
271
272 glBindTexture(GL_TEXTURE_2D, mTexture[0]);
273 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, width, height);
274 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RED_INTEGER, GL_UNSIGNED_INT,
275 inputValues);
276 EXPECT_GL_NO_ERROR();
277
278 glBindImageTexture(0, mTexture[0], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
279 EXPECT_GL_NO_ERROR();
280
281 glBindTexture(GL_TEXTURE_2D, mTexture[1]);
282 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, width, height);
283 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RED_INTEGER, GL_UNSIGNED_INT,
284 inputValues);
285 EXPECT_GL_NO_ERROR();
286
287 glBindImageTexture(1, mTexture[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
288 EXPECT_GL_NO_ERROR();
289
290 glDispatchCompute(2, 1, 1);
291 EXPECT_GL_NO_ERROR();
292
293 glUseProgram(0);
294 GLuint outputValues[2][8];
295 GLuint expectedValue = 100;
296 glBindFramebuffer(GL_READ_FRAMEBUFFER, mFramebuffer);
297
298 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTexture[0],
299 0);
300 EXPECT_GL_NO_ERROR();
301 glReadPixels(0, 0, width, height, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues[0]);
302 EXPECT_GL_NO_ERROR();
303
304 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTexture[1],
305 0);
306 EXPECT_GL_NO_ERROR();
307 glReadPixels(0, 0, width, height, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues[1]);
308 EXPECT_GL_NO_ERROR();
309
310 for (int i = 0; i < width * height; i++)
311 {
312 EXPECT_EQ(expectedValue, outputValues[0][i]);
313 EXPECT_EQ(expectedValue, outputValues[1][i]);
314 }
315}
316
Xinghua Cao0328b572017-06-26 15:51:36 +0800317// When declare a image array without a binding qualifier, all elements are bound to unit zero.
318TEST_P(ComputeShaderTest, ImageArrayWithoutBindingQualifier)
319{
320 ANGLE_SKIP_TEST_IF(IsD3D11());
321
322 // TODO(xinghua.cao@intel.com): On AMD desktop OpenGL, bind two image variables to unit 0,
323 // only one variable is valid.
Corentin Wallez2bde9192017-07-28 14:15:01 -0400324 ANGLE_SKIP_TEST_IF(IsAMD() && IsDesktopOpenGL());
Xinghua Cao0328b572017-06-26 15:51:36 +0800325
326 GLTexture mTexture;
327 GLFramebuffer mFramebuffer;
328 const std::string csSource =
329 "#version 310 es\n"
330 "layout(local_size_x=2, local_size_y=2, local_size_z=1) in;\n"
331 "layout(r32ui) writeonly uniform highp uimage2D uImage[2];"
332 "void main()\n"
333 "{\n"
334 " imageStore(uImage[0], ivec2(gl_LocalInvocationIndex, 0), uvec4(100, 0, 0, 0));"
335 " imageStore(uImage[1], ivec2(gl_LocalInvocationIndex, 1), uvec4(100, 0, 0, 0));"
336 "}\n";
337
338 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
339 glUseProgram(program.get());
340 constexpr int kTextureWidth = 4, kTextureHeight = 2;
341 GLuint inputValues[] = {200, 200, 200, 200, 200, 200, 200, 200};
342
343 glBindTexture(GL_TEXTURE_2D, mTexture);
344 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kTextureWidth, kTextureHeight);
345 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kTextureWidth, kTextureHeight, GL_RED_INTEGER,
346 GL_UNSIGNED_INT, inputValues);
347 EXPECT_GL_NO_ERROR();
348
349 glBindImageTexture(0, mTexture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
350 glDispatchCompute(1, 1, 1);
351 EXPECT_GL_NO_ERROR();
352
353 glUseProgram(0);
354 glBindFramebuffer(GL_READ_FRAMEBUFFER, mFramebuffer);
355
356 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTexture, 0);
357 GLuint outputValues[8];
358 glReadPixels(0, 0, kTextureWidth, kTextureHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
359 outputValues);
360 EXPECT_GL_NO_ERROR();
361
362 GLuint expectedValue = 100;
363 for (int i = 0; i < kTextureWidth * kTextureHeight; i++)
364 {
365 EXPECT_EQ(expectedValue, outputValues[i]);
366 }
367}
368
Xinghua Cao711b7a12017-10-09 13:38:12 +0800369// imageLoad functions
370TEST_P(ComputeShaderTest, ImageLoad)
371{
372 const std::string csSource =
373 "#version 310 es\n"
374 "layout(local_size_x=8) in;\n"
375 "layout(rgba8) uniform highp readonly image2D mImage2DInput;\n"
376 "layout(rgba16i) uniform highp readonly iimageCube mImageCubeInput;\n"
377 "layout(rgba32ui) uniform highp readonly uimage3D mImage3DInput;\n"
378 "void main()\n"
379 "{\n"
380 " vec4 result2d = imageLoad(mImage2DInput, ivec2(gl_LocalInvocationID.xy));\n"
381 " ivec4 resultCube = imageLoad(mImageCubeInput, ivec3(gl_LocalInvocationID.xyz));\n"
382 " uvec4 result3d = imageLoad(mImage3DInput, ivec3(gl_LocalInvocationID.xyz));\n"
383 "}\n";
384
385 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
386 EXPECT_GL_NO_ERROR();
387}
388
389// imageStore functions
390TEST_P(ComputeShaderTest, ImageStore)
391{
392 const std::string csSource =
393 "#version 310 es\n"
394 "layout(local_size_x=8) in;\n"
395 "layout(rgba16f) uniform highp writeonly imageCube mImageCubeOutput;\n"
396 "layout(r32f) uniform highp writeonly image3D mImage3DOutput;\n"
397 "layout(rgba8ui) uniform highp writeonly uimage2DArray mImage2DArrayOutput;\n"
398 "void main()\n"
399 "{\n"
400 " imageStore(mImageCubeOutput, ivec3(gl_LocalInvocationID.xyz), vec4(0.0));\n"
401 " imageStore(mImage3DOutput, ivec3(gl_LocalInvocationID.xyz), vec4(0.0));\n"
402 " imageStore(mImage2DArrayOutput, ivec3(gl_LocalInvocationID.xyz), uvec4(0));\n"
403 "}\n";
404
405 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
406 EXPECT_GL_NO_ERROR();
407}
408
409// imageSize functions
410TEST_P(ComputeShaderTest, ImageSize)
411{
412 const std::string csSource =
413 "#version 310 es\n"
414 "layout(local_size_x=8) in;\n"
415 "layout(rgba8) uniform highp readonly imageCube mImageCubeInput;\n"
416 "layout(r32i) uniform highp readonly iimage2D mImage2DInput;\n"
417 "layout(rgba16ui) uniform highp readonly uimage2DArray mImage2DArrayInput;\n"
418 "void main()\n"
419 "{\n"
420 " ivec2 sizeCube = imageSize(mImageCubeInput);\n"
421 " ivec2 size2D = imageSize(mImage2DInput);\n"
422 " ivec3 size2DArray = imageSize(mImage2DArrayInput);\n"
423 "}\n";
424
425 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
426 EXPECT_GL_NO_ERROR();
427}
428
Martin Radev4c4c8e72016-08-04 12:25:34 +0300429// Check that it is not possible to create a compute shader when the context does not support ES
430// 3.10
431TEST_P(ComputeShaderTestES3, NotSupported)
432{
433 GLuint computeShaderHandle = glCreateShader(GL_COMPUTE_SHADER);
434 EXPECT_EQ(0u, computeShaderHandle);
435 EXPECT_GL_ERROR(GL_INVALID_ENUM);
436}
437
Xinghua Caob1239382016-12-13 15:07:05 +0800438ANGLE_INSTANTIATE_TEST(ComputeShaderTest, ES31_OPENGL(), ES31_OPENGLES(), ES31_D3D11());
Martin Radev4c4c8e72016-08-04 12:25:34 +0300439ANGLE_INSTANTIATE_TEST(ComputeShaderTestES3, ES3_OPENGL(), ES3_OPENGLES());
440
441} // namespace