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