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