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