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