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