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