1 /*-------------------------------------------------------------------------
2 * OpenGL Conformance Test Suite
3 * -----------------------------
4 *
5 * Copyright (c) 2014-2016 The Khronos Group Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 */ /*!
20 * \file
21 * \brief
22 */ /*-------------------------------------------------------------------*/
23
24 #include "es31cComputeShaderTests.hpp"
25 #include "gluContextInfo.hpp"
26 #include "glwEnums.hpp"
27 #include "glwFunctions.hpp"
28 #include "tcuMatrix.hpp"
29 #include "tcuMatrixUtil.hpp"
30 #include "tcuRenderTarget.hpp"
31 #include <cstdarg>
32 #include <sstream>
33
34 namespace glcts
35 {
36
37 using namespace glw;
38 using tcu::Vec2;
39 using tcu::Vec3;
40 using tcu::Vec4;
41 using tcu::UVec4;
42 using tcu::UVec3;
43 using tcu::Mat4;
44
45 namespace
46 {
47
48 typedef Vec3 vec2;
49 typedef Vec3 vec3;
50 typedef Vec4 vec4;
51 typedef UVec3 uvec3;
52 typedef UVec4 uvec4;
53 typedef Mat4 mat4;
54
55 const char* const kGLSLVer = "#version 310 es\n";
56
57 class ComputeShaderBase : public glcts::SubcaseBase
58 {
59
60 public:
~ComputeShaderBase()61 virtual ~ComputeShaderBase()
62 {
63 }
64
ComputeShaderBase()65 ComputeShaderBase()
66 : renderTarget(m_context.getRenderContext().getRenderTarget()), pixelFormat(renderTarget.getPixelFormat())
67 {
68 g_color_eps = vec4(1.f / (1 << 13));
69 if (pixelFormat.redBits != 0)
70 {
71 g_color_eps.x() += 1.f / (static_cast<float>(1 << pixelFormat.redBits) - 1.0f);
72 }
73 if (pixelFormat.greenBits != 0)
74 {
75 g_color_eps.y() += 1.f / (static_cast<float>(1 << pixelFormat.greenBits) - 1.0f);
76 }
77 if (pixelFormat.blueBits != 0)
78 {
79 g_color_eps.z() += 1.f / (static_cast<float>(1 << pixelFormat.blueBits) - 1.0f);
80 }
81 if (pixelFormat.alphaBits != 0)
82 {
83 g_color_eps.w() += 1.f / (static_cast<float>(1 << pixelFormat.alphaBits) - 1.0f);
84 }
85 }
86
87 const tcu::RenderTarget& renderTarget;
88 const tcu::PixelFormat& pixelFormat;
89 vec4 g_color_eps;
90
IndexTo3DCoord(GLuint idx,GLuint max_x,GLuint max_y)91 uvec3 IndexTo3DCoord(GLuint idx, GLuint max_x, GLuint max_y)
92 {
93 const GLuint x = idx % max_x;
94 idx /= max_x;
95 const GLuint y = idx % max_y;
96 idx /= max_y;
97 const GLuint z = idx;
98 return uvec3(x, y, z);
99 }
100
CheckProgram(GLuint program,bool * compile_error=NULL)101 bool CheckProgram(GLuint program, bool* compile_error = NULL)
102 {
103 GLint compile_status = GL_TRUE;
104 GLint status;
105 glGetProgramiv(program, GL_LINK_STATUS, &status);
106
107 if (status == GL_FALSE)
108 {
109 GLint attached_shaders = 0;
110 glGetProgramiv(program, GL_ATTACHED_SHADERS, &attached_shaders);
111
112 if (attached_shaders > 0)
113 {
114 std::vector<GLuint> shaders(attached_shaders);
115 glGetAttachedShaders(program, attached_shaders, NULL, &shaders[0]);
116
117 for (GLint i = 0; i < attached_shaders; ++i)
118 {
119 GLenum type;
120 glGetShaderiv(shaders[i], GL_SHADER_TYPE, reinterpret_cast<GLint*>(&type));
121 switch (type)
122 {
123 case GL_VERTEX_SHADER:
124 m_context.getTestContext().getLog()
125 << tcu::TestLog::Message << "*** Vertex Shader ***" << tcu::TestLog::EndMessage;
126 break;
127 case GL_FRAGMENT_SHADER:
128 m_context.getTestContext().getLog()
129 << tcu::TestLog::Message << "*** Fragment Shader ***" << tcu::TestLog::EndMessage;
130 break;
131 case GL_COMPUTE_SHADER:
132 m_context.getTestContext().getLog()
133 << tcu::TestLog::Message << "*** Compute Shader ***" << tcu::TestLog::EndMessage;
134 break;
135 default:
136 m_context.getTestContext().getLog()
137 << tcu::TestLog::Message << "*** Unknown Shader ***" << tcu::TestLog::EndMessage;
138 break;
139 }
140
141 GLint res;
142 glGetShaderiv(shaders[i], GL_COMPILE_STATUS, &res);
143 if (res != GL_TRUE)
144 compile_status = res;
145
146 GLint length = 0;
147 glGetShaderiv(shaders[i], GL_SHADER_SOURCE_LENGTH, &length);
148 if (length > 0)
149 {
150 std::vector<GLchar> source(length);
151 glGetShaderSource(shaders[i], length, NULL, &source[0]);
152 m_context.getTestContext().getLog()
153 << tcu::TestLog::Message << &source[0] << tcu::TestLog::EndMessage;
154 }
155
156 glGetShaderiv(shaders[i], GL_INFO_LOG_LENGTH, &length);
157 if (length > 0)
158 {
159 std::vector<GLchar> log(length);
160 glGetShaderInfoLog(shaders[i], length, NULL, &log[0]);
161 m_context.getTestContext().getLog()
162 << tcu::TestLog::Message << &log[0] << tcu::TestLog::EndMessage;
163 }
164 }
165 }
166
167 GLint length;
168 glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length);
169 if (length > 0)
170 {
171 std::vector<GLchar> log(length);
172 glGetProgramInfoLog(program, length, NULL, &log[0]);
173 m_context.getTestContext().getLog() << tcu::TestLog::Message << &log[0] << tcu::TestLog::EndMessage;
174 }
175 }
176
177 if (compile_error)
178 *compile_error = (compile_status == GL_TRUE ? false : true);
179 if (compile_status != GL_TRUE)
180 return false;
181 return status == GL_TRUE ? true : false;
182 }
183
CreateComputeProgram(const std::string & cs)184 GLuint CreateComputeProgram(const std::string& cs)
185 {
186 const GLuint p = glCreateProgram();
187
188 if (!cs.empty())
189 {
190 const GLuint sh = glCreateShader(GL_COMPUTE_SHADER);
191 glAttachShader(p, sh);
192 glDeleteShader(sh);
193 const char* const src[2] = { kGLSLVer, cs.c_str() };
194 glShaderSource(sh, 2, src, NULL);
195 glCompileShader(sh);
196 }
197
198 return p;
199 }
200
CreateProgram(const std::string & vs,const std::string & fs)201 GLuint CreateProgram(const std::string& vs, const std::string& fs)
202 {
203 const GLuint p = glCreateProgram();
204
205 if (!vs.empty())
206 {
207 const GLuint sh = glCreateShader(GL_VERTEX_SHADER);
208 glAttachShader(p, sh);
209 glDeleteShader(sh);
210 const char* const src[2] = { kGLSLVer, vs.c_str() };
211 glShaderSource(sh, 2, src, NULL);
212 glCompileShader(sh);
213 }
214 if (!fs.empty())
215 {
216 const GLuint sh = glCreateShader(GL_FRAGMENT_SHADER);
217 glAttachShader(p, sh);
218 glDeleteShader(sh);
219 const char* const src[2] = { kGLSLVer, fs.c_str() };
220 glShaderSource(sh, 2, src, NULL);
221 glCompileShader(sh);
222 }
223
224 return p;
225 }
226
BuildShaderProgram(GLenum type,const std::string & source)227 GLuint BuildShaderProgram(GLenum type, const std::string& source)
228 {
229 const char* const src[2] = { kGLSLVer, source.c_str() };
230 return glCreateShaderProgramv(type, 2, src);
231 }
232
distance(GLfloat p0,GLfloat p1)233 GLfloat distance(GLfloat p0, GLfloat p1)
234 {
235 return de::abs(p0 - p1);
236 }
237
ColorEqual(const vec4 & c0,const vec4 & c1,const vec4 & epsilon)238 inline bool ColorEqual(const vec4& c0, const vec4& c1, const vec4& epsilon)
239 {
240 if (distance(c0.x(), c1.x()) > epsilon.x())
241 return false;
242 if (distance(c0.y(), c1.y()) > epsilon.y())
243 return false;
244 if (distance(c0.z(), c1.z()) > epsilon.z())
245 return false;
246 if (distance(c0.w(), c1.w()) > epsilon.w())
247 return false;
248 return true;
249 }
250
ColorEqual(const vec3 & c0,const vec3 & c1,const vec4 & epsilon)251 inline bool ColorEqual(const vec3& c0, const vec3& c1, const vec4& epsilon)
252 {
253 if (distance(c0.x(), c1.x()) > epsilon.x())
254 return false;
255 if (distance(c0.y(), c1.y()) > epsilon.y())
256 return false;
257 if (distance(c0.z(), c1.z()) > epsilon.z())
258 return false;
259 return true;
260 }
261
ValidateReadBuffer(int x,int y,int w,int h,const vec4 & expected)262 bool ValidateReadBuffer(int x, int y, int w, int h, const vec4& expected)
263 {
264 std::vector<vec4> display(w * h);
265 std::vector<GLubyte> data(w * h * 4);
266 glReadPixels(x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]);
267
268 for (int i = 0; i < w * h * 4; i += 4)
269 {
270 display[i / 4] = vec4(static_cast<GLfloat>(data[i] / 255.), static_cast<GLfloat>(data[i + 1] / 255.),
271 static_cast<GLfloat>(data[i + 2] / 255.), static_cast<GLfloat>(data[i + 3] / 255.));
272 }
273
274 for (int j = 0; j < h; ++j)
275 {
276 for (int i = 0; i < w; ++i)
277 {
278 if (!ColorEqual(display[j * w + i], expected, g_color_eps))
279 {
280 m_context.getTestContext().getLog()
281 << tcu::TestLog::Message << "Color at (" << x + i << ", " << y + j << ") is ["
282 << display[j * w + i].x() << ", " << display[j * w + i].y() << ", " << display[j * w + i].z()
283 << ", " << display[j * w + i].w() << "] should be [" << expected.x() << ", " << expected.y()
284 << ", " << expected.z() << ", " << expected.w() << "]." << tcu::TestLog::EndMessage;
285 return false;
286 }
287 }
288 }
289
290 return true;
291 }
292
ValidateReadBufferCenteredQuad(int width,int height,const vec3 & expected)293 bool ValidateReadBufferCenteredQuad(int width, int height, const vec3& expected)
294 {
295 bool result = true;
296 std::vector<vec3> fb(width * height);
297 std::vector<GLubyte> data(width * height * 4);
298 glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]);
299
300 for (int i = 0; i < width * height * 4; i += 4)
301 {
302 fb[i / 4] = vec3(static_cast<GLfloat>(data[i] / 255.), static_cast<GLfloat>(data[i + 1] / 255.),
303 static_cast<GLfloat>(data[i + 2] / 255.));
304 }
305
306 int startx = int((static_cast<float>(width) * 0.1f) + 1);
307 int starty = int((static_cast<float>(height) * 0.1f) + 1);
308 int endx = int(static_cast<float>(width) - 2 * ((static_cast<float>(width) * 0.1f) + 1) - 1);
309 int endy = int(static_cast<float>(height) - 2 * ((static_cast<float>(height) * 0.1f) + 1) - 1);
310
311 for (int y = starty; y < endy; ++y)
312 {
313 for (int x = startx; x < endx; ++x)
314 {
315 const int idx = y * width + x;
316 if (!ColorEqual(fb[idx], expected, g_color_eps))
317 {
318 return false;
319 }
320 }
321 }
322
323 if (!ColorEqual(fb[2 * width + 2], vec3(0), g_color_eps))
324 {
325 result = false;
326 }
327 if (!ColorEqual(fb[2 * width + (width - 3)], vec3(0), g_color_eps))
328 {
329 result = false;
330 }
331 if (!ColorEqual(fb[(height - 3) * width + (width - 3)], vec3(0), g_color_eps))
332 {
333 result = false;
334 }
335 if (!ColorEqual(fb[(height - 3) * width + 2], vec3(0), g_color_eps))
336 {
337 result = false;
338 }
339
340 return result;
341 }
342
getWindowWidth()343 int getWindowWidth()
344 {
345 return renderTarget.getWidth();
346 }
347
getWindowHeight()348 int getWindowHeight()
349 {
350 return renderTarget.getHeight();
351 }
352
ValidateWindow4Quads(const vec3 & lb,const vec3 & rb,const vec3 & rt,const vec3 & lt)353 bool ValidateWindow4Quads(const vec3& lb, const vec3& rb, const vec3& rt, const vec3& lt)
354 {
355 int width = 100;
356 int height = 100;
357 std::vector<vec3> fb(width * height);
358 std::vector<GLubyte> data(width * height * 4);
359 glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]);
360
361 for (int i = 0; i < width * height * 4; i += 4)
362 {
363 fb[i / 4] = vec3(static_cast<GLfloat>(data[i] / 255.), static_cast<GLfloat>(data[i + 1] / 255.),
364 static_cast<GLfloat>(data[i + 2] / 255.));
365 }
366
367 bool status = true;
368
369 // left-bottom quad
370 for (int y = 10; y < height / 2 - 10; ++y)
371 {
372 for (int x = 10; x < width / 2 - 10; ++x)
373 {
374 const int idx = y * width + x;
375 if (!ColorEqual(fb[idx], lb, g_color_eps))
376 {
377 m_context.getTestContext().getLog()
378 << tcu::TestLog::Message << "First bad color (" << x << ", " << y << "): " << fb[idx].x() << " "
379 << fb[idx].y() << " " << fb[idx].z() << tcu::TestLog::EndMessage;
380 status = false;
381 }
382 }
383 }
384 // right-bottom quad
385 for (int y = 10; y < height / 2 - 10; ++y)
386 {
387 for (int x = width / 2 + 10; x < width - 10; ++x)
388 {
389 const int idx = y * width + x;
390 if (!ColorEqual(fb[idx], rb, g_color_eps))
391 {
392 m_context.getTestContext().getLog()
393 << tcu::TestLog::Message << "Bad color at (" << x << ", " << y << "): " << fb[idx].x() << " "
394 << fb[idx].y() << " " << fb[idx].z() << tcu::TestLog::EndMessage;
395 status = false;
396 }
397 }
398 }
399 // right-top quad
400 for (int y = height / 2 + 10; y < height - 10; ++y)
401 {
402 for (int x = width / 2 + 10; x < width - 10; ++x)
403 {
404 const int idx = y * width + x;
405 if (!ColorEqual(fb[idx], rt, g_color_eps))
406 {
407 m_context.getTestContext().getLog()
408 << tcu::TestLog::Message << "Bad color at (" << x << ", " << y << "): " << fb[idx].x() << " "
409 << fb[idx].y() << " " << fb[idx].z() << tcu::TestLog::EndMessage;
410 status = false;
411 }
412 }
413 }
414 // left-top quad
415 for (int y = height / 2 + 10; y < height - 10; ++y)
416 {
417 for (int x = 10; x < width / 2 - 10; ++x)
418 {
419 const int idx = y * width + x;
420 if (!ColorEqual(fb[idx], lt, g_color_eps))
421 {
422 m_context.getTestContext().getLog()
423 << tcu::TestLog::Message << "Bad color at (" << x << ", " << y << "): " << fb[idx].x() << " "
424 << fb[idx].y() << " " << fb[idx].z() << tcu::TestLog::EndMessage;
425 status = false;
426 }
427 }
428 }
429 // middle horizontal line should be black
430 for (int y = height / 2 - 2; y < height / 2 + 2; ++y)
431 {
432 for (int x = 0; x < width; ++x)
433 {
434 const int idx = y * width + x;
435 if (!ColorEqual(fb[idx], vec3(0), g_color_eps))
436 {
437 m_context.getTestContext().getLog()
438 << tcu::TestLog::Message << "Bad color at (" << x << ", " << y << "): " << fb[idx].x() << " "
439 << fb[idx].y() << " " << fb[idx].z() << tcu::TestLog::EndMessage;
440 status = false;
441 }
442 }
443 }
444 // middle vertical line should be black
445 for (int y = 0; y < height; ++y)
446 {
447 for (int x = width / 2 - 2; x < width / 2 + 2; ++x)
448 {
449 const int idx = y * width + x;
450 if (!ColorEqual(fb[idx], vec3(0), g_color_eps))
451 {
452 m_context.getTestContext().getLog()
453 << tcu::TestLog::Message << "Bad color at (" << x << ", " << y << "): " << fb[idx].x() << " "
454 << fb[idx].y() << " " << fb[idx].z() << tcu::TestLog::EndMessage;
455 status = false;
456 }
457 }
458 }
459
460 return status;
461 }
462
IsEqual(vec4 a,vec4 b)463 bool IsEqual(vec4 a, vec4 b)
464 {
465 return (a.x() == b.x()) && (a.y() == b.y()) && (a.z() == b.z()) && (a.w() == b.w());
466 }
467
IsEqual(uvec4 a,uvec4 b)468 bool IsEqual(uvec4 a, uvec4 b)
469 {
470 return (a.x() == b.x()) && (a.y() == b.y()) && (a.z() == b.z()) && (a.w() == b.w());
471 }
472 };
473
474 class SimpleCompute : public ComputeShaderBase
475 {
476
Title()477 virtual std::string Title()
478 {
479 return "Simplest possible Compute Shader";
480 }
481
Purpose()482 virtual std::string Purpose()
483 {
484 return "1. Verify that CS can be created, compiled and linked.\n"
485 "2. Verify that local work size can be queried with GetProgramiv command.\n"
486 "3. Verify that CS can be dispatched with DispatchCompute command.\n"
487 "4. Verify that CS can write to SSBO.";
488 }
489
Method()490 virtual std::string Method()
491 {
492 return "Create and dispatch CS. Verify SSBO content.";
493 }
494
PassCriteria()495 virtual std::string PassCriteria()
496 {
497 return "Everything works as expected.";
498 }
499
500 GLuint m_program;
501 GLuint m_buffer;
502
Setup()503 virtual long Setup()
504 {
505
506 const char* const glsl_cs =
507 NL "layout(local_size_x = 1, local_size_y = 1) in;" NL "layout(std430) buffer Output {" NL " vec4 data;" NL
508 "} g_out;" NL "void main() {" NL " g_out.data = vec4(1.0, 2.0, 3.0, 4.0);" NL "}";
509 m_program = CreateComputeProgram(glsl_cs);
510 glLinkProgram(m_program);
511 if (!CheckProgram(m_program))
512 return ERROR;
513
514 GLint v[3];
515 glGetProgramiv(m_program, GL_COMPUTE_WORK_GROUP_SIZE, v);
516 if (v[0] != 1 || v[1] != 1 || v[2] != 1)
517 {
518 m_context.getTestContext().getLog()
519 << tcu::TestLog::Message << "Got " << v[0] << ", " << v[1] << ", " << v[2]
520 << ", expected: 1, 1, 1 in GL_COMPUTE_WORK_GROUP_SIZE check" << tcu::TestLog::EndMessage;
521 return ERROR;
522 }
523
524 glGenBuffers(1, &m_buffer);
525 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer);
526 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(vec4), NULL, GL_DYNAMIC_DRAW);
527 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
528
529 return NO_ERROR;
530 }
531
Run()532 virtual long Run()
533 {
534 glUseProgram(m_program);
535 glDispatchCompute(1, 1, 1);
536
537 vec4* data;
538 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_buffer);
539 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
540 data = static_cast<vec4*>(glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(vec4), GL_MAP_READ_BIT));
541 long error = NO_ERROR;
542 if (!IsEqual(data[0], vec4(1.0f, 2.0f, 3.0f, 4.0f)))
543 {
544 error = ERROR;
545 }
546 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
547 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
548 return error;
549 }
550
Cleanup()551 virtual long Cleanup()
552 {
553 glUseProgram(0);
554 glDeleteProgram(m_program);
555 glDeleteBuffers(1, &m_buffer);
556 return NO_ERROR;
557 }
558 };
559
560 class BasicOneWorkGroup : public ComputeShaderBase
561 {
562
Title()563 virtual std::string Title()
564 {
565 return "One work group with various local sizes";
566 }
567
Purpose()568 virtual std::string Purpose()
569 {
570 return NL "1. Verify that declared local work size has correct effect." NL
571 "2. Verify that the number of shader invocations is correct." NL
572 "3. Verify that the built-in variables: gl_WorkGroupSize, gl_WorkGroupID, gl_GlobalInvocationID," NL
573 " gl_LocalInvocationID and gl_LocalInvocationIndex has correct values." NL
574 "4. Verify that DispatchCompute and DispatchComputeIndirect commands work as expected.";
575 }
576
Method()577 virtual std::string Method()
578 {
579 return NL "1. Create several CS with various local sizes." NL
580 "2. Dispatch each CS with DispatchCompute and DispatchComputeIndirect commands." NL
581 "3. Verify SSBO content.";
582 }
583
PassCriteria()584 virtual std::string PassCriteria()
585 {
586 return "Everything works as expected.";
587 }
588
589 GLuint m_program;
590 GLuint m_storage_buffer;
591 GLuint m_dispatch_buffer;
592
GenSource(int x,int y,int z,GLuint binding)593 std::string GenSource(int x, int y, int z, GLuint binding)
594 {
595 std::stringstream ss;
596 ss << NL "layout(local_size_x = " << x << ", local_size_y = " << y << ", local_size_z = " << z
597 << ") in;" NL "layout(std430, binding = " << binding
598 << ") buffer Output {" NL " uvec4 local_id[];" NL "} g_out;" NL "void main() {" NL
599 " if (gl_WorkGroupSize == uvec3("
600 << x << ", " << y << ", " << z
601 << ") && gl_WorkGroupID == uvec3(0) &&" NL " gl_GlobalInvocationID == gl_LocalInvocationID) {" NL
602 " g_out.local_id[gl_LocalInvocationIndex] = uvec4(gl_LocalInvocationID, 0);" NL " } else {" NL
603 " g_out.local_id[gl_LocalInvocationIndex] = uvec4(0xffff);" NL " }" NL "}";
604 return ss.str();
605 }
606
RunIteration(int local_size_x,int local_size_y,int local_size_z,GLuint binding,bool dispatch_indirect)607 bool RunIteration(int local_size_x, int local_size_y, int local_size_z, GLuint binding, bool dispatch_indirect)
608 {
609 if (m_program != 0)
610 glDeleteProgram(m_program);
611 m_program = CreateComputeProgram(GenSource(local_size_x, local_size_y, local_size_z, binding));
612 glLinkProgram(m_program);
613 if (!CheckProgram(m_program))
614 return false;
615
616 GLint v[3];
617 glGetProgramiv(m_program, GL_COMPUTE_WORK_GROUP_SIZE, v);
618 if (v[0] != local_size_x || v[1] != local_size_y || v[2] != local_size_z)
619 {
620 m_context.getTestContext().getLog()
621 << tcu::TestLog::Message << "GL_COMPUTE_LOCAL_WORK_SIZE is (" << v[0] << " " << v[1] << " " << v[2]
622 << ") should be (" << local_size_x << " " << local_size_y << " " << local_size_z << ")"
623 << tcu::TestLog::EndMessage;
624 return false;
625 }
626
627 const int kSize = local_size_x * local_size_y * local_size_z;
628
629 if (m_storage_buffer == 0)
630 glGenBuffers(1, &m_storage_buffer);
631 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, binding, m_storage_buffer);
632 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(uvec4) * kSize, NULL, GL_DYNAMIC_DRAW);
633 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
634
635 glUseProgram(m_program);
636 if (dispatch_indirect)
637 {
638 const GLuint num_groups[3] = { 1, 1, 1 };
639 if (m_dispatch_buffer == 0)
640 glGenBuffers(1, &m_dispatch_buffer);
641 glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer);
642 glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(num_groups), num_groups, GL_STATIC_DRAW);
643 glDispatchComputeIndirect(0);
644 }
645 else
646 {
647 glDispatchCompute(1, 1, 1);
648 }
649
650 uvec4* data;
651 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer);
652 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
653 data =
654 static_cast<uvec4*>(glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, kSize * sizeof(uvec4), GL_MAP_READ_BIT));
655
656 bool ret = true;
657 for (int z = 0; z < local_size_z; ++z)
658 {
659 for (int y = 0; y < local_size_y; ++y)
660 {
661 for (int x = 0; x < local_size_x; ++x)
662 {
663 const int index = z * local_size_x * local_size_y + y * local_size_x + x;
664 if (!IsEqual(data[index], uvec4(x, y, z, 0)))
665 {
666 m_context.getTestContext().getLog()
667 << tcu::TestLog::Message << "Invalid data at offset " << index << tcu::TestLog::EndMessage;
668 ret = false;
669 }
670 }
671 }
672 }
673 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
674 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
675 return ret;
676 }
677
Setup()678 virtual long Setup()
679 {
680 m_program = 0;
681 m_storage_buffer = 0;
682 m_dispatch_buffer = 0;
683 return NO_ERROR;
684 }
685
Run()686 virtual long Run()
687 {
688 if (!RunIteration(16, 1, 1, 0, true))
689 return ERROR;
690 if (!RunIteration(8, 8, 1, 1, false))
691 return ERROR;
692 if (!RunIteration(4, 4, 4, 2, true))
693 return ERROR;
694 if (!RunIteration(1, 2, 3, 3, false))
695 return ERROR;
696 if (!RunIteration(128, 1, 1, 3, true))
697 return ERROR;
698 if (!RunIteration(2, 8, 8, 3, false))
699 return ERROR;
700 if (!RunIteration(2, 2, 32, 7, true))
701 return ERROR;
702 return NO_ERROR;
703 }
704
Cleanup()705 virtual long Cleanup()
706 {
707 glUseProgram(0);
708 glDeleteProgram(m_program);
709 glDeleteBuffers(1, &m_storage_buffer);
710 glDeleteBuffers(1, &m_dispatch_buffer);
711 return NO_ERROR;
712 }
713 };
714
715 class BasicResourceUBO : public ComputeShaderBase
716 {
717
Title()718 virtual std::string Title()
719 {
720 return "Compute Shader resources - UBOs";
721 }
722
Purpose()723 virtual std::string Purpose()
724 {
725 return "Verify that CS is able to read data from UBOs and write it to SSBO.";
726 }
727
Method()728 virtual std::string Method()
729 {
730 return NL "1. Create CS which uses array of UBOs." NL
731 "2. Dispatch CS with DispatchCompute and DispatchComputeIndirect commands." NL
732 "3. Read data from each UBO and write it to SSBO." NL "4. Verify SSBO content." NL
733 "5. Repeat for different buffer and CS work sizes.";
734 }
735
PassCriteria()736 virtual std::string PassCriteria()
737 {
738 return "Everything works as expected.";
739 }
740
741 GLuint m_program;
742 GLuint m_storage_buffer;
743 GLuint m_uniform_buffer[12];
744 GLuint m_dispatch_buffer;
745
GenSource(const uvec3 & local_size,const uvec3 & num_groups)746 std::string GenSource(const uvec3& local_size, const uvec3& num_groups)
747 {
748 const uvec3 global_size = local_size * num_groups;
749 std::stringstream ss;
750 ss << NL "layout(local_size_x = " << local_size.x() << ", local_size_y = " << local_size.y()
751 << ", local_size_z = " << local_size.z() << ") in;" NL "const uvec3 kGlobalSize = uvec3(" << global_size.x()
752 << ", " << global_size.y() << ", " << global_size.z()
753 << ");" NL "layout(std140) uniform InputBuffer {" NL " vec4 data["
754 << global_size.x() * global_size.y() * global_size.z()
755 << "];" NL "} g_in_buffer[12];" NL "layout(std430) buffer OutputBuffer {" NL " vec4 data0["
756 << global_size.x() * global_size.y() * global_size.z() << "];" NL " vec4 data1["
757 << global_size.x() * global_size.y() * global_size.z() << "];" NL " vec4 data2["
758 << global_size.x() * global_size.y() * global_size.z() << "];" NL " vec4 data3["
759 << global_size.x() * global_size.y() * global_size.z() << "];" NL " vec4 data4["
760 << global_size.x() * global_size.y() * global_size.z() << "];" NL " vec4 data5["
761 << global_size.x() * global_size.y() * global_size.z() << "];" NL " vec4 data6["
762 << global_size.x() * global_size.y() * global_size.z() << "];" NL " vec4 data7["
763 << global_size.x() * global_size.y() * global_size.z() << "];" NL " vec4 data8["
764 << global_size.x() * global_size.y() * global_size.z() << "];" NL " vec4 data9["
765 << global_size.x() * global_size.y() * global_size.z() << "];" NL " vec4 data10["
766 << global_size.x() * global_size.y() * global_size.z() << "];" NL " vec4 data11["
767 << global_size.x() * global_size.y() * global_size.z()
768 << "];" NL "} g_out_buffer;" NL "void main() {" NL " uint global_index = gl_GlobalInvocationID.x +" NL
769 " gl_GlobalInvocationID.y * kGlobalSize.x +" NL
770 " gl_GlobalInvocationID.z * kGlobalSize.x * kGlobalSize.y;" NL
771 " g_out_buffer.data0[global_index] = g_in_buffer[0].data[global_index];" NL
772 " g_out_buffer.data1[global_index] = g_in_buffer[1].data[global_index];" NL
773 " g_out_buffer.data2[global_index] = g_in_buffer[2].data[global_index];" NL
774 " g_out_buffer.data3[global_index] = g_in_buffer[3].data[global_index];" NL
775 " g_out_buffer.data4[global_index] = g_in_buffer[4].data[global_index];" NL
776 " g_out_buffer.data5[global_index] = g_in_buffer[5].data[global_index];" NL
777 " g_out_buffer.data6[global_index] = g_in_buffer[6].data[global_index];" NL
778 " g_out_buffer.data7[global_index] = g_in_buffer[7].data[global_index];" NL
779 " g_out_buffer.data8[global_index] = g_in_buffer[8].data[global_index];" NL
780 " g_out_buffer.data9[global_index] = g_in_buffer[9].data[global_index];" NL
781 " g_out_buffer.data10[global_index] = g_in_buffer[10].data[global_index];" NL
782 " g_out_buffer.data11[global_index] = g_in_buffer[11].data[global_index];" NL "}";
783 return ss.str();
784 }
785
RunIteration(const uvec3 & local_size,const uvec3 & num_groups,bool dispatch_indirect)786 bool RunIteration(const uvec3& local_size, const uvec3& num_groups, bool dispatch_indirect)
787 {
788 if (m_program != 0)
789 glDeleteProgram(m_program);
790 m_program = CreateComputeProgram(GenSource(local_size, num_groups));
791 glLinkProgram(m_program);
792 if (!CheckProgram(m_program))
793 return false;
794
795 for (GLuint i = 0; i < 12; ++i)
796 {
797 char name[32];
798 sprintf(name, "InputBuffer[%u]", i);
799 const GLuint index = glGetUniformBlockIndex(m_program, name);
800 glUniformBlockBinding(m_program, index, i);
801 }
802
803 const GLuint kBufferSize =
804 local_size.x() * num_groups.x() * local_size.y() * num_groups.y() * local_size.z() * num_groups.z();
805
806 if (m_storage_buffer == 0)
807 glGenBuffers(1, &m_storage_buffer);
808 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
809 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(vec4) * kBufferSize * 12, NULL, GL_DYNAMIC_DRAW);
810 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
811
812 if (m_uniform_buffer[0] == 0)
813 glGenBuffers(12, m_uniform_buffer);
814 for (GLuint i = 0; i < 12; ++i)
815 {
816 std::vector<vec4> data(kBufferSize);
817 for (GLuint j = 0; j < kBufferSize; ++j)
818 {
819 data[j] = vec4(static_cast<float>(i) * static_cast<float>(kBufferSize) + static_cast<float>(j));
820 }
821 glBindBufferBase(GL_UNIFORM_BUFFER, i, m_uniform_buffer[i]);
822 glBufferData(GL_UNIFORM_BUFFER, sizeof(vec4) * kBufferSize, &data[0], GL_DYNAMIC_DRAW);
823 }
824 glBindBuffer(GL_UNIFORM_BUFFER, 0);
825
826 glUseProgram(m_program);
827 if (dispatch_indirect)
828 {
829 if (m_dispatch_buffer == 0)
830 glGenBuffers(1, &m_dispatch_buffer);
831 glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer);
832 glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(num_groups), &num_groups[0], GL_STATIC_DRAW);
833 glDispatchComputeIndirect(0);
834 }
835 else
836 {
837 glDispatchCompute(num_groups.x(), num_groups.y(), num_groups.z());
838 }
839
840 vec4* data;
841 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer);
842 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
843 data = static_cast<vec4*>(
844 glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(vec4) * 12 * kBufferSize, GL_MAP_READ_BIT));
845
846 bool ret = true;
847 for (GLuint z = 0; z < local_size.z() * num_groups.z(); ++z)
848 {
849 for (GLuint y = 0; y < local_size.y() * num_groups.y(); ++y)
850 {
851 for (GLuint x = 0; x < local_size.x() * num_groups.x(); ++x)
852 {
853 const GLuint index = z * local_size.x() * num_groups.x() * local_size.y() * num_groups.y() +
854 y * local_size.x() * num_groups.x() + x;
855 for (int i = 0; i < 1; ++i)
856 {
857 if (!IsEqual(data[index * 12 + i], vec4(static_cast<float>(index * 12 + i))))
858 {
859 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Invalid data at offset "
860 << index * 12 + i << tcu::TestLog::EndMessage;
861 ret = false;
862 }
863 }
864 }
865 }
866 }
867 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
868 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
869 return ret;
870 }
871
Setup()872 virtual long Setup()
873 {
874 m_program = 0;
875 m_storage_buffer = 0;
876 memset(m_uniform_buffer, 0, sizeof(m_uniform_buffer));
877 m_dispatch_buffer = 0;
878 return NO_ERROR;
879 }
880
Run()881 virtual long Run()
882 {
883 if (!RunIteration(uvec3(64, 1, 1), uvec3(8, 1, 1), false))
884 return ERROR;
885 if (!RunIteration(uvec3(2, 2, 2), uvec3(2, 2, 2), true))
886 return ERROR;
887 if (!RunIteration(uvec3(2, 4, 2), uvec3(2, 4, 1), false))
888 return ERROR;
889 return NO_ERROR;
890 }
891
Cleanup()892 virtual long Cleanup()
893 {
894 glUseProgram(0);
895 glDeleteProgram(m_program);
896 glDeleteBuffers(1, &m_storage_buffer);
897 glDeleteBuffers(12, m_uniform_buffer);
898 glDeleteBuffers(1, &m_dispatch_buffer);
899 return NO_ERROR;
900 }
901 };
902
903 class BasicResourceTexture : public ComputeShaderBase
904 {
905
Title()906 virtual std::string Title()
907 {
908 return NL "Compute Shader resources - Textures";
909 }
910
Purpose()911 virtual std::string Purpose()
912 {
913 return NL "Verify that texture access works correctly in CS.";
914 }
915
Method()916 virtual std::string Method()
917 {
918 return NL "1. Create CS which uses all sampler types (sampler2D, sampler3D," NL " sampler2DArray)." NL
919 "2. Dispatch CS with DispatchCompute and DispatchComputeIndirect commands." NL
920 "3. Sample each texture and write sampled value to SSBO." NL "4. Verify SSBO content." NL
921 "5. Repeat for different texture and CS work sizes.";
922 }
923
PassCriteria()924 virtual std::string PassCriteria()
925 {
926 return NL "Everything works as expected.";
927 }
928
929 GLuint m_program;
930 GLuint m_storage_buffer;
931 GLuint m_texture[3];
932 GLuint m_dispatch_buffer;
933
GenSource(const uvec3 & local_size,const uvec3 & num_groups)934 std::string GenSource(const uvec3& local_size, const uvec3& num_groups)
935 {
936 const uvec3 global_size = local_size * num_groups;
937 std::stringstream ss;
938 ss << NL "layout(local_size_x = " << local_size.x() << ", local_size_y = " << local_size.y()
939 << ", local_size_z = " << local_size.z() << ") in;" NL "const uvec3 kGlobalSize = uvec3(" << global_size.x()
940 << ", " << global_size.y() << ", " << global_size.z()
941 << ");" NL "uniform sampler2D g_sampler0;" NL "uniform lowp sampler3D g_sampler1;" NL
942 "uniform mediump sampler2DArray g_sampler2;" NL "layout(std430) buffer OutputBuffer {" NL " vec4 data0["
943 << global_size.x() * global_size.y() * global_size.z() << "];" NL " vec4 data1["
944 << global_size.x() * global_size.y() * global_size.z() << "];" NL " vec4 data2["
945 << global_size.x() * global_size.y() * global_size.z()
946 << "];" NL "} g_out_buffer;" NL "void main() {" NL " uint global_index = gl_GlobalInvocationID.x +" NL
947 " gl_GlobalInvocationID.y * kGlobalSize.x +" NL
948 " gl_GlobalInvocationID.z * kGlobalSize.x * kGlobalSize.y;" NL
949 " g_out_buffer.data0[global_index] = texture(g_sampler0, vec2(gl_GlobalInvocationID) / "
950 "vec2(kGlobalSize));" NL " g_out_buffer.data1[global_index] = textureProj(g_sampler1, "
951 "vec4(vec3(gl_GlobalInvocationID) / vec3(kGlobalSize), 1.0));" NL
952 " g_out_buffer.data2[global_index] = texelFetchOffset(g_sampler2, ivec3(gl_GlobalInvocationID), 0, "
953 "ivec2(0));" NL "}";
954 return ss.str();
955 }
956
RunIteration(const uvec3 & local_size,const uvec3 & num_groups,bool dispatch_indirect)957 bool RunIteration(const uvec3& local_size, const uvec3& num_groups, bool dispatch_indirect)
958 {
959 if (m_program != 0)
960 glDeleteProgram(m_program);
961 m_program = CreateComputeProgram(GenSource(local_size, num_groups));
962 glLinkProgram(m_program);
963 if (!CheckProgram(m_program))
964 return false;
965
966 glUseProgram(m_program);
967 for (int i = 0; i < 4; ++i)
968 {
969 char name[32];
970 sprintf(name, "g_sampler%d", i);
971 glUniform1i(glGetUniformLocation(m_program, name), i);
972 }
973 glUseProgram(0);
974
975 const GLuint kBufferSize =
976 local_size.x() * num_groups.x() * local_size.y() * num_groups.y() * local_size.z() * num_groups.z();
977 const GLint kWidth = static_cast<GLint>(local_size.x() * num_groups.x());
978 const GLint kHeight = static_cast<GLint>(local_size.y() * num_groups.y());
979 const GLint kDepth = static_cast<GLint>(local_size.z() * num_groups.z());
980
981 std::vector<vec4> buffer_data(kBufferSize * 4);
982 if (m_storage_buffer == 0)
983 glGenBuffers(1, &m_storage_buffer);
984 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
985 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(vec4) * kBufferSize * 4, &buffer_data[0], GL_DYNAMIC_DRAW);
986 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
987
988 std::vector<vec4> texture_data(kBufferSize, vec4(123.0f));
989 if (m_texture[0] == 0)
990 glGenTextures(3, m_texture);
991
992 glActiveTexture(GL_TEXTURE0);
993 glBindTexture(GL_TEXTURE_2D, m_texture[0]);
994 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
995 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
996 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, kWidth, kHeight, 0, GL_RGBA, GL_FLOAT, &texture_data[0]);
997
998 glActiveTexture(GL_TEXTURE1);
999 glBindTexture(GL_TEXTURE_3D, m_texture[1]);
1000 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1001 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1002 glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA32F, kWidth, kHeight, kDepth, 0, GL_RGBA, GL_FLOAT, &texture_data[0]);
1003
1004 glActiveTexture(GL_TEXTURE2);
1005 glBindTexture(GL_TEXTURE_2D_ARRAY, m_texture[2]);
1006 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1007 glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1008 glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA32F, kWidth, kHeight, kDepth, 0, GL_RGBA, GL_FLOAT,
1009 &texture_data[0]);
1010
1011 glUseProgram(m_program);
1012 if (dispatch_indirect)
1013 {
1014 if (m_dispatch_buffer == 0)
1015 glGenBuffers(1, &m_dispatch_buffer);
1016 glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer);
1017 glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(num_groups), &num_groups[0], GL_STATIC_DRAW);
1018 glDispatchComputeIndirect(0);
1019 }
1020 else
1021 {
1022 glDispatchCompute(num_groups.x(), num_groups.y(), num_groups.z());
1023 }
1024
1025 vec4* data;
1026 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer);
1027 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
1028
1029 data = static_cast<vec4*>(
1030 glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(vec4) * 3 * kBufferSize, GL_MAP_READ_BIT));
1031 bool ret = true;
1032 for (GLuint index = 0; index < kBufferSize * 3; ++index)
1033 {
1034 if (!IsEqual(data[index], vec4(123.0f)))
1035 {
1036 m_context.getTestContext().getLog()
1037 << tcu::TestLog::Message << "Invalid data at index " << index << tcu::TestLog::EndMessage;
1038 ret = false;
1039 }
1040 }
1041 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
1042 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
1043
1044 return ret;
1045 }
1046
Setup()1047 virtual long Setup()
1048 {
1049 m_program = 0;
1050 m_storage_buffer = 0;
1051 memset(m_texture, 0, sizeof(m_texture));
1052 m_dispatch_buffer = 0;
1053 return NO_ERROR;
1054 }
1055
Run()1056 virtual long Run()
1057 {
1058 if (!RunIteration(uvec3(4, 4, 4), uvec3(8, 1, 1), false))
1059 return ERROR;
1060 if (!RunIteration(uvec3(2, 4, 2), uvec3(2, 4, 1), true))
1061 return ERROR;
1062 if (!RunIteration(uvec3(2, 2, 2), uvec3(2, 2, 2), false))
1063 return ERROR;
1064 return NO_ERROR;
1065 }
1066
Cleanup()1067 virtual long Cleanup()
1068 {
1069 glActiveTexture(GL_TEXTURE0);
1070 glUseProgram(0);
1071 glDeleteProgram(m_program);
1072 glDeleteBuffers(1, &m_storage_buffer);
1073 glDeleteTextures(3, m_texture);
1074 glDeleteBuffers(1, &m_dispatch_buffer);
1075 return NO_ERROR;
1076 }
1077 };
1078
1079 class BasicResourceImage : public ComputeShaderBase
1080 {
1081
Title()1082 virtual std::string Title()
1083 {
1084 return NL "Compute Shader resources - Images";
1085 }
1086
Purpose()1087 virtual std::string Purpose()
1088 {
1089 return NL "Verify that reading/writing GPU memory via image variables work as expected.";
1090 }
1091
Method()1092 virtual std::string Method()
1093 {
1094 return NL "1. Create CS which uses two image2D variables to read and write underlying GPU memory." NL
1095 "2. Dispatch CS with DispatchCompute and DispatchComputeIndirect commands." NL
1096 "3. Verify memory content." NL "4. Repeat for different texture and CS work sizes.";
1097 }
1098
PassCriteria()1099 virtual std::string PassCriteria()
1100 {
1101 return NL "Everything works as expected.";
1102 }
1103
1104 GLuint m_program;
1105 GLuint m_draw_program;
1106 GLuint m_texture[2];
1107 GLuint m_dispatch_buffer;
1108 GLuint m_vertex_array;
1109
GenSource(const uvec3 & local_size,const uvec3 & num_groups)1110 std::string GenSource(const uvec3& local_size, const uvec3& num_groups)
1111 {
1112 const uvec3 global_size = local_size * num_groups;
1113 std::stringstream ss;
1114 if (m_context.getContextInfo().isExtensionSupported("GL_OES_shader_image_atomic"))
1115 {
1116 ss << NL "#extension GL_OES_shader_image_atomic : enable";
1117 }
1118 ss << NL "layout(local_size_x = " << local_size.x() << ", local_size_y = " << local_size.y()
1119 << ", local_size_z = " << local_size.z()
1120 << ") in;" NL "layout(r32ui, binding=0) coherent uniform mediump uimage2D g_image1;" NL
1121 "layout(r32ui, binding=1) uniform mediump uimage2D g_image2;" NL "const uvec3 kGlobalSize = uvec3("
1122 << global_size.x() << ", " << global_size.y() << ", " << global_size.z()
1123 << ");" NL "void main() {" NL
1124 " if (gl_GlobalInvocationID.x >= kGlobalSize.x || gl_GlobalInvocationID.y >= kGlobalSize.y) return;" NL
1125 " uvec4 color = uvec4(gl_GlobalInvocationID.x + gl_GlobalInvocationID.y);";
1126 if (!m_context.getContextInfo().isExtensionSupported("GL_OES_shader_image_atomic"))
1127 {
1128 m_context.getTestContext().getLog()
1129 << tcu::TestLog::Message << "Function imageAtomicAdd not supported, using imageStore"
1130 << tcu::TestLog::EndMessage;
1131 ss << NL " imageStore(g_image1, ivec2(gl_GlobalInvocationID), color);" NL
1132 " uvec4 c = imageLoad(g_image1, ivec2(gl_GlobalInvocationID));" NL
1133 " imageStore(g_image2, ivec2(gl_GlobalInvocationID), c);" NL "}";
1134 }
1135 else
1136 {
1137 m_context.getTestContext().getLog()
1138 << tcu::TestLog::Message << "Using imageAtomicAdd" << tcu::TestLog::EndMessage;
1139 ss << NL " imageStore(g_image1, ivec2(gl_GlobalInvocationID), uvec4(0));" NL
1140 " imageAtomicAdd(g_image1, ivec2(gl_GlobalInvocationID), color.x);" NL
1141 " uvec4 c = imageLoad(g_image1, ivec2(gl_GlobalInvocationID));" NL
1142 " imageStore(g_image2, ivec2(gl_GlobalInvocationID), c);" NL "}";
1143 }
1144
1145 return ss.str();
1146 }
1147
RunIteration(const uvec3 & local_size,const uvec3 & num_groups,bool dispatch_indirect)1148 bool RunIteration(const uvec3& local_size, const uvec3& num_groups, bool dispatch_indirect)
1149 {
1150 if (m_program != 0)
1151 glDeleteProgram(m_program);
1152 m_program = CreateComputeProgram(GenSource(local_size, num_groups));
1153 glLinkProgram(m_program);
1154 if (!CheckProgram(m_program))
1155 return false;
1156
1157 const GLint kWidth = static_cast<GLint>(local_size.x() * num_groups.x());
1158 const GLint kHeight = static_cast<GLint>(local_size.y() * num_groups.y());
1159 const GLint kDepth = static_cast<GLint>(local_size.z() * num_groups.z());
1160 const GLuint kSize = kWidth * kHeight * kDepth;
1161
1162 std::vector<uvec4> data(kSize);
1163 glGenTextures(2, m_texture);
1164
1165 for (int i = 0; i < 2; ++i)
1166 {
1167 glBindTexture(GL_TEXTURE_2D, m_texture[i]);
1168 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1169 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1170 glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32UI, kWidth, kHeight);
1171 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight, GL_RED_INTEGER, GL_UNSIGNED_INT, &data[0]);
1172 }
1173 glBindTexture(GL_TEXTURE_2D, 0);
1174
1175 glBindImageTexture(0, m_texture[0], 0, GL_FALSE, 0, GL_READ_WRITE, GL_R32UI);
1176 glBindImageTexture(1, m_texture[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_R32UI);
1177 glUseProgram(m_program);
1178 if (dispatch_indirect)
1179 {
1180 if (m_dispatch_buffer == 0)
1181 glGenBuffers(1, &m_dispatch_buffer);
1182 glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer);
1183 glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(num_groups), &num_groups[0], GL_STATIC_DRAW);
1184 glDispatchComputeIndirect(0);
1185 }
1186 else
1187 {
1188 glDispatchCompute(num_groups.x(), num_groups.y(), num_groups.z());
1189 }
1190 glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
1191
1192 glClear(GL_COLOR_BUFFER_BIT);
1193 glActiveTexture(GL_TEXTURE0);
1194 glBindTexture(GL_TEXTURE_2D, m_texture[0]);
1195 glActiveTexture(GL_TEXTURE1);
1196 glBindTexture(GL_TEXTURE_2D, m_texture[1]);
1197 glUseProgram(m_draw_program);
1198 glBindVertexArray(m_vertex_array);
1199 glViewport(0, 0, kWidth, kHeight);
1200 glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, 1);
1201
1202 std::vector<vec4> display(kWidth * kHeight);
1203 std::vector<GLubyte> colorData(kWidth * kHeight * 4);
1204 glReadPixels(0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE, &colorData[0]);
1205 glDeleteTextures(2, m_texture);
1206
1207 for (int i = 0; i < kWidth * kHeight * 4; i += 4)
1208 {
1209 display[i / 4] =
1210 vec4(static_cast<GLfloat>(colorData[i] / 255.), static_cast<GLfloat>(colorData[i + 1] / 255.),
1211 static_cast<GLfloat>(colorData[i + 2] / 255.), static_cast<GLfloat>(colorData[i + 3] / 255.));
1212 }
1213
1214 /* As the colors are converted R8->Rx and then read back as Rx->R8,
1215 need to add both conversions to the epsilon. */
1216 vec4 kColorEps = g_color_eps;
1217 kColorEps.x() += 1.f / ((1 << 8) - 1.0f);
1218 for (int y = 0; y < kHeight; ++y)
1219 {
1220 for (int x = 0; x < kWidth; ++x)
1221 {
1222 if (y >= getWindowHeight() || x >= getWindowWidth())
1223 {
1224 continue;
1225 }
1226 const vec4 c = vec4(float(y + x) / 255.0f, 1.0f, 1.0f, 1.0f);
1227 if (!ColorEqual(display[y * kWidth + x], c, kColorEps))
1228 {
1229 m_context.getTestContext().getLog()
1230 << tcu::TestLog::Message << "Got red: " << display[y * kWidth + x].x() << ", expected " << c.x()
1231 << ", at (" << x << ", " << y << ")" << tcu::TestLog::EndMessage;
1232 return false;
1233 }
1234 }
1235 }
1236
1237 return true;
1238 }
1239
Setup()1240 virtual long Setup()
1241 {
1242 m_program = 0;
1243 memset(m_texture, 0, sizeof(m_texture));
1244 m_dispatch_buffer = 0;
1245 return NO_ERROR;
1246 }
1247
Run()1248 virtual long Run()
1249 {
1250
1251 const char* const glsl_vs =
1252 NL "const vec2 g_quad[] = vec2[](vec2(-1, -1), vec2(1, -1), vec2(-1, 1), vec2(1, 1));" NL "void main() {" NL
1253 " gl_Position = vec4(g_quad[gl_VertexID], 0, 1);" NL "}";
1254
1255 const char* glsl_fs =
1256 NL "layout(location = 0) out mediump vec4 o_color;" NL "uniform mediump usampler2D g_image1;" NL
1257 "uniform mediump usampler2D g_image2;" NL "void main() {" NL
1258 " mediump uvec4 c1 = texelFetch(g_image1, ivec2(gl_FragCoord.xy), 0);" NL
1259 " mediump uvec4 c2 = texelFetch(g_image2, ivec2(gl_FragCoord.xy), 0);" NL
1260 " if (c1 == c2) o_color = vec4(float(c1.x)/255.0, 1.0, 1.0, 1.0);" NL
1261 " else o_color = vec4(1, 0, 0, 1);" NL "}";
1262
1263 m_draw_program = CreateProgram(glsl_vs, glsl_fs);
1264 glLinkProgram(m_draw_program);
1265 if (!CheckProgram(m_draw_program))
1266 return ERROR;
1267
1268 glUseProgram(m_draw_program);
1269 glUniform1i(glGetUniformLocation(m_draw_program, "g_image1"), 0);
1270 glUniform1i(glGetUniformLocation(m_draw_program, "g_image2"), 1);
1271 glUseProgram(0);
1272
1273 glGenVertexArrays(1, &m_vertex_array);
1274
1275 if (!RunIteration(uvec3(8, 16, 1), uvec3(8, 4, 1), true))
1276 return ERROR;
1277 if (!RunIteration(uvec3(4, 32, 1), uvec3(16, 2, 1), false))
1278 return ERROR;
1279 if (!RunIteration(uvec3(16, 4, 1), uvec3(4, 16, 1), false))
1280 return ERROR;
1281 if (!RunIteration(uvec3(8, 8, 1), uvec3(8, 8, 1), true))
1282 return ERROR;
1283
1284 return NO_ERROR;
1285 }
1286
Cleanup()1287 virtual long Cleanup()
1288 {
1289 glUseProgram(0);
1290 glDeleteProgram(m_program);
1291 glDeleteProgram(m_draw_program);
1292 glDeleteVertexArrays(1, &m_vertex_array);
1293 glDeleteTextures(2, m_texture);
1294 glDeleteBuffers(1, &m_dispatch_buffer);
1295 glViewport(0, 0, getWindowWidth(), getWindowHeight());
1296 return NO_ERROR;
1297 }
1298 };
1299
1300 class BasicResourceAtomicCounter : public ComputeShaderBase
1301 {
1302
Title()1303 virtual std::string Title()
1304 {
1305 return "Compute Shader resources - Atomic Counters";
1306 }
1307
Purpose()1308 virtual std::string Purpose()
1309 {
1310 return NL
1311 "1. Verify that Atomic Counters work as expected in CS." NL
1312 "2. Verify that built-in functions: atomicCounterIncrement and atomicCounterDecrement work correctly.";
1313 }
1314
Method()1315 virtual std::string Method()
1316 {
1317 return NL
1318 "1. Create CS which uses two atomic_uint variables." NL
1319 "2. In CS write values returned by atomicCounterIncrement and atomicCounterDecrement functions to SSBO." NL
1320 "3. Dispatch CS with DispatchCompute and DispatchComputeIndirect commands." NL "4. Verify SSBO content." NL
1321 "5. Repeat for different buffer and CS work sizes.";
1322 }
1323
PassCriteria()1324 virtual std::string PassCriteria()
1325 {
1326 return "Everything works as expected.";
1327 }
1328
1329 GLuint m_program;
1330 GLuint m_storage_buffer;
1331 GLuint m_counter_buffer;
1332 GLuint m_dispatch_buffer;
1333
GenSource(const uvec3 & local_size,const uvec3 & num_groups)1334 std::string GenSource(const uvec3& local_size, const uvec3& num_groups)
1335 {
1336 const uvec3 global_size = local_size * num_groups;
1337 std::stringstream ss;
1338 ss << NL "layout(local_size_x = " << local_size.x() << ", local_size_y = " << local_size.y()
1339 << ", local_size_z = " << local_size.z()
1340 << ") in;" NL "layout(std430, binding = 0) buffer Output {" NL " uint inc_data["
1341 << global_size.x() * global_size.y() * global_size.z() << "];" NL " uint dec_data["
1342 << global_size.x() * global_size.y() * global_size.z()
1343 << "];" NL "};" NL "layout(binding = 0, offset = 0) uniform atomic_uint g_inc_counter;" NL
1344 "layout(binding = 0, offset = 4) uniform atomic_uint g_dec_counter;" NL "void main() {" NL
1345 " uint index = atomicCounterIncrement(g_inc_counter);" NL " inc_data[index] = index;" NL
1346 " dec_data[index] = atomicCounterDecrement(g_dec_counter);" NL "}";
1347 return ss.str();
1348 }
1349
RunIteration(const uvec3 & local_size,const uvec3 & num_groups,bool dispatch_indirect)1350 bool RunIteration(const uvec3& local_size, const uvec3& num_groups, bool dispatch_indirect)
1351 {
1352 if (m_program != 0)
1353 glDeleteProgram(m_program);
1354 m_program = CreateComputeProgram(GenSource(local_size, num_groups));
1355 glLinkProgram(m_program);
1356 if (!CheckProgram(m_program))
1357 return false;
1358
1359 const GLint kWidth = static_cast<GLint>(local_size.x() * num_groups.x());
1360 const GLint kHeight = static_cast<GLint>(local_size.y() * num_groups.y());
1361 const GLint kDepth = static_cast<GLint>(local_size.z() * num_groups.z());
1362 const GLuint kSize = kWidth * kHeight * kDepth;
1363
1364 if (m_storage_buffer == 0)
1365 glGenBuffers(1, &m_storage_buffer);
1366 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
1367 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLuint) * kSize * 2, NULL, GL_DYNAMIC_DRAW);
1368 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
1369
1370 if (m_counter_buffer == 0)
1371 glGenBuffers(1, &m_counter_buffer);
1372
1373 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, m_counter_buffer);
1374 glBufferData(GL_ATOMIC_COUNTER_BUFFER, 2 * sizeof(GLuint), NULL, GL_STREAM_DRAW);
1375 *static_cast<GLuint*>(glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint), GL_MAP_WRITE_BIT)) = 0;
1376 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
1377 *static_cast<GLuint*>(
1378 glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, sizeof(GLuint), sizeof(GLuint), GL_MAP_WRITE_BIT)) = kSize;
1379 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
1380
1381 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
1382
1383 glUseProgram(m_program);
1384 if (dispatch_indirect)
1385 {
1386 if (m_dispatch_buffer == 0)
1387 glGenBuffers(1, &m_dispatch_buffer);
1388 glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer);
1389 glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(num_groups), &num_groups[0], GL_STATIC_DRAW);
1390 glDispatchComputeIndirect(0);
1391 }
1392 else
1393 {
1394 glDispatchCompute(num_groups.x(), num_groups.y(), num_groups.z());
1395 }
1396
1397 GLuint* data;
1398 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer);
1399 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
1400 data = static_cast<GLuint*>(
1401 glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(GLuint) * kSize, GL_MAP_READ_BIT));
1402
1403 bool ret = true;
1404 for (GLuint i = 0; i < kSize; ++i)
1405 {
1406 if (data[i] != i)
1407 {
1408 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Value at index " << i << " is "
1409 << data[i] << " should be " << i << tcu::TestLog::EndMessage;
1410 ret = false;
1411 }
1412 }
1413 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
1414 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
1415
1416 GLuint* value;
1417 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_counter_buffer);
1418 value =
1419 static_cast<GLuint*>(glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 2 * sizeof(GLuint), GL_MAP_READ_BIT));
1420 if (value[0] != kSize)
1421 {
1422 m_context.getTestContext().getLog()
1423 << tcu::TestLog::Message << "Final atomic counter value (buffer 0, offset 0) is " << value[0]
1424 << " should be " << kSize << tcu::TestLog::EndMessage;
1425 ret = false;
1426 }
1427 if (value[1] != 0)
1428 {
1429 m_context.getTestContext().getLog()
1430 << tcu::TestLog::Message << "Final atomic counter value (buffer 0, offset 4) is " << value[1]
1431 << " should be 0" << tcu::TestLog::EndMessage;
1432 ret = false;
1433 }
1434 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
1435 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
1436
1437 return ret;
1438 }
1439
Setup()1440 virtual long Setup()
1441 {
1442 m_program = 0;
1443 m_storage_buffer = 0;
1444 m_counter_buffer = 0;
1445 m_dispatch_buffer = 0;
1446 return NO_ERROR;
1447 }
1448
Run()1449 virtual long Run()
1450 {
1451 if (!RunIteration(uvec3(4, 3, 2), uvec3(2, 3, 4), false))
1452 return ERROR;
1453 if (!RunIteration(uvec3(1, 1, 1), uvec3(1, 1, 1), true))
1454 return ERROR;
1455 if (!RunIteration(uvec3(1, 6, 1), uvec3(1, 1, 8), false))
1456 return ERROR;
1457 if (!RunIteration(uvec3(4, 1, 2), uvec3(10, 3, 4), true))
1458 return ERROR;
1459 return NO_ERROR;
1460 }
1461
Cleanup()1462 virtual long Cleanup()
1463 {
1464 glUseProgram(0);
1465 glDeleteProgram(m_program);
1466 glDeleteBuffers(1, &m_counter_buffer);
1467 glDeleteBuffers(1, &m_dispatch_buffer);
1468 glDeleteBuffers(1, &m_storage_buffer);
1469 return NO_ERROR;
1470 }
1471 };
1472
1473 class BasicResourceUniform : public ComputeShaderBase
1474 {
1475
Title()1476 virtual std::string Title()
1477 {
1478 return "Compute Shader resources - Uniforms";
1479 }
1480
Purpose()1481 virtual std::string Purpose()
1482 {
1483 return NL "1. Verify that all types of uniform variables work as expected in CS." NL
1484 "2. Verify that uniform variables can be updated with Uniform* commands.";
1485 }
1486
Method()1487 virtual std::string Method()
1488 {
1489 return NL "1. Create CS which uses all (single precision and integer) types of uniform variables." NL
1490 "2. Update uniform variables with Uniform* commands." NL
1491 "3. Verify that uniform variables were updated correctly.";
1492 }
1493
PassCriteria()1494 virtual std::string PassCriteria()
1495 {
1496 return "Everything works as expected.";
1497 }
1498
1499 GLuint m_program;
1500 GLuint m_storage_buffer;
1501
Setup()1502 virtual long Setup()
1503 {
1504 m_program = 0;
1505 m_storage_buffer = 0;
1506 return NO_ERROR;
1507 }
1508
Run()1509 virtual long Run()
1510 {
1511 const char* const glsl_cs = NL
1512 "layout(local_size_x = 1) in;" NL "buffer Result {" NL " int g_result;" NL "};" NL "uniform float g_0;" NL
1513 "uniform vec2 g_1;" NL "uniform vec3 g_2;" NL "uniform vec4 g_3;" NL "uniform mat2 g_4;" NL
1514 "uniform mat2x3 g_5;" NL "uniform mat2x4 g_6;" NL "uniform mat3x2 g_7;" NL "uniform mat3 g_8;" NL
1515 "uniform mat3x4 g_9;" NL "uniform mat4x2 g_10;" NL "uniform mat4x3 g_11;" NL "uniform mat4 g_12;" NL
1516 "uniform int g_13;" NL "uniform ivec2 g_14;" NL "uniform ivec3 g_15;" NL "uniform ivec4 g_16;" NL
1517 "uniform uint g_17;" NL "uniform uvec2 g_18;" NL "uniform uvec3 g_19;" NL "uniform uvec4 g_20;" NL NL
1518 "void main() {" NL " g_result = 1;" NL NL " if (g_0 != 1.0) g_result = 0;" NL
1519 " if (g_1 != vec2(2.0, 3.0)) g_result = 0;" NL " if (g_2 != vec3(4.0, 5.0, 6.0)) g_result = 0;" NL
1520 " if (g_3 != vec4(7.0, 8.0, 9.0, 10.0)) g_result = 0;" NL NL
1521 " if (g_4 != mat2(11.0, 12.0, 13.0, 14.0)) g_result = 0;" NL
1522 " if (g_5 != mat2x3(15.0, 16.0, 17.0, 18.0, 19.0, 20.0)) g_result = 0;" NL
1523 " if (g_6 != mat2x4(21.0, 22.0, 23.0, 24.0, 25.0, 26.0, 27.0, 28.0)) g_result = 0;" NL NL
1524 " if (g_7 != mat3x2(29.0, 30.0, 31.0, 32.0, 33.0, 34.0)) g_result = 0;" NL
1525 " if (g_8 != mat3(35.0, 36.0, 37.0, 38.0, 39.0, 40.0, 41.0, 42.0, 43.0)) g_result = 0;" NL
1526 " if (g_9 != mat3x4(44.0, 45.0, 46.0, 47.0, 48.0, 49.0, 50.0, 51.0, 52.0, 53.0, 54.0, 55.0)) g_result = "
1527 "0;" NL NL " if (g_10 != mat4x2(56.0, 57.0, 58.0, 59.0, 60.0, 61.0, 62.0, 63.0)) g_result = 0;" NL
1528 " if (g_11 != mat4x3(63.0, 64.0, 65.0, 66.0, 67.0, 68.0, 69.0, 70.0, 71.0, 27.0, 73, 74.0)) g_result = "
1529 "0;" NL " if (g_12 != mat4(75.0, 76.0, 77.0, 78.0, 79.0, 80.0, 81.0, 82.0, 83.0, 84.0, 85.0, 86.0, 87.0, "
1530 "88.0, 89.0, 90.0)) g_result = 0;" NL NL " if (g_13 != 91) g_result = 0;" NL
1531 " if (g_14 != ivec2(92, 93)) g_result = 0;" NL " if (g_15 != ivec3(94, 95, 96)) g_result = 0;" NL
1532 " if (g_16 != ivec4(97, 98, 99, 100)) g_result = 0;" NL NL " if (g_17 != 101u) g_result = 0;" NL
1533 " if (g_18 != uvec2(102u, 103u)) g_result = 0;" NL
1534 " if (g_19 != uvec3(104u, 105u, 106u)) g_result = 0;" NL
1535 " if (g_20 != uvec4(107u, 108u, 109u, 110u)) g_result = 0;" NL "}";
1536
1537 m_program = CreateComputeProgram(glsl_cs);
1538 glLinkProgram(m_program);
1539 glUseProgram(m_program);
1540 if (!CheckProgram(m_program))
1541 return ERROR;
1542
1543 glGenBuffers(1, &m_storage_buffer);
1544 /* create buffer */
1545 {
1546 const int data = 123;
1547 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
1548 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(data), &data, GL_STATIC_DRAW);
1549 }
1550
1551 glUniform1f(glGetUniformLocation(m_program, "g_0"), 1.0f);
1552 glUniform2f(glGetUniformLocation(m_program, "g_1"), 2.0f, 3.0f);
1553 glUniform3f(glGetUniformLocation(m_program, "g_2"), 4.0f, 5.0f, 6.0f);
1554 glUniform4f(glGetUniformLocation(m_program, "g_3"), 7.0f, 8.0f, 9.0f, 10.0f);
1555
1556 /* mat2 */
1557 {
1558 const GLfloat value[4] = { 11.0f, 12.0f, 13.0f, 14.0f };
1559 glUniformMatrix2fv(glGetUniformLocation(m_program, "g_4"), 1, GL_FALSE, value);
1560 }
1561 /* mat2x3 */
1562 {
1563 const GLfloat value[6] = { 15.0f, 16.0f, 17.0f, 18.0f, 19.0f, 20.0f };
1564 glUniformMatrix2x3fv(glGetUniformLocation(m_program, "g_5"), 1, GL_FALSE, value);
1565 }
1566 /* mat2x4 */
1567 {
1568 const GLfloat value[8] = { 21.0f, 22.0f, 23.0f, 24.0f, 25.0f, 26.0f, 27.0f, 28.0f };
1569 glUniformMatrix2x4fv(glGetUniformLocation(m_program, "g_6"), 1, GL_FALSE, value);
1570 }
1571
1572 /* mat3x2 */
1573 {
1574 const GLfloat value[6] = { 29.0f, 30.0f, 31.0f, 32.0f, 33.0f, 34.0f };
1575 glUniformMatrix3x2fv(glGetUniformLocation(m_program, "g_7"), 1, GL_FALSE, value);
1576 }
1577 /* mat3 */
1578 {
1579 const GLfloat value[9] = { 35.0f, 36.0f, 37.0f, 38.0f, 39.0f, 40.0f, 41.0f, 42.0f, 43.0f };
1580 glUniformMatrix3fv(glGetUniformLocation(m_program, "g_8"), 1, GL_FALSE, value);
1581 }
1582 /* mat3x4 */
1583 {
1584 const GLfloat value[12] = { 44.0f, 45.0f, 46.0f, 47.0f, 48.0f, 49.0f,
1585 50.0f, 51.0f, 52.0f, 53.0f, 54.0f, 55.0f };
1586 glUniformMatrix3x4fv(glGetUniformLocation(m_program, "g_9"), 1, GL_FALSE, value);
1587 }
1588
1589 /* mat4x2 */
1590 {
1591 const GLfloat value[8] = { 56.0f, 57.0f, 58.0f, 59.0f, 60.0f, 61.0f, 62.0f, 63.0f };
1592 glUniformMatrix4x2fv(glGetUniformLocation(m_program, "g_10"), 1, GL_FALSE, value);
1593 }
1594 /* mat4x3 */
1595 {
1596 const GLfloat value[12] = {
1597 63.0f, 64.0f, 65.0f, 66.0f, 67.0f, 68.0f, 69.0f, 70.0f, 71.0f, 27.0f, 73, 74.0f
1598 };
1599 glUniformMatrix4x3fv(glGetUniformLocation(m_program, "g_11"), 1, GL_FALSE, value);
1600 }
1601 /* mat4 */
1602 {
1603 const GLfloat value[16] = { 75.0f, 76.0f, 77.0f, 78.0f, 79.0f, 80.0f, 81.0f, 82.0f,
1604 83.0f, 84.0f, 85.0f, 86.0f, 87.0f, 88.0f, 89.0f, 90.0f };
1605 glUniformMatrix4fv(glGetUniformLocation(m_program, "g_12"), 1, GL_FALSE, value);
1606 }
1607
1608 glUniform1i(glGetUniformLocation(m_program, "g_13"), 91);
1609 glUniform2i(glGetUniformLocation(m_program, "g_14"), 92, 93);
1610 glUniform3i(glGetUniformLocation(m_program, "g_15"), 94, 95, 96);
1611 glUniform4i(glGetUniformLocation(m_program, "g_16"), 97, 98, 99, 100);
1612
1613 glUniform1ui(glGetUniformLocation(m_program, "g_17"), 101);
1614 glUniform2ui(glGetUniformLocation(m_program, "g_18"), 102, 103);
1615 glUniform3ui(glGetUniformLocation(m_program, "g_19"), 104, 105, 106);
1616 glUniform4ui(glGetUniformLocation(m_program, "g_20"), 107, 108, 109, 110);
1617
1618 glDispatchCompute(1, 1, 1);
1619 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
1620
1621 long error = NO_ERROR;
1622 /* validate */
1623 {
1624 int* data;
1625 data = static_cast<int*>(glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(int), GL_MAP_READ_BIT));
1626 if (data[0] != 1)
1627 {
1628 m_context.getTestContext().getLog()
1629 << tcu::TestLog::Message << "Data is " << data[0] << " should be 1." << tcu::TestLog::EndMessage;
1630 error = ERROR;
1631 }
1632 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
1633 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
1634 }
1635
1636 return error;
1637 }
1638
Cleanup()1639 virtual long Cleanup()
1640 {
1641 glUseProgram(0);
1642 glDeleteProgram(m_program);
1643 glDeleteBuffers(1, &m_storage_buffer);
1644 return NO_ERROR;
1645 }
1646 };
1647
1648 class BasicBuiltinVariables : public ComputeShaderBase
1649 {
1650
Title()1651 virtual std::string Title()
1652 {
1653 return "CS built-in variables";
1654 }
1655
Purpose()1656 virtual std::string Purpose()
1657 {
1658 return NL "Verify that all (gl_WorkGroupSize, gl_WorkGroupID, gl_LocalInvocationID," NL
1659 "gl_GlobalInvocationID, gl_NumWorkGroups, gl_WorkGroupSize)" NL
1660 "CS built-in variables has correct values.";
1661 }
1662
Method()1663 virtual std::string Method()
1664 {
1665 return NL "1. Create CS which writes all built-in variables to SSBO." NL
1666 "2. Dispatch CS with DispatchCompute and DispatchComputeIndirect commands." NL
1667 "3. Verify SSBO content." NL "4. Repeat for several different local and global work sizes.";
1668 }
1669
PassCriteria()1670 virtual std::string PassCriteria()
1671 {
1672 return "Everything works as expected.";
1673 }
1674
1675 GLuint m_program;
1676 GLuint m_storage_buffer;
1677 GLuint m_dispatch_buffer;
1678
GenSource(const uvec3 & local_size,const uvec3 & num_groups)1679 std::string GenSource(const uvec3& local_size, const uvec3& num_groups)
1680 {
1681 const uvec3 global_size = local_size * num_groups;
1682 std::stringstream ss;
1683 ss << NL "layout(local_size_x = " << local_size.x() << ", local_size_y = " << local_size.y()
1684 << ", local_size_z = " << local_size.z() << ") in;" NL "const uvec3 kGlobalSize = uvec3(" << global_size.x()
1685 << ", " << global_size.y() << ", " << global_size.z()
1686 << ");" NL "layout(std430) buffer OutputBuffer {" NL " uvec4 num_work_groups["
1687 << global_size.x() * global_size.y() * global_size.z() << "];" NL " uvec4 work_group_size["
1688 << global_size.x() * global_size.y() * global_size.z() << "];" NL " uvec4 work_group_id["
1689 << global_size.x() * global_size.y() * global_size.z() << "];" NL " uvec4 local_invocation_id["
1690 << global_size.x() * global_size.y() * global_size.z() << "];" NL " uvec4 global_invocation_id["
1691 << global_size.x() * global_size.y() * global_size.z() << "];" NL " uvec4 local_invocation_index["
1692 << global_size.x() * global_size.y() * global_size.z()
1693 << "];" NL "} g_out_buffer;" NL "void main() {" NL
1694 " if ((gl_WorkGroupSize * gl_WorkGroupID + gl_LocalInvocationID) != gl_GlobalInvocationID) return;" NL
1695 " uint global_index = gl_GlobalInvocationID.x +" NL
1696 " gl_GlobalInvocationID.y * kGlobalSize.x +" NL
1697 " gl_GlobalInvocationID.z * kGlobalSize.x * kGlobalSize.y;" NL
1698 " g_out_buffer.num_work_groups[global_index] = uvec4(gl_NumWorkGroups, 0);" NL
1699 " g_out_buffer.work_group_size[global_index] = uvec4(gl_WorkGroupSize, 0);" NL
1700 " g_out_buffer.work_group_id[global_index] = uvec4(gl_WorkGroupID, 0);" NL
1701 " g_out_buffer.local_invocation_id[global_index] = uvec4(gl_LocalInvocationID, 0);" NL
1702 " g_out_buffer.global_invocation_id[global_index] = uvec4(gl_GlobalInvocationID, 0);" NL
1703 " g_out_buffer.local_invocation_index[global_index] = uvec4(gl_LocalInvocationIndex);" NL "}";
1704 return ss.str();
1705 }
1706
RunIteration(const uvec3 & local_size,const uvec3 & num_groups,bool dispatch_indirect)1707 bool RunIteration(const uvec3& local_size, const uvec3& num_groups, bool dispatch_indirect)
1708 {
1709 if (m_program != 0)
1710 glDeleteProgram(m_program);
1711 m_program = CreateComputeProgram(GenSource(local_size, num_groups));
1712 glLinkProgram(m_program);
1713 if (!CheckProgram(m_program))
1714 return false;
1715
1716 const GLuint kBufferSize =
1717 local_size.x() * num_groups.x() * local_size.y() * num_groups.y() * local_size.z() * num_groups.z();
1718
1719 std::vector<uvec4> data(kBufferSize * 6);
1720 if (m_storage_buffer == 0)
1721 glGenBuffers(1, &m_storage_buffer);
1722 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
1723 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(uvec4) * kBufferSize * 6, &data[0], GL_DYNAMIC_DRAW);
1724 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
1725
1726 glUseProgram(m_program);
1727 if (dispatch_indirect)
1728 {
1729 if (m_dispatch_buffer == 0)
1730 glGenBuffers(1, &m_dispatch_buffer);
1731 glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer);
1732 glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(num_groups), &num_groups[0], GL_STATIC_DRAW);
1733 glDispatchComputeIndirect(0);
1734 }
1735 else
1736 {
1737 glDispatchCompute(num_groups.x(), num_groups.y(), num_groups.z());
1738 }
1739
1740 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer);
1741 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
1742 uvec4* result;
1743 result = static_cast<uvec4*>(
1744 glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(uvec4) * kBufferSize * 6, GL_MAP_READ_BIT));
1745
1746 // gl_NumWorkGroups
1747 for (GLuint index = 0; index < kBufferSize; ++index)
1748 {
1749 if (!IsEqual(result[index], uvec4(num_groups.x(), num_groups.y(), num_groups.z(), 0)))
1750 {
1751 m_context.getTestContext().getLog()
1752 << tcu::TestLog::Message << "gl_NumWorkGroups: Invalid data at index " << index
1753 << tcu::TestLog::EndMessage;
1754 return false;
1755 }
1756 }
1757 // gl_WorkGroupSize
1758 for (GLuint index = kBufferSize; index < 2 * kBufferSize; ++index)
1759 {
1760 if (!IsEqual(result[index], uvec4(local_size.x(), local_size.y(), local_size.z(), 0)))
1761 {
1762 m_context.getTestContext().getLog()
1763 << tcu::TestLog::Message << "gl_WorkGroupSize: Invalid data at index " << index
1764 << tcu::TestLog::EndMessage;
1765 return false;
1766 }
1767 }
1768 // gl_WorkGroupID
1769 for (GLuint index = 2 * kBufferSize; index < 3 * kBufferSize; ++index)
1770 {
1771 uvec3 expected = IndexTo3DCoord(index - 2 * kBufferSize, local_size.x() * num_groups.x(),
1772 local_size.y() * num_groups.y());
1773 expected.x() /= local_size.x();
1774 expected.y() /= local_size.y();
1775 expected.z() /= local_size.z();
1776 if (!IsEqual(result[index], uvec4(expected.x(), expected.y(), expected.z(), 0)))
1777 {
1778 m_context.getTestContext().getLog()
1779 << tcu::TestLog::Message << "gl_WorkGroupSize: Invalid data at index " << index
1780 << tcu::TestLog::EndMessage;
1781 return false;
1782 }
1783 }
1784 // gl_LocalInvocationID
1785 for (GLuint index = 3 * kBufferSize; index < 4 * kBufferSize; ++index)
1786 {
1787 uvec3 expected = IndexTo3DCoord(index - 3 * kBufferSize, local_size.x() * num_groups.x(),
1788 local_size.y() * num_groups.y());
1789 expected.x() %= local_size.x();
1790 expected.y() %= local_size.y();
1791 expected.z() %= local_size.z();
1792 if (!IsEqual(result[index], uvec4(expected.x(), expected.y(), expected.z(), 0)))
1793 {
1794 m_context.getTestContext().getLog()
1795 << tcu::TestLog::Message << "gl_LocalInvocationID: Invalid data at index " << index
1796 << tcu::TestLog::EndMessage;
1797 return false;
1798 }
1799 }
1800 // gl_GlobalInvocationID
1801 for (GLuint index = 4 * kBufferSize; index < 5 * kBufferSize; ++index)
1802 {
1803 uvec3 expected = IndexTo3DCoord(index - 4 * kBufferSize, local_size.x() * num_groups.x(),
1804 local_size.y() * num_groups.y());
1805 if (!IsEqual(result[index], uvec4(expected.x(), expected.y(), expected.z(), 0)))
1806 {
1807 m_context.getTestContext().getLog()
1808 << tcu::TestLog::Message << "gl_GlobalInvocationID: Invalid data at index " << index
1809 << tcu::TestLog::EndMessage;
1810 return false;
1811 }
1812 }
1813 // gl_LocalInvocationIndex
1814 for (GLuint index = 5 * kBufferSize; index < 6 * kBufferSize; ++index)
1815 {
1816 uvec3 coord = IndexTo3DCoord(index - 5 * kBufferSize, local_size.x() * num_groups.x(),
1817 local_size.y() * num_groups.y());
1818 const GLuint expected = (coord.x() % local_size.x()) + (coord.y() % local_size.y()) * local_size.x() +
1819 (coord.z() % local_size.z()) * local_size.x() * local_size.y();
1820 if (!IsEqual(result[index], uvec4(expected)))
1821 {
1822 m_context.getTestContext().getLog()
1823 << tcu::TestLog::Message << "gl_LocalInvocationIndex: Invalid data at index " << index
1824 << tcu::TestLog::EndMessage;
1825 return false;
1826 }
1827 }
1828 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
1829 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
1830 return true;
1831 }
1832
Setup()1833 virtual long Setup()
1834 {
1835 m_program = 0;
1836 m_storage_buffer = 0;
1837 m_dispatch_buffer = 0;
1838 return NO_ERROR;
1839 }
1840
Run()1841 virtual long Run()
1842 {
1843 if (!RunIteration(uvec3(64, 1, 1), uvec3(8, 1, 1), false))
1844 return ERROR;
1845 if (!RunIteration(uvec3(1, 1, 64), uvec3(1, 5, 2), true))
1846 return ERROR;
1847 if (!RunIteration(uvec3(1, 1, 4), uvec3(2, 2, 2), false))
1848 return ERROR;
1849 if (!RunIteration(uvec3(3, 2, 1), uvec3(1, 2, 3), true))
1850 return ERROR;
1851 if (!RunIteration(uvec3(2, 4, 2), uvec3(2, 4, 1), false))
1852 return ERROR;
1853 if (!RunIteration(uvec3(2, 4, 7), uvec3(2, 1, 4), true))
1854 return ERROR;
1855 return NO_ERROR;
1856 }
1857
Cleanup()1858 virtual long Cleanup()
1859 {
1860 glUseProgram(0);
1861 glDeleteProgram(m_program);
1862 glDeleteBuffers(1, &m_storage_buffer);
1863 glDeleteBuffers(1, &m_dispatch_buffer);
1864 return NO_ERROR;
1865 }
1866 };
1867
1868 class BasicMax : public ComputeShaderBase
1869 {
1870
Title()1871 virtual std::string Title()
1872 {
1873 return NL "CS max values";
1874 }
1875
Purpose()1876 virtual std::string Purpose()
1877 {
1878 return NL "Verify (on the API and GLSL side) that all GL_MAX_COMPUTE_* values are not less than" NL
1879 "required by the OpenGL specification.";
1880 }
1881
Method()1882 virtual std::string Method()
1883 {
1884 return NL "1. Use all API commands to query all GL_MAX_COMPUTE_* values. Verify that they are correct." NL
1885 "2. Verify all gl_MaxCompute* constants in the GLSL.";
1886 }
1887
PassCriteria()1888 virtual std::string PassCriteria()
1889 {
1890 return NL "Everything works as expected.";
1891 }
1892
1893 GLuint m_program;
1894 GLuint m_buffer;
1895
CheckIndexed(GLenum target,const GLint * min_values)1896 bool CheckIndexed(GLenum target, const GLint* min_values)
1897 {
1898 GLint i;
1899 GLint64 i64;
1900
1901 for (GLuint c = 0; c < 3; c++)
1902 {
1903 glGetIntegeri_v(target, c, &i);
1904 if (i < min_values[c])
1905 {
1906 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Is " << i << " should be at least "
1907 << min_values[c] << tcu::TestLog::EndMessage;
1908 return false;
1909 }
1910 }
1911 for (GLuint c = 0; c < 3; c++)
1912 {
1913 glGetInteger64i_v(target, c, &i64);
1914 if (static_cast<GLint>(i64) < min_values[c])
1915 {
1916 m_context.getTestContext().getLog()
1917 << tcu::TestLog::Message << "Is " << static_cast<GLint>(i64) << " should be at least "
1918 << min_values[c] << tcu::TestLog::EndMessage;
1919 return false;
1920 }
1921 }
1922
1923 return true;
1924 }
1925
Check(GLenum target,const GLint min_value)1926 bool Check(GLenum target, const GLint min_value)
1927 {
1928 GLint i;
1929 GLint64 i64;
1930 GLfloat f;
1931 GLboolean b;
1932
1933 glGetIntegerv(target, &i);
1934 if (i < min_value)
1935 {
1936 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Is " << i << " should be at least "
1937 << min_value << tcu::TestLog::EndMessage;
1938 return false;
1939 }
1940 glGetInteger64v(target, &i64);
1941 if (static_cast<GLint>(i64) < min_value)
1942 {
1943 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Is " << static_cast<GLint>(i64)
1944 << " should be at least " << min_value << tcu::TestLog::EndMessage;
1945 return false;
1946 }
1947 glGetFloatv(target, &f);
1948 if (static_cast<GLint>(f) < min_value)
1949 {
1950 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Is " << static_cast<GLint>(f)
1951 << " should be at least " << min_value << tcu::TestLog::EndMessage;
1952 return false;
1953 }
1954 glGetBooleanv(target, &b);
1955 if (b == GL_FALSE)
1956 {
1957 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Is GL_FALSE should be at least GL_TRUE."
1958 << min_value << tcu::TestLog::EndMessage;
1959 return false;
1960 }
1961
1962 return true;
1963 }
1964
Setup()1965 virtual long Setup()
1966 {
1967 m_program = 0;
1968 m_buffer = 0;
1969 return NO_ERROR;
1970 }
1971
Run()1972 virtual long Run()
1973 {
1974 const GLint work_group_count[3] = { 65535, 65535, 65535 };
1975 if (!CheckIndexed(GL_MAX_COMPUTE_WORK_GROUP_COUNT, work_group_count))
1976 return ERROR;
1977
1978 const GLint work_group_size[3] = { 128, 128, 64 };
1979 if (!CheckIndexed(GL_MAX_COMPUTE_WORK_GROUP_SIZE, work_group_size))
1980 return ERROR;
1981
1982 if (!Check(GL_MAX_COMPUTE_UNIFORM_BLOCKS, 12))
1983 return ERROR;
1984 if (!Check(GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS, 16))
1985 return ERROR;
1986 if (!Check(GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS, 1))
1987 return ERROR;
1988 if (!Check(GL_MAX_COMPUTE_ATOMIC_COUNTERS, 8))
1989 return ERROR;
1990 if (!Check(GL_MAX_COMPUTE_SHARED_MEMORY_SIZE, 16384))
1991 return ERROR;
1992 if (!Check(GL_MAX_COMPUTE_UNIFORM_COMPONENTS, 512))
1993 return ERROR;
1994 if (!Check(GL_MAX_COMPUTE_IMAGE_UNIFORMS, 4))
1995 return ERROR;
1996 if (!Check(GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS, 512))
1997 return ERROR;
1998
1999 const char* const glsl_cs =
2000 NL "layout(local_size_x = 1) in;" NL "layout(std430) buffer Output {" NL " int g_output;" NL "};" NL
2001 "uniform ivec3 MaxComputeWorkGroupCount;" NL "uniform ivec3 MaxComputeWorkGroupSize;" NL
2002 "uniform int MaxComputeUniformComponents;" NL "uniform int MaxComputeTextureImageUnits;" NL
2003 "uniform int MaxComputeImageUniforms;" NL "uniform int MaxComputeAtomicCounters;" NL
2004 "uniform int MaxComputeAtomicCounterBuffers;" NL "void main() {" NL " g_output = 1;" NL
2005 " if (MaxComputeWorkGroupCount != gl_MaxComputeWorkGroupCount) g_output = 0;" NL
2006 " if (MaxComputeWorkGroupSize != gl_MaxComputeWorkGroupSize) g_output = 0;" NL
2007 " if (MaxComputeUniformComponents != gl_MaxComputeUniformComponents) g_output = 0;" NL
2008 " if (MaxComputeTextureImageUnits != gl_MaxComputeTextureImageUnits) g_output = 0;" NL
2009 " if (MaxComputeImageUniforms != gl_MaxComputeImageUniforms) g_output = 0;" NL
2010 " if (MaxComputeAtomicCounters != gl_MaxComputeAtomicCounters) g_output = 0;" NL
2011 " if (MaxComputeAtomicCounterBuffers != gl_MaxComputeAtomicCounterBuffers) g_output = 0;" NL "}";
2012 m_program = CreateComputeProgram(glsl_cs);
2013 glLinkProgram(m_program);
2014 if (!CheckProgram(m_program))
2015 return ERROR;
2016 glUseProgram(m_program);
2017
2018 GLint p[3];
2019 glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 0, &p[0]);
2020 glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 1, &p[1]);
2021 glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 2, &p[2]);
2022 glUniform3i(glGetUniformLocation(m_program, "MaxComputeWorkGroupCount"), p[0], p[1], p[2]);
2023
2024 glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 0, &p[0]);
2025 glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 1, &p[1]);
2026 glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 2, &p[2]);
2027 glUniform3iv(glGetUniformLocation(m_program, "MaxComputeWorkGroupSize"), 1, p);
2028
2029 glGetIntegerv(GL_MAX_COMPUTE_UNIFORM_COMPONENTS, p);
2030 glUniform1i(glGetUniformLocation(m_program, "MaxComputeUniformComponents"), p[0]);
2031
2032 glGetIntegerv(GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS, p);
2033 glUniform1iv(glGetUniformLocation(m_program, "MaxComputeTextureImageUnits"), 1, p);
2034
2035 glGetIntegerv(GL_MAX_COMPUTE_IMAGE_UNIFORMS, p);
2036 glUniform1i(glGetUniformLocation(m_program, "MaxComputeImageUniforms"), p[0]);
2037
2038 glGetIntegerv(GL_MAX_COMPUTE_ATOMIC_COUNTERS, p);
2039 glUniform1i(glGetUniformLocation(m_program, "MaxComputeAtomicCounters"), p[0]);
2040
2041 glGetIntegerv(GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS, p);
2042 glUniform1i(glGetUniformLocation(m_program, "MaxComputeAtomicCounterBuffers"), p[0]);
2043
2044 GLint data = 0xffff;
2045 glGenBuffers(1, &m_buffer);
2046 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer);
2047 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLint), &data, GL_DYNAMIC_DRAW);
2048
2049 glDispatchCompute(1, 1, 1);
2050
2051 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
2052
2053 GLint* result;
2054 result = static_cast<GLint*>(glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(GLint), GL_MAP_READ_BIT));
2055 long error = NO_ERROR;
2056 if (result[0] != 1)
2057 {
2058 error = ERROR;
2059 }
2060
2061 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
2062 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
2063 return error;
2064 }
Cleanup()2065 virtual long Cleanup()
2066 {
2067 glUseProgram(0);
2068 glDeleteProgram(m_program);
2069 glDeleteBuffers(1, &m_buffer);
2070 return NO_ERROR;
2071 }
2072 };
2073
2074 class NegativeAttachShader : public ComputeShaderBase
2075 {
2076
Title()2077 virtual std::string Title()
2078 {
2079 return "Api Attach Shader";
2080 }
2081
Purpose()2082 virtual std::string Purpose()
2083 {
2084 return NL "Verify that calling AttachShader with multiple shader objects of type COMPUTE_SHADER generates "
2085 "INVALID_OPERATION.";
2086 }
2087
Method()2088 virtual std::string Method()
2089 {
2090 return NL "Try to attach multiple shader objects of the same type and verify that proper error is generated.";
2091 }
2092
PassCriteria()2093 virtual std::string PassCriteria()
2094 {
2095 return "INVALID_OPERATION is generated.";
2096 }
2097
Run()2098 virtual long Run()
2099 {
2100 const char* const cs1[2] = { "#version 310 es", NL "layout(local_size_x = 1) in;" NL "void Run();" NL
2101 "void main() {" NL " Run();" NL "}" };
2102
2103 const char* const cs2 =
2104 "#version 310 es" NL "layout(binding = 0, std430) buffer Output {" NL " vec4 g_output;" NL "};" NL
2105 "vec4 CalculateOutput();" NL "void Run() {" NL " g_output = CalculateOutput();" NL "}";
2106
2107 const char* const cs3 =
2108 "#version 310 es" NL "layout(local_size_x = 1) in;" NL "layout(binding = 0, std430) buffer Output {" NL
2109 " vec4 g_output;" NL "};" NL "vec4 CalculateOutput() {" NL " g_output = vec4(0);" NL
2110 " return vec4(1, 2, 3, 4);" NL "}";
2111
2112 const GLuint sh1 = glCreateShader(GL_COMPUTE_SHADER);
2113
2114 GLint type;
2115 glGetShaderiv(sh1, GL_SHADER_TYPE, &type);
2116 if (static_cast<GLenum>(type) != GL_COMPUTE_SHADER)
2117 {
2118 m_context.getTestContext().getLog()
2119 << tcu::TestLog::Message << "SHADER_TYPE should be COMPUTE_SHADER." << tcu::TestLog::EndMessage;
2120 glDeleteShader(sh1);
2121 return false;
2122 }
2123
2124 glShaderSource(sh1, 2, cs1, NULL);
2125 glCompileShader(sh1);
2126
2127 const GLuint sh2 = glCreateShader(GL_COMPUTE_SHADER);
2128 glShaderSource(sh2, 1, &cs2, NULL);
2129 glCompileShader(sh2);
2130
2131 const GLuint sh3 = glCreateShader(GL_COMPUTE_SHADER);
2132 glShaderSource(sh3, 1, &cs3, NULL);
2133 glCompileShader(sh3);
2134
2135 const GLuint p = glCreateProgram();
2136 glAttachShader(p, sh1);
2137 glAttachShader(p, sh2);
2138 if (glGetError() != GL_INVALID_OPERATION)
2139 {
2140 m_context.getTestContext().getLog()
2141 << tcu::TestLog::Message
2142 << "GL_INVALID_OPERATION error expected after attaching shader of the same type."
2143 << tcu::TestLog::EndMessage;
2144 return ERROR;
2145 }
2146 glAttachShader(p, sh3);
2147 if (glGetError() != GL_INVALID_OPERATION)
2148 {
2149 m_context.getTestContext().getLog()
2150 << tcu::TestLog::Message
2151 << "GL_INVALID_OPERATION error expected after attaching shader of the same type."
2152 << tcu::TestLog::EndMessage;
2153 return ERROR;
2154 }
2155
2156 glDeleteShader(sh1);
2157 glDeleteShader(sh2);
2158 glDeleteShader(sh3);
2159
2160 glUseProgram(0);
2161 glDeleteProgram(p);
2162
2163 return NO_ERROR;
2164 }
2165 };
2166
2167 class BasicBuildSeparable : public ComputeShaderBase
2168 {
2169
Title()2170 virtual std::string Title()
2171 {
2172 return "Building CS separable program";
2173 }
2174
Purpose()2175 virtual std::string Purpose()
2176 {
2177 return NL "1. Verify that building separable CS program works as expected." NL
2178 "2. Verify that program consisting from 4 strings works as expected.";
2179 }
2180
Method()2181 virtual std::string Method()
2182 {
2183 return NL "1. Create, compile and link CS using CreateShaderProgramv command." NL
2184 "2. Dispatch and verify CS program.";
2185 }
2186
PassCriteria()2187 virtual std::string PassCriteria()
2188 {
2189 return "Everything works as expected.";
2190 }
2191
Run()2192 virtual long Run()
2193 {
2194 const char* const cs[4] = {
2195 "#version 310 es",
2196
2197 NL "layout(local_size_x = 1) in;" NL "void Run();" NL "void main() {" NL " Run();" NL "}",
2198
2199 NL "layout(binding = 0, std430) buffer Output {" NL " vec4 g_output;" NL "};" NL
2200 "vec4 CalculateOutput();" NL "void Run() {" NL " g_output = CalculateOutput();" NL "}",
2201
2202 NL "vec4 CalculateOutput() {" NL " g_output = vec4(0);" NL " return vec4(1, 2, 3, 4);" NL "}"
2203 };
2204
2205 const GLuint p = glCreateShaderProgramv(GL_COMPUTE_SHADER, 4, cs);
2206 bool res = CheckProgram(p);
2207
2208 GLuint buffer;
2209 glGenBuffers(1, &buffer);
2210 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, buffer);
2211 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(vec4), &vec4(0.0f)[0], GL_DYNAMIC_DRAW);
2212 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
2213
2214 glUseProgram(p);
2215 glDispatchCompute(1, 1, 1);
2216
2217 vec4* data;
2218 glBindBuffer(GL_SHADER_STORAGE_BUFFER, buffer);
2219 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
2220 data = static_cast<vec4*>(glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(vec4), GL_MAP_READ_BIT));
2221 if (!IsEqual(data[0], vec4(1.0f, 2.0f, 3.0f, 4.0f)))
2222 {
2223 m_context.getTestContext().getLog()
2224 << tcu::TestLog::Message << "Invalid value!" << tcu::TestLog::EndMessage;
2225 res = false;
2226 }
2227 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
2228
2229 glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(vec4), &vec4(0.0f)[0]);
2230
2231 GLuint pipeline;
2232 glGenProgramPipelines(1, &pipeline);
2233 glUseProgramStages(pipeline, GL_COMPUTE_SHADER_BIT, p);
2234
2235 glUseProgram(0);
2236 glBindProgramPipeline(pipeline);
2237 glDispatchCompute(1, 1, 1);
2238
2239 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
2240 data = static_cast<vec4*>(glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(vec4), GL_MAP_READ_BIT));
2241
2242 if (!IsEqual(data[0], vec4(1.0f, 2.0f, 3.0f, 4.0f)))
2243 {
2244 m_context.getTestContext().getLog()
2245 << tcu::TestLog::Message << "Invalid value!" << tcu::TestLog::EndMessage;
2246 res = false;
2247 }
2248
2249 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
2250 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
2251 glDeleteProgramPipelines(1, &pipeline);
2252 glDeleteBuffers(1, &buffer);
2253 glDeleteProgram(p);
2254
2255 return res == true ? NO_ERROR : ERROR;
2256 }
2257 };
2258
2259 class BasicSharedSimple : public ComputeShaderBase
2260 {
Title()2261 virtual std::string Title()
2262 {
2263 return "Shared Memory - simple usage";
2264 }
2265
Purpose()2266 virtual std::string Purpose()
2267 {
2268 return NL "1. Verify that shared array of uints works as expected." NL
2269 "2. Verify that shared memory written by one invocation is observable by other invocations" NL
2270 " when groupMemoryBarrier() and barrier() built-in functions are used.";
2271 }
2272
Method()2273 virtual std::string Method()
2274 {
2275 return NL "1. Create and dispatch CS with DispatchCompute and DispatchComputeIndirect commands." NL
2276 "2. Verify results written by CS to SSBO." NL
2277 "3. Repeat for several different number of work groups.";
2278 }
2279
PassCriteria()2280 virtual std::string PassCriteria()
2281 {
2282 return "Everything works as expected.";
2283 }
2284
2285 GLuint m_program;
2286 GLuint m_storage_buffer;
2287 GLuint m_dispatch_buffer;
2288
RunIteration(const GLuint num_groups,bool dispatch_indirect)2289 bool RunIteration(const GLuint num_groups, bool dispatch_indirect)
2290 {
2291 const GLuint kBufferSize = 128 * num_groups;
2292
2293 std::vector<GLuint> data(kBufferSize, 0xffff);
2294 if (m_storage_buffer == 0)
2295 glGenBuffers(1, &m_storage_buffer);
2296 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
2297 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLuint) * kBufferSize, &data[0], GL_DYNAMIC_DRAW);
2298 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
2299
2300 glUseProgram(m_program);
2301 if (dispatch_indirect)
2302 {
2303 const GLuint groups[3] = { num_groups, 1, 1 };
2304 if (m_dispatch_buffer == 0)
2305 glGenBuffers(1, &m_dispatch_buffer);
2306 glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer);
2307 glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(groups), groups, GL_STATIC_DRAW);
2308 glDispatchComputeIndirect(0);
2309 }
2310 else
2311 {
2312 glDispatchCompute(num_groups, 1, 1);
2313 }
2314
2315 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer);
2316 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
2317 GLuint* result;
2318 result = static_cast<GLuint*>(
2319 glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(GLuint) * kBufferSize, GL_MAP_READ_BIT));
2320 bool res = true;
2321 for (GLuint i = 0; i < kBufferSize; ++i)
2322 {
2323 if (result[i] != 1)
2324 {
2325 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Data at index " << i << " is "
2326 << result[i] << " should be 1." << tcu::TestLog::EndMessage;
2327 res = false;
2328 }
2329 }
2330 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
2331 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
2332 return res;
2333 }
2334
Setup()2335 virtual long Setup()
2336 {
2337 m_program = 0;
2338 m_storage_buffer = 0;
2339 m_dispatch_buffer = 0;
2340 return NO_ERROR;
2341 }
2342
Run()2343 virtual long Run()
2344 {
2345 const char* const glsl_cs =
2346 NL "layout(local_size_x = 128) in;" NL "layout(std430) buffer Output {" NL " uint g_output[];" NL "};" NL
2347 "shared uint g_shared_data[128];" NL "void main() {" NL
2348 " g_shared_data[gl_LocalInvocationID.x] = gl_LocalInvocationIndex;" NL
2349 " groupMemoryBarrier();" // flush memory stores
2350 NL " barrier();" // wait for all stores to finish
2351 NL " g_output[gl_GlobalInvocationID.x] = 1u;" NL " if (gl_LocalInvocationIndex < 127u) {" NL
2352 " uint res = g_shared_data[gl_LocalInvocationID.x + "
2353 "1u];" // load data from shared memory filled by other thread
2354 NL " if (res != (gl_LocalInvocationIndex + 1u)) {" NL " g_output[gl_GlobalInvocationID.x] = 0u;" NL
2355 " }" NL " }" NL "}";
2356 m_program = CreateComputeProgram(glsl_cs);
2357 glLinkProgram(m_program);
2358 if (!CheckProgram(m_program))
2359 return ERROR;
2360
2361 if (!RunIteration(1, false))
2362 return ERROR;
2363 if (!RunIteration(8, true))
2364 return ERROR;
2365 if (!RunIteration(13, false))
2366 return ERROR;
2367 if (!RunIteration(7, true))
2368 return ERROR;
2369 return NO_ERROR;
2370 }
Cleanup()2371 virtual long Cleanup()
2372 {
2373 glUseProgram(0);
2374 glDeleteProgram(m_program);
2375 glDeleteBuffers(1, &m_storage_buffer);
2376 glDeleteBuffers(1, &m_dispatch_buffer);
2377 return NO_ERROR;
2378 }
2379 };
2380
2381 class BasicSharedStruct : public ComputeShaderBase
2382 {
Title()2383 virtual std::string Title()
2384 {
2385 return "Shared Memory - arrays and structers";
2386 }
2387
Purpose()2388 virtual std::string Purpose()
2389 {
2390 return NL "1. Verify that vectors, matrices, structers and arrays of those can be used" NL
2391 " as a shared memory." NL
2392 "2. Verify that shared memory can be indexed with constant values, built-in" NL
2393 " variables and dynamic expressions." NL
2394 "3. Verify that memoryBarrierAtomicCounter(), memoryBarrierImage(), memoryBarrier()," NL
2395 " memoryBarrierBuffer() and memoryBarrierShared() built-in functions are accepted" NL
2396 " by the GLSL compiler.";
2397 }
2398
Method()2399 virtual std::string Method()
2400 {
2401 return NL "1. Create and dispatch CS with DispatchCompute and DispatchComputeIndirect commands." NL
2402 "2. Verify results written by CS to SSBO.";
2403 }
2404
PassCriteria()2405 virtual std::string PassCriteria()
2406 {
2407 return "Everything works as expected.";
2408 }
2409
2410 GLuint m_program;
2411 GLuint m_storage_buffer;
2412 GLuint m_dispatch_buffer;
2413
RunIteration(bool dispatch_indirect)2414 bool RunIteration(bool dispatch_indirect)
2415 {
2416 const GLuint kBufferSize = 256;
2417
2418 std::vector<vec4> data(kBufferSize);
2419 if (m_storage_buffer == 0)
2420 glGenBuffers(1, &m_storage_buffer);
2421 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
2422 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(vec4) * kBufferSize, &data[0], GL_DYNAMIC_DRAW);
2423 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
2424
2425 glUseProgram(m_program);
2426 if (dispatch_indirect)
2427 {
2428 const GLuint groups[3] = { 1, 1, 1 };
2429 if (m_dispatch_buffer == 0)
2430 glGenBuffers(1, &m_dispatch_buffer);
2431 glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer);
2432 glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(groups), groups, GL_STATIC_DRAW);
2433 glDispatchComputeIndirect(0);
2434 }
2435 else
2436 {
2437 glDispatchCompute(1, 1, 1);
2438 }
2439
2440 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer);
2441 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
2442 vec4* result;
2443 result = static_cast<vec4*>(
2444 glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(vec4) * kBufferSize, GL_MAP_READ_BIT));
2445 bool res = true;
2446 for (GLuint i = 0; i < kBufferSize; ++i)
2447 {
2448 if (!IsEqual(result[i], vec4(static_cast<float>(i))))
2449 {
2450 m_context.getTestContext().getLog()
2451 << tcu::TestLog::Message << "Invalid data at index " << i << tcu::TestLog::EndMessage;
2452 res = false;
2453 }
2454 }
2455 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
2456 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
2457 return res;
2458 }
2459
Setup()2460 virtual long Setup()
2461 {
2462 m_program = 0;
2463 m_storage_buffer = 0;
2464 m_dispatch_buffer = 0;
2465 return NO_ERROR;
2466 }
2467
Run()2468 virtual long Run()
2469 {
2470 const char* const glsl_cs = NL
2471 "layout(local_size_x = 128) in;" NL "layout(std430) buffer Output {" NL " vec4 g_output[256];" NL "};" NL
2472 "struct SubData {" NL " mat2x4 data;" NL "};" NL "struct Data {" NL " vec3 data0;" NL " uint index;" NL
2473 " SubData data1;" NL "};" NL "shared Data g_shared_data[256];" NL "shared int g_shared_buf[2];" NL
2474 "void main() {" NL " if (gl_LocalInvocationID.x == 0u) {" NL " g_shared_buf[1] = 1;" NL
2475 " g_shared_buf[1u + gl_LocalInvocationID.x] = 0;" NL " g_shared_buf[0] = 128;" NL
2476 " g_output[0] = vec4(g_shared_buf[1]);" NL " g_output[128] = vec4(g_shared_buf[0]);" NL
2477 " memoryBarrierBuffer();" // note: this call is not needed here, just check if compiler accepts it
2478 NL " } else {" NL " uint index = gl_LocalInvocationIndex;" NL
2479 " g_shared_data[index].index = index;" NL " g_shared_data[index + 128u].index = index + 128u;" NL
2480 " g_shared_data[index].data1.data = mat2x4(0.0);" NL
2481 " g_shared_data[index + 128u].data1.data = mat2x4(0.0);" NL
2482 " g_output[index] = vec4(g_shared_data[index].index);" // load data from shared memory
2483 NL " g_output[index + 128u] = vec4(g_shared_data[index + 128u].index);" NL
2484 " memoryBarrierShared();" // note: this call is not needed here, just check if compiler accepts it
2485 NL " }" NL " memoryBarrierAtomicCounter();" NL " memoryBarrierImage();" NL
2486 " memoryBarrier();" // note: these calls are not needed here, just check if compiler accepts them
2487 NL "}";
2488 m_program = CreateComputeProgram(glsl_cs);
2489 glLinkProgram(m_program);
2490 if (!CheckProgram(m_program))
2491 return ERROR;
2492
2493 if (!RunIteration(false))
2494 return ERROR;
2495 if (!RunIteration(true))
2496 return ERROR;
2497 return NO_ERROR;
2498 }
2499
Cleanup()2500 virtual long Cleanup()
2501 {
2502 glUseProgram(0);
2503 glDeleteProgram(m_program);
2504 glDeleteBuffers(1, &m_storage_buffer);
2505 glDeleteBuffers(1, &m_dispatch_buffer);
2506 return NO_ERROR;
2507 }
2508 };
2509
2510 class BasicDispatchIndirect : public ComputeShaderBase
2511 {
Title()2512 virtual std::string Title()
2513 {
2514 return NL "DispatchComputeIndirect command";
2515 }
2516
Purpose()2517 virtual std::string Purpose()
2518 {
2519 return NL
2520 "1. Verify that DispatchComputeIndirect command works as described in the OpenGL specification." NL
2521 "2. Verify that <offset> parameter is correctly applied." NL
2522 "3. Verify that updating dispatch buffer with different methods (BufferData, BufferSubData, MapBuffer)" NL
2523 " just before DispatchComputeIndirect call works as expected." NL
2524 "4. Verify that GL_DISPATCH_INDIRECT_BUFFER_BINDING binding point is set correctly.";
2525 }
2526
Method()2527 virtual std::string Method()
2528 {
2529 return NL
2530 "1. Create CS and dispatch indirect buffer." NL "2. Dispatch CS with DispatchComputeIndirect command." NL
2531 "3. Update dispatch indirect buffer." NL
2532 "4. Repeat several times updating dispatch buffer with different methods and changing <offset> parameter.";
2533 }
2534
PassCriteria()2535 virtual std::string PassCriteria()
2536 {
2537 return NL "Everything works as expected.";
2538 }
2539
2540 GLuint m_program;
2541 GLuint m_storage_buffer;
2542 GLuint m_dispatch_buffer[2];
2543
RunIteration(GLintptr offset,GLuint buffer_size)2544 bool RunIteration(GLintptr offset, GLuint buffer_size)
2545 {
2546 std::vector<GLuint> data(buffer_size);
2547 if (m_storage_buffer == 0)
2548 glGenBuffers(1, &m_storage_buffer);
2549 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
2550 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLuint) * buffer_size, &data[0], GL_DYNAMIC_DRAW);
2551
2552 glDispatchComputeIndirect(offset);
2553
2554 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
2555 GLuint* result;
2556 result = static_cast<GLuint*>(
2557 glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(GLuint) * buffer_size, GL_MAP_READ_BIT));
2558 bool res = true;
2559 for (GLuint i = 0; i < buffer_size; ++i)
2560 {
2561 if (result[i] != i)
2562 {
2563 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Data at index " << i << " is "
2564 << result[i] << " should be " << i << tcu::TestLog::EndMessage;
2565 res = false;
2566 }
2567 }
2568 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
2569 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
2570 return res;
2571 }
2572
CheckBinding(GLuint expected)2573 bool CheckBinding(GLuint expected)
2574 {
2575 GLint i;
2576 GLint64 i64;
2577 GLfloat f;
2578 GLboolean b;
2579
2580 GLfloat expectedFloat = static_cast<GLfloat>(expected);
2581
2582 glGetIntegerv(GL_DISPATCH_INDIRECT_BUFFER_BINDING, &i);
2583 if (static_cast<GLuint>(i) != expected)
2584 {
2585 return false;
2586 }
2587 glGetInteger64v(GL_DISPATCH_INDIRECT_BUFFER_BINDING, &i64);
2588 if (static_cast<GLuint>(i64) != expected)
2589 {
2590 return false;
2591 }
2592 glGetFloatv(GL_DISPATCH_INDIRECT_BUFFER_BINDING, &f);
2593 if (f != expectedFloat)
2594 {
2595 return false;
2596 }
2597 glGetBooleanv(GL_DISPATCH_INDIRECT_BUFFER_BINDING, &b);
2598 if (b != (expected != 0 ? GL_TRUE : GL_FALSE))
2599 {
2600 return false;
2601 }
2602
2603 return true;
2604 }
2605
Setup()2606 virtual long Setup()
2607 {
2608 m_program = 0;
2609 m_storage_buffer = 0;
2610 memset(m_dispatch_buffer, 0, sizeof(m_dispatch_buffer));
2611 return NO_ERROR;
2612 }
2613
Run()2614 virtual long Run()
2615 {
2616 const char* const glsl_cs =
2617 NL "layout(local_size_x = 1) in;" NL "layout(std430) buffer Output {" NL " uint g_output[];" NL "};" NL
2618 "uniform uvec3 g_global_size;" NL "void main() {" NL " uint global_index = gl_GlobalInvocationID.x +" NL
2619 " gl_GlobalInvocationID.y * g_global_size.x +" NL
2620 " gl_GlobalInvocationID.z * g_global_size.x * g_global_size.y;" NL
2621 " if (gl_NumWorkGroups != g_global_size) {" NL " g_output[global_index] = 0xffffu;" NL
2622 " return;" NL " }" NL " g_output[global_index] = global_index;" NL "}";
2623 m_program = CreateComputeProgram(glsl_cs);
2624 glLinkProgram(m_program);
2625 if (!CheckProgram(m_program))
2626 return ERROR;
2627
2628 if (!CheckBinding(0))
2629 return ERROR;
2630
2631 glGenBuffers(2, m_dispatch_buffer);
2632
2633 const GLuint data[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
2634 const GLuint data2[] = { 3, 1, 4, 4 };
2635
2636 glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer[0]);
2637 glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(data), data, GL_STREAM_DRAW);
2638 if (!CheckBinding(m_dispatch_buffer[0]))
2639 return ERROR;
2640
2641 glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer[1]);
2642 glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(data2), data2, GL_STREAM_READ);
2643 if (!CheckBinding(m_dispatch_buffer[1]))
2644 return ERROR;
2645
2646 glUseProgram(m_program);
2647 glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer[0]);
2648
2649 glUniform3ui(glGetUniformLocation(m_program, "g_global_size"), 1, 2, 3);
2650 if (!RunIteration(0, 6))
2651 return ERROR;
2652
2653 glUniform3ui(glGetUniformLocation(m_program, "g_global_size"), 2, 3, 4);
2654 if (!RunIteration(4, 24))
2655 return ERROR;
2656
2657 glUniform3ui(glGetUniformLocation(m_program, "g_global_size"), 4, 5, 6);
2658 if (!RunIteration(12, 120))
2659 return ERROR;
2660
2661 glBufferSubData(GL_DISPATCH_INDIRECT_BUFFER, 20, 12, data);
2662 glUniform3ui(glGetUniformLocation(m_program, "g_global_size"), 1, 2, 3);
2663 if (!RunIteration(20, 6))
2664 return ERROR;
2665
2666 GLuint* ptr = static_cast<GLuint*>(
2667 glMapBufferRange(GL_DISPATCH_INDIRECT_BUFFER, 0, sizeof(GLuint) * 4, GL_MAP_WRITE_BIT));
2668 *ptr++ = 4;
2669 *ptr++ = 4;
2670 *ptr++ = 4;
2671 glUnmapBuffer(GL_DISPATCH_INDIRECT_BUFFER);
2672
2673 glUniform3ui(glGetUniformLocation(m_program, "g_global_size"), 4, 4, 4);
2674 if (!RunIteration(0, 64))
2675 return ERROR;
2676
2677 glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer[1]);
2678
2679 glUniform3ui(glGetUniformLocation(m_program, "g_global_size"), 1, 4, 4);
2680 if (!RunIteration(4, 16))
2681 return ERROR;
2682
2683 glDeleteBuffers(2, m_dispatch_buffer);
2684 memset(m_dispatch_buffer, 0, sizeof(m_dispatch_buffer));
2685
2686 if (!CheckBinding(0))
2687 return ERROR;
2688
2689 return NO_ERROR;
2690 }
Cleanup()2691 virtual long Cleanup()
2692 {
2693 glUseProgram(0);
2694 glDeleteProgram(m_program);
2695 glDeleteBuffers(1, &m_storage_buffer);
2696 glDeleteBuffers(2, m_dispatch_buffer);
2697 return NO_ERROR;
2698 }
2699 };
2700
2701 class BasicSSOComputePipeline : public ComputeShaderBase
2702 {
Title()2703 virtual std::string Title()
2704 {
2705 return NL "Separable CS Programs - Compute and non-compute stages (1)";
2706 }
Purpose()2707 virtual std::string Purpose()
2708 {
2709 return NL "1. Verify that compute and non-compute stages can be attached to one pipeline object." NL
2710 "2. Verify that DrawArrays and ComputeDispatch commands works as expected in this case.";
2711 }
Method()2712 virtual std::string Method()
2713 {
2714 return NL "1. Create VS, FS and CS. Attach all created stages to one pipeline object." NL
2715 "2. Bind pipeline object." NL "3. Invoke compute stage with DispatchCompute commmand." NL
2716 "4. Issue MemoryBarrier command." NL
2717 "5. Issue DrawArrays command which uses data written by the compute stage." NL "6. Verify result.";
2718 }
PassCriteria()2719 virtual std::string PassCriteria()
2720 {
2721 return NL "Everything works as expected.";
2722 }
2723
2724 GLuint m_vsp, m_fsp, m_csp;
2725 GLuint m_storage_buffer;
2726 GLuint m_vertex_array;
2727 GLuint m_pipeline;
2728
Setup()2729 virtual long Setup()
2730 {
2731 m_vsp = m_fsp = m_csp = 0;
2732 m_storage_buffer = 0;
2733 m_vertex_array = 0;
2734 m_pipeline = 0;
2735 return NO_ERROR;
2736 }
Run()2737 virtual long Run()
2738 {
2739 const char* const glsl_cs = NL
2740 "layout(local_size_x = 4) in;" NL "layout(std430) buffer Output {" NL " vec4 g_output[4];" NL "};" NL
2741 "void main() {" NL " const vec2 quad[4] = vec2[](vec2(-1, -1), vec2(1, -1), vec2(-1, 1), vec2(1, 1));" NL
2742 " g_output[gl_GlobalInvocationID.x] = vec4(quad[gl_GlobalInvocationID.x], 0, 1);" NL "}";
2743 m_csp = CreateComputeProgram(glsl_cs);
2744 glProgramParameteri(m_csp, GL_PROGRAM_SEPARABLE, GL_TRUE);
2745 glLinkProgram(m_csp);
2746 if (!CheckProgram(m_csp))
2747 return ERROR;
2748
2749 const char* const glsl_vs =
2750 NL "layout(location = 0) in vec4 i_position;" NL "void main() {" NL " gl_Position = i_position;" NL "}";
2751 m_vsp = BuildShaderProgram(GL_VERTEX_SHADER, glsl_vs);
2752 if (!CheckProgram(m_vsp))
2753 return ERROR;
2754
2755 const char* const glsl_fs = NL "layout(location = 0) out mediump vec4 o_color;" NL "void main() {" NL
2756 " o_color = vec4(0, 1, 0, 1);" NL "}";
2757 m_fsp = BuildShaderProgram(GL_FRAGMENT_SHADER, glsl_fs);
2758 if (!CheckProgram(m_fsp))
2759 return ERROR;
2760
2761 glGenProgramPipelines(1, &m_pipeline);
2762 glUseProgramStages(m_pipeline, GL_VERTEX_SHADER_BIT, m_vsp);
2763 glUseProgramStages(m_pipeline, GL_FRAGMENT_SHADER_BIT, m_fsp);
2764 glUseProgramStages(m_pipeline, GL_COMPUTE_SHADER_BIT, m_csp);
2765
2766 glGenBuffers(1, &m_storage_buffer);
2767 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer);
2768 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(vec4) * 4, NULL, GL_DYNAMIC_DRAW);
2769 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
2770
2771 glGenVertexArrays(1, &m_vertex_array);
2772 glBindVertexArray(m_vertex_array);
2773 glBindBuffer(GL_ARRAY_BUFFER, m_storage_buffer);
2774 glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
2775 glBindBuffer(GL_ARRAY_BUFFER, 0);
2776 glEnableVertexAttribArray(0);
2777 glBindVertexArray(0);
2778
2779 glBindProgramPipeline(m_pipeline);
2780 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
2781 glDispatchCompute(1, 1, 1);
2782
2783 glClear(GL_COLOR_BUFFER_BIT);
2784 glBindVertexArray(m_vertex_array);
2785 glMemoryBarrier(GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT);
2786 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
2787
2788 if (!ValidateReadBuffer(0, 0, getWindowWidth(), getWindowHeight(), vec4(0, 1, 0, 1)))
2789 return ERROR;
2790 return NO_ERROR;
2791 }
2792
Cleanup()2793 virtual long Cleanup()
2794 {
2795 glDeleteProgram(m_vsp);
2796 glDeleteProgram(m_fsp);
2797 glDeleteProgram(m_csp);
2798 glDeleteBuffers(1, &m_storage_buffer);
2799 glDeleteVertexArrays(1, &m_vertex_array);
2800 glDeleteProgramPipelines(1, &m_pipeline);
2801 return NO_ERROR;
2802 }
2803 };
2804
2805 class BasicSSOCase2 : public ComputeShaderBase
2806 {
Title()2807 virtual std::string Title()
2808 {
2809 return NL "Separable CS Programs - Compute and non-compute stages (2)";
2810 }
Purpose()2811 virtual std::string Purpose()
2812 {
2813 return NL "1. Verify that data computed by the compute stage is visible to non-compute stage after "
2814 "MemoryBarrier command." NL "2. Verify that ProgramParameteri(program, GL_PROGRAM_SEPARABLE, "
2815 "GL_TRUE) command works correctly for CS." NL
2816 "3. Verify that gl_WorkGroupSize built-in variable is a contant and can be used as an array size.";
2817 }
Method()2818 virtual std::string Method()
2819 {
2820 return NL "1. Create VS, FS and CS. Attach all created stages to one pipeline object." NL
2821 "2. Bind pipeline object." NL "3. Invoke compute stage with DispatchCompute commmand." NL
2822 "4. Issue MemoryBarrier command." NL
2823 "5. Issue DrawArrays command which uses data written to the buffer object by the compute stage." NL
2824 "6. Verify result.";
2825 }
PassCriteria()2826 virtual std::string PassCriteria()
2827 {
2828 return NL "Everything works as expected.";
2829 }
2830
2831 GLuint m_program_ab;
2832 GLuint m_program_c;
2833 GLuint m_pipeline;
2834 GLuint m_storage_buffer;
2835 GLuint m_vao;
2836
Setup()2837 virtual long Setup()
2838 {
2839 m_program_ab = 0;
2840 m_program_c = 0;
2841 m_pipeline = 0;
2842 m_storage_buffer = 0;
2843 m_vao = 0;
2844 return NO_ERROR;
2845 }
Run()2846 virtual long Run()
2847 {
2848 GLint res;
2849 glGetIntegerv(GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, &res);
2850 if (res <= 0)
2851 {
2852 OutputNotSupported("GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS <= 0");
2853 return NO_ERROR;
2854 }
2855
2856 const char* const glsl_a =
2857 "#version 310 es" NL "layout(binding = 1, std430) buffer Input {" NL " mediump vec2 g_input[4];" NL "};" NL
2858 "flat out mediump vec3 color;" NL "void main() {" NL
2859 " gl_Position = vec4(g_input[gl_VertexID], 0.0, 1.0);" NL " color = vec3(0.0, 1.0, 0.0);" NL "}";
2860 const char* const glsl_b =
2861 "#version 310 es" NL "flat in mediump vec3 color;" NL "layout(location = 0) out mediump vec4 g_color;" NL
2862 "void main() {" NL " g_color = vec4(color, 1.0);" NL "}";
2863 const char* const glsl_c =
2864 "#version 310 es" NL "layout(local_size_x = 4) in;" NL "layout(binding = 1, std430) buffer Output {" NL
2865 " vec2 g_output[gl_WorkGroupSize.x];" NL "};" NL "void main() {" NL
2866 " if (gl_GlobalInvocationID.x == 0u) {" NL " g_output[0] = vec2(-0.8, -0.8);" NL
2867 " } else if (gl_GlobalInvocationID.x == 1u) {" NL " g_output[1] = vec2(0.8, -0.8);" NL
2868 " } else if (gl_GlobalInvocationID.x == 2u) {" NL " g_output[2] = vec2(-0.8, 0.8);" NL
2869 " } else if (gl_GlobalInvocationID.x == 3u) {" NL " g_output[3] = vec2(0.8, 0.8);" NL " }" NL "}";
2870
2871 m_program_ab = glCreateProgram();
2872 GLuint sh = glCreateShader(GL_VERTEX_SHADER);
2873 glAttachShader(m_program_ab, sh);
2874 glDeleteShader(sh);
2875 glShaderSource(sh, 1, &glsl_a, NULL);
2876 glCompileShader(sh);
2877
2878 sh = glCreateShader(GL_FRAGMENT_SHADER);
2879 glAttachShader(m_program_ab, sh);
2880 glDeleteShader(sh);
2881 glShaderSource(sh, 1, &glsl_b, NULL);
2882 glCompileShader(sh);
2883
2884 glProgramParameteri(m_program_ab, GL_PROGRAM_SEPARABLE, GL_TRUE);
2885 glLinkProgram(m_program_ab);
2886
2887 m_program_c = glCreateShaderProgramv(GL_COMPUTE_SHADER, 1, &glsl_c);
2888
2889 glGenVertexArrays(1, &m_vao);
2890 glGenProgramPipelines(1, &m_pipeline);
2891 glUseProgramStages(m_pipeline, GL_ALL_SHADER_BITS, m_program_ab);
2892 glUseProgramStages(m_pipeline, GL_COMPUTE_SHADER_BIT, m_program_c);
2893
2894 glGenBuffers(1, &m_storage_buffer);
2895 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, m_storage_buffer);
2896 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(vec2) * 4, NULL, GL_STREAM_DRAW);
2897
2898 glClear(GL_COLOR_BUFFER_BIT);
2899 glBindProgramPipeline(m_pipeline);
2900 glDispatchCompute(1, 1, 1);
2901 glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
2902 glBindVertexArray(m_vao);
2903 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
2904
2905 if (getWindowWidth() < 500 &&
2906 !ValidateReadBufferCenteredQuad(getWindowWidth(), getWindowHeight(), vec3(0, 1, 0)))
2907 {
2908 return ERROR;
2909 }
2910 return NO_ERROR;
2911 }
Cleanup()2912 virtual long Cleanup()
2913 {
2914 glDeleteProgram(m_program_ab);
2915 glDeleteProgram(m_program_c);
2916 glDeleteProgramPipelines(1, &m_pipeline);
2917 glDeleteBuffers(1, &m_storage_buffer);
2918 glDeleteVertexArrays(1, &m_vao);
2919 return NO_ERROR;
2920 }
2921 };
2922
2923 class BasicSSOCase3 : public ComputeShaderBase
2924 {
Title()2925 virtual std::string Title()
2926 {
2927 return NL "Separable CS Programs - Compute stage";
2928 }
Purpose()2929 virtual std::string Purpose()
2930 {
2931 return NL "Verify that compute shader stage selected with UseProgram command has precedence" NL
2932 "over compute shader stage selected with BindProgramPipeline command.";
2933 }
Method()2934 virtual std::string Method()
2935 {
2936 return NL "1. Create CS0 with CreateProgram command. Create CS1 with CreateShaderProgramv command." NL
2937 "2. Verify that CS program selected with UseProgram is dispatched even if there is active" NL
2938 " compute stage bound by BindProgramPipeline.";
2939 }
PassCriteria()2940 virtual std::string PassCriteria()
2941 {
2942 return NL "Everything works as expected.";
2943 }
2944
2945 GLuint m_program_a;
2946 GLuint m_program_b;
2947 GLuint m_pipeline;
2948 GLuint m_storage_buffer;
2949
Setup()2950 virtual long Setup()
2951 {
2952 m_program_a = 0;
2953 m_program_b = 0;
2954 m_pipeline = 0;
2955 m_storage_buffer = 0;
2956 return NO_ERROR;
2957 }
Run()2958 virtual long Run()
2959 {
2960 const char* const glsl_a =
2961 "#version 310 es" NL "layout(local_size_x = 1) in;" NL "layout(binding = 3, std430) buffer Output {" NL
2962 " int g_output;" NL "};" NL "void main() {" NL " g_output = 1;" NL "}";
2963 const char* const glsl_b =
2964 "#version 310 es" NL "layout(local_size_x = 1) in;" NL "layout(binding = 3, std430) buffer Output {" NL
2965 " int g_output;" NL "};" NL "void main() {" NL " g_output = 2;" NL "}";
2966 /* create program A */
2967 {
2968 m_program_a = glCreateProgram();
2969 GLuint sh = glCreateShader(GL_COMPUTE_SHADER);
2970 glAttachShader(m_program_a, sh);
2971 glDeleteShader(sh);
2972 glShaderSource(sh, 1, &glsl_a, NULL);
2973 glCompileShader(sh);
2974 glProgramParameteri(m_program_a, GL_PROGRAM_SEPARABLE, GL_TRUE);
2975 glLinkProgram(m_program_a);
2976 }
2977 m_program_b = glCreateShaderProgramv(GL_COMPUTE_SHADER, 1, &glsl_b);
2978
2979 /* create storage buffer */
2980 {
2981 int data = 0;
2982 glGenBuffers(1, &m_storage_buffer);
2983 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, m_storage_buffer);
2984 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(int), &data, GL_STREAM_READ);
2985 }
2986
2987 glGenProgramPipelines(1, &m_pipeline);
2988 glUseProgramStages(m_pipeline, GL_ALL_SHADER_BITS, m_program_b);
2989
2990 glUseProgram(m_program_a);
2991 glBindProgramPipeline(m_pipeline);
2992 glDispatchCompute(1, 1, 1);
2993 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
2994
2995 long error = NO_ERROR;
2996 {
2997 int* data;
2998 data = static_cast<int*>(glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(int), GL_MAP_READ_BIT));
2999 if (data[0] != 1)
3000 {
3001 m_context.getTestContext().getLog()
3002 << tcu::TestLog::Message << "Data is " << data[0] << " should be 1." << tcu::TestLog::EndMessage;
3003 error = ERROR;
3004 }
3005 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
3006 }
3007
3008 glUseProgram(0);
3009 glDispatchCompute(1, 1, 1);
3010 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
3011
3012 {
3013 int* data;
3014 data = static_cast<int*>(glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(int), GL_MAP_READ_BIT));
3015 if (data[0] != 2)
3016 {
3017 m_context.getTestContext().getLog()
3018 << tcu::TestLog::Message << "Data is " << data[0] << " should be 2." << tcu::TestLog::EndMessage;
3019 error = ERROR;
3020 }
3021 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
3022 }
3023
3024 glUseProgram(m_program_b);
3025 glDispatchCompute(1, 1, 1);
3026 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
3027
3028 {
3029 int* data;
3030 data = static_cast<int*>(glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(int), GL_MAP_READ_BIT));
3031 if (data[0] != 2)
3032 {
3033 m_context.getTestContext().getLog()
3034 << tcu::TestLog::Message << "Data is " << data[0] << " should be 2." << tcu::TestLog::EndMessage;
3035 error = ERROR;
3036 }
3037 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
3038 }
3039
3040 glUseProgram(0);
3041 glUseProgramStages(m_pipeline, GL_COMPUTE_SHADER_BIT, m_program_a);
3042 glDispatchCompute(1, 1, 1);
3043 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
3044
3045 {
3046 int* data;
3047 data = static_cast<int*>(glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(int), GL_MAP_READ_BIT));
3048 if (data[0] != 1)
3049 {
3050 m_context.getTestContext().getLog()
3051 << tcu::TestLog::Message << "Data is " << data[0] << " should be 1." << tcu::TestLog::EndMessage;
3052 error = ERROR;
3053 }
3054 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
3055 }
3056
3057 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
3058 return error;
3059 }
Cleanup()3060 virtual long Cleanup()
3061 {
3062 glDeleteProgram(m_program_a);
3063 glDeleteProgram(m_program_b);
3064 glDeleteProgramPipelines(1, &m_pipeline);
3065 glDeleteBuffers(1, &m_storage_buffer);
3066 return NO_ERROR;
3067 }
3068 };
3069
3070 class BasicAtomicCase1 : public ComputeShaderBase
3071 {
Title()3072 virtual std::string Title()
3073 {
3074 return NL "Atomic functions";
3075 }
Purpose()3076 virtual std::string Purpose()
3077 {
3078 return NL "1. Verify that atomicAdd function works as expected with int and uint parameters." NL
3079 "2. Verify that shared memory can be used with atomic functions." NL
3080 "3. Verify that groupMemoryBarrier() and barrier() built-in functions work as expected.";
3081 }
Method()3082 virtual std::string Method()
3083 {
3084 return NL "1. Use shared memory as a 'counter' with-in one CS work group." NL
3085 "2. Each shader invocation increments/decrements 'counter' value using atomicAdd function." NL
3086 "3. Values returned by atomicAdd function are written to SSBO." NL
3087 "4. Verify SSBO content (values from 0 to 7 should be written).";
3088 }
PassCriteria()3089 virtual std::string PassCriteria()
3090 {
3091 return NL "Everything works as expected.";
3092 }
3093
3094 GLuint m_program;
3095 GLuint m_storage_buffer;
3096
Setup()3097 virtual long Setup()
3098 {
3099 m_program = 0;
3100 m_storage_buffer = 0;
3101 return NO_ERROR;
3102 }
Run()3103 virtual long Run()
3104 {
3105 const char* const glsl_cs =
3106 NL "layout(local_size_x = 8) in;" NL "layout(std430, binding = 0) buffer Output {" NL
3107 " uint g_add_output[8];" NL " int g_sub_output[8];" NL "};" NL "shared uint g_add_value;" NL
3108 "shared int g_sub_value;" NL "void main() {" NL " if (gl_LocalInvocationIndex == 0u) {" NL
3109 " g_add_value = 0u;" NL " g_sub_value = 7;" NL " }" NL
3110 " g_add_output[gl_LocalInvocationIndex] = 0u;" NL " g_sub_output[gl_LocalInvocationIndex] = 0;" NL
3111 " groupMemoryBarrier();" NL " barrier();" NL
3112 " g_add_output[gl_LocalInvocationIndex] = atomicAdd(g_add_value, 1u);" NL
3113 " g_sub_output[gl_LocalInvocationIndex] = atomicAdd(g_sub_value, -1);" NL "}";
3114 m_program = CreateComputeProgram(glsl_cs);
3115 glLinkProgram(m_program);
3116 if (!CheckProgram(m_program))
3117 return ERROR;
3118
3119 glGenBuffers(1, &m_storage_buffer);
3120 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
3121 glBufferData(GL_SHADER_STORAGE_BUFFER, 16 * sizeof(int), NULL, GL_STATIC_DRAW);
3122
3123 glUseProgram(m_program);
3124 glDispatchCompute(1, 1, 1);
3125 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
3126
3127 int* data;
3128 data = static_cast<int*>(glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(int) * 8, GL_MAP_READ_BIT));
3129 std::sort(data, data + 8);
3130 long error = NO_ERROR;
3131 for (int i = 0; i < 8; ++i)
3132 {
3133 if (data[i] != i)
3134 {
3135 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Data at index " << i << " is "
3136 << data[i] << " should be " << i << tcu::TestLog::EndMessage;
3137 error = ERROR;
3138 }
3139 }
3140 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
3141
3142 data = static_cast<int*>(
3143 glMapBufferRange(GL_SHADER_STORAGE_BUFFER, sizeof(int) * 8, sizeof(int) * 8, GL_MAP_READ_BIT));
3144 std::sort(data, data + 8);
3145 for (int i = 0; i < 8; ++i)
3146 {
3147 if (data[i] != i)
3148 {
3149 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Data at index " << i << " is "
3150 << data[i] << " should be " << i << tcu::TestLog::EndMessage;
3151 error = ERROR;
3152 }
3153 }
3154 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
3155 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
3156 return error;
3157 }
Cleanup()3158 virtual long Cleanup()
3159 {
3160 glUseProgram(0);
3161 glDeleteProgram(m_program);
3162 glDeleteBuffers(1, &m_storage_buffer);
3163 return NO_ERROR;
3164 }
3165 };
3166
3167 class BasicAtomicCase2 : public ComputeShaderBase
3168 {
Title()3169 virtual std::string Title()
3170 {
3171 return NL "Atomic functions - buffer variables";
3172 }
Purpose()3173 virtual std::string Purpose()
3174 {
3175 return NL "1. Verify that all atomic functions (atomicExchange, atomicMin, atomicMax," NL
3176 " atomicAnd, atomicOr, atomicXor and atomicCompSwap) works as expected with buffer variables." NL
3177 "2. Verify that atomic functions work with parameters being constants and" NL
3178 " with parameters being uniforms." NL
3179 "3. Verify that barrier() built-in function can be used in a control flow.";
3180 }
Method()3181 virtual std::string Method()
3182 {
3183 return NL "1. Create CS that uses all atomic functions. Values returned by the atomic functions are written to "
3184 "SSBO." NL "2. Dispatch CS with DispatchCompute and DispatchComputeIndirect commands." NL
3185 "3. Verify SSBO content." NL
3186 "4. Repeat for different number of work groups and different work group sizes.";
3187 }
PassCriteria()3188 virtual std::string PassCriteria()
3189 {
3190 return NL "Everything works as expected.";
3191 }
3192
3193 GLuint m_program;
3194 GLuint m_storage_buffer[2];
3195 GLuint m_dispatch_buffer;
3196
GenSource(const uvec3 & local_size,const uvec3 & num_groups)3197 std::string GenSource(const uvec3& local_size, const uvec3& num_groups)
3198 {
3199 const uvec3 global_size = local_size * num_groups;
3200 std::stringstream ss;
3201 ss << NL "layout(local_size_x = " << local_size.x() << ", local_size_y = " << local_size.y()
3202 << ", local_size_z = " << local_size.z() << ") in;" NL "const uvec3 kGlobalSize = uvec3(" << global_size.x()
3203 << ", " << global_size.y() << ", " << global_size.z()
3204 << ");" NL "layout(std430, binding = 0) buffer OutputU {" NL " uint g_uint_out["
3205 << global_size.x() * global_size.y() * global_size.z()
3206 << "];" NL "};" NL "layout(std430, binding = 1) buffer OutputI {" NL " int data["
3207 << global_size.x() * global_size.y() * global_size.z()
3208 << "];" NL "} g_int_out;" NL "uniform uint g_uint_value[8];" NL "void main() {" NL
3209 " uint global_index = gl_GlobalInvocationID.x +" NL
3210 " gl_GlobalInvocationID.y * kGlobalSize.x +" NL
3211 " gl_GlobalInvocationID.z * kGlobalSize.x * kGlobalSize.y;" NL
3212 " atomicExchange(g_uint_out[global_index], g_uint_value[0]);" NL
3213 " atomicMin(g_uint_out[global_index], g_uint_value[1]);" NL
3214 " atomicMax(g_uint_out[global_index], g_uint_value[2]);" NL
3215 " atomicAnd(g_uint_out[global_index], g_uint_value[3]);" NL
3216 " atomicOr(g_uint_out[global_index], g_uint_value[4]);" NL " if (g_uint_value[0] > 0u) {" NL
3217 " barrier();" // not needed here, just check if compiler accepts it in a control flow
3218 NL " atomicXor(g_uint_out[global_index], g_uint_value[5]);" NL " }" NL
3219 " atomicCompSwap(g_uint_out[global_index], g_uint_value[6], g_uint_value[7]);" NL NL
3220 " atomicExchange(g_int_out.data[global_index], 3);" NL " atomicMin(g_int_out.data[global_index], 1);" NL
3221 " atomicMax(g_int_out.data[global_index], 2);" NL " atomicAnd(g_int_out.data[global_index], 0x1);" NL
3222 " atomicOr(g_int_out.data[global_index], 0x3);" NL " atomicXor(g_int_out.data[global_index], 0x1);" NL
3223 " atomicCompSwap(g_int_out.data[global_index], 0x2, 0x7);" NL "}";
3224 return ss.str();
3225 }
RunIteration(const uvec3 & local_size,const uvec3 & num_groups,bool dispatch_indirect)3226 bool RunIteration(const uvec3& local_size, const uvec3& num_groups, bool dispatch_indirect)
3227 {
3228 if (m_program != 0)
3229 glDeleteProgram(m_program);
3230 m_program = CreateComputeProgram(GenSource(local_size, num_groups));
3231 glLinkProgram(m_program);
3232 if (!CheckProgram(m_program))
3233 return false;
3234
3235 const GLuint kBufferSize =
3236 local_size.x() * num_groups.x() * local_size.y() * num_groups.y() * local_size.z() * num_groups.z();
3237
3238 if (m_storage_buffer[0] == 0)
3239 glGenBuffers(2, m_storage_buffer);
3240 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer[0]);
3241 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLuint) * kBufferSize, NULL, GL_DYNAMIC_DRAW);
3242 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, m_storage_buffer[1]);
3243 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLint) * kBufferSize, NULL, GL_DYNAMIC_DRAW);
3244
3245 glUseProgram(m_program);
3246 GLuint values[8] = { 3u, 1u, 2u, 0x1u, 0x3u, 0x1u, 0x2u, 0x7u };
3247 glUniform1uiv(glGetUniformLocation(m_program, "g_uint_value"), 8, values);
3248 if (dispatch_indirect)
3249 {
3250 if (m_dispatch_buffer == 0)
3251 glGenBuffers(1, &m_dispatch_buffer);
3252 glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer);
3253 glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(num_groups), &num_groups[0], GL_STATIC_DRAW);
3254 glDispatchComputeIndirect(0);
3255 }
3256 else
3257 {
3258 glDispatchCompute(num_groups.x(), num_groups.y(), num_groups.z());
3259 }
3260 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
3261
3262 bool res = true;
3263 GLuint* udata;
3264 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer[0]);
3265 udata = static_cast<GLuint*>(
3266 glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(GLuint) * kBufferSize, GL_MAP_READ_BIT));
3267 for (GLuint i = 0; i < kBufferSize; ++i)
3268 {
3269 if (udata[i] != 7)
3270 {
3271 m_context.getTestContext().getLog() << tcu::TestLog::Message << "uData at index " << i << " is "
3272 << udata[i] << " should be 7." << tcu::TestLog::EndMessage;
3273 res = false;
3274 }
3275 }
3276 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
3277 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
3278
3279 GLint* idata;
3280 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer[1]);
3281 idata = static_cast<GLint*>(
3282 glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(GLint) * kBufferSize, GL_MAP_READ_BIT));
3283 for (GLint i = 0; i < static_cast<GLint>(kBufferSize); ++i)
3284 {
3285 if (idata[i] != 7)
3286 {
3287 m_context.getTestContext().getLog() << tcu::TestLog::Message << "iData at index " << i << " is "
3288 << idata[i] << " should be 7." << tcu::TestLog::EndMessage;
3289 res = false;
3290 }
3291 }
3292 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
3293 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
3294 return res;
3295 }
Setup()3296 virtual long Setup()
3297 {
3298 m_program = 0;
3299 m_storage_buffer[0] = m_storage_buffer[1] = 0;
3300 m_dispatch_buffer = 0;
3301 return NO_ERROR;
3302 }
Run()3303 virtual long Run()
3304 {
3305 if (!RunIteration(uvec3(64, 1, 1), uvec3(8, 1, 1), false))
3306 return ERROR;
3307 if (!RunIteration(uvec3(1, 1, 64), uvec3(1, 5, 2), true))
3308 return ERROR;
3309 if (!RunIteration(uvec3(1, 1, 4), uvec3(2, 2, 2), false))
3310 return ERROR;
3311 if (!RunIteration(uvec3(3, 2, 1), uvec3(1, 2, 3), true))
3312 return ERROR;
3313 if (!RunIteration(uvec3(2, 4, 2), uvec3(2, 4, 1), false))
3314 return ERROR;
3315 if (!RunIteration(uvec3(2, 4, 7), uvec3(2, 1, 4), true))
3316 return ERROR;
3317 return NO_ERROR;
3318 }
Cleanup()3319 virtual long Cleanup()
3320 {
3321 glUseProgram(0);
3322 glDeleteProgram(m_program);
3323 glDeleteBuffers(2, m_storage_buffer);
3324 glDeleteBuffers(1, &m_dispatch_buffer);
3325 return NO_ERROR;
3326 }
3327 };
3328
3329 class BasicAtomicCase3 : public ComputeShaderBase
3330 {
Title()3331 virtual std::string Title()
3332 {
3333 return NL "Atomic functions - shared variables";
3334 }
Purpose()3335 virtual std::string Purpose()
3336 {
3337 return NL "1. Verify that all atomic functions (atomicExchange, atomicMin, atomicMax," NL
3338 " atomicAnd, atomicOr, atomicXor and atomicCompSwap) works as expected with shared variables." NL
3339 "2. Verify that atomic functions work with parameters being constants and" NL
3340 " with parameters being uniforms." NL
3341 "3. Verify that atomic functions can be used in a control flow.";
3342 }
Method()3343 virtual std::string Method()
3344 {
3345 return NL "1. Create CS that uses all atomic functions. Values returned by the atomic functions are written to "
3346 "SSBO." NL "2. Dispatch CS with DispatchCompute and DispatchComputeIndirect commands." NL
3347 "3. Verify SSBO content." NL
3348 "4. Repeat for different number of work groups and different work group sizes.";
3349 }
PassCriteria()3350 virtual std::string PassCriteria()
3351 {
3352 return NL "Everything works as expected.";
3353 }
3354
3355 GLuint m_program;
3356 GLuint m_storage_buffer;
3357 GLuint m_dispatch_buffer;
3358
GenSource(const uvec3 & local_size)3359 std::string GenSource(const uvec3& local_size)
3360 {
3361 std::stringstream ss;
3362 ss << NL "layout(local_size_x = " << local_size.x() << ", local_size_y = " << local_size.y()
3363 << ", local_size_z = " << local_size.z()
3364 << ") in;" NL "layout(std430, binding = 0) buffer Output {" NL " uint g_uint_out["
3365 << local_size.x() * local_size.y() * local_size.z() << "];" NL " int g_int_out["
3366 << local_size.x() * local_size.y() * local_size.z() << "];" NL "};" NL "shared uint g_shared_uint["
3367 << local_size.x() * local_size.y() * local_size.z() << "];" NL "shared int g_shared_int["
3368 << local_size.x() * local_size.y() * local_size.z()
3369 << "];" NL "uniform uint g_uint_value[8];" NL "void main() {" NL
3370 " atomicExchange(g_shared_uint[gl_LocalInvocationIndex], g_uint_value[0]);" NL
3371 " atomicMin(g_shared_uint[gl_LocalInvocationIndex], g_uint_value[1]);" NL
3372 " atomicMax(g_shared_uint[gl_LocalInvocationIndex], g_uint_value[2]);" NL
3373 " atomicAnd(g_shared_uint[gl_LocalInvocationIndex], g_uint_value[3]);" NL
3374 " atomicOr(g_shared_uint[gl_LocalInvocationIndex], g_uint_value[4]);" NL
3375 " atomicXor(g_shared_uint[gl_LocalInvocationIndex], g_uint_value[5]);" NL
3376 " atomicCompSwap(g_shared_uint[gl_LocalInvocationIndex], g_uint_value[6], g_uint_value[7]);" NL NL
3377 " atomicExchange(g_shared_int[gl_LocalInvocationIndex], 3);" NL
3378 " atomicMin(g_shared_int[gl_LocalInvocationIndex], 1);" NL
3379 " atomicMax(g_shared_int[gl_LocalInvocationIndex], 2);" NL
3380 " atomicAnd(g_shared_int[gl_LocalInvocationIndex], 0x1);" NL " if (g_uint_value[1] > 0u) {" NL
3381 " atomicOr(g_shared_int[gl_LocalInvocationIndex], 0x3);" NL
3382 " atomicXor(g_shared_int[gl_LocalInvocationIndex], 0x1);" NL
3383 " atomicCompSwap(g_shared_int[gl_LocalInvocationIndex], 0x2, 0x7);" NL " }" NL NL
3384 " g_uint_out[gl_LocalInvocationIndex] = g_shared_uint[gl_LocalInvocationIndex];" NL
3385 " g_int_out[gl_LocalInvocationIndex] = g_shared_int[gl_LocalInvocationIndex];" NL "}";
3386 return ss.str();
3387 }
RunIteration(const uvec3 & local_size,bool dispatch_indirect)3388 bool RunIteration(const uvec3& local_size, bool dispatch_indirect)
3389 {
3390 if (m_program != 0)
3391 glDeleteProgram(m_program);
3392 m_program = CreateComputeProgram(GenSource(local_size));
3393 glLinkProgram(m_program);
3394 if (!CheckProgram(m_program))
3395 return false;
3396
3397 const GLuint kBufferSize = local_size.x() * local_size.y() * local_size.z();
3398
3399 if (m_storage_buffer == 0)
3400 glGenBuffers(1, &m_storage_buffer);
3401 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
3402 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLuint) * kBufferSize * 2, NULL, GL_DYNAMIC_DRAW);
3403
3404 glUseProgram(m_program);
3405 GLuint values[8] = { 3u, 1u, 2u, 0x1u, 0x3u, 0x1u, 0x2u, 0x7u };
3406 glUniform1uiv(glGetUniformLocation(m_program, "g_uint_value"), 8, values);
3407 if (dispatch_indirect)
3408 {
3409 const GLuint num_groups[3] = { 1, 1, 1 };
3410 if (m_dispatch_buffer == 0)
3411 glGenBuffers(1, &m_dispatch_buffer);
3412 glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer);
3413 glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(num_groups), &num_groups[0], GL_STATIC_DRAW);
3414 glDispatchComputeIndirect(0);
3415 }
3416 else
3417 {
3418 glDispatchCompute(1, 1, 1);
3419 }
3420 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
3421
3422 bool ret = true;
3423 GLuint* udata;
3424 udata = static_cast<GLuint*>(
3425 glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(GLuint) * kBufferSize, GL_MAP_READ_BIT));
3426 for (GLuint i = 0; i < kBufferSize; ++i)
3427 {
3428 if (udata[i] != 7)
3429 {
3430 m_context.getTestContext().getLog() << tcu::TestLog::Message << "uData at index " << i << " is "
3431 << udata[i] << " should be 7." << tcu::TestLog::EndMessage;
3432 ret = false;
3433 }
3434 }
3435 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
3436
3437 GLint* idata;
3438 idata = static_cast<GLint*>(glMapBufferRange(GL_SHADER_STORAGE_BUFFER, sizeof(GLuint) * kBufferSize,
3439 sizeof(GLint) * kBufferSize, GL_MAP_READ_BIT));
3440 for (GLint i = 0; i < static_cast<GLint>(kBufferSize); ++i)
3441 {
3442 if (idata[i] != 7)
3443 {
3444 m_context.getTestContext().getLog() << tcu::TestLog::Message << "iData at index " << i << " is "
3445 << idata[i] << " should be 7." << tcu::TestLog::EndMessage;
3446 ret = false;
3447 }
3448 }
3449 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
3450 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
3451
3452 return ret;
3453 }
Setup()3454 virtual long Setup()
3455 {
3456 m_program = 0;
3457 m_storage_buffer = 0;
3458 m_dispatch_buffer = 0;
3459 return NO_ERROR;
3460 }
Run()3461 virtual long Run()
3462 {
3463 if (!RunIteration(uvec3(64, 1, 1), false))
3464 return ERROR;
3465 if (!RunIteration(uvec3(1, 1, 64), true))
3466 return ERROR;
3467 if (!RunIteration(uvec3(1, 1, 4), false))
3468 return ERROR;
3469 if (!RunIteration(uvec3(3, 2, 1), true))
3470 return ERROR;
3471 if (!RunIteration(uvec3(2, 4, 2), false))
3472 return ERROR;
3473 if (!RunIteration(uvec3(2, 4, 7), true))
3474 return ERROR;
3475 return NO_ERROR;
3476 }
Cleanup()3477 virtual long Cleanup()
3478 {
3479 glUseProgram(0);
3480 glDeleteProgram(m_program);
3481 glDeleteBuffers(1, &m_storage_buffer);
3482 glDeleteBuffers(1, &m_dispatch_buffer);
3483 return NO_ERROR;
3484 }
3485 };
3486
3487 class AdvancedCopyImage : public ComputeShaderBase
3488 {
Title()3489 virtual std::string Title()
3490 {
3491 return NL "Copy Image";
3492 }
Purpose()3493 virtual std::string Purpose()
3494 {
3495 return NL "Verify that copying two textures using CS works as expected.";
3496 }
Method()3497 virtual std::string Method()
3498 {
3499 return NL "Use shader image load and store operations to copy two textures in the CS.";
3500 }
PassCriteria()3501 virtual std::string PassCriteria()
3502 {
3503 return NL "Everything works as expected.";
3504 }
3505
3506 GLuint m_program;
3507 GLuint m_texture[2];
3508 GLuint m_fbo;
3509
Setup()3510 virtual long Setup()
3511 {
3512 m_program = 0;
3513 m_fbo = 0;
3514 memset(m_texture, 0, sizeof(m_texture));
3515 return NO_ERROR;
3516 }
Run()3517 virtual long Run()
3518 {
3519 const char* const glsl_cs =
3520 NL "#define TILE_WIDTH 8" NL "#define TILE_HEIGHT 8" NL
3521 "const ivec2 kTileSize = ivec2(TILE_WIDTH, TILE_HEIGHT);" NL NL
3522 "layout(binding = 0, rgba8) readonly uniform mediump image2D g_input_image;" NL
3523 "layout(binding = 1, rgba8) writeonly uniform mediump image2D g_output_image;" NL NL
3524 "layout(local_size_x=TILE_WIDTH, local_size_y=TILE_HEIGHT) in;" NL NL "void main() {" NL
3525 " ivec2 tile_xy = ivec2(gl_WorkGroupID);" NL " ivec2 thread_xy = ivec2(gl_LocalInvocationID);" NL
3526 " ivec2 pixel_xy = tile_xy * kTileSize + thread_xy;" NL NL
3527 " vec4 pixel = imageLoad(g_input_image, pixel_xy);" NL
3528 " imageStore(g_output_image, pixel_xy, pixel);" NL "}";
3529 m_program = CreateComputeProgram(glsl_cs);
3530 glLinkProgram(m_program);
3531 if (!CheckProgram(m_program))
3532 return ERROR;
3533
3534 std::vector<GLubyte> in_image(64 * 64 * 4, 0x0f);
3535 std::vector<GLubyte> out_image(64 * 64 * 4, 0xff);
3536
3537 glGenTextures(2, m_texture);
3538 glBindTexture(GL_TEXTURE_2D, m_texture[0]);
3539 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
3540 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 64, 64);
3541 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 64, 64, GL_RGBA, GL_UNSIGNED_BYTE, &in_image[0]);
3542
3543 glBindTexture(GL_TEXTURE_2D, m_texture[1]);
3544 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
3545 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 64, 64);
3546 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 64, 64, GL_RGBA, GL_UNSIGNED_BYTE, &out_image[0]);
3547
3548 glUseProgram(m_program);
3549 glBindImageTexture(0, m_texture[0], 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA8);
3550 glBindImageTexture(1, m_texture[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA8);
3551 glDispatchCompute(9, 8,
3552 1); // 9 is on purpose, to ensure that out of bounds image load and stores have no effect
3553 glMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT);
3554
3555 std::vector<GLubyte> data(64 * 64 * 4);
3556 glGenFramebuffers(1, &m_fbo);
3557 glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
3558 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture[1], 0);
3559 glReadPixels(0, 0, 64, 64, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]);
3560 for (std::size_t i = 0; i < data.size(); ++i)
3561 {
3562 if (data[i] != 0x0f)
3563 {
3564 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Data at index " << i << " is "
3565 << data[i] << " should be " << 0x0f << tcu::TestLog::EndMessage;
3566 return ERROR;
3567 }
3568 }
3569
3570 return NO_ERROR;
3571 }
Cleanup()3572 virtual long Cleanup()
3573 {
3574 glUseProgram(0);
3575 glDeleteProgram(m_program);
3576 glDeleteFramebuffers(1, &m_fbo);
3577 glDeleteTextures(2, m_texture);
3578 return NO_ERROR;
3579 }
3580 };
3581
3582 class AdvancedPipelinePreVS : public ComputeShaderBase
3583 {
Title()3584 virtual std::string Title()
3585 {
3586 return NL "CS as an additional pipeline stage - Before VS (1)";
3587 }
Purpose()3588 virtual std::string Purpose()
3589 {
3590 return NL "Verify that CS which runs just before VS and modifies VBO content works as expected.";
3591 }
Method()3592 virtual std::string Method()
3593 {
3594 return NL "1. Prepare VBO and VAO for a drawing operation." NL "2. Run CS to modify existing VBO content." NL
3595 "3. Issue MemoryBarrier(GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT) command." NL
3596 "4. Issue draw call command." NL "5. Verify that the framebuffer content is as expected.";
3597 }
PassCriteria()3598 virtual std::string PassCriteria()
3599 {
3600 return NL "Everything works as expected.";
3601 }
3602
3603 GLuint m_program[2];
3604 GLuint m_vertex_buffer;
3605 GLuint m_vertex_array;
3606
Setup()3607 virtual long Setup()
3608 {
3609 memset(m_program, 0, sizeof(m_program));
3610 m_vertex_buffer = 0;
3611 m_vertex_array = 0;
3612 return NO_ERROR;
3613 }
Run()3614 virtual long Run()
3615 {
3616 const char* const glsl_cs = NL "layout(local_size_x = 4) in;" NL "struct Vertex {" NL " vec4 position;" NL
3617 " vec4 color;" NL "};" NL "layout(binding = 0, std430) buffer VertexBuffer {" NL
3618 " Vertex g_vertex[];" NL "};" NL "uniform float g_scale;" NL "void main() {" NL
3619 " g_vertex[gl_GlobalInvocationID.x].position.xyz *= g_scale;" NL
3620 " g_vertex[gl_GlobalInvocationID.x].color *= vec4(0.0, 1.0, 0.0, 1.0);" NL "}";
3621 m_program[0] = CreateComputeProgram(glsl_cs);
3622 glLinkProgram(m_program[0]);
3623 glUseProgram(m_program[0]);
3624 glUniform1f(glGetUniformLocation(m_program[0], "g_scale"), 0.8f);
3625 glUseProgram(0);
3626 if (!CheckProgram(m_program[0]))
3627 return ERROR;
3628
3629 const char* const glsl_vs =
3630 NL "layout(location = 0) in mediump vec4 g_position;" NL "layout(location = 1) in mediump vec4 g_color;" NL
3631 "flat out mediump vec4 color;" NL "void main() {" NL " gl_Position = g_position;" NL
3632 " color = g_color;" NL "}";
3633 const char* const glsl_fs =
3634 NL "flat in mediump vec4 color;" NL "layout(location = 0) out mediump vec4 g_color;" NL "void main() {" NL
3635 " g_color = color;" NL "}";
3636 m_program[1] = CreateProgram(glsl_vs, glsl_fs);
3637 glLinkProgram(m_program[1]);
3638 if (!CheckProgram(m_program[1]))
3639 return ERROR;
3640
3641 /* vertex buffer */
3642 {
3643 const float data[] = { -1, -1, 0, 1, 1, 1, 1, 1, 1, -1, 0, 1, 1, 1, 1, 1,
3644 -1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1 };
3645 glGenBuffers(1, &m_vertex_buffer);
3646 glBindBuffer(GL_ARRAY_BUFFER, m_vertex_buffer);
3647 glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
3648 glBindBuffer(GL_ARRAY_BUFFER, 0);
3649 }
3650
3651 glGenVertexArrays(1, &m_vertex_array);
3652 glBindVertexArray(m_vertex_array);
3653 glBindBuffer(GL_ARRAY_BUFFER, m_vertex_buffer);
3654 glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 2 * sizeof(vec4), 0);
3655 glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 2 * sizeof(vec4), reinterpret_cast<void*>(sizeof(vec4)));
3656 glBindBuffer(GL_ARRAY_BUFFER, 0);
3657 glEnableVertexAttribArray(0);
3658 glEnableVertexAttribArray(1);
3659 glBindVertexArray(0);
3660
3661 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_vertex_buffer);
3662 glUseProgram(m_program[0]);
3663 glDispatchCompute(1, 1, 1);
3664
3665 glClear(GL_COLOR_BUFFER_BIT);
3666 glUseProgram(m_program[1]);
3667 glBindVertexArray(m_vertex_array);
3668 glMemoryBarrier(GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT);
3669 glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, 1);
3670
3671 if (getWindowWidth() < 500 &&
3672 !ValidateReadBufferCenteredQuad(getWindowWidth(), getWindowHeight(), vec3(0, 1, 0)))
3673 {
3674 return ERROR;
3675 }
3676 return NO_ERROR;
3677 }
Cleanup()3678 virtual long Cleanup()
3679 {
3680 glUseProgram(0);
3681 for (int i = 0; i < 2; ++i)
3682 glDeleteProgram(m_program[i]);
3683 glDeleteBuffers(1, &m_vertex_buffer);
3684 glDeleteVertexArrays(1, &m_vertex_array);
3685 return NO_ERROR;
3686 }
3687 };
3688
3689 class AdvancedPipelineGenDrawCommands : public ComputeShaderBase
3690 {
Title()3691 virtual std::string Title()
3692 {
3693 return NL "CS as an additional pipeline stage - Before VS (2)";
3694 }
Purpose()3695 virtual std::string Purpose()
3696 {
3697 return NL "Verify that a complex scenario where CS is used to generate drawing commands" NL
3698 "and write them to a draw indirect buffer works as expected. This is a practial usage of CS." NL
3699 "CS is used for culling objects which are outside of the viewing frustum.";
3700 }
Method()3701 virtual std::string Method()
3702 {
3703 return NL "1. Run CS which will generate four sets of draw call parameters and write them to the draw indirect "
3704 "buffer." NL "2. One set of draw call parameters will be: 0, 0, 0, 0" NL
3705 " (which means that an object is outside of the viewing frustum and should not be drawn)." NL
3706 "3. Issue MemoryBarrier(GL_COMMAND_BARRIER_BIT) command." NL
3707 "4. Issue four draw indirect commands." NL "5. Verify that the framebuffer content is as expected.";
3708 }
PassCriteria()3709 virtual std::string PassCriteria()
3710 {
3711 return NL "Everything works as expected.";
3712 }
3713
3714 GLuint m_program[2];
3715 GLuint m_vertex_buffer;
3716 GLuint m_index_buffer;
3717 GLuint m_vertex_array;
3718 GLuint m_draw_buffer;
3719 GLuint m_object_buffer;
3720
Setup()3721 virtual long Setup()
3722 {
3723 memset(m_program, 0, sizeof(m_program));
3724 m_vertex_buffer = 0;
3725 m_index_buffer = 0;
3726 m_vertex_array = 0;
3727 m_draw_buffer = 0;
3728 m_object_buffer = 0;
3729 return NO_ERROR;
3730 }
Run()3731 virtual long Run()
3732 {
3733 GLint res;
3734 glGetIntegerv(GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, &res);
3735 if (res <= 0)
3736 {
3737 OutputNotSupported("GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS <= 0");
3738 return NOT_SUPPORTED;
3739 }
3740
3741 const char* const glsl_cs =
3742 NL "layout(local_size_x = 4) in;" NL "struct DrawCommand {" NL " uint count;" NL
3743 " uint instance_count;" NL " uint first_index;" NL " int base_vertex;" NL " uint base_instance;" NL
3744 "};" NL "layout(std430) buffer;" NL "layout(binding = 0) readonly buffer ObjectBuffer {" NL
3745 " mat4 transform[4];" NL " uint count[4];" NL " uint first_index[4];" NL "} g_objects;" NL
3746 "layout(binding = 1) writeonly buffer DrawCommandBuffer {" NL " DrawCommand g_command[4];" NL "};" NL
3747 "bool IsObjectVisible(uint id) {" NL
3748 " if (g_objects.transform[id][3].x < -1.0 || g_objects.transform[id][3].x > 1.0) return false;" NL
3749 " if (g_objects.transform[id][3][1] < -1.0 || g_objects.transform[id][3][1] > 1.0) return false;" NL
3750 " if (g_objects.transform[id][3][2] < -1.0 || g_objects.transform[id][3].z > 1.0) return false;" NL
3751 " return true;" NL "}" NL "void main() {" NL " uint id = gl_GlobalInvocationID.x;" NL
3752 " g_command[id].count = 0u;" NL " g_command[id].instance_count = 0u;" NL
3753 " g_command[id].first_index = 0u;" NL " g_command[id].base_vertex = int(0);" NL
3754 " g_command[id].base_instance = 0u;" NL " if (IsObjectVisible(id)) {" NL
3755 " g_command[id].count = g_objects.count[id];" NL " g_command[id].instance_count = 1u;" NL
3756 " g_command[id].first_index = g_objects.first_index[id];" NL " }" NL "}";
3757 m_program[0] = CreateComputeProgram(glsl_cs);
3758 glLinkProgram(m_program[0]);
3759 if (!CheckProgram(m_program[0]))
3760 return ERROR;
3761
3762 const char* const glsl_vs =
3763 NL "layout(location = 0) in mediump vec4 g_position;" NL "layout(location = 1) in mediump vec3 g_color;" NL
3764 "flat out mediump vec3 color;" NL "layout(binding = 0, std430) buffer ObjectBuffer {" NL
3765 " mediump mat4 transform[4];" NL " uint count[4];" NL " uint first_index[4];" NL "} g_objects;" NL
3766 "uniform int g_object_id;" NL "void main() {" NL
3767 " gl_Position = g_objects.transform[g_object_id] * g_position;" NL " color = g_color;" NL "}";
3768 const char* const glsl_fs =
3769 NL "flat in mediump vec3 color;" NL "layout(location = 0) out mediump vec4 g_color;" NL "void main() {" NL
3770 " g_color = vec4(color, 1.0);" NL "}";
3771 m_program[1] = CreateProgram(glsl_vs, glsl_fs);
3772 glLinkProgram(m_program[1]);
3773 if (!CheckProgram(m_program[1]))
3774 return ERROR;
3775 glViewport(0, 0, 100, 100);
3776
3777 /* object buffer */
3778 {
3779 struct
3780 {
3781 mat4 transform[4];
3782 GLuint count[4];
3783 GLuint first_index[4];
3784 } data = {
3785 { tcu::translationMatrix(vec3(-1.5f, -0.5f, 0.0f)), tcu::translationMatrix(vec3(0.5f, -0.5f, 0.0f)),
3786 tcu::translationMatrix(vec3(-0.5f, 0.5f, 0.0f)), tcu::translationMatrix(vec3(0.5f, 0.5f, 0.0f)) },
3787 { 4, 4, 4, 4 },
3788 { 0, 4, 8, 12 }
3789 };
3790 glGenBuffers(1, &m_object_buffer);
3791 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_object_buffer);
3792 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(data), &data, GL_STATIC_DRAW);
3793 }
3794 /* vertex buffer */
3795 {
3796 const vec3 data[] = { vec3(-0.4f, -0.4f, 0.0f), vec3(1, 0, 0), vec3(0.4f, -0.4f, 0.0f), vec3(1, 0, 0),
3797 vec3(-0.4f, 0.4f, 0.0f), vec3(1, 0, 0), vec3(0.4f, 0.4f, 0.0f), vec3(1, 0, 0),
3798 vec3(-0.4f, -0.4f, 0.0f), vec3(0, 1, 0), vec3(0.4f, -0.4f, 0.0f), vec3(0, 1, 0),
3799 vec3(-0.4f, 0.4f, 0.0f), vec3(0, 1, 0), vec3(0.4f, 0.4f, 0.0f), vec3(0, 1, 0),
3800 vec3(-0.4f, -0.4f, 0.0f), vec3(0, 0, 1), vec3(0.4f, -0.4f, 0.0f), vec3(0, 0, 1),
3801 vec3(-0.4f, 0.4f, 0.0f), vec3(0, 0, 1), vec3(0.4f, 0.4f, 0.0f), vec3(0, 0, 1),
3802 vec3(-0.4f, -0.4f, 0.0f), vec3(1, 1, 0), vec3(0.4f, -0.4f, 0.0f), vec3(1, 1, 0),
3803 vec3(-0.4f, 0.4f, 0.0f), vec3(1, 1, 0), vec3(0.4f, 0.4f, 0.0f), vec3(1, 1, 0) };
3804 glGenBuffers(1, &m_vertex_buffer);
3805 glBindBuffer(GL_ARRAY_BUFFER, m_vertex_buffer);
3806 glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
3807 glBindBuffer(GL_ARRAY_BUFFER, 0);
3808 }
3809 /* index buffer */
3810 {
3811 const GLushort data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
3812 glGenBuffers(1, &m_index_buffer);
3813 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_index_buffer);
3814 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(data), data, GL_DYNAMIC_DRAW);
3815 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
3816 }
3817 glGenBuffers(1, &m_draw_buffer);
3818 glBindBuffer(GL_DRAW_INDIRECT_BUFFER, m_draw_buffer);
3819 glBufferData(GL_DRAW_INDIRECT_BUFFER, 4 * sizeof(GLuint) * 5, NULL, GL_DYNAMIC_DRAW);
3820 glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0);
3821
3822 glGenVertexArrays(1, &m_vertex_array);
3823 glBindVertexArray(m_vertex_array);
3824 glBindBuffer(GL_ARRAY_BUFFER, m_vertex_buffer);
3825 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 2 * sizeof(vec3), 0);
3826 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 2 * sizeof(vec3), reinterpret_cast<void*>(sizeof(vec3)));
3827 glBindBuffer(GL_ARRAY_BUFFER, 0);
3828 glEnableVertexAttribArray(0);
3829 glEnableVertexAttribArray(1);
3830 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_index_buffer);
3831 glBindVertexArray(0);
3832
3833 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, m_draw_buffer);
3834 glUseProgram(m_program[0]);
3835 glDispatchCompute(1, 1, 1);
3836
3837 glClear(GL_COLOR_BUFFER_BIT);
3838 glUseProgram(m_program[1]);
3839 glBindVertexArray(m_vertex_array);
3840 glBindBuffer(GL_DRAW_INDIRECT_BUFFER, m_draw_buffer);
3841 glMemoryBarrier(GL_COMMAND_BARRIER_BIT);
3842 /* draw (CPU draw calls dispatch, could be done by the GPU with ARB_multi_draw_indirect) */
3843 {
3844 GLsizeiptr offset = 0;
3845 for (int i = 0; i < 4; ++i)
3846 {
3847 glUniform1i(glGetUniformLocation(m_program[1], "g_object_id"), i);
3848 glDrawElementsIndirect(GL_TRIANGLE_STRIP, GL_UNSIGNED_SHORT, reinterpret_cast<void*>(offset));
3849 offset += 5 * sizeof(GLuint);
3850 }
3851 }
3852 if (getWindowWidth() >= 100 && getWindowHeight() >= 100 &&
3853 !ValidateWindow4Quads(vec3(0), vec3(0, 1, 0), vec3(1, 1, 0), vec3(0, 0, 1)))
3854 {
3855 return ERROR;
3856 }
3857 return NO_ERROR;
3858 }
Cleanup()3859 virtual long Cleanup()
3860 {
3861 glUseProgram(0);
3862 for (int i = 0; i < 2; ++i)
3863 glDeleteProgram(m_program[i]);
3864 glDeleteBuffers(1, &m_vertex_buffer);
3865 glDeleteBuffers(1, &m_index_buffer);
3866 glDeleteVertexArrays(1, &m_vertex_array);
3867 glDeleteBuffers(1, &m_draw_buffer);
3868 glDeleteBuffers(1, &m_object_buffer);
3869 glViewport(0, 0, getWindowWidth(), getWindowHeight());
3870 return NO_ERROR;
3871 }
3872 };
3873
3874 class AdvancedPipelineComputeChain : public ComputeShaderBase
3875 {
Title()3876 virtual std::string Title()
3877 {
3878 return NL "Compute Chain";
3879 }
Purpose()3880 virtual std::string Purpose()
3881 {
3882 return NL "1. Verify that dispatching several compute kernels that work in a sequence" NL
3883 " with a common set of resources works as expected." NL
3884 "2. Verify that indexing nested structures with built-in variables work as expected." NL
3885 "3. Verify that two kernels can write to the same resource without MemoryBarrier" NL
3886 " command if target regions of memory do not overlap.";
3887 }
Method()3888 virtual std::string Method()
3889 {
3890 return NL "1. Create a set of GPU resources (buffers, images, atomic counters)." NL
3891 "2. Dispatch Kernel0 that write to these resources." NL "3. Issue MemoryBarrier command." NL
3892 "4. Dispatch Kernel1 that read/write from/to these resources." NL "5. Issue MemoryBarrier command." NL
3893 "6. Dispatch Kernel2 that read/write from/to these resources." NL
3894 "7. Verify that content of all resources is as expected.";
3895 }
PassCriteria()3896 virtual std::string PassCriteria()
3897 {
3898 return NL "Everything works as expected.";
3899 }
3900
3901 GLuint m_program[3];
3902 GLuint m_storage_buffer[4];
3903 GLuint m_counter_buffer;
3904 GLuint m_texture;
3905 GLuint m_fbo;
3906
Common()3907 std::string Common()
3908 {
3909 return NL "precision highp image2D;" NL "struct S0 {" NL " int m0[8];" NL "};" NL "struct S1 {" NL
3910 " S0 m0[8];" NL "};" NL "layout(binding = 0, std430) buffer Buffer0 {" NL " int m0[5];" NL
3911 " S1 m1[8];" NL "} g_buffer0;" NL "layout(binding = 1, std430) buffer Buffer1 {" NL
3912 " uint data[8];" NL "} g_buffer1;" NL "layout(binding = 2, std430) buffer Buffer2 {" NL
3913 " int data[256];" NL "} g_buffer2;" NL "layout(binding = 3, std430) buffer Buffer3 {" NL
3914 " int data[256];" NL "} g_buffer3;" NL "layout(binding = 4, std430) buffer Buffer4 {" NL
3915 " mat4 data0;" NL " mat4 data1;" NL "} g_buffer4;" NL
3916 "layout(binding = 0, rgba8) writeonly uniform mediump image2D g_image0;" NL
3917 "layout(binding = 0, offset = 8) uniform atomic_uint g_counter[2];";
3918 }
GenGLSL(int p)3919 std::string GenGLSL(int p)
3920 {
3921 std::stringstream ss;
3922 ss << Common();
3923 if (p == 0)
3924 {
3925 ss << NL "layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in;" NL
3926 "void UpdateBuffer0(uvec3 id, int add_val) {" NL " if (id.x < 8u && id.y < 8u && id.z < 8u) {" NL
3927 " g_buffer0.m1[id.z].m0[id.y].m0[id.x] += add_val;" NL " }" NL "}" NL
3928 "uniform int g_add_value;" NL "uniform uint g_counter_y;" NL "uniform vec4 g_image_value;" NL
3929 "void main() {" NL " uvec3 id = gl_GlobalInvocationID;" NL " UpdateBuffer0(id, 1);" NL
3930 " UpdateBuffer0(id, g_add_value);" NL " if (id == uvec3(1, g_counter_y, 1)) {" NL
3931 " uint idx = atomicCounterIncrement(g_counter[1]);" NL " g_buffer1.data[idx] = idx;" NL
3932 " idx = atomicCounterIncrement(g_counter[1]);" NL " g_buffer1.data[idx] = idx;" NL " }" NL
3933 " if (id.x < 4u && id.y < 4u && id.z == 0u) {" NL
3934 " imageStore(g_image0, ivec2(id.xy), g_image_value);" NL " }" NL
3935 " if (id.x < 2u && id.y == 0u && id.z == 0u) {" NL
3936 " g_buffer2.data[id.x] -= int(g_counter_y);" NL " }" NL "}";
3937 }
3938 else if (p == 1)
3939 {
3940 ss << NL "layout(local_size_x = 4, local_size_y = 4, local_size_z = 1) in;"
3941 // translation matrix
3942 NL "uniform mat4 g_mvp;" NL "void main() {" NL " if (gl_GlobalInvocationID == uvec3(0)) {" NL
3943 " g_buffer4.data0 *= g_mvp;" NL " }" NL " if (gl_WorkGroupID == uvec3(0)) {" NL
3944 " g_buffer4.data1[gl_LocalInvocationID.y][gl_LocalInvocationID.x] = "
3945 "g_mvp[gl_LocalInvocationID.x][gl_LocalInvocationID.y];" NL " }" NL "}";
3946 }
3947 else if (p == 2)
3948 {
3949 ss << NL "layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in;" NL "void main() {" NL "}";
3950 }
3951 return ss.str();
3952 }
Setup()3953 virtual long Setup()
3954 {
3955 memset(m_program, 0, sizeof(m_program));
3956 memset(m_storage_buffer, 0, sizeof(m_storage_buffer));
3957 m_counter_buffer = 0;
3958 m_texture = 0;
3959 m_fbo = 0;
3960 return NO_ERROR;
3961 }
Run()3962 virtual long Run()
3963 {
3964 using namespace tcu;
3965
3966 for (int i = 0; i < 3; ++i)
3967 {
3968 m_program[i] = CreateComputeProgram(GenGLSL(i));
3969 glLinkProgram(m_program[i]);
3970 if (i == 0)
3971 {
3972 glUseProgram(m_program[i]);
3973 glUniform1i(glGetUniformLocation(m_program[i], "g_add_value"), 1);
3974 glUniform1ui(glGetUniformLocation(m_program[i], "g_counter_y"), 1u);
3975 glUniform4f(glGetUniformLocation(m_program[i], "g_image_value"), 0.25f, 0.5f, 0.75f, 1.0f);
3976 glUseProgram(0);
3977 }
3978 else if (i == 1)
3979 {
3980 glUseProgram(m_program[i]);
3981 GLfloat values[16] = { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
3982 0.0f, 0.0f, 1.0f, 0.0f, 10.0f, 20.0f, 30.0f, 1.0f };
3983 glUniformMatrix4fv(glGetUniformLocation(m_program[i], "g_mvp"), 1, GL_FALSE, values);
3984 glUseProgram(0);
3985 }
3986 if (!CheckProgram(m_program[i]))
3987 return ERROR;
3988 }
3989
3990 glGenBuffers(4, m_storage_buffer);
3991 /* storage buffer 0 */
3992 {
3993 std::vector<int> data(5 + 8 * 8 * 8);
3994 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer[0]);
3995 glBufferData(GL_SHADER_STORAGE_BUFFER, (GLsizeiptr)(data.size() * sizeof(int)), &data[0], GL_STATIC_COPY);
3996 }
3997 /* storage buffer 1 */
3998 {
3999 const GLuint data[8] = { 0 };
4000 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, m_storage_buffer[1]);
4001 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(data), data, GL_STATIC_COPY);
4002 }
4003 /* storage buffer 2 & 3 */
4004 {
4005 std::vector<GLint> data(512, 7);
4006 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer[2]);
4007 glBufferData(GL_SHADER_STORAGE_BUFFER, (GLsizeiptr)(data.size() * sizeof(GLint)), &data[0], GL_STATIC_COPY);
4008
4009 glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 2, m_storage_buffer[2], 0,
4010 (GLsizeiptr)(sizeof(GLint) * data.size() / 2));
4011 glBindBufferRange(GL_SHADER_STORAGE_BUFFER, 3, m_storage_buffer[2],
4012 (GLintptr)(sizeof(GLint) * data.size() / 2),
4013 (GLsizeiptr)(sizeof(GLint) * data.size() / 2));
4014 }
4015 /* storage buffer 4 */
4016 {
4017 std::vector<mat4> data(2);
4018 data[0] = mat4(1);
4019 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 4, m_storage_buffer[3]);
4020 glBufferData(GL_SHADER_STORAGE_BUFFER, (GLsizeiptr)(data.size() * sizeof(mat4)), &data[0], GL_STATIC_COPY);
4021 }
4022 /* counter buffer */
4023 {
4024 GLuint data[4] = { 0 };
4025 glGenBuffers(1, &m_counter_buffer);
4026 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, m_counter_buffer);
4027 glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(data), data, GL_STATIC_COPY);
4028 }
4029 /* texture */
4030 {
4031 std::vector<GLint> data(4 * 4 * 4, 0);
4032 glGenTextures(1, &m_texture);
4033 glBindTexture(GL_TEXTURE_2D, m_texture);
4034 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
4035 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
4036 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 4, 4);
4037 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 4, 4, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]);
4038 glBindTexture(GL_TEXTURE_2D, 0);
4039 }
4040
4041 glUseProgram(m_program[0]);
4042 glBindImageTexture(0, m_texture, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA8);
4043 glDispatchCompute(2, 2, 2);
4044 glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT | GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
4045 glDispatchCompute(3, 2, 2);
4046
4047 glUseProgram(m_program[1]);
4048 glDispatchCompute(4, 3, 7);
4049
4050 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT | GL_TEXTURE_UPDATE_BARRIER_BIT |
4051 GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
4052
4053 long error = NO_ERROR;
4054 /* validate storage buffer 0 */
4055 {
4056 int* data;
4057 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer[0]);
4058 data = static_cast<int*>(
4059 glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(int) * (5 + 8 * 8 * 8), GL_MAP_READ_BIT));
4060 for (std::size_t i = 5; i < 5 + 8 * 8 * 8; ++i)
4061 {
4062 if (data[i] != 4)
4063 {
4064 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Data is: " << data[i]
4065 << " should be: 2." << tcu::TestLog::EndMessage;
4066 error = ERROR;
4067 }
4068 }
4069 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
4070 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
4071 }
4072 /* validate storage buffer 1 */
4073 {
4074 GLuint* data;
4075 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer[1]);
4076 data = static_cast<GLuint*>(
4077 glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(GLuint) * 8, GL_MAP_READ_BIT));
4078 for (GLuint i = 0; i < 4; ++i)
4079 {
4080 if (data[i] != i)
4081 {
4082 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Data is: " << data[i]
4083 << " should be: " << i << tcu::TestLog::EndMessage;
4084 error = ERROR;
4085 }
4086 }
4087 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
4088 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
4089 }
4090 /* validate storage buffer 2 & 3 */
4091 {
4092 GLint* data;
4093 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer[2]);
4094 data = static_cast<GLint*>(
4095 glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(GLint) * 512, GL_MAP_READ_BIT));
4096 for (int i = 0; i < 2; ++i)
4097 {
4098 if (data[i] != 5)
4099 {
4100 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Data is: " << data[i]
4101 << " should be: 5." << tcu::TestLog::EndMessage;
4102 error = ERROR;
4103 }
4104 if (data[i + 256] != 7)
4105 {
4106 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Data is: " << data[i + 256]
4107 << " should be: 7." << tcu::TestLog::EndMessage;
4108 error = ERROR;
4109 }
4110 }
4111 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
4112 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
4113 }
4114 /* validate storage buffer 4 */
4115 {
4116 mat4* data;
4117 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer[3]);
4118 data = static_cast<mat4*>(glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(mat4) * 2, GL_MAP_READ_BIT));
4119 if (transpose(data[1]) != translationMatrix(vec3(10.0f, 20.0f, 30.0f)))
4120 {
4121 m_context.getTestContext().getLog()
4122 << tcu::TestLog::Message << "Data is incorrect." << tcu::TestLog::EndMessage;
4123 error = ERROR;
4124 }
4125 if (transpose(data[0]) != transpose(translationMatrix(vec3(10.0f, 20.0f, 30.0f))))
4126 {
4127 m_context.getTestContext().getLog()
4128 << tcu::TestLog::Message << "Data is incorrect." << tcu::TestLog::EndMessage;
4129 error = ERROR;
4130 }
4131 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
4132 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
4133 }
4134 /* validate counter buffer */
4135 {
4136 GLuint* data;
4137 data = static_cast<GLuint*>(
4138 glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint) * 4, GL_MAP_READ_BIT));
4139 if (data[3] != 4)
4140 {
4141 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Data is: " << data[3]
4142 << " should be: " << 4 << tcu::TestLog::EndMessage;
4143 error = ERROR;
4144 }
4145 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
4146 }
4147 /* validate texture */
4148 {
4149 std::vector<vec4> data(4 * 4);
4150 glBindTexture(GL_TEXTURE_2D, m_texture);
4151 glGenFramebuffers(1, &m_fbo);
4152 glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
4153 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture, 0);
4154 std::vector<GLubyte> colorData(4 * 4 * 4);
4155 glReadPixels(0, 0, 4, 4, GL_RGBA, GL_UNSIGNED_BYTE, &colorData[0]);
4156 for (int i = 0; i < 4 * 4 * 4; i += 4)
4157 {
4158 data[i / 4] =
4159 vec4(static_cast<GLfloat>(colorData[i] / 255.), static_cast<GLfloat>(colorData[i + 1] / 255.),
4160 static_cast<GLfloat>(colorData[i + 2] / 255.), static_cast<GLfloat>(colorData[i + 3] / 255.));
4161 }
4162 vec4 epsilon = vec4(1.0f / 255.0f, 1.0f / 255.0f, 1.0f / 255.0f, 1.0f / 255.0f); // texture format is RGBA8.
4163 for (std::size_t i = 0; i < data.size(); ++i)
4164 {
4165 if (!ColorEqual(data[i], vec4(0.25f, 0.5f, 0.75f, 1.0f), epsilon))
4166 {
4167 m_context.getTestContext().getLog()
4168 << tcu::TestLog::Message << "Invalid data at texture." << tcu::TestLog::EndMessage;
4169 return ERROR;
4170 }
4171 }
4172 }
4173
4174 return error;
4175 }
Cleanup()4176 virtual long Cleanup()
4177 {
4178 glUseProgram(0);
4179 for (int i = 0; i < 3; ++i)
4180 glDeleteProgram(m_program[i]);
4181 glDeleteBuffers(4, m_storage_buffer);
4182 glDeleteBuffers(1, &m_counter_buffer);
4183 glDeleteTextures(1, &m_texture);
4184 glDeleteFramebuffers(1, &m_fbo);
4185 return NO_ERROR;
4186 }
4187 };
4188
4189 class AdvancedPipelinePostFS : public ComputeShaderBase
4190 {
Title()4191 virtual std::string Title()
4192 {
4193 return NL "CS as an additional pipeline stage - After FS";
4194 }
Purpose()4195 virtual std::string Purpose()
4196 {
4197 return NL "1. Verify that CS which runs just after FS to do a post-processing on a rendered image works as "
4198 "expected." NL "2. Verify that CS used as a post-processing filter works as expected." NL
4199 "3. Verify that several CS kernels which run in a sequence to do a post-processing on a rendered "
4200 "image works as expected.";
4201 }
Method()4202 virtual std::string Method()
4203 {
4204 return NL
4205 "1. Render image to Texture0 using VS and FS." NL
4206 "2. Use Texture0 as an input to Kernel0 which performs post-processing and writes result to Texture1." NL
4207 "3. Issue MemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT) command." NL
4208 "4. Use Texture1 as an input to Kernel1 which performs post-processing and writes result to Texture0." NL
4209 "5. Issue MemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT) command." NL
4210 "6. Verify content of the final post-processed image (Texture0).";
4211 }
PassCriteria()4212 virtual std::string PassCriteria()
4213 {
4214 return NL "Everything works as expected.";
4215 }
4216
4217 GLuint m_program[3];
4218 GLuint m_render_target[2];
4219 GLuint m_framebuffer;
4220 GLuint m_vertex_array;
4221 GLuint m_fbo;
4222
Setup()4223 virtual long Setup()
4224 {
4225 memset(m_program, 0, sizeof(m_program));
4226 memset(m_render_target, 0, sizeof(m_render_target));
4227 m_framebuffer = 0;
4228 m_vertex_array = 0;
4229 m_fbo = 0;
4230 return NO_ERROR;
4231 }
4232
Run()4233 virtual long Run()
4234 {
4235 const char* const glsl_vs =
4236 NL "const mediump vec2 g_vertex[4] = vec2[4](vec2(0.0), vec2(-1.0, -1.0), vec2(3.0, -1.0), vec2(-1.0, "
4237 "3.0));" NL "void main() {" NL " gl_Position = vec4(g_vertex[gl_VertexID], 0.0, 1.0);" NL "}";
4238 const char* const glsl_fs = NL "layout(location = 0) out mediump vec4 g_color;" NL "void main() {" NL
4239 " g_color = vec4(1.0, 0.0, 0.0, 1.0);" NL "}";
4240 m_program[0] = CreateProgram(glsl_vs, glsl_fs);
4241 glLinkProgram(m_program[0]);
4242 if (!CheckProgram(m_program[0]))
4243 return ERROR;
4244
4245 const char* const glsl_cs =
4246 NL "#define TILE_WIDTH 4" NL "#define TILE_HEIGHT 4" NL
4247 "const ivec2 kTileSize = ivec2(TILE_WIDTH, TILE_HEIGHT);" NL NL
4248 "layout(binding = 0, rgba8) readonly uniform mediump image2D g_input_image;" NL
4249 "layout(binding = 1, rgba8) writeonly uniform mediump image2D g_output_image;" NL NL
4250 "layout(local_size_x = TILE_WIDTH, local_size_y=TILE_HEIGHT) in;" NL NL "void main() {" NL
4251 " ivec2 tile_xy = ivec2(gl_WorkGroupID);" NL " ivec2 thread_xy = ivec2(gl_LocalInvocationID);" NL NL
4252 " if (thread_xy == ivec2(0)) {" NL " ivec2 pixel_xy = tile_xy * kTileSize;" NL
4253 " for (int y = 0; y < TILE_HEIGHT; ++y) {" NL " for (int x = 0; x < TILE_WIDTH; ++x) {" NL
4254 " imageStore(g_output_image, pixel_xy + ivec2(x, y), vec4(0, 1, 0, 1));" NL " }" NL
4255 " }" NL " }" NL "}";
4256
4257 m_program[1] = CreateComputeProgram(glsl_cs);
4258 glLinkProgram(m_program[1]);
4259 if (!CheckProgram(m_program[1]))
4260 return ERROR;
4261
4262 const char* const glsl_cs2 =
4263 NL "#define TILE_WIDTH 8" NL "#define TILE_HEIGHT 8" NL
4264 "const ivec2 kTileSize = ivec2(TILE_WIDTH, TILE_HEIGHT);" NL NL
4265 "layout(binding = 0, rgba8) readonly uniform mediump image2D g_input_image;" NL
4266 "layout(binding = 1, rgba8) writeonly uniform mediump image2D g_output_image;" NL NL
4267 "layout(local_size_x = TILE_WIDTH, local_size_y=TILE_HEIGHT) in;" NL NL "vec4 Process(vec4 ic) {" NL
4268 " return ic + vec4(1.0, 0.0, 0.0, 0.0);" NL "}" NL "void main() {" NL
4269 " ivec2 tile_xy = ivec2(gl_WorkGroupID);" NL " ivec2 thread_xy = ivec2(gl_LocalInvocationID);" NL
4270 " ivec2 pixel_xy = tile_xy * kTileSize + thread_xy;" NL
4271 " vec4 ic = imageLoad(g_input_image, pixel_xy);" NL
4272 " imageStore(g_output_image, pixel_xy, Process(ic));" NL "}";
4273
4274 m_program[2] = CreateComputeProgram(glsl_cs2);
4275 glLinkProgram(m_program[2]);
4276 if (!CheckProgram(m_program[2]))
4277 return ERROR;
4278
4279 glGenVertexArrays(1, &m_vertex_array);
4280
4281 /* init render targets */
4282 {
4283 std::vector<GLint> data(128 * 128 * 4);
4284 glGenTextures(2, m_render_target);
4285 for (int i = 0; i < 2; ++i)
4286 {
4287 glBindTexture(GL_TEXTURE_2D, m_render_target[i]);
4288 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
4289 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 128, 128);
4290 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 128, 128, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]);
4291 }
4292 glBindTexture(GL_TEXTURE_2D, 0);
4293 }
4294
4295 glGenFramebuffers(1, &m_framebuffer);
4296 glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
4297 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_render_target[0], 0);
4298 glBindFramebuffer(GL_FRAMEBUFFER, 0);
4299
4300 glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
4301 glUseProgram(m_program[0]);
4302 glBindVertexArray(m_vertex_array);
4303 glClear(GL_COLOR_BUFFER_BIT);
4304 glViewport(0, 0, 128, 128);
4305 // draw full-viewport triangle
4306 glDrawArrays(GL_TRIANGLES, 1,
4307 3); // note: <first> is 1 this means that gl_VertexID in the VS will be: 1, 2 and 3
4308 glBindFramebuffer(GL_FRAMEBUFFER, 0);
4309
4310 glBindImageTexture(0, m_render_target[0], 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA8); // input
4311 glBindImageTexture(1, m_render_target[1], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA8); // output
4312 glUseProgram(m_program[1]);
4313 glDispatchCompute(128 / 4, 128 / 4, 1);
4314
4315 glBindImageTexture(0, m_render_target[1], 0, GL_FALSE, 0, GL_READ_ONLY, GL_RGBA8); // input
4316 glBindImageTexture(1, m_render_target[0], 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA8); // output
4317 glUseProgram(m_program[2]);
4318 glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
4319 glDispatchCompute(128 / 8, 128 / 8, 1);
4320
4321 /* validate render target */
4322 {
4323 std::vector<vec4> data(128 * 128);
4324 glBindTexture(GL_TEXTURE_2D, m_render_target[0]);
4325 glMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT);
4326 glGenFramebuffers(1, &m_fbo);
4327 glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
4328 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_render_target[0], 0);
4329 std::vector<GLubyte> colorData(128 * 128 * 4);
4330 glReadPixels(0, 0, 128, 128, GL_RGBA, GL_UNSIGNED_BYTE, &colorData[0]);
4331 for (int i = 0; i < 128 * 128 * 4; i += 4)
4332 {
4333 data[i / 4] =
4334 vec4(static_cast<GLfloat>(colorData[i] / 255.), static_cast<GLfloat>(colorData[i + 1] / 255.),
4335 static_cast<GLfloat>(colorData[i + 2] / 255.), static_cast<GLfloat>(colorData[i + 3] / 255.));
4336 }
4337 for (std::size_t i = 0; i < data.size(); ++i)
4338 {
4339 if (!IsEqual(data[i], vec4(1, 1, 0, 1)))
4340 {
4341 m_context.getTestContext().getLog()
4342 << tcu::TestLog::Message << "Invalid data at index " << i << ": " << data[i].x() << ", "
4343 << data[i].y() << ", " << data[i].z() << ", " << data[i].w() << tcu::TestLog::EndMessage;
4344 return ERROR;
4345 }
4346 }
4347 }
4348 return NO_ERROR;
4349 }
4350
Cleanup()4351 virtual long Cleanup()
4352 {
4353 glViewport(0, 0, getWindowWidth(), getWindowHeight());
4354 glUseProgram(0);
4355 for (int i = 0; i < 3; ++i)
4356 glDeleteProgram(m_program[i]);
4357 glDeleteTextures(2, m_render_target);
4358 glDeleteVertexArrays(1, &m_vertex_array);
4359 glDeleteFramebuffers(1, &m_framebuffer);
4360 glDeleteFramebuffers(1, &m_fbo);
4361 return NO_ERROR;
4362 }
4363 };
4364
4365 class AdvancedPipelinePostXFB : public ComputeShaderBase
4366 {
Title()4367 virtual std::string Title()
4368 {
4369 return NL "CS as an additional pipeline stage - After XFB";
4370 }
Purpose()4371 virtual std::string Purpose()
4372 {
4373 return NL "1. Verify that CS which process data fedback by VS works as expected." NL
4374 "2. Verify that XFB and SSBO works correctly together in one shader." NL
4375 "3. Verify that 'switch' statment which selects different execution path for each CS thread works as "
4376 "expected.";
4377 }
Method()4378 virtual std::string Method()
4379 {
4380 return NL "1. Draw triangle with XFB enabled. Some data is written to the XFB buffer." NL
4381 "2. Use XFB buffer as 'input SSBO' in CS. Process data and write it to 'output SSBO'." NL
4382 "3. Verify 'output SSBO' content.";
4383 }
PassCriteria()4384 virtual std::string PassCriteria()
4385 {
4386 return NL "Everything works as expected.";
4387 }
4388
4389 GLuint m_program[2];
4390 GLuint m_storage_buffer;
4391 GLuint m_xfb_buffer;
4392 GLuint m_vertex_buffer;
4393 GLuint m_vertex_array;
4394
Setup()4395 virtual long Setup()
4396 {
4397 memset(m_program, 0, sizeof(m_program));
4398 m_storage_buffer = 0;
4399 m_xfb_buffer = 0;
4400 m_vertex_buffer = 0;
4401 m_vertex_array = 0;
4402 return NO_ERROR;
4403 }
Run()4404 virtual long Run()
4405 {
4406 GLint res;
4407 glGetIntegerv(GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, &res);
4408 if (res <= 0)
4409 {
4410 OutputNotSupported("GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS <= 0");
4411 return NOT_SUPPORTED;
4412 }
4413
4414 const char* const glsl_vs =
4415 NL "layout(location = 0) in mediump vec4 g_position;" NL "layout(location = 1) in mediump vec4 g_color;" NL
4416 "struct Vertex {" NL " mediump vec4 position;" NL " mediump vec4 color;" NL "};" NL
4417 "flat out mediump vec4 color;" NL "layout(binding = 0) buffer StageData {" NL " Vertex vertex[];" NL
4418 "} g_vs_buffer;" NL "void main() {" NL " gl_Position = g_position;" NL " color = g_color;" NL
4419 " g_vs_buffer.vertex[gl_VertexID].position = g_position;" NL
4420 " g_vs_buffer.vertex[gl_VertexID].color = g_color;" NL "}";
4421 const char* const glsl_fs =
4422 NL "flat mediump in vec4 color;" NL "layout(location = 0) out mediump vec4 g_color;" NL "void main() {" NL
4423 " g_color = color;" NL "}";
4424 m_program[0] = CreateProgram(glsl_vs, glsl_fs);
4425 /* setup xfb varyings */
4426 {
4427 const char* const var[2] = { "gl_Position", "color" };
4428 glTransformFeedbackVaryings(m_program[0], 2, var, GL_INTERLEAVED_ATTRIBS);
4429 }
4430 glLinkProgram(m_program[0]);
4431 if (!CheckProgram(m_program[0]))
4432 return ERROR;
4433
4434 const char* const glsl_cs =
4435 NL "layout(local_size_x = 3) in;" NL "struct Vertex {" NL " vec4 position;" NL " vec4 color;" NL "};" NL
4436 "layout(binding = 3, std430) buffer Buffer {" NL " Vertex g_vertex[3];" NL "};" NL
4437 "uniform vec4 g_color1;" NL "uniform int g_two;" NL "void UpdateVertex2(int i) {" NL
4438 " g_vertex[i].color -= vec4(-1, 1, 0, 0);" NL "}" NL "void main() {" NL
4439 " switch (gl_GlobalInvocationID.x) {" NL
4440 " case 0u: g_vertex[gl_GlobalInvocationID.x].color += vec4(1, 0, 0, 0); break;" NL
4441 " case 1u: g_vertex[1].color += g_color1; break;" NL " case 2u: UpdateVertex2(g_two); break;" NL
4442 " default: return;" NL " }" NL "}";
4443 m_program[1] = CreateComputeProgram(glsl_cs);
4444 glLinkProgram(m_program[1]);
4445 glUseProgram(m_program[1]);
4446 glUniform4f(glGetUniformLocation(m_program[1], "g_color1"), 0.f, 0.f, 1.f, 0.f);
4447 glUniform1i(glGetUniformLocation(m_program[1], "g_two"), 2);
4448 glUseProgram(0);
4449 if (!CheckProgram(m_program[1]))
4450 return ERROR;
4451
4452 glGenBuffers(1, &m_storage_buffer);
4453 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
4454 glBufferData(GL_SHADER_STORAGE_BUFFER, 3 * sizeof(vec4) * 2, NULL, GL_STATIC_COPY);
4455
4456 glGenBuffers(1, &m_xfb_buffer);
4457 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, m_xfb_buffer);
4458 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 3 * sizeof(vec4) * 2, NULL, GL_STREAM_COPY);
4459
4460 const float in_data[3 * 8] = { -1, -1, 0, 1, 0, 1, 0, 1, 3, -1, 0, 1, 0, 1, 0, 1, -1, 3, 0, 1, 0, 1, 0, 1 };
4461 glGenBuffers(1, &m_vertex_buffer);
4462 glBindBuffer(GL_ARRAY_BUFFER, m_vertex_buffer);
4463 glBufferData(GL_ARRAY_BUFFER, sizeof(in_data), in_data, GL_STATIC_DRAW);
4464 glBindBuffer(GL_ARRAY_BUFFER, 0);
4465
4466 glGenVertexArrays(1, &m_vertex_array);
4467 glBindVertexArray(m_vertex_array);
4468 glBindBuffer(GL_ARRAY_BUFFER, m_vertex_buffer);
4469 glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 2 * sizeof(vec4), 0);
4470 glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 2 * sizeof(vec4), reinterpret_cast<void*>(sizeof(vec4)));
4471 glBindBuffer(GL_ARRAY_BUFFER, 0);
4472 glEnableVertexAttribArray(0);
4473 glEnableVertexAttribArray(1);
4474 glBindVertexArray(0);
4475
4476 glClear(GL_COLOR_BUFFER_BIT);
4477 glUseProgram(m_program[0]);
4478 glBindVertexArray(m_vertex_array);
4479 glBeginTransformFeedback(GL_TRIANGLES);
4480 glDrawArrays(GL_TRIANGLES, 0, 3);
4481 glEndTransformFeedback();
4482
4483 glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
4484
4485 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, m_xfb_buffer);
4486 glUseProgram(m_program[1]);
4487 glDispatchCompute(1, 1, 1);
4488
4489 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
4490
4491 long error = NO_ERROR;
4492 /* validate storage buffer */
4493 {
4494 float* data;
4495 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer);
4496 data = static_cast<float*>(
4497 glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(float) * 3 * 8, GL_MAP_READ_BIT));
4498 if (memcmp(data, in_data, sizeof(float) * 3 * 8) != 0)
4499 {
4500 m_context.getTestContext().getLog()
4501 << tcu::TestLog::Message << "Data in shader storage buffer is incorrect."
4502 << tcu::TestLog::EndMessage;
4503 error = ERROR;
4504 }
4505 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
4506 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
4507 }
4508 /* validate xfb buffer */
4509 {
4510 const float ref_data[3 * 8] = {
4511 -1, -1, 0, 1, 1, 1, 0, 1, 3, -1, 0, 1, 0, 1, 1, 1, -1, 3, 0, 1, 1, 0, 0, 1
4512 };
4513 float* data;
4514 data = static_cast<float*>(
4515 glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sizeof(float) * 3 * 8, GL_MAP_READ_BIT));
4516 if (memcmp(data, ref_data, sizeof(float) * 3 * 8) != 0)
4517 {
4518 m_context.getTestContext().getLog()
4519 << tcu::TestLog::Message << "Data in xfb buffer is incorrect." << tcu::TestLog::EndMessage;
4520 error = ERROR;
4521 }
4522 glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
4523 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0);
4524 }
4525 if (!ValidateReadBuffer(0, 0, getWindowWidth(), getWindowHeight(), vec4(0, 1, 0, 1)))
4526 {
4527 error = ERROR;
4528 }
4529 return error;
4530 }
Cleanup()4531 virtual long Cleanup()
4532 {
4533 glUseProgram(0);
4534 for (int i = 0; i < 2; ++i)
4535 glDeleteProgram(m_program[i]);
4536 glDeleteBuffers(1, &m_vertex_buffer);
4537 glDeleteBuffers(1, &m_storage_buffer);
4538 glDeleteBuffers(1, &m_xfb_buffer);
4539 glDeleteVertexArrays(1, &m_vertex_array);
4540 return NO_ERROR;
4541 }
4542 };
4543
4544 class AdvancedSharedIndexing : public ComputeShaderBase
4545 {
Title()4546 virtual std::string Title()
4547 {
4548 return NL "Shared Memory - Indexing";
4549 }
Purpose()4550 virtual std::string Purpose()
4551 {
4552 return NL "1. Verify that indexing various types of shared memory works as expected." NL
4553 "2. Verify that indexing shared memory with different types of expressions work as expected." NL
4554 "3. Verify that all declaration types of shared structures are supported by the GLSL compiler.";
4555 }
Method()4556 virtual std::string Method()
4557 {
4558 return NL "1. Create CS which uses shared memory in many different ways." NL
4559 "2. Write to shared memory using different expressions." NL "3. Validate shared memory content." NL
4560 "4. Use synchronization primitives (barrier, groupMemoryBarrier) where applicable.";
4561 }
PassCriteria()4562 virtual std::string PassCriteria()
4563 {
4564 return NL "Everyting works as expected.";
4565 }
4566
4567 GLuint m_program;
4568 GLuint m_texture;
4569 GLuint m_fbo;
4570
Setup()4571 virtual long Setup()
4572 {
4573 m_program = 0;
4574 m_texture = 0;
4575 m_fbo = 0;
4576 return NO_ERROR;
4577 }
Run()4578 virtual long Run()
4579 {
4580 const char* const glsl_cs =
4581 NL "layout(binding = 3, rgba8) uniform mediump writeonly image2D g_result_image;" NL
4582 "layout (local_size_x = 4,local_size_y=4 ) in;" NL "shared vec4 g_shared1[4];" NL
4583 "shared mat4 g_shared2;" NL "shared struct {" NL " float data[4];" NL "} g_shared3[4];" NL
4584 "shared struct Type { float data[4]; } g_shared4[4];" NL "shared Type g_shared5[4];" NL
4585 "uniform bool g_true;" NL "uniform float g_values[16];" NL NL "void Sync() {" NL
4586 " groupMemoryBarrier();" NL " barrier();" NL "}" NL "void SetMemory(ivec2 xy, float value) {" NL
4587 " g_shared1[xy.y][gl_LocalInvocationID.x] = value;" NL " g_shared2[xy.y][xy.x] = value;" NL
4588 " g_shared3[xy[1]].data[xy[0]] = value;" NL " g_shared4[xy.y].data[xy[0]] = value;" NL
4589 " g_shared5[gl_LocalInvocationID.y].data[gl_LocalInvocationID.x] = value;" NL "}" NL
4590 "bool CheckMemory(ivec2 xy, float expected) {" NL
4591 " if (g_shared1[xy.y][xy[0]] != expected) return false;" NL
4592 " if (g_shared2[xy[1]][xy[0]] != expected) return false;" NL
4593 " if (g_shared3[gl_LocalInvocationID.y].data[gl_LocalInvocationID.x] != expected) return false;" NL
4594 " if (g_shared4[gl_LocalInvocationID.y].data[xy.x] != expected) return false;" NL
4595 " if (g_shared5[xy.y].data[xy.x] != expected) return false;" NL " return true;" NL "}" NL
4596 "void main() {" NL " ivec2 thread_xy = ivec2(gl_LocalInvocationID);" NL
4597 " vec4 result = vec4(0.0, 1.0, 0.0, 1.0);" NL NL
4598 " SetMemory(thread_xy, g_values[gl_LocalInvocationIndex] * 1.0);" NL " Sync();" NL
4599 " if (!CheckMemory(thread_xy, g_values[gl_LocalInvocationIndex] * 1.0)) result = vec4(1.0, 0.0, 0.0, "
4600 "1.0);" NL NL " SetMemory(thread_xy, g_values[gl_LocalInvocationIndex] * -1.0);" NL " Sync();" NL
4601 " if (!CheckMemory(thread_xy, g_values[gl_LocalInvocationIndex] * -1.0)) result = vec4(1.0, 0.0, 0.0, "
4602 "1.0);" NL NL " if (g_true && gl_LocalInvocationID.x < 10u) {" NL
4603 " SetMemory(thread_xy, g_values[gl_LocalInvocationIndex] * 7.0);" NL " Sync();" NL
4604 " if (!CheckMemory(thread_xy, g_values[gl_LocalInvocationIndex] * 7.0)) result = vec4(1.0, 0.0, 0.0, "
4605 "1.0);" NL " }" NL NL " imageStore(g_result_image, thread_xy, result);" NL "}";
4606
4607 m_program = CreateComputeProgram(glsl_cs);
4608 glLinkProgram(m_program);
4609 if (!CheckProgram(m_program))
4610 return ERROR;
4611
4612 /* init texture */
4613 {
4614 std::vector<GLint> data(4 * 4 * 4);
4615 glGenTextures(1, &m_texture);
4616 glBindTexture(GL_TEXTURE_2D, m_texture);
4617 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
4618 glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 4, 4);
4619 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 4, 4, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]);
4620 glBindTexture(GL_TEXTURE_2D, 0);
4621 }
4622
4623 glBindImageTexture(3, m_texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA8);
4624 glUseProgram(m_program);
4625 glUniform1i(glGetUniformLocation(m_program, "g_true"), GL_TRUE);
4626 GLfloat values[16] = { 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, 9.f, 10.f, 11.f, 12.f, 13.f, 14.f, 15.f, 16.f };
4627 glUniform1fv(glGetUniformLocation(m_program, "g_values"), 16, values);
4628 glDispatchCompute(1, 1, 1);
4629
4630 /* validate render target */
4631 {
4632 std::vector<vec4> data(4 * 4);
4633 glBindTexture(GL_TEXTURE_2D, m_texture);
4634 glMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT);
4635 glGenFramebuffers(1, &m_fbo);
4636 glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
4637 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture, 0);
4638 std::vector<GLubyte> colorData(4 * 4 * 4);
4639 glReadPixels(0, 0, 4, 4, GL_RGBA, GL_UNSIGNED_BYTE, &colorData[0]);
4640 for (int i = 0; i < 4 * 4 * 4; i += 4)
4641 {
4642 data[i / 4] =
4643 vec4(static_cast<GLfloat>(colorData[i] / 255.), static_cast<GLfloat>(colorData[i + 1] / 255.),
4644 static_cast<GLfloat>(colorData[i + 2] / 255.), static_cast<GLfloat>(colorData[i + 3] / 255.));
4645 }
4646 for (std::size_t i = 0; i < data.size(); ++i)
4647 {
4648 if (!IsEqual(data[i], vec4(0, 1, 0, 1)))
4649 {
4650 m_context.getTestContext().getLog()
4651 << tcu::TestLog::Message << "Invalid data at index " << i << tcu::TestLog::EndMessage;
4652 return ERROR;
4653 }
4654 }
4655 }
4656 return NO_ERROR;
4657 }
Cleanup()4658 virtual long Cleanup()
4659 {
4660 glUseProgram(0);
4661 glDeleteProgram(m_program);
4662 glDeleteTextures(1, &m_texture);
4663 glDeleteFramebuffers(1, &m_fbo);
4664 return NO_ERROR;
4665 }
4666 };
4667
4668 class AdvancedSharedMax : public ComputeShaderBase
4669 {
Title()4670 virtual std::string Title()
4671 {
4672 return NL "Shared Memory - 16K";
4673 }
Purpose()4674 virtual std::string Purpose()
4675 {
4676 return NL "Support for 16K of shared memory is required by the OpenGL specifaction. Verify if an "
4677 "implementation supports it.";
4678 }
Method()4679 virtual std::string Method()
4680 {
4681 return NL "Create and dispatch CS which uses 16K of shared memory.";
4682 }
PassCriteria()4683 virtual std::string PassCriteria()
4684 {
4685 return NL "Everything works as expected.";
4686 }
4687
4688 GLuint m_program;
4689 GLuint m_buffer;
4690
Setup()4691 virtual long Setup()
4692 {
4693 m_program = 0;
4694 m_buffer = 0;
4695 return NO_ERROR;
4696 }
Run()4697 virtual long Run()
4698 {
4699 const char* const glsl_cs = NL
4700 "layout(local_size_x = 64) in;" NL
4701 "shared struct Type { vec4 v[16]; } g_shared[64];" // 16384 bytes of shared memory
4702 NL "layout(std430) buffer Output {" NL " Type g_output[64];" NL "};" NL NL "void main() {" NL
4703 " int id = int(gl_GlobalInvocationID.x);" NL
4704 " g_shared[id].v = vec4[16](vec4(1.0), vec4(1.0), vec4(1.0), vec4(1.0), vec4(1.0), vec4(1.0), vec4(1.0), "
4705 "vec4(1.0)," NL " vec4(1.0), vec4(1.0), vec4(1.0), vec4(1.0), vec4(1.0), "
4706 "vec4(1.0), vec4(1.0), vec4(1.0));" NL " memoryBarrierShared();" NL " barrier();" NL NL
4707 " vec4 sum = vec4(0.0);" NL " int sum_count = 0;" NL " for (int i = id - 6; i < id + 9; ++i) {" NL
4708 " if (id >= 0 && id < g_shared.length()) {" NL " sum += g_shared[id].v[0];" NL
4709 " sum += g_shared[id].v[1];" NL " sum += g_shared[id].v[2];" NL
4710 " sum += g_shared[id].v[3];" NL " sum += g_shared[id].v[4];" NL
4711 " sum += g_shared[id].v[5];" NL " sum += g_shared[id].v[6];" NL
4712 " sum += g_shared[id].v[7];" NL " sum += g_shared[id].v[8];" NL
4713 " sum += g_shared[id].v[9];" NL " sum += g_shared[id].v[10];" NL
4714 " sum += g_shared[id].v[11];" NL " sum += g_shared[id].v[12];" NL
4715 " sum += g_shared[id].v[13];" NL " sum += g_shared[id].v[14];" NL
4716 " sum += g_shared[id].v[15];" NL " sum_count += 16;" NL " }" NL " }" NL
4717 " sum = abs((sum / float(sum_count)) - vec4(1.0));" NL
4718 " if (sum.x > 0.0000001f || sum.y > 0.0000001f || sum.z > 0.0000001f || sum.w > 0.0000001f) return;" NL NL
4719 " g_output[id] = g_shared[id];" NL "}";
4720
4721 m_program = CreateComputeProgram(glsl_cs);
4722 glLinkProgram(m_program);
4723 if (!CheckProgram(m_program))
4724 return ERROR;
4725
4726 /* init buffer */
4727 {
4728 std::vector<vec4> data(1024);
4729 glGenBuffers(1, &m_buffer);
4730 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer);
4731 glBufferData(GL_SHADER_STORAGE_BUFFER, (GLsizeiptr)(sizeof(vec4) * data.size()), &data[0][0],
4732 GL_DYNAMIC_COPY);
4733 }
4734
4735 glUseProgram(m_program);
4736 glDispatchCompute(1, 1, 1);
4737 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
4738
4739 long error = NO_ERROR;
4740 /* validate buffer */
4741 {
4742 vec4* data;
4743 data =
4744 static_cast<vec4*>(glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(vec4) * 1024, GL_MAP_READ_BIT));
4745 for (std::size_t i = 0; i < 1024; ++i)
4746 {
4747 if (!IsEqual(data[i], vec4(1.0f)))
4748 {
4749 m_context.getTestContext().getLog()
4750 << tcu::TestLog::Message << "Invalid data at index " << i << tcu::TestLog::EndMessage;
4751 error = ERROR;
4752 }
4753 }
4754 }
4755 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
4756 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
4757 return error;
4758 }
Cleanup()4759 virtual long Cleanup()
4760 {
4761 glUseProgram(0);
4762 glDeleteProgram(m_program);
4763 glDeleteBuffers(1, &m_buffer);
4764 return NO_ERROR;
4765 }
4766 };
4767
4768 class AdvancedResourcesMax : public ComputeShaderBase
4769 {
Title()4770 virtual std::string Title()
4771 {
4772 return NL "Maximum number of resources in one shader";
4773 }
Purpose()4774 virtual std::string Purpose()
4775 {
4776 return NL "1. Verify that using 4 SSBOs, 12 UBOs, 8 atomic counters" NL " in one CS works as expected.";
4777 }
Method()4778 virtual std::string Method()
4779 {
4780 return NL "Create and dispatch CS. Verify result.";
4781 }
PassCriteria()4782 virtual std::string PassCriteria()
4783 {
4784 return NL "Everything works as expected.";
4785 }
4786
4787 GLuint m_program;
4788 GLuint m_storage_buffer[4];
4789 GLuint m_uniform_buffer[12];
4790 GLuint m_atomic_buffer;
4791
RunIteration(GLuint index)4792 bool RunIteration(GLuint index)
4793 {
4794 for (GLuint i = 0; i < 4; ++i)
4795 {
4796 const GLuint data = i + 1;
4797 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, i, m_storage_buffer[i]);
4798 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(data), &data, GL_STATIC_DRAW);
4799 }
4800 for (GLuint i = 0; i < 12; ++i)
4801 {
4802 const GLuint data = i + 1;
4803 glBindBufferBase(GL_UNIFORM_BUFFER, i, m_uniform_buffer[i]);
4804 glBufferData(GL_UNIFORM_BUFFER, sizeof(data), &data, GL_STATIC_DRAW);
4805 }
4806 {
4807 GLuint data[8];
4808 for (GLuint i = 0; i < 8; ++i)
4809 data[i] = i + 1;
4810 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, m_atomic_buffer);
4811 glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(data), &data[0], GL_STATIC_DRAW);
4812 }
4813
4814 glUseProgram(m_program);
4815 glUniform1ui(glGetUniformLocation(m_program, "g_index"), index);
4816 /* uniform array */
4817 {
4818 std::vector<GLuint> data(480);
4819 for (GLuint i = 0; i < static_cast<GLuint>(data.size()); ++i)
4820 data[i] = i + 1;
4821 glUniform1uiv(glGetUniformLocation(m_program, "g_uniform_def"), static_cast<GLsizei>(data.size()),
4822 &data[0]);
4823 }
4824 glDispatchCompute(1, 1, 1);
4825 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
4826
4827 bool ret = true;
4828 /* validate buffer */
4829 {
4830 GLuint* data;
4831 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer[index]);
4832 data = static_cast<GLuint*>(glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(GLuint), GL_MAP_READ_BIT));
4833 if (data[0] != (index + 1) * 4)
4834 {
4835 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Data is " << data[0] << " should be "
4836 << ((index + 1) * 4) << tcu::TestLog::EndMessage;
4837 ret = false;
4838 }
4839 }
4840 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
4841 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
4842 return ret;
4843 }
Setup()4844 virtual long Setup()
4845 {
4846 m_program = 0;
4847 memset(m_storage_buffer, 0, sizeof(m_storage_buffer));
4848 memset(m_uniform_buffer, 0, sizeof(m_uniform_buffer));
4849 m_atomic_buffer = 0;
4850 return NO_ERROR;
4851 }
Run()4852 virtual long Run()
4853 {
4854 const char* const glsl_cs =
4855 NL "layout(local_size_x = 1) in;" NL "layout(std140, binding = 0) buffer ShaderStorageBlock {" NL
4856 " uint data;" NL "} g_shader_storage[4];" NL "layout(std140, binding = 0) uniform UniformBlock {" NL
4857 " uint data;" NL "} g_uniform[12];" NL
4858 "layout(binding = 0, offset = 0) uniform atomic_uint g_atomic_counter0;" NL
4859 "layout(binding = 0, offset = 4) uniform atomic_uint g_atomic_counter1;" NL
4860 "layout(binding = 0, offset = 8) uniform atomic_uint g_atomic_counter2;" NL
4861 "layout(binding = 0, offset = 12) uniform atomic_uint g_atomic_counter3;" NL
4862 "layout(binding = 0, offset = 16) uniform atomic_uint g_atomic_counter4;" NL
4863 "layout(binding = 0, offset = 20) uniform atomic_uint g_atomic_counter5;" NL
4864 "layout(binding = 0, offset = 24) uniform atomic_uint g_atomic_counter6;" NL
4865 "layout(binding = 0, offset = 28) uniform atomic_uint g_atomic_counter7;" NL
4866 "uniform uint g_uniform_def[480];" NL "uniform uint g_index;" NL NL "uint Add() {" NL
4867 " switch (g_index) {" NL " case 0u: return atomicCounter(g_atomic_counter0);" NL
4868 " case 1u: return atomicCounter(g_atomic_counter1);" NL
4869 " case 2u: return atomicCounter(g_atomic_counter2);" NL
4870 " case 3u: return atomicCounter(g_atomic_counter3);" NL
4871 " case 4u: return atomicCounter(g_atomic_counter4);" NL
4872 " case 5u: return atomicCounter(g_atomic_counter5);" NL
4873 " case 6u: return atomicCounter(g_atomic_counter6);" NL
4874 " case 7u: return atomicCounter(g_atomic_counter7);" NL " }" NL "}" NL "void main() {" NL
4875 " switch (g_index) {" NL " case 0u: {" NL " g_shader_storage[0].data += g_uniform[0].data;" NL
4876 " g_shader_storage[0].data += Add();" NL " g_shader_storage[0].data += g_uniform_def[0];" NL
4877 " break;" NL " }" NL " case 1u: {" NL
4878 " g_shader_storage[1].data += g_uniform[1].data;" NL " g_shader_storage[1].data += Add();" NL
4879 " g_shader_storage[1].data += g_uniform_def[1];" NL " break;" NL " }" NL " case 2u: {" NL
4880 " g_shader_storage[2].data += g_uniform[2].data;" NL " g_shader_storage[2].data += Add();" NL
4881 " g_shader_storage[2].data += g_uniform_def[2];" NL " break;" NL " }" NL " case 3u: {" NL
4882 " g_shader_storage[3].data += g_uniform[3].data;" NL " g_shader_storage[3].data += Add();" NL
4883 " g_shader_storage[3].data += g_uniform_def[3];" NL " break;" NL " }" NL " }" NL "}";
4884 m_program = CreateComputeProgram(glsl_cs);
4885 glLinkProgram(m_program);
4886 if (!CheckProgram(m_program))
4887 return ERROR;
4888
4889 glGenBuffers(4, m_storage_buffer);
4890 glGenBuffers(12, m_uniform_buffer);
4891 glGenBuffers(1, &m_atomic_buffer);
4892
4893 if (!RunIteration(0))
4894 return ERROR;
4895 if (!RunIteration(1))
4896 return ERROR;
4897 if (!RunIteration(3))
4898 return ERROR;
4899
4900 return NO_ERROR;
4901 }
Cleanup()4902 virtual long Cleanup()
4903 {
4904 glUseProgram(0);
4905 glDeleteProgram(m_program);
4906 glDeleteBuffers(4, m_storage_buffer);
4907 glDeleteBuffers(12, m_uniform_buffer);
4908 glDeleteBuffers(1, &m_atomic_buffer);
4909 return NO_ERROR;
4910 }
4911 };
4912
4913 class WorkGroupSizeUsage : public ComputeShaderBase
4914 {
Title()4915 virtual std::string Title()
4916 {
4917 return NL "gl_WorkGroupSize usage";
4918 }
Purpose()4919 virtual std::string Purpose()
4920 {
4921 return NL "Verify gl_WorkGroupSize usage rules.";
4922 }
Method()4923 virtual std::string Method()
4924 {
4925 return NL "";
4926 }
PassCriteria()4927 virtual std::string PassCriteria()
4928 {
4929 return NL "";
4930 }
4931
Run()4932 virtual long Run()
4933 {
4934 // local group size declared with some dimensions omitted - omitted dimensions should have size of 1
4935 if (!CheckOmittedDimensions('x') || !CheckOmittedDimensions('y') || !CheckOmittedDimensions('z'))
4936 return ERROR;
4937
4938 // check if compilation error is generated when shader doesn't declare
4939 // fixed local group size and tries to use gl_WorkGroupSize
4940 if (!CheckCompilationError("#version 310 es" NL "layout(std430) buffer Output {" NL " uint g_output;" NL
4941 "};" NL "void main() {" NL " g_output = gl_WorkGroupSize.x;" NL "}"))
4942 return ERROR;
4943
4944 // check if compilation error is generated when shader tries using
4945 // gl_WorkGroupSize in a function before declaring local group size
4946 if (!CheckCompilationError("#version 310 es" NL "layout(std430) buffer Output {" NL " uint g_output;" NL
4947 "};" NL "void main() {" NL " g_output = gl_WorkGroupSize.x;" NL "}" NL
4948 "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;"))
4949 return ERROR;
4950
4951 return NO_ERROR;
4952 }
4953
CheckOmittedDimensions(GLchar defined_component)4954 bool CheckOmittedDimensions(GLchar defined_component)
4955 {
4956 std::stringstream ss;
4957 ss << "layout(std430) buffer Output {" NL " uint g_output;" NL "};" NL "layout(local_size_"
4958 << defined_component
4959 << " = 1) in;" NL "void main() {" NL " g_output = gl_WorkGroupSize.x + gl_WorkGroupSize.z;" NL "}";
4960
4961 std::string glsl_cs = ss.str();
4962 GLuint program = CreateComputeProgram(glsl_cs);
4963 glLinkProgram(program);
4964 if (!CheckProgram(program))
4965 return false;
4966
4967 GLint v[3];
4968 glGetProgramiv(program, GL_COMPUTE_WORK_GROUP_SIZE, v);
4969 if (v[0] != 1 || v[1] != 1 || v[2] != 1)
4970 {
4971 m_context.getTestContext().getLog()
4972 << tcu::TestLog::Message << "Got " << v[0] << ", " << v[1] << ", " << v[2]
4973 << ", expected: 1, 1, 1 in GL_COMPUTE_WORK_GROUP_SIZE check" << tcu::TestLog::EndMessage;
4974 return false;
4975 }
4976
4977 glDeleteProgram(program);
4978 return true;
4979 }
4980
CheckCompilationError(const std::string & source)4981 bool CheckCompilationError(const std::string& source)
4982 {
4983 const GLuint sh = glCreateShader(GL_COMPUTE_SHADER);
4984
4985 const char* const src = source.c_str();
4986 glShaderSource(sh, 1, &src, NULL);
4987 glCompileShader(sh);
4988
4989 GLchar log[1024];
4990 glGetShaderInfoLog(sh, sizeof(log), NULL, log);
4991 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Shader Info Log:\n"
4992 << log << tcu::TestLog::EndMessage;
4993
4994 GLint status;
4995 glGetShaderiv(sh, GL_COMPILE_STATUS, &status);
4996 glDeleteShader(sh);
4997
4998 if (status == GL_TRUE)
4999 {
5000 m_context.getTestContext().getLog()
5001 << tcu::TestLog::Message << "Compilation should fail." << tcu::TestLog::EndMessage;
5002 return false;
5003 }
5004
5005 return true;
5006 }
5007 };
5008
5009 class NegativeAPINoActiveProgram : public ComputeShaderBase
5010 {
Title()5011 virtual std::string Title()
5012 {
5013 return NL "API errors - no active program";
5014 }
Purpose()5015 virtual std::string Purpose()
5016 {
5017 return NL "Verify that appropriate errors are generated by the OpenGL API.";
5018 }
Method()5019 virtual std::string Method()
5020 {
5021 return NL "";
5022 }
PassCriteria()5023 virtual std::string PassCriteria()
5024 {
5025 return NL "";
5026 }
5027
5028 GLuint m_program;
5029
Setup()5030 virtual long Setup()
5031 {
5032 m_program = 0;
5033 return NO_ERROR;
5034 }
Run()5035 virtual long Run()
5036 {
5037 glDispatchCompute(1, 2, 3);
5038 if (glGetError() != GL_INVALID_OPERATION)
5039 {
5040 m_context.getTestContext().getLog()
5041 << tcu::TestLog::Message << "INVALID_OPERATION is generated by DispatchCompute or\n"
5042 "DispatchComputeIndirect if there is no active program for the compute\n"
5043 "shader stage."
5044 << tcu::TestLog::EndMessage;
5045 return ERROR;
5046 }
5047
5048 /* indirect dispatch */
5049 {
5050 GLuint buffer;
5051 const GLuint num_group[3] = { 3, 2, 1 };
5052 glGenBuffers(1, &buffer);
5053 glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, buffer);
5054 glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(num_group), num_group, GL_STATIC_DRAW);
5055 glDispatchComputeIndirect(0);
5056 glDeleteBuffers(1, &buffer);
5057 if (glGetError() != GL_INVALID_OPERATION)
5058 {
5059 m_context.getTestContext().getLog()
5060 << tcu::TestLog::Message
5061 << "INVALID_OPERATION is generated by DispatchCompute or\n"
5062 "DispatchComputeIndirect if there is no active program for the compute\n"
5063 "shader stage."
5064 << tcu::TestLog::EndMessage;
5065 return ERROR;
5066 }
5067 }
5068
5069 const char* const glsl_vs = NL "layout(location = 0) in mediump vec4 g_position;" NL "void main() {" NL
5070 " gl_Position = g_position;" NL "}";
5071 const char* const glsl_fs =
5072 NL "layout(location = 0) out mediump vec4 g_color;" NL "void main() {" NL " g_color = vec4(1);" NL "}";
5073 m_program = CreateProgram(glsl_vs, glsl_fs);
5074 glLinkProgram(m_program);
5075 if (!CheckProgram(m_program))
5076 return ERROR;
5077
5078 glUseProgram(m_program);
5079
5080 glDispatchCompute(1, 2, 3);
5081 if (glGetError() != GL_INVALID_OPERATION)
5082 {
5083 m_context.getTestContext().getLog()
5084 << tcu::TestLog::Message << "INVALID_OPERATION is generated by DispatchCompute or\n"
5085 "DispatchComputeIndirect if there is no active program for the compute\n"
5086 "shader stage."
5087 << tcu::TestLog::EndMessage;
5088 return ERROR;
5089 }
5090
5091 /* indirect dispatch */
5092 {
5093 GLuint buffer;
5094 const GLuint num_group[3] = { 3, 2, 1 };
5095 glGenBuffers(1, &buffer);
5096 glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, buffer);
5097 glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(num_group), num_group, GL_STATIC_DRAW);
5098 glDispatchComputeIndirect(0);
5099 glDeleteBuffers(1, &buffer);
5100 if (glGetError() != GL_INVALID_OPERATION)
5101 {
5102 m_context.getTestContext().getLog()
5103 << tcu::TestLog::Message
5104 << "INVALID_OPERATION is generated by DispatchCompute or\n"
5105 "DispatchComputeIndirect if there is no active program for the compute\n"
5106 "shader stage."
5107 << tcu::TestLog::EndMessage;
5108 return ERROR;
5109 }
5110 }
5111
5112 return NO_ERROR;
5113 }
Cleanup()5114 virtual long Cleanup()
5115 {
5116 glUseProgram(0);
5117 glDeleteProgram(m_program);
5118 return NO_ERROR;
5119 }
5120 };
5121
5122 class NegativeAPIWorkGroupCount : public ComputeShaderBase
5123 {
Title()5124 virtual std::string Title()
5125 {
5126 return NL "API errors - invalid work group count";
5127 }
Purpose()5128 virtual std::string Purpose()
5129 {
5130 return NL "Verify that appropriate errors are generated by the OpenGL API.";
5131 }
Method()5132 virtual std::string Method()
5133 {
5134 return NL "";
5135 }
PassCriteria()5136 virtual std::string PassCriteria()
5137 {
5138 return NL "";
5139 }
5140
5141 GLuint m_program;
5142 GLuint m_storage_buffer;
5143
Setup()5144 virtual long Setup()
5145 {
5146 m_program = 0;
5147 m_storage_buffer = 0;
5148 return NO_ERROR;
5149 }
Run()5150 virtual long Run()
5151 {
5152 const char* const glsl_cs =
5153 NL "layout(local_size_x = 1) in;" NL "layout(std430) buffer Output {" NL " uint g_output[];" NL "};" NL
5154 "void main() {" NL
5155 " g_output[gl_GlobalInvocationID.x * gl_GlobalInvocationID.y * gl_GlobalInvocationID.z] = 0u;" NL "}";
5156 m_program = CreateComputeProgram(glsl_cs);
5157 glLinkProgram(m_program);
5158 if (!CheckProgram(m_program))
5159 return ERROR;
5160
5161 glGenBuffers(1, &m_storage_buffer);
5162 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
5163 glBufferData(GL_SHADER_STORAGE_BUFFER, 100000, NULL, GL_DYNAMIC_DRAW);
5164
5165 GLint x, y, z;
5166 glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 0, &x);
5167 glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 1, &y);
5168 glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 2, &z);
5169
5170 glUseProgram(m_program);
5171
5172 glDispatchCompute(x + 1, 1, 1);
5173 if (glGetError() != GL_INVALID_VALUE)
5174 {
5175 m_context.getTestContext().getLog()
5176 << tcu::TestLog::Message << "INVALID_VALUE is generated by DispatchCompute if any of <num_groups_x>,\n"
5177 "<num_groups_y> or <num_groups_z> is greater than the value of\n"
5178 "MAX_COMPUTE_WORK_GROUP_COUNT for the corresponding dimension."
5179 << tcu::TestLog::EndMessage;
5180 return ERROR;
5181 }
5182
5183 glDispatchCompute(1, y + 1, 1);
5184 if (glGetError() != GL_INVALID_VALUE)
5185 {
5186 m_context.getTestContext().getLog()
5187 << tcu::TestLog::Message << "INVALID_VALUE is generated by DispatchCompute if any of <num_groups_x>,\n"
5188 "<num_groups_y> or <num_groups_z> is greater than the value of\n"
5189 "MAX_COMPUTE_WORK_GROUP_COUNT for the corresponding dimension."
5190 << tcu::TestLog::EndMessage;
5191 return ERROR;
5192 }
5193
5194 glDispatchCompute(1, 1, z + 1);
5195 if (glGetError() != GL_INVALID_VALUE)
5196 {
5197 m_context.getTestContext().getLog()
5198 << tcu::TestLog::Message << "INVALID_VALUE is generated by DispatchCompute if any of <num_groups_x>,\n"
5199 "<num_groups_y> or <num_groups_z> is greater than the value of\n"
5200 "MAX_COMPUTE_WORK_GROUP_COUNT for the corresponding dimension."
5201 << tcu::TestLog::EndMessage;
5202 return ERROR;
5203 }
5204
5205 return NO_ERROR;
5206 }
Cleanup()5207 virtual long Cleanup()
5208 {
5209 glUseProgram(0);
5210 glDeleteProgram(m_program);
5211 glDeleteBuffers(1, &m_storage_buffer);
5212 return NO_ERROR;
5213 }
5214 };
5215
5216 class NegativeAPIIndirect : public ComputeShaderBase
5217 {
Title()5218 virtual std::string Title()
5219 {
5220 return NL "API errors - incorrect DispatchComputeIndirect usage";
5221 }
Purpose()5222 virtual std::string Purpose()
5223 {
5224 return NL "Verify that appropriate errors are generated by the OpenGL API.";
5225 }
Method()5226 virtual std::string Method()
5227 {
5228 return NL "";
5229 }
PassCriteria()5230 virtual std::string PassCriteria()
5231 {
5232 return NL "";
5233 }
5234
5235 GLuint m_program;
5236 GLuint m_storage_buffer;
5237 GLuint m_dispatch_buffer;
5238
Setup()5239 virtual long Setup()
5240 {
5241 m_program = 0;
5242 m_storage_buffer = 0;
5243 m_dispatch_buffer = 0;
5244 return NO_ERROR;
5245 }
5246
Run()5247 virtual long Run()
5248 {
5249 const char* const glsl_cs =
5250 NL "layout(local_size_x = 1) in;" NL "layout(std430) buffer Output {" NL " uint g_output[];" NL "};" NL
5251 "void main() {" NL " g_output[gl_GlobalInvocationID.x] = 0u;" NL "}";
5252 m_program = CreateComputeProgram(glsl_cs);
5253 glLinkProgram(m_program);
5254 if (!CheckProgram(m_program))
5255 return ERROR;
5256 glUseProgram(m_program);
5257
5258 glGenBuffers(1, &m_storage_buffer);
5259 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
5260 glBufferData(GL_SHADER_STORAGE_BUFFER, 100000, NULL, GL_DYNAMIC_DRAW);
5261
5262 const GLuint num_groups[6] = { 1, 1, 1, 1, 1, 1 };
5263 glGenBuffers(1, &m_dispatch_buffer);
5264 glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, m_dispatch_buffer);
5265 glBufferData(GL_DISPATCH_INDIRECT_BUFFER, sizeof(num_groups), num_groups, GL_STATIC_COPY);
5266
5267 glDispatchComputeIndirect(-2);
5268 if (glGetError() != GL_INVALID_VALUE)
5269 {
5270 m_context.getTestContext().getLog()
5271 << tcu::TestLog::Message << "INVALID_VALUE is generated by DispatchComputeIndirect if <indirect> is\n"
5272 "less than zero or not a multiple of four."
5273 << tcu::TestLog::EndMessage;
5274 return ERROR;
5275 }
5276
5277 glDispatchComputeIndirect(3);
5278 if (glGetError() != GL_INVALID_VALUE)
5279 {
5280 m_context.getTestContext().getLog()
5281 << tcu::TestLog::Message << "INVALID_VALUE is generated by DispatchComputeIndirect if <indirect> is\n"
5282 "less than zero or not a multiple of four."
5283 << tcu::TestLog::EndMessage;
5284 return ERROR;
5285 }
5286
5287 glDispatchComputeIndirect(16);
5288 if (glGetError() != GL_INVALID_OPERATION)
5289 {
5290 m_context.getTestContext().getLog()
5291 << tcu::TestLog::Message
5292 << "INVALID_OPERATION is generated by DispatchComputeIndirect if no buffer is\n"
5293 "bound to DISPATCH_INDIRECT_BUFFER or if the command would source data\n"
5294 "beyond the end of the bound buffer object."
5295 << tcu::TestLog::EndMessage;
5296 return ERROR;
5297 }
5298
5299 glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, 0);
5300 glDispatchComputeIndirect(0);
5301 if (glGetError() != GL_INVALID_OPERATION)
5302 {
5303 m_context.getTestContext().getLog()
5304 << tcu::TestLog::Message
5305 << "INVALID_OPERATION is generated by DispatchComputeIndirect if no buffer is\n"
5306 "bound to DISPATCH_INDIRECT_BUFFER or if the command would source data\n"
5307 "beyond the end of the bound buffer object."
5308 << tcu::TestLog::EndMessage;
5309 return ERROR;
5310 }
5311
5312 return NO_ERROR;
5313 }
Cleanup()5314 virtual long Cleanup()
5315 {
5316 glUseProgram(0);
5317 glDeleteProgram(m_program);
5318 glDeleteBuffers(1, &m_storage_buffer);
5319 glDeleteBuffers(1, &m_dispatch_buffer);
5320 return NO_ERROR;
5321 }
5322 };
5323
5324 class NegativeAPIProgram : public ComputeShaderBase
5325 {
Title()5326 virtual std::string Title()
5327 {
5328 return NL "API errors - program state";
5329 }
Purpose()5330 virtual std::string Purpose()
5331 {
5332 return NL "Verify that appropriate errors are generated by the OpenGL API.";
5333 }
Method()5334 virtual std::string Method()
5335 {
5336 return NL "";
5337 }
PassCriteria()5338 virtual std::string PassCriteria()
5339 {
5340 return NL "";
5341 }
5342
5343 GLuint m_program;
5344 GLuint m_storage_buffer;
5345
Setup()5346 virtual long Setup()
5347 {
5348 m_program = 0;
5349 m_storage_buffer = 0;
5350 return NO_ERROR;
5351 }
Run()5352 virtual long Run()
5353 {
5354 const char* const glsl_vs = NL "layout(location = 0) in mediump vec4 g_position;" NL "void main() {" NL
5355 " gl_Position = g_position;" NL "}";
5356 const char* const glsl_fs =
5357 NL "layout(location = 0) out mediump vec4 g_color;" NL "void main() {" NL " g_color = vec4(1);" NL "}";
5358 m_program = CreateProgram(glsl_vs, glsl_fs);
5359
5360 GLint v[3];
5361 glGetProgramiv(m_program, GL_COMPUTE_WORK_GROUP_SIZE, v);
5362 if (glGetError() != GL_INVALID_OPERATION)
5363 {
5364 m_context.getTestContext().getLog()
5365 << tcu::TestLog::Message << "INVALID_OPERATION is generated by GetProgramiv if <pname> is\n"
5366 "COMPUTE_LOCAL_WORK_SIZE and either the program has not been linked\n"
5367 "successfully, or has been linked but contains no compute shaders."
5368 << tcu::TestLog::EndMessage;
5369 return ERROR;
5370 }
5371
5372 glLinkProgram(m_program);
5373 if (!CheckProgram(m_program))
5374 return ERROR;
5375
5376 glGetProgramiv(m_program, GL_COMPUTE_WORK_GROUP_SIZE, v);
5377 if (glGetError() != GL_INVALID_OPERATION)
5378 {
5379 m_context.getTestContext().getLog()
5380 << tcu::TestLog::Message << "INVALID_OPERATION is generated by GetProgramiv if <pname> is\n"
5381 "COMPUTE_LOCAL_WORK_SIZE and either the program has not been linked\n"
5382 "successfully, or has been linked but contains no compute shaders."
5383 << tcu::TestLog::EndMessage;
5384 return ERROR;
5385 }
5386 glDeleteProgram(m_program);
5387
5388 const char* const glsl_cs =
5389 "#version 310 es" NL "layout(local_size_x = 1) in;" NL "layout(std430) buffer Output {" NL
5390 " uint g_output[];" NL "};" NL "void main() {" NL " g_output[gl_GlobalInvocationID.x] = 0;" NL "}";
5391 m_program = glCreateProgram();
5392
5393 GLuint sh = glCreateShader(GL_COMPUTE_SHADER);
5394 glAttachShader(m_program, sh);
5395 glDeleteShader(sh);
5396 glShaderSource(sh, 1, &glsl_cs, NULL);
5397 glCompileShader(sh);
5398
5399 sh = glCreateShader(GL_VERTEX_SHADER);
5400 glAttachShader(m_program, sh);
5401 glDeleteShader(sh);
5402 glShaderSource(sh, 1, &glsl_vs, NULL);
5403 glCompileShader(sh);
5404
5405 sh = glCreateShader(GL_FRAGMENT_SHADER);
5406 glAttachShader(m_program, sh);
5407 glDeleteShader(sh);
5408 glShaderSource(sh, 1, &glsl_fs, NULL);
5409 glCompileShader(sh);
5410
5411 glLinkProgram(m_program);
5412 GLint status;
5413 glGetProgramiv(m_program, GL_LINK_STATUS, &status);
5414 if (status == GL_TRUE)
5415 {
5416 m_context.getTestContext().getLog()
5417 << tcu::TestLog::Message << "LinkProgram will fail if <program> contains a combination of compute and\n"
5418 "non-compute shaders."
5419 << tcu::TestLog::EndMessage;
5420 return ERROR;
5421 }
5422
5423 return NO_ERROR;
5424 }
Cleanup()5425 virtual long Cleanup()
5426 {
5427 glUseProgram(0);
5428 glDeleteProgram(m_program);
5429 glDeleteBuffers(1, &m_storage_buffer);
5430 return NO_ERROR;
5431 }
5432 };
5433
5434 class NegativeGLSLCompileTimeErrors : public ComputeShaderBase
5435 {
Title()5436 virtual std::string Title()
5437 {
5438 return NL "Compile-time errors";
5439 }
Purpose()5440 virtual std::string Purpose()
5441 {
5442 return NL "Verify that appropriate errors are generated by the GLSL compiler.";
5443 }
Method()5444 virtual std::string Method()
5445 {
5446 return NL "";
5447 }
PassCriteria()5448 virtual std::string PassCriteria()
5449 {
5450 return NL "";
5451 }
5452
Shader1(int x,int y,int z)5453 static std::string Shader1(int x, int y, int z)
5454 {
5455 std::stringstream ss;
5456 ss << "#version 310 es" NL "layout(local_size_x = " << x << ", local_size_y = " << y << ", local_size_z = " << z
5457 << ") in;" NL "layout(std430) buffer Output {" NL " uint g_output[];" NL "};" NL "void main() {" NL
5458 " g_output[gl_GlobalInvocationID.x] = 0;" NL "}";
5459 return ss.str();
5460 }
Run()5461 virtual long Run()
5462 {
5463 // gl_GlobalInvocationID requires "#version 310" or later
5464 if (!Compile("#version 300 es" NL "layout(local_size_x = 1) in;" NL "layout(std430) buffer Output {" NL
5465 " uint g_output[];" NL "};" NL "void main() {" NL " g_output[gl_GlobalInvocationID.x] = 0;" NL
5466 "}"))
5467 return ERROR;
5468
5469 if (!Compile("#version 310 es" NL "layout(local_size_x = 1) in;" NL "layout(local_size_x = 2) in;" NL
5470 "layout(std430) buffer Output {" NL " uint g_output[];" NL "};" NL "void main() {" NL
5471 " g_output[gl_GlobalInvocationID.x] = 0;" NL "}"))
5472 return ERROR;
5473
5474 if (!Compile("#version 310 es" NL "layout(local_size_x = 1) in;" NL "in uint x;" NL
5475 "layout(std430) buffer Output {" NL " uint g_output[];" NL "};" NL "void main() {" NL
5476 " g_output[gl_GlobalInvocationID.x] = x;" NL "}"))
5477 return ERROR;
5478
5479 if (!Compile("#version 310 es" NL "layout(local_size_x = 1) in;" NL "out uint x;" NL
5480 "layout(std430) buffer Output {" NL " uint g_output[];" NL "};" NL "void main() {" NL
5481 " g_output[gl_GlobalInvocationID.x] = 0;" NL " x = 0;" NL "}"))
5482 return ERROR;
5483
5484 {
5485 GLint x, y, z;
5486 glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 0, &x);
5487 glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 0, &y);
5488 glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 0, &z);
5489
5490 if (!Compile(Shader1(x + 1, 1, 1)))
5491 return ERROR;
5492 if (!Compile(Shader1(1, y + 1, 1)))
5493 return ERROR;
5494 if (!Compile(Shader1(1, 1, z + 1)))
5495 return ERROR;
5496 }
5497
5498 return NO_ERROR;
5499 }
5500
Compile(const std::string & source)5501 bool Compile(const std::string& source)
5502 {
5503 const GLuint sh = glCreateShader(GL_COMPUTE_SHADER);
5504
5505 const char* const src = source.c_str();
5506 glShaderSource(sh, 1, &src, NULL);
5507 glCompileShader(sh);
5508
5509 GLchar log[1024];
5510 glGetShaderInfoLog(sh, sizeof(log), NULL, log);
5511 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Shader Info Log:\n"
5512 << log << tcu::TestLog::EndMessage;
5513
5514 GLint status;
5515 glGetShaderiv(sh, GL_COMPILE_STATUS, &status);
5516 glDeleteShader(sh);
5517
5518 if (status == GL_TRUE)
5519 {
5520 m_context.getTestContext().getLog()
5521 << tcu::TestLog::Message << "Compilation should fail." << tcu::TestLog::EndMessage;
5522 return false;
5523 }
5524
5525 return true;
5526 }
5527 };
5528
5529 class NegativeGLSLLinkTimeErrors : public ComputeShaderBase
5530 {
Title()5531 virtual std::string Title()
5532 {
5533 return NL "Link-time errors";
5534 }
Purpose()5535 virtual std::string Purpose()
5536 {
5537 return NL "Verify that appropriate errors are generated by the GLSL linker.";
5538 }
Method()5539 virtual std::string Method()
5540 {
5541 return NL "";
5542 }
PassCriteria()5543 virtual std::string PassCriteria()
5544 {
5545 return NL "";
5546 }
5547
Run()5548 virtual long Run()
5549 {
5550 const char* const glsl_cs =
5551 NL "layout(local_size_x = 1, local_size_y = 1) in;" NL "layout(std430) buffer Output {" NL " vec4 data;" NL
5552 "} g_out;" NL "void main() {" NL " g_out.data = vec4(1.0, 2.0, 3.0, 4.0);" NL "}";
5553 const char* const glsl_vs = NL "layout(location = 0) in mediump vec4 g_position;" NL "void main() {" NL
5554 " gl_Position = g_position;" NL "}";
5555 const char* const glsl_fs =
5556 NL "layout(location = 0) out mediump vec4 g_color;" NL "void main() {" NL " g_color = vec4(1);" NL "}";
5557
5558 GLuint p = CreateComputeProgram(glsl_cs);
5559
5560 {
5561 const GLuint sh = glCreateShader(GL_VERTEX_SHADER);
5562 glAttachShader(p, sh);
5563 glDeleteShader(sh);
5564 const char* const src[2] = { kGLSLVer, glsl_vs };
5565 glShaderSource(sh, 2, src, NULL);
5566 glCompileShader(sh);
5567 }
5568 {
5569 const GLuint sh = glCreateShader(GL_FRAGMENT_SHADER);
5570 glAttachShader(p, sh);
5571 glDeleteShader(sh);
5572 const char* const src[2] = { kGLSLVer, glsl_fs };
5573 glShaderSource(sh, 2, src, NULL);
5574 glCompileShader(sh);
5575 }
5576 long error = NO_ERROR;
5577 glLinkProgram(p);
5578 if (CheckProgram(p))
5579 error = ERROR;
5580
5581 /* no layout */
5582 const char* const glsl_cs2 = NL "layout(std430) buffer Output {" NL " vec4 data;" NL "} g_out;" NL
5583 "void main() {" NL " g_out.data = vec4(1.0, 2.0, 3.0, 4.0);" NL "}";
5584
5585 GLuint p2 = CreateComputeProgram(glsl_cs2);
5586 glLinkProgram(p2);
5587 if (CheckProgram(p2))
5588 error = ERROR;
5589
5590 glDeleteProgram(p);
5591 glDeleteProgram(p2);
5592 return error;
5593 }
5594 };
5595
5596 class BasicWorkGroupSizeIsConst : public ComputeShaderBase
5597 {
Title()5598 virtual std::string Title()
5599 {
5600 return NL "gl_WorkGroupSize is an constant";
5601 }
Purpose()5602 virtual std::string Purpose()
5603 {
5604 return NL "Verify that gl_WorkGroupSize can be used as an constant expression.";
5605 }
Method()5606 virtual std::string Method()
5607 {
5608 return NL "";
5609 }
PassCriteria()5610 virtual std::string PassCriteria()
5611 {
5612 return NL "";
5613 }
5614
5615 GLuint m_program;
5616 GLuint m_storage_buffer;
5617
Setup()5618 virtual long Setup()
5619 {
5620 m_program = 0;
5621 m_storage_buffer = 0;
5622 return NO_ERROR;
5623 }
5624
Run()5625 virtual long Run()
5626 {
5627 const char* const glsl_cs =
5628 NL "layout(local_size_x = 2, local_size_y = 3, local_size_z = 4) in;" NL
5629 "layout(std430, binding = 0) buffer Output {" NL " uint g_buffer[22u + gl_WorkGroupSize.x];" NL "};" NL
5630 "shared uint g_shared[gl_WorkGroupSize.x * gl_WorkGroupSize.y * gl_WorkGroupSize.z];" NL
5631 "uniform uint g_uniform[gl_WorkGroupSize.z + 20u];" NL "void main() {" NL
5632 " g_shared[gl_LocalInvocationIndex] = 1U;" NL " groupMemoryBarrier();" NL " barrier();" NL
5633 " uint sum = 0u;" NL
5634 " for (uint i = 0u; i < gl_WorkGroupSize.x * gl_WorkGroupSize.y * gl_WorkGroupSize.z; ++i) {" NL
5635 " sum += g_shared[i];" NL " }" NL " sum += g_uniform[gl_LocalInvocationIndex];" NL
5636 " g_buffer[gl_LocalInvocationIndex] = sum;" NL "}";
5637 m_program = CreateComputeProgram(glsl_cs);
5638 glLinkProgram(m_program);
5639 if (!CheckProgram(m_program))
5640 return ERROR;
5641
5642 glGenBuffers(1, &m_storage_buffer);
5643 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_storage_buffer);
5644 glBufferData(GL_SHADER_STORAGE_BUFFER, 24 * sizeof(GLuint), NULL, GL_STATIC_DRAW);
5645
5646 glUseProgram(m_program);
5647 GLuint values[24] = { 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u, 11u, 12u,
5648 13u, 14u, 15u, 16u, 17u, 18u, 19u, 20u, 21u, 22u, 23u, 24u };
5649 glUniform1uiv(glGetUniformLocation(m_program, "g_uniform"), 24, values);
5650 glDispatchCompute(1, 1, 1);
5651 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
5652
5653 long error = NO_ERROR;
5654 GLuint* data;
5655 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_storage_buffer);
5656 data =
5657 static_cast<GLuint*>(glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(GLuint) * 24, GL_MAP_READ_BIT));
5658 for (GLuint i = 0; i < 24; ++i)
5659 {
5660 if (data[i] != (i + 25))
5661 {
5662 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Data at index " << i << " is "
5663 << data[i] << " should be" << (i + 25) << tcu::TestLog::EndMessage;
5664 error = ERROR;
5665 }
5666 }
5667 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
5668 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
5669 return error;
5670 }
5671
Cleanup()5672 virtual long Cleanup()
5673 {
5674 glUseProgram(0);
5675 glDeleteProgram(m_program);
5676 glDeleteBuffers(1, &m_storage_buffer);
5677 return NO_ERROR;
5678 }
5679 };
5680
5681 } // anonymous namespace
5682
ComputeShaderTests(glcts::Context & context)5683 ComputeShaderTests::ComputeShaderTests(glcts::Context& context) : TestCaseGroup(context, "compute_shader", "")
5684 {
5685 }
5686
~ComputeShaderTests(void)5687 ComputeShaderTests::~ComputeShaderTests(void)
5688 {
5689 }
5690
init()5691 void ComputeShaderTests::init()
5692 {
5693 using namespace glcts;
5694 addChild(new TestSubcase(m_context, "simple-compute", TestSubcase::Create<SimpleCompute>));
5695 addChild(new TestSubcase(m_context, "one-work-group", TestSubcase::Create<BasicOneWorkGroup>));
5696 addChild(new TestSubcase(m_context, "resource-ubo", TestSubcase::Create<BasicResourceUBO>));
5697 addChild(new TestSubcase(m_context, "resource-texture", TestSubcase::Create<BasicResourceTexture>));
5698 addChild(new TestSubcase(m_context, "resource-image", TestSubcase::Create<BasicResourceImage>));
5699 addChild(new TestSubcase(m_context, "resource-atomic-counter", TestSubcase::Create<BasicResourceAtomicCounter>));
5700 addChild(new TestSubcase(m_context, "resource-uniform", TestSubcase::Create<BasicResourceUniform>));
5701 addChild(new TestSubcase(m_context, "built-in-variables", TestSubcase::Create<BasicBuiltinVariables>));
5702 addChild(new TestSubcase(m_context, "max", TestSubcase::Create<BasicMax>));
5703 addChild(new TestSubcase(m_context, "work-group-size", TestSubcase::Create<BasicWorkGroupSizeIsConst>));
5704 addChild(new TestSubcase(m_context, "build-separable", TestSubcase::Create<BasicBuildSeparable>));
5705 addChild(new TestSubcase(m_context, "shared-simple", TestSubcase::Create<BasicSharedSimple>));
5706 addChild(new TestSubcase(m_context, "shared-struct", TestSubcase::Create<BasicSharedStruct>));
5707 addChild(new TestSubcase(m_context, "dispatch-indirect", TestSubcase::Create<BasicDispatchIndirect>));
5708 addChild(new TestSubcase(m_context, "sso-compute-pipeline", TestSubcase::Create<BasicSSOComputePipeline>));
5709 addChild(new TestSubcase(m_context, "sso-case2", TestSubcase::Create<BasicSSOCase2>));
5710 addChild(new TestSubcase(m_context, "sso-case3", TestSubcase::Create<BasicSSOCase3>));
5711 addChild(new TestSubcase(m_context, "atomic-case1", TestSubcase::Create<BasicAtomicCase1>));
5712 addChild(new TestSubcase(m_context, "atomic-case2", TestSubcase::Create<BasicAtomicCase2>));
5713 addChild(new TestSubcase(m_context, "atomic-case3", TestSubcase::Create<BasicAtomicCase3>));
5714 addChild(new TestSubcase(m_context, "copy-image", TestSubcase::Create<AdvancedCopyImage>));
5715 addChild(new TestSubcase(m_context, "pipeline-pre-vs", TestSubcase::Create<AdvancedPipelinePreVS>));
5716 addChild(
5717 new TestSubcase(m_context, "pipeline-gen-draw-commands", TestSubcase::Create<AdvancedPipelineGenDrawCommands>));
5718 addChild(new TestSubcase(m_context, "pipeline-compute-chain", TestSubcase::Create<AdvancedPipelineComputeChain>));
5719 addChild(new TestSubcase(m_context, "pipeline-post-fs", TestSubcase::Create<AdvancedPipelinePostFS>));
5720 addChild(new TestSubcase(m_context, "pipeline-post-xfb", TestSubcase::Create<AdvancedPipelinePostXFB>));
5721 addChild(new TestSubcase(m_context, "shared-indexing", TestSubcase::Create<AdvancedSharedIndexing>));
5722 addChild(new TestSubcase(m_context, "shared-max", TestSubcase::Create<AdvancedSharedMax>));
5723 addChild(new TestSubcase(m_context, "resources-max", TestSubcase::Create<AdvancedResourcesMax>));
5724 addChild(new TestSubcase(m_context, "work-group-size-usage", TestSubcase::Create<WorkGroupSizeUsage>));
5725 addChild(new TestSubcase(m_context, "api-no-active-program", TestSubcase::Create<NegativeAPINoActiveProgram>));
5726 addChild(new TestSubcase(m_context, "api-work-group-count", TestSubcase::Create<NegativeAPIWorkGroupCount>));
5727 addChild(new TestSubcase(m_context, "api-indirect", TestSubcase::Create<NegativeAPIIndirect>));
5728 addChild(new TestSubcase(m_context, "api-program", TestSubcase::Create<NegativeAPIProgram>));
5729 addChild(
5730 new TestSubcase(m_context, "glsl-compile-time-errors", TestSubcase::Create<NegativeGLSLCompileTimeErrors>));
5731 addChild(new TestSubcase(m_context, "glsl-link-time-errors", TestSubcase::Create<NegativeGLSLLinkTimeErrors>));
5732 addChild(new TestSubcase(m_context, "api-attach-shader", TestSubcase::Create<NegativeAttachShader>));
5733 }
5734 } // glcts namespace
5735