blob: f7326a211df1963770de05c8c78b758378d85284 [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
80 GLint uniformLoc = glGetUniformLocation(program.get(), "myUniformInt");
81 EXPECT_NE(-1, uniformLoc);
82
83 uniformLoc = glGetUniformLocation(program.get(), "myUniformSampler");
84 EXPECT_NE(-1, uniformLoc);
85
86 EXPECT_GL_NO_ERROR();
87}
88
89// Attach both compute and non-compute shaders. A link time error should occur.
90// OpenGL ES 3.10, 7.3 Program Objects
91TEST_P(ComputeShaderTest, AttachMultipleShaders)
92{
93 const std::string csSource =
94 "#version 310 es\n"
95 "layout(local_size_x=1) in;\n"
96 "void main()\n"
97 "{\n"
98 "}\n";
99
100 const std::string vsSource =
101 "#version 310 es\n"
102 "void main()\n"
103 "{\n"
104 "}\n";
105
106 const std::string fsSource =
107 "#version 310 es\n"
108 "void main()\n"
109 "{\n"
110 "}\n";
111
112 GLuint program = glCreateProgram();
113
114 GLuint vs = CompileShader(GL_VERTEX_SHADER, vsSource);
115 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fsSource);
116 GLuint cs = CompileShader(GL_COMPUTE_SHADER, csSource);
117
118 EXPECT_NE(0u, vs);
119 EXPECT_NE(0u, fs);
120 EXPECT_NE(0u, cs);
121
122 glAttachShader(program, vs);
123 glDeleteShader(vs);
124
125 glAttachShader(program, fs);
126 glDeleteShader(fs);
127
128 glAttachShader(program, cs);
129 glDeleteShader(cs);
130
131 glLinkProgram(program);
132
133 GLint linkStatus;
134 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
135
136 EXPECT_EQ(0, linkStatus);
137
138 EXPECT_GL_NO_ERROR();
139}
140
141// Attach a vertex, fragment and compute shader.
142// Query for the number of attached shaders and check the count.
143TEST_P(ComputeShaderTest, AttachmentCount)
144{
Martin Radev4c4c8e72016-08-04 12:25:34 +0300145 const std::string csSource =
146 "#version 310 es\n"
147 "layout(local_size_x=1) in;\n"
148 "void main()\n"
149 "{\n"
150 "}\n";
151
152 const std::string vsSource =
153 "#version 310 es\n"
154 "void main()\n"
155 "{\n"
156 "}\n";
157
158 const std::string fsSource =
159 "#version 310 es\n"
160 "void main()\n"
161 "{\n"
162 "}\n";
163
164 GLuint program = glCreateProgram();
165
166 GLuint vs = CompileShader(GL_VERTEX_SHADER, vsSource);
167 GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fsSource);
168 GLuint cs = CompileShader(GL_COMPUTE_SHADER, csSource);
169
170 EXPECT_NE(0u, vs);
171 EXPECT_NE(0u, fs);
172 EXPECT_NE(0u, cs);
173
174 glAttachShader(program, vs);
175 glDeleteShader(vs);
176
177 glAttachShader(program, fs);
178 glDeleteShader(fs);
179
180 glAttachShader(program, cs);
181 glDeleteShader(cs);
182
183 GLint numAttachedShaders;
184 glGetProgramiv(program, GL_ATTACHED_SHADERS, &numAttachedShaders);
185
186 EXPECT_EQ(3, numAttachedShaders);
187
188 glDeleteProgram(program);
189
190 EXPECT_GL_NO_ERROR();
191}
192
Xinghua Caob1239382016-12-13 15:07:05 +0800193// Access all compute shader special variables.
194TEST_P(ComputeShaderTest, AccessAllSpecialVariables)
195{
196 const std::string csSource =
197 "#version 310 es\n"
198 "layout(local_size_x=4, local_size_y=3, local_size_z=2) in;\n"
199 "void main()\n"
200 "{\n"
201 " uvec3 temp1 = gl_NumWorkGroups;\n"
202 " uvec3 temp2 = gl_WorkGroupSize;\n"
203 " uvec3 temp3 = gl_WorkGroupID;\n"
204 " uvec3 temp4 = gl_LocalInvocationID;\n"
205 " uvec3 temp5 = gl_GlobalInvocationID;\n"
206 " uint temp6 = gl_LocalInvocationIndex;\n"
207 "}\n";
208
209 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
210}
211
212// Access part compute shader special variables.
213TEST_P(ComputeShaderTest, AccessPartSpecialVariables)
214{
215 const std::string csSource =
216 "#version 310 es\n"
217 "layout(local_size_x=4, local_size_y=3, local_size_z=2) in;\n"
218 "void main()\n"
219 "{\n"
220 " uvec3 temp1 = gl_WorkGroupSize;\n"
221 " uvec3 temp2 = gl_WorkGroupID;\n"
222 " uint temp3 = gl_LocalInvocationIndex;\n"
223 "}\n";
224
225 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
226}
227
Xinghua Cao73badc02017-03-29 19:14:53 +0800228// Use glDispatchCompute to define work group count.
229TEST_P(ComputeShaderTest, DispatchCompute)
Xinghua Cao2b396592017-03-29 15:36:04 +0800230{
231 const std::string csSource =
232 "#version 310 es\n"
233 "layout(local_size_x=4, local_size_y=3, local_size_z=2) in;\n"
234 "void main()\n"
235 "{\n"
Xinghua Cao73badc02017-03-29 19:14:53 +0800236 " uvec3 temp = gl_NumWorkGroups;\n"
Xinghua Cao2b396592017-03-29 15:36:04 +0800237 "}\n";
238
239 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
240
241 glUseProgram(program.get());
242 glDispatchCompute(8, 4, 2);
243 EXPECT_GL_NO_ERROR();
244}
245
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800246// Use image uniform to write texture in compute shader, and verify the content is expected.
247TEST_P(ComputeShaderTest, BindImageTexture)
248{
Xinghua Cao0328b572017-06-26 15:51:36 +0800249 ANGLE_SKIP_TEST_IF(IsD3D11());
Xinghua Cao65ec0b22017-03-28 16:10:52 +0800250
251 GLTexture mTexture[2];
252 GLFramebuffer mFramebuffer;
253 const std::string csSource =
254 "#version 310 es\n"
255 "layout(local_size_x=2, local_size_y=2, local_size_z=1) in;\n"
256 "layout(r32ui, binding = 0) writeonly uniform highp uimage2D uImage[2];"
257 "void main()\n"
258 "{\n"
259 " imageStore(uImage[0], ivec2(gl_LocalInvocationIndex, gl_WorkGroupID.x), uvec4(100, 0, "
260 "0, 0));"
261 " imageStore(uImage[1], ivec2(gl_LocalInvocationIndex, gl_WorkGroupID.x), uvec4(100, 0, "
262 "0, 0));"
263 "}\n";
264
265 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
266 glUseProgram(program.get());
267 int width = 4, height = 2;
268 GLuint inputValues[] = {200, 200, 200, 200, 200, 200, 200, 200};
269
270 glBindTexture(GL_TEXTURE_2D, mTexture[0]);
271 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, width, height);
272 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RED_INTEGER, GL_UNSIGNED_INT,
273 inputValues);
274 EXPECT_GL_NO_ERROR();
275
276 glBindImageTexture(0, mTexture[0], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
277 EXPECT_GL_NO_ERROR();
278
279 glBindTexture(GL_TEXTURE_2D, mTexture[1]);
280 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, width, height);
281 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RED_INTEGER, GL_UNSIGNED_INT,
282 inputValues);
283 EXPECT_GL_NO_ERROR();
284
285 glBindImageTexture(1, mTexture[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
286 EXPECT_GL_NO_ERROR();
287
288 glDispatchCompute(2, 1, 1);
289 EXPECT_GL_NO_ERROR();
290
291 glUseProgram(0);
292 GLuint outputValues[2][8];
293 GLuint expectedValue = 100;
294 glBindFramebuffer(GL_READ_FRAMEBUFFER, mFramebuffer);
295
296 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTexture[0],
297 0);
298 EXPECT_GL_NO_ERROR();
299 glReadPixels(0, 0, width, height, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues[0]);
300 EXPECT_GL_NO_ERROR();
301
302 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTexture[1],
303 0);
304 EXPECT_GL_NO_ERROR();
305 glReadPixels(0, 0, width, height, GL_RED_INTEGER, GL_UNSIGNED_INT, outputValues[1]);
306 EXPECT_GL_NO_ERROR();
307
308 for (int i = 0; i < width * height; i++)
309 {
310 EXPECT_EQ(expectedValue, outputValues[0][i]);
311 EXPECT_EQ(expectedValue, outputValues[1][i]);
312 }
313}
314
Xinghua Cao0328b572017-06-26 15:51:36 +0800315// When declare a image array without a binding qualifier, all elements are bound to unit zero.
316TEST_P(ComputeShaderTest, ImageArrayWithoutBindingQualifier)
317{
318 ANGLE_SKIP_TEST_IF(IsD3D11());
319
320 // TODO(xinghua.cao@intel.com): On AMD desktop OpenGL, bind two image variables to unit 0,
321 // only one variable is valid.
Corentin Wallez2bde9192017-07-28 14:15:01 -0400322 ANGLE_SKIP_TEST_IF(IsAMD() && IsDesktopOpenGL());
Xinghua Cao0328b572017-06-26 15:51:36 +0800323
324 GLTexture mTexture;
325 GLFramebuffer mFramebuffer;
326 const std::string csSource =
327 "#version 310 es\n"
328 "layout(local_size_x=2, local_size_y=2, local_size_z=1) in;\n"
329 "layout(r32ui) writeonly uniform highp uimage2D uImage[2];"
330 "void main()\n"
331 "{\n"
332 " imageStore(uImage[0], ivec2(gl_LocalInvocationIndex, 0), uvec4(100, 0, 0, 0));"
333 " imageStore(uImage[1], ivec2(gl_LocalInvocationIndex, 1), uvec4(100, 0, 0, 0));"
334 "}\n";
335
336 ANGLE_GL_COMPUTE_PROGRAM(program, csSource);
337 glUseProgram(program.get());
338 constexpr int kTextureWidth = 4, kTextureHeight = 2;
339 GLuint inputValues[] = {200, 200, 200, 200, 200, 200, 200, 200};
340
341 glBindTexture(GL_TEXTURE_2D, mTexture);
342 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kTextureWidth, kTextureHeight);
343 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kTextureWidth, kTextureHeight, GL_RED_INTEGER,
344 GL_UNSIGNED_INT, inputValues);
345 EXPECT_GL_NO_ERROR();
346
347 glBindImageTexture(0, mTexture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
348 glDispatchCompute(1, 1, 1);
349 EXPECT_GL_NO_ERROR();
350
351 glUseProgram(0);
352 glBindFramebuffer(GL_READ_FRAMEBUFFER, mFramebuffer);
353
354 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTexture, 0);
355 GLuint outputValues[8];
356 glReadPixels(0, 0, kTextureWidth, kTextureHeight, GL_RED_INTEGER, GL_UNSIGNED_INT,
357 outputValues);
358 EXPECT_GL_NO_ERROR();
359
360 GLuint expectedValue = 100;
361 for (int i = 0; i < kTextureWidth * kTextureHeight; i++)
362 {
363 EXPECT_EQ(expectedValue, outputValues[i]);
364 }
365}
366
Martin Radev4c4c8e72016-08-04 12:25:34 +0300367// Check that it is not possible to create a compute shader when the context does not support ES
368// 3.10
369TEST_P(ComputeShaderTestES3, NotSupported)
370{
371 GLuint computeShaderHandle = glCreateShader(GL_COMPUTE_SHADER);
372 EXPECT_EQ(0u, computeShaderHandle);
373 EXPECT_GL_ERROR(GL_INVALID_ENUM);
374}
375
Xinghua Caob1239382016-12-13 15:07:05 +0800376ANGLE_INSTANTIATE_TEST(ComputeShaderTest, ES31_OPENGL(), ES31_OPENGLES(), ES31_D3D11());
Martin Radev4c4c8e72016-08-04 12:25:34 +0300377ANGLE_INSTANTIATE_TEST(ComputeShaderTestES3, ES3_OPENGL(), ES3_OPENGLES());
378
379} // namespace