xref: /aosp_15_r20/external/deqp/external/openglcts/modules/gles31/es31cShaderAtomicCountersTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * OpenGL Conformance Test Suite
3  * -----------------------------
4  *
5  * Copyright (c) 2014-2016 The Khronos Group Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  */ /*!
20  * \file
21  * \brief
22  */ /*-------------------------------------------------------------------*/
23 
24 #include "es31cShaderAtomicCountersTests.hpp"
25 #include "gluContextInfo.hpp"
26 #include "gluPixelTransfer.hpp"
27 #include "glwEnums.hpp"
28 #include "glwFunctions.hpp"
29 #include "tcuImageCompare.hpp"
30 #include "tcuRenderTarget.hpp"
31 #include "tcuSurface.hpp"
32 #include "tcuVector.hpp"
33 #include <assert.h>
34 #include <cstdarg>
35 #include <map>
36 
37 namespace glcts
38 {
39 using namespace glw;
40 using tcu::UVec4;
41 using tcu::Vec4;
42 
43 namespace
44 {
45 
46 class SACSubcaseBase : public glcts::SubcaseBase
47 {
48 public:
Title()49     virtual std::string Title()
50     {
51         return NL "";
52     }
Purpose()53     virtual std::string Purpose()
54     {
55         return NL "";
56     }
Method()57     virtual std::string Method()
58     {
59         return NL "";
60     }
PassCriteria()61     virtual std::string PassCriteria()
62     {
63         return NL "";
64     }
65 
~SACSubcaseBase()66     virtual ~SACSubcaseBase()
67     {
68     }
69 
CheckProgram(GLuint program)70     bool CheckProgram(GLuint program)
71     {
72         GLint status;
73         glGetProgramiv(program, GL_LINK_STATUS, &status);
74         GLint length;
75         glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length);
76         if (length > 1)
77         {
78             std::vector<GLchar> log(length);
79             glGetProgramInfoLog(program, length, NULL, &log[0]);
80             m_context.getTestContext().getLog() << tcu::TestLog::Message << &log[0] << tcu::TestLog::EndMessage;
81         }
82         return status == GL_TRUE;
83     }
84 
getWindowWidth()85     int getWindowWidth()
86     {
87         const tcu::RenderTarget &renderTarget = m_context.getRenderContext().getRenderTarget();
88         return renderTarget.getWidth();
89     }
90 
getWindowHeight()91     int getWindowHeight()
92     {
93         const tcu::RenderTarget &renderTarget = m_context.getRenderContext().getRenderTarget();
94         return renderTarget.getHeight();
95     }
96 
ValidateReadBuffer(const Vec4 & expected)97     long ValidateReadBuffer(const Vec4 &expected)
98     {
99         const tcu::RenderTarget &renderTarget = m_context.getRenderContext().getRenderTarget();
100         int viewportW                         = renderTarget.getWidth();
101         int viewportH                         = renderTarget.getHeight();
102         tcu::Surface renderedFrame(viewportW, viewportH);
103         tcu::Surface referenceFrame(viewportW, viewportH);
104 
105         glu::readPixels(m_context.getRenderContext(), 0, 0, renderedFrame.getAccess());
106 
107         for (int y = 0; y < viewportH; ++y)
108         {
109             for (int x = 0; x < viewportW; ++x)
110             {
111                 referenceFrame.setPixel(
112                     x, y,
113                     tcu::RGBA(static_cast<int>(expected[0] * 255), static_cast<int>(expected[1] * 255),
114                               static_cast<int>(expected[2] * 255), static_cast<int>(expected[3] * 255)));
115             }
116         }
117         tcu::TestLog &log = m_context.getTestContext().getLog();
118         bool isOk = tcu::fuzzyCompare(log, "Result", "Image comparison result", referenceFrame, renderedFrame, 0.05f,
119                                       tcu::COMPARE_LOG_RESULT);
120         return (isOk ? NO_ERROR : ERROR);
121     }
122 
LinkProgram(GLuint program)123     void LinkProgram(GLuint program)
124     {
125         glLinkProgram(program);
126         GLsizei length;
127         GLchar log[1024];
128         glGetProgramInfoLog(program, sizeof(log), &length, log);
129         if (length > 1)
130         {
131             m_context.getTestContext().getLog() << tcu::TestLog::Message << "Program Info Log:\n"
132                                                 << log << tcu::TestLog::EndMessage;
133         }
134     }
135 
CreateProgram(const char * src_vs,const char * src_fs,bool link)136     GLuint CreateProgram(const char *src_vs, const char *src_fs, bool link)
137     {
138         const GLuint p = glCreateProgram();
139 
140         if (src_vs)
141         {
142             GLuint sh = glCreateShader(GL_VERTEX_SHADER);
143             glAttachShader(p, sh);
144             glDeleteShader(sh);
145             glShaderSource(sh, 1, &src_vs, NULL);
146             glCompileShader(sh);
147         }
148         if (src_fs)
149         {
150             GLuint sh = glCreateShader(GL_FRAGMENT_SHADER);
151             glAttachShader(p, sh);
152             glDeleteShader(sh);
153             glShaderSource(sh, 1, &src_fs, NULL);
154             glCompileShader(sh);
155         }
156         if (link)
157         {
158             LinkProgram(p);
159         }
160         return p;
161     }
162 
CreateShaderProgram(GLenum type,GLsizei count,const GLchar ** strings)163     GLuint CreateShaderProgram(GLenum type, GLsizei count, const GLchar **strings)
164     {
165         GLuint program = glCreateShaderProgramv(type, count, strings);
166         GLint status   = GL_TRUE;
167         glGetProgramiv(program, GL_LINK_STATUS, &status);
168         if (status == GL_FALSE)
169         {
170             GLsizei length;
171             GLchar log[1024];
172             glGetProgramInfoLog(program, sizeof(log), &length, log);
173             if (length > 1)
174             {
175                 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Program Info Log:\n"
176                                                     << log << tcu::TestLog::EndMessage;
177             }
178         }
179         return program;
180     }
181 
CreateQuad(GLuint * vao,GLuint * vbo,GLuint * ebo)182     void CreateQuad(GLuint *vao, GLuint *vbo, GLuint *ebo)
183     {
184         assert(vao && vbo);
185 
186         // interleaved data (vertex, color0 (green), color1 (blue), color2 (red))
187         const float v[] = {
188             -1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,  1.0f, 0.0f, 0.0f, 1.0f, -1.0f, 0.0f, 1.0f,
189             0.0f,  0.0f,  0.0f, 1.0f, 1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f,  0.0f, 1.0f,
190             1.0f,  0.0f,  0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f,  0.0f, 0.0f, 1.0f, 1.0f, 0.0f,  0.0f,
191         };
192         glGenBuffers(1, vbo);
193         glBindBuffer(GL_ARRAY_BUFFER, *vbo);
194         glBufferData(GL_ARRAY_BUFFER, sizeof(v), v, GL_STATIC_DRAW);
195         glBindBuffer(GL_ARRAY_BUFFER, 0);
196 
197         if (ebo)
198         {
199             std::vector<GLushort> index_data(4);
200             for (int i = 0; i < 4; ++i)
201             {
202                 index_data[i] = static_cast<GLushort>(i);
203             }
204             glGenBuffers(1, ebo);
205             glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, *ebo);
206             glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort) * 4, &index_data[0], GL_STATIC_DRAW);
207             glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
208         }
209 
210         glGenVertexArrays(1, vao);
211         glBindVertexArray(*vao);
212         glBindBuffer(GL_ARRAY_BUFFER, *vbo);
213         glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 11, 0);
214         glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 11,
215                               reinterpret_cast<void *>(sizeof(float) * 2));
216         glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 11,
217                               reinterpret_cast<void *>(sizeof(float) * 5));
218         glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 11,
219                               reinterpret_cast<void *>(sizeof(float) * 8));
220         glBindBuffer(GL_ARRAY_BUFFER, 0);
221         glEnableVertexAttribArray(0);
222         glEnableVertexAttribArray(1);
223         glEnableVertexAttribArray(2);
224         glEnableVertexAttribArray(3);
225         if (ebo)
226         {
227             glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, *ebo);
228         }
229         glBindVertexArray(0);
230     }
231 
CreateTriangle(GLuint * vao,GLuint * vbo,GLuint * ebo)232     void CreateTriangle(GLuint *vao, GLuint *vbo, GLuint *ebo)
233     {
234         assert(vao && vbo);
235 
236         // interleaved data (vertex, color0 (green), color1 (blue), color2 (red))
237         const float v[] = {
238             -1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f,  0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 3.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f,
239             0.0f,  1.0f,  1.0f, 0.0f, 0.0f, -1.0f, 3.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,  1.0f, 0.0f, 0.0f,
240         };
241         glGenBuffers(1, vbo);
242         glBindBuffer(GL_ARRAY_BUFFER, *vbo);
243         glBufferData(GL_ARRAY_BUFFER, sizeof(v), v, GL_STATIC_DRAW);
244         glBindBuffer(GL_ARRAY_BUFFER, 0);
245 
246         if (ebo)
247         {
248             std::vector<GLushort> index_data(3);
249             for (int i = 0; i < 3; ++i)
250             {
251                 index_data[i] = static_cast<GLushort>(i);
252             }
253             glGenBuffers(1, ebo);
254             glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, *ebo);
255             glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort) * 4, &index_data[0], GL_STATIC_DRAW);
256             glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
257         }
258 
259         glGenVertexArrays(1, vao);
260         glBindVertexArray(*vao);
261         glBindBuffer(GL_ARRAY_BUFFER, *vbo);
262         glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 11, 0);
263         glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 11,
264                               reinterpret_cast<void *>(sizeof(float) * 2));
265         glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 11,
266                               reinterpret_cast<void *>(sizeof(float) * 5));
267         glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 11,
268                               reinterpret_cast<void *>(sizeof(float) * 8));
269         glBindBuffer(GL_ARRAY_BUFFER, 0);
270         glEnableVertexAttribArray(0);
271         glEnableVertexAttribArray(1);
272         glEnableVertexAttribArray(2);
273         glEnableVertexAttribArray(3);
274         if (ebo)
275         {
276             glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, *ebo);
277         }
278         glBindVertexArray(0);
279     }
280 
GLenumToString(GLenum e)281     const char *GLenumToString(GLenum e)
282     {
283         switch (e)
284         {
285         case GL_ATOMIC_COUNTER_BUFFER_BINDING:
286             return "GL_ATOMIC_COUNTER_BUFFER_BINDING";
287         case GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS:
288             return "GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS";
289         case GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS:
290             return "GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS";
291         case GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS:
292             return "GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS";
293         case GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS:
294             return "GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS";
295 
296         case GL_MAX_VERTEX_ATOMIC_COUNTERS:
297             return "GL_MAX_VERTEX_ATOMIC_COUNTERS";
298         case GL_MAX_COMPUTE_ATOMIC_COUNTERS:
299             return "GL_MAX_GEOMETRY_ATOMIC_COUNTERS";
300         case GL_MAX_FRAGMENT_ATOMIC_COUNTERS:
301             return "GL_MAX_FRAGMENT_ATOMIC_COUNTERS";
302         case GL_MAX_COMBINED_ATOMIC_COUNTERS:
303             return "GL_MAX_COMBINED_ATOMIC_COUNTERS";
304 
305         case GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE:
306             return "GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE";
307         case GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS:
308             return "GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS";
309 
310         default:
311             assert(0);
312             break;
313         }
314         return NULL;
315     }
316 
CheckMaxValue(GLenum e,GLint expected)317     bool CheckMaxValue(GLenum e, GLint expected)
318     {
319         bool ok = true;
320 
321         GLint i;
322         glGetIntegerv(e, &i);
323         m_context.getTestContext().getLog()
324             << tcu::TestLog::Message << GLenumToString(e) << " = " << i << tcu::TestLog::EndMessage;
325 
326         if (i < expected)
327         {
328             ok = false;
329             m_context.getTestContext().getLog()
330                 << tcu::TestLog::Message << GLenumToString(e) << " state is incorrect (GetIntegerv, is: " << i
331                 << ", expected: " << expected << ")" << tcu::TestLog::EndMessage;
332         }
333 
334         GLint64 i64;
335         glGetInteger64v(e, &i64);
336         if (i64 < static_cast<GLint64>(expected))
337         {
338             ok = false;
339             m_context.getTestContext().getLog() << tcu::TestLog::Message << GLenumToString(e)
340                                                 << " state is incorrect (GetInteger64v, is: " << static_cast<GLint>(i64)
341                                                 << ", expected: " << expected << ")" << tcu::TestLog::EndMessage;
342         }
343 
344         GLfloat f;
345         glGetFloatv(e, &f);
346         if (f < static_cast<GLfloat>(expected))
347         {
348             ok = false;
349             m_context.getTestContext().getLog()
350                 << tcu::TestLog::Message << GLenumToString(e) << " state is incorrect (GetFloatv, is: " << f
351                 << ", expected: " << expected << ")" << tcu::TestLog::EndMessage;
352         }
353 
354         GLboolean b;
355         glGetBooleanv(e, &b);
356 
357         return ok;
358     }
359 
CheckGetCommands(GLenum e,GLint expected)360     bool CheckGetCommands(GLenum e, GLint expected)
361     {
362         bool ok = true;
363 
364         GLint i;
365         glGetIntegerv(e, &i);
366         if (i != expected)
367         {
368             ok = false;
369             m_context.getTestContext().getLog()
370                 << tcu::TestLog::Message << GLenumToString(e) << " state is incorrect (GetIntegerv, is: " << i
371                 << ", expected: " << expected << ")" << tcu::TestLog::EndMessage;
372         }
373 
374         GLint64 i64;
375         glGetInteger64v(e, &i64);
376         if (i64 != static_cast<GLint64>(expected))
377         {
378             ok = false;
379             m_context.getTestContext().getLog() << tcu::TestLog::Message << GLenumToString(e)
380                                                 << " state is incorrect (GetInteger64v, is: " << static_cast<GLint>(i64)
381                                                 << ", expected: " << expected << ")" << tcu::TestLog::EndMessage;
382         }
383 
384         GLfloat f;
385         glGetFloatv(e, &f);
386         if (f != static_cast<GLfloat>(expected))
387         {
388             ok = false;
389             m_context.getTestContext().getLog()
390                 << tcu::TestLog::Message << GLenumToString(e) << " state is incorrect (GetFloatv, is: " << f
391                 << ", expected: " << expected << ")" << tcu::TestLog::EndMessage;
392         }
393 
394         GLboolean b;
395         glGetBooleanv(e, &b);
396         if (b != (expected ? GL_TRUE : GL_FALSE))
397         {
398             ok = false;
399             m_context.getTestContext().getLog()
400                 << tcu::TestLog::Message << GLenumToString(e) << " state is incorrect (GetBooleanv, is: " << b
401                 << ", expected: " << (expected ? GL_TRUE : GL_FALSE) << ")" << tcu::TestLog::EndMessage;
402         }
403 
404         return ok;
405     }
406 
CheckBufferBindingState(GLuint index,GLint binding,GLint64 start,GLint64 size)407     bool CheckBufferBindingState(GLuint index, GLint binding, GLint64 start, GLint64 size)
408     {
409         bool ok = true;
410 
411         GLint i;
412         glGetIntegeri_v(GL_ATOMIC_COUNTER_BUFFER_BINDING, index, &i);
413         if (i != binding)
414         {
415             ok = false;
416             m_context.getTestContext().getLog()
417                 << tcu::TestLog::Message
418                 << "GL_ATOMIC_COUNTER_BUFFER_BINDING state is incorrect (GetIntegeri_v, is: " << i
419                 << ", expected: " << binding << ", index: " << index << tcu::TestLog::EndMessage;
420         }
421 
422         GLint64 i64;
423         glGetInteger64i_v(GL_ATOMIC_COUNTER_BUFFER_BINDING, index, &i64);
424         if (i64 != static_cast<GLint64>(binding))
425         {
426             ok = false;
427             m_context.getTestContext().getLog()
428                 << tcu::TestLog::Message << "GL_ATOMIC_COUNTER_BUFFER_BINDING state is incorrect (GetInteger64i_v, is: "
429                 << static_cast<GLint>(i64) << ", expected: " << binding << ", index: " << index
430                 << tcu::TestLog::EndMessage;
431         }
432 
433         glGetInteger64i_v(GL_ATOMIC_COUNTER_BUFFER_START, index, &i64);
434         if (i64 != start)
435         {
436             ok = false;
437             m_context.getTestContext().getLog()
438                 << tcu::TestLog::Message
439                 << "GL_ATOMIC_COUNTER_BUFFER_START state is incorrect (GetInteger64i_v, is: " << static_cast<GLint>(i64)
440                 << ", expected: " << static_cast<GLint>(start) << ", index: " << index << tcu::TestLog::EndMessage;
441         }
442         glGetInteger64i_v(GL_ATOMIC_COUNTER_BUFFER_SIZE, index, &i64);
443         if (i64 != size && i64 != 0)
444         {
445             ok = false;
446             m_context.getTestContext().getLog()
447                 << tcu::TestLog::Message
448                 << "GL_ATOMIC_COUNTER_BUFFER_SIZE state is incorrect (GetInteger64i_v, is: " << static_cast<GLint>(i64)
449                 << ", expected: (" << static_cast<GLint>(size) << " or 0), index: " << index
450                 << tcu::TestLog::EndMessage;
451         }
452 
453         return ok;
454     }
455 
CheckUniform(GLuint prog,const GLchar * uniform_name,GLuint uniform_index,GLint uniform_type,GLint uniform_size,GLint uniform_offset,GLint uniform_array_stride)456     bool CheckUniform(GLuint prog, const GLchar *uniform_name, GLuint uniform_index, GLint uniform_type,
457                       GLint uniform_size, GLint uniform_offset, GLint uniform_array_stride)
458     {
459         bool ok = true;
460 
461         GLuint index;
462         glGetUniformIndices(prog, 1, &uniform_name, &index);
463         if (index != uniform_index)
464         {
465             m_context.getTestContext().getLog()
466                 << tcu::TestLog::Message << "Uniform: " << uniform_name
467                 << ": Bad index returned by glGetUniformIndices." << tcu::TestLog::EndMessage;
468             ok = false;
469         }
470 
471         const GLsizei uniform_length = static_cast<GLsizei>(strlen(uniform_name));
472 
473         GLsizei length;
474         GLint size;
475         GLenum type;
476         GLchar name[32];
477 
478         glGetProgramResourceName(prog, GL_UNIFORM, uniform_index, sizeof(name), &length, name);
479         if (length != uniform_length)
480         {
481             m_context.getTestContext().getLog()
482                 << tcu::TestLog::Message << "Uniform: " << uniform_name << ": Length is " << length << " should be "
483                 << uniform_length << tcu::TestLog::EndMessage;
484             ok = false;
485         }
486         glGetActiveUniform(prog, uniform_index, sizeof(name), &length, &size, &type, name);
487         if (strcmp(name, uniform_name))
488         {
489             m_context.getTestContext().getLog()
490                 << tcu::TestLog::Message << "Uniform: " << uniform_name << ": Bad name returned by glGetActiveUniform."
491                 << tcu::TestLog::EndMessage;
492             ok = false;
493         }
494         if (length != uniform_length)
495         {
496             m_context.getTestContext().getLog()
497                 << tcu::TestLog::Message << "Uniform: " << uniform_name << ": Length is " << length << " should be "
498                 << uniform_length << tcu::TestLog::EndMessage;
499             ok = false;
500         }
501         if (size != uniform_size)
502         {
503             m_context.getTestContext().getLog() << tcu::TestLog::Message << "Uniform: " << uniform_name << ": Size is "
504                                                 << size << " should be " << uniform_size << tcu::TestLog::EndMessage;
505             ok = false;
506         }
507         if (type != static_cast<GLenum>(uniform_type))
508         {
509             m_context.getTestContext().getLog() << tcu::TestLog::Message << "Uniform: " << uniform_name << ": Type is "
510                                                 << type << " should be " << uniform_type << tcu::TestLog::EndMessage;
511             ok = false;
512         }
513 
514         GLint param;
515         glGetActiveUniformsiv(prog, 1, &uniform_index, GL_UNIFORM_TYPE, &param);
516         if (param != uniform_type)
517         {
518             m_context.getTestContext().getLog() << tcu::TestLog::Message << "Uniform: " << uniform_name << ": Type is "
519                                                 << param << " should be " << uniform_type << tcu::TestLog::EndMessage;
520             ok = false;
521         }
522         glGetActiveUniformsiv(prog, 1, &uniform_index, GL_UNIFORM_SIZE, &param);
523         if (param != uniform_size)
524         {
525             m_context.getTestContext().getLog()
526                 << tcu::TestLog::Message << "Uniform: " << uniform_name << ": GL_UNIFORM_SIZE is " << param
527                 << " should be " << uniform_size << tcu::TestLog::EndMessage;
528             ok = false;
529         }
530         glGetActiveUniformsiv(prog, 1, &uniform_index, GL_UNIFORM_NAME_LENGTH, &param);
531         if (param != (uniform_length + 1))
532         {
533             m_context.getTestContext().getLog()
534                 << tcu::TestLog::Message << "Uniform: " << uniform_name << ": GL_UNIFORM_NAME_LENGTH is " << param
535                 << " should be " << (uniform_length + 1) << tcu::TestLog::EndMessage;
536             ok = false;
537         }
538         glGetActiveUniformsiv(prog, 1, &uniform_index, GL_UNIFORM_BLOCK_INDEX, &param);
539         if (param != -1)
540         {
541             m_context.getTestContext().getLog() << tcu::TestLog::Message << "Uniform: " << uniform_name
542                                                 << ": GL_UNIFORM_BLOCK_INDEX should be -1." << tcu::TestLog::EndMessage;
543             ok = false;
544         }
545         glGetActiveUniformsiv(prog, 1, &uniform_index, GL_UNIFORM_OFFSET, &param);
546         if (param != uniform_offset)
547         {
548             m_context.getTestContext().getLog()
549                 << tcu::TestLog::Message << "Uniform: " << uniform_name << ": GL_UNIFORM_OFFSET is " << param
550                 << " should be " << uniform_offset << tcu::TestLog::EndMessage;
551             ok = false;
552         }
553         glGetActiveUniformsiv(prog, 1, &uniform_index, GL_UNIFORM_ARRAY_STRIDE, &param);
554         if (param != uniform_array_stride)
555         {
556             m_context.getTestContext().getLog()
557                 << tcu::TestLog::Message << "Uniform: " << uniform_name << ": GL_UNIFORM_ARRAY_STRIDE is " << param
558                 << " should be " << uniform_array_stride << tcu::TestLog::EndMessage;
559             ok = false;
560         }
561         glGetActiveUniformsiv(prog, 1, &uniform_index, GL_UNIFORM_MATRIX_STRIDE, &param);
562         if (param != 0)
563         {
564             m_context.getTestContext().getLog()
565                 << tcu::TestLog::Message << "Uniform: " << uniform_name << ": GL_UNIFORM_MATRIX_STRIDE should be 0 is "
566                 << param << tcu::TestLog::EndMessage;
567             ok = false;
568         }
569         glGetActiveUniformsiv(prog, 1, &uniform_index, GL_UNIFORM_IS_ROW_MAJOR, &param);
570         if (param != 0)
571         {
572             m_context.getTestContext().getLog()
573                 << tcu::TestLog::Message << "Uniform: " << uniform_name << ": GL_UNIFORM_MATRIX_STRIDE should be 0 is "
574                 << param << tcu::TestLog::EndMessage;
575             ok = false;
576         }
577 
578         return ok;
579     }
580 
CheckCounterValues(GLuint size,GLuint * values,GLuint min_value)581     bool CheckCounterValues(GLuint size, GLuint *values, GLuint min_value)
582     {
583         std::sort(values, values + size);
584         for (GLuint i = 0; i < size; ++i)
585         {
586             m_context.getTestContext().getLog() << tcu::TestLog::Message << values[i] << tcu::TestLog::EndMessage;
587             if (values[i] != i + min_value)
588             {
589                 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Counter value is " << values[i]
590                                                     << " should be " << i + min_value << tcu::TestLog::EndMessage;
591                 return false;
592             }
593         }
594         return true;
595     }
596 
CheckCounterValues(GLuint size,UVec4 * data,GLuint min_value)597     bool CheckCounterValues(GLuint size, UVec4 *data, GLuint min_value)
598     {
599         std::vector<GLuint> values(size);
600         for (GLuint j = 0; j < size; ++j)
601         {
602             values[j] = data[j].x();
603         }
604         std::sort(values.begin(), values.end());
605         for (GLuint i = 0; i < size; ++i)
606         {
607             m_context.getTestContext().getLog() << tcu::TestLog::Message << values[i] << tcu::TestLog::EndMessage;
608             if (values[i] != i + min_value)
609             {
610                 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Counter value is " << values[i]
611                                                     << " should be " << i + min_value << tcu::TestLog::EndMessage;
612                 return false;
613             }
614         }
615         return true;
616     }
617 
CheckFinalCounterValue(GLuint buffer,GLintptr offset,GLuint expected_value)618     bool CheckFinalCounterValue(GLuint buffer, GLintptr offset, GLuint expected_value)
619     {
620         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, buffer);
621         GLuint *value = static_cast<GLuint *>(glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, offset, 4, GL_MAP_READ_BIT));
622         if (value[0] != expected_value)
623         {
624             m_context.getTestContext().getLog() << tcu::TestLog::Message << "Counter value is " << value[0]
625                                                 << " should be " << expected_value << tcu::TestLog::EndMessage;
626             glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
627             glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
628             return false;
629         }
630         glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
631         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
632         return true;
633     }
634 };
635 
636 class Buffer : public glcts::GLWrapper
637 {
638 public:
Buffer()639     Buffer()
640         : size_(0)
641         , usage_(GL_STATIC_DRAW)
642         , access_(GL_WRITE_ONLY)
643         , access_flags_(0)
644         , mapped_(GL_FALSE)
645         , map_pointer_(NULL)
646         , map_offset_(0)
647         , map_length_(0)
648     {
649         glGenBuffers(1, &name_);
650         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, name_);
651         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
652     }
~Buffer()653     ~Buffer()
654     {
655         glDeleteBuffers(1, &name_);
656     }
name() const657     GLuint name() const
658     {
659         return name_;
660     }
Verify()661     long Verify()
662     {
663         GLint i;
664         GLint64 i64;
665 
666         glGetBufferParameteri64v(GL_ATOMIC_COUNTER_BUFFER, GL_BUFFER_SIZE, &i64);
667         if (i64 != size_)
668         {
669             m_context.getTestContext().getLog()
670                 << tcu::TestLog::Message << "BUFFER_SIZE is " << static_cast<GLint>(i64) << " should be "
671                 << static_cast<GLint>(size_) << tcu::TestLog::EndMessage;
672             return ERROR;
673         }
674         glGetBufferParameteriv(GL_ATOMIC_COUNTER_BUFFER, GL_BUFFER_USAGE, &i);
675         if (i != static_cast<GLint>(usage_))
676         {
677             m_context.getTestContext().getLog() << tcu::TestLog::Message << "BUFFER_USAGE is " << i << " should be "
678                                                 << usage_ << tcu::TestLog::EndMessage;
679             return ERROR;
680         }
681         if (this->m_context.getContextInfo().isExtensionSupported("GL_OES_mapbuffer"))
682         {
683             glGetBufferParameteriv(GL_ATOMIC_COUNTER_BUFFER, GL_BUFFER_ACCESS, &i);
684             if (i != static_cast<GLint>(access_))
685             {
686                 m_context.getTestContext().getLog() << tcu::TestLog::Message << "BUFFER_ACCESS is " << i
687                                                     << " should be " << access_ << tcu::TestLog::EndMessage;
688                 return ERROR;
689             }
690         }
691         else
692         {
693             m_context.getTestContext().getLog()
694                 << tcu::TestLog::Message << "GL_OES_mapbuffer not supported, skipping GL_BUFFER_ACCESS enum"
695                 << tcu::TestLog::EndMessage;
696         }
697         glGetBufferParameteriv(GL_ATOMIC_COUNTER_BUFFER, GL_BUFFER_ACCESS_FLAGS, &i);
698         if (i != access_flags_)
699         {
700             m_context.getTestContext().getLog() << tcu::TestLog::Message << "BUFFER_ACCESS_FLAGS is " << i
701                                                 << " should be " << access_flags_ << tcu::TestLog::EndMessage;
702             return ERROR;
703         }
704         glGetBufferParameteriv(GL_ATOMIC_COUNTER_BUFFER, GL_BUFFER_MAPPED, &i);
705         if (i != mapped_)
706         {
707             m_context.getTestContext().getLog() << tcu::TestLog::Message << "BUFFER_MAPPED is " << i << " should be "
708                                                 << mapped_ << tcu::TestLog::EndMessage;
709             return ERROR;
710         }
711         glGetBufferParameteri64v(GL_ATOMIC_COUNTER_BUFFER, GL_BUFFER_MAP_OFFSET, &i64);
712         if (i64 != map_offset_)
713         {
714             m_context.getTestContext().getLog()
715                 << tcu::TestLog::Message << "BUFFER_MAP_OFFSET is " << static_cast<GLint>(i64) << " should be "
716                 << static_cast<GLint>(map_offset_) << tcu::TestLog::EndMessage;
717             return ERROR;
718         }
719         glGetBufferParameteri64v(GL_ATOMIC_COUNTER_BUFFER, GL_BUFFER_MAP_LENGTH, &i64);
720         if (i64 != map_length_)
721         {
722             m_context.getTestContext().getLog()
723                 << tcu::TestLog::Message << "BUFFER_MAP_LENGTH is " << static_cast<GLint>(i64) << " should be "
724                 << static_cast<GLint>(map_length_) << tcu::TestLog::EndMessage;
725             return ERROR;
726         }
727         void *ptr;
728         glGetBufferPointerv(GL_ATOMIC_COUNTER_BUFFER, GL_BUFFER_MAP_POINTER, &ptr);
729         if (ptr != map_pointer_)
730         {
731             m_context.getTestContext().getLog()
732                 << tcu::TestLog::Message << "BUFFER_MAP_POINTER is "
733                 << reinterpret_cast<uintptr_t>(static_cast<int *>(ptr)) << " should be "
734                 << reinterpret_cast<uintptr_t>(static_cast<int *>(map_pointer_)) << tcu::TestLog::EndMessage;
735             return ERROR;
736         }
737         return NO_ERROR;
738     }
Data(GLsizeiptr size,const void * data,GLenum usage)739     void Data(GLsizeiptr size, const void *data, GLenum usage)
740     {
741         size_  = size;
742         usage_ = usage;
743         glBufferData(GL_ATOMIC_COUNTER_BUFFER, size, data, usage);
744     }
MapRange(GLintptr offset,GLsizeiptr length,GLbitfield access)745     void *MapRange(GLintptr offset, GLsizeiptr length, GLbitfield access)
746     {
747         assert(mapped_ == GL_FALSE);
748 
749         map_pointer_ = glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, offset, length, access);
750         if (map_pointer_)
751         {
752             map_offset_   = offset;
753             map_length_   = length;
754             access_flags_ = access;
755             if (access & GL_MAP_READ_BIT)
756                 access_ = GL_READ_ONLY;
757             else if (access & GL_MAP_WRITE_BIT)
758                 access_ = GL_WRITE_ONLY;
759             mapped_ = GL_TRUE;
760         }
761         return map_pointer_;
762     }
Unmap()763     GLboolean Unmap()
764     {
765         assert(mapped_ == GL_TRUE);
766 
767         if (glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER))
768         {
769             map_offset_   = 0;
770             map_length_   = 0;
771             map_pointer_  = 0;
772             mapped_       = GL_FALSE;
773             access_       = GL_WRITE_ONLY;
774             access_flags_ = 0;
775             return GL_TRUE;
776         }
777         return GL_FALSE;
778     }
779 
780 private:
781     GLuint name_;
782     GLint64 size_;
783     GLenum usage_;
784     GLenum access_;
785     GLint access_flags_;
786     GLboolean mapped_;
787     void *map_pointer_;
788     GLint64 map_offset_;
789     GLint64 map_length_;
790 };
791 } // namespace
792 
793 class BasicUsageCS : public SACSubcaseBase
794 {
795 public:
Title()796     virtual std::string Title()
797     {
798         return NL "Atomic Counters usage in the Compute Shader stage";
799     }
Purpose()800     virtual std::string Purpose()
801     {
802         return NL "Verify that atomic counters work as expected in the Compute Shader stage." NL
803                   "In particular make sure that values returned by GLSL built-in functions" NL
804                   "atomicCounterIncrement and atomicCounterDecrement are unique in every shader invocation." NL
805                   "Also make sure that the final values in atomic counter buffer objects are as expected.";
806     }
Method()807     virtual std::string Method()
808     {
809         return NL "";
810     }
PassCriteria()811     virtual std::string PassCriteria()
812     {
813         return NL "";
814     }
815 
816     GLuint counter_buffer_;
817     GLuint prog_;
818     GLuint m_buffer;
819 
Setup()820     virtual long Setup()
821     {
822         counter_buffer_ = 0;
823         prog_           = 0;
824         m_buffer        = 0;
825         return NO_ERROR;
826     }
827 
CreateComputeProgram(const std::string & cs)828     GLuint CreateComputeProgram(const std::string &cs)
829     {
830         const GLuint p = glCreateProgram();
831 
832         const char *const kGLSLVer = "#version 310 es\n";
833 
834         if (!cs.empty())
835         {
836             const GLuint sh = glCreateShader(GL_COMPUTE_SHADER);
837             glAttachShader(p, sh);
838             glDeleteShader(sh);
839             const char *const src[2] = {kGLSLVer, cs.c_str()};
840             glShaderSource(sh, 2, src, NULL);
841             glCompileShader(sh);
842         }
843 
844         return p;
845     }
846 
CheckProgram(GLuint program,bool * compile_error=NULL)847     bool CheckProgram(GLuint program, bool *compile_error = NULL)
848     {
849         GLint compile_status = GL_TRUE;
850         GLint status;
851         glGetProgramiv(program, GL_LINK_STATUS, &status);
852 
853         if (status == GL_FALSE)
854         {
855             GLint attached_shaders;
856             glGetProgramiv(program, GL_ATTACHED_SHADERS, &attached_shaders);
857 
858             if (attached_shaders > 0)
859             {
860                 std::vector<GLuint> shaders(attached_shaders);
861                 glGetAttachedShaders(program, attached_shaders, NULL, &shaders[0]);
862 
863                 for (GLint i = 0; i < attached_shaders; ++i)
864                 {
865                     GLenum type;
866                     glGetShaderiv(shaders[i], GL_SHADER_TYPE, reinterpret_cast<GLint *>(&type));
867                     switch (type)
868                     {
869                     case GL_VERTEX_SHADER:
870                         m_context.getTestContext().getLog()
871                             << tcu::TestLog::Message << "*** Vertex Shader ***" << tcu::TestLog::EndMessage;
872                         break;
873                     case GL_TESS_CONTROL_SHADER:
874                         m_context.getTestContext().getLog()
875                             << tcu::TestLog::Message << "*** Tessellation Control Shader ***"
876                             << tcu::TestLog::EndMessage;
877                         break;
878                     case GL_TESS_EVALUATION_SHADER:
879                         m_context.getTestContext().getLog()
880                             << tcu::TestLog::Message << "*** Tessellation Evaluation Shader ***"
881                             << tcu::TestLog::EndMessage;
882                         break;
883                     case GL_GEOMETRY_SHADER:
884                         m_context.getTestContext().getLog()
885                             << tcu::TestLog::Message << "*** Geometry Shader ***" << tcu::TestLog::EndMessage;
886                         break;
887                     case GL_FRAGMENT_SHADER:
888                         m_context.getTestContext().getLog()
889                             << tcu::TestLog::Message << "*** Fragment Shader ***" << tcu::TestLog::EndMessage;
890                         break;
891                     case GL_COMPUTE_SHADER:
892                         m_context.getTestContext().getLog()
893                             << tcu::TestLog::Message << "*** Compute Shader ***" << tcu::TestLog::EndMessage;
894                         break;
895                     default:
896                         m_context.getTestContext().getLog()
897                             << tcu::TestLog::Message << "*** Unknown Shader ***" << tcu::TestLog::EndMessage;
898                         break;
899                     }
900 
901                     GLint res;
902                     glGetShaderiv(shaders[i], GL_COMPILE_STATUS, &res);
903                     if (res != GL_TRUE)
904                         compile_status = res;
905 
906                     // shader source
907                     GLint length;
908                     glGetShaderiv(shaders[i], GL_SHADER_SOURCE_LENGTH, &length);
909                     if (length > 0)
910                     {
911                         std::vector<GLchar> source(length);
912                         glGetShaderSource(shaders[i], length, NULL, &source[0]);
913                         m_context.getTestContext().getLog()
914                             << tcu::TestLog::Message << &source[0] << tcu::TestLog::EndMessage;
915                     }
916 
917                     // shader info log
918                     glGetShaderiv(shaders[i], GL_INFO_LOG_LENGTH, &length);
919                     if (length > 0)
920                     {
921                         std::vector<GLchar> log(length);
922                         glGetShaderInfoLog(shaders[i], length, NULL, &log[0]);
923                         m_context.getTestContext().getLog()
924                             << tcu::TestLog::Message << &log[0] << tcu::TestLog::EndMessage;
925                     }
926                 }
927             }
928 
929             // program info log
930             GLint length;
931             glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length);
932             if (length > 0)
933             {
934                 std::vector<GLchar> log(length);
935                 glGetProgramInfoLog(program, length, NULL, &log[0]);
936                 m_context.getTestContext().getLog() << tcu::TestLog::Message << &log[0] << tcu::TestLog::EndMessage;
937             }
938         }
939 
940         if (compile_error)
941             *compile_error = (compile_status == GL_TRUE ? false : true);
942         if (compile_status != GL_TRUE)
943             return false;
944         return status == GL_TRUE ? true : false;
945     }
946 
Run()947     virtual long Run()
948     {
949         // create program
950         const char *const glsl_cs = NL
951             "layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;" NL
952             "layout(binding = 0, offset = 0) uniform atomic_uint ac_counter_inc;" NL
953             "layout(binding = 0, offset = 4) uniform atomic_uint ac_counter_dec;" NL "layout(std430) buffer Output {" NL
954             "  mediump uint data_inc[256];" NL "  mediump uint data_dec[256];" NL "} g_out;" NL "void main() {" NL
955             "  mediump uint offset = 32u * gl_GlobalInvocationID.y + gl_GlobalInvocationID.x;" NL
956             "  g_out.data_inc[offset] = atomicCounterIncrement(ac_counter_inc);" NL
957             "  g_out.data_dec[offset] = atomicCounterDecrement(ac_counter_dec);" NL "}";
958         prog_ = CreateComputeProgram(glsl_cs);
959         glLinkProgram(prog_);
960         if (!CheckProgram(prog_))
961             return ERROR;
962 
963         // create atomic counter buffer
964         glGenBuffers(1, &counter_buffer_);
965         glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, counter_buffer_);
966         glBufferData(GL_ATOMIC_COUNTER_BUFFER, 8, NULL, GL_DYNAMIC_COPY);
967         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
968 
969         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_);
970         unsigned int *ptr = static_cast<unsigned int *>(
971             glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 8, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT));
972         *ptr++ = 0;
973         *ptr++ = 256;
974         glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
975 
976         glGenBuffers(1, &m_buffer);
977         glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer);
978         glBufferData(GL_SHADER_STORAGE_BUFFER, 512 * sizeof(GLuint), NULL, GL_DYNAMIC_DRAW);
979         glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
980 
981         glUseProgram(prog_);
982         glDispatchCompute(4, 1, 1);
983 
984         long error = NO_ERROR;
985         GLuint *data;
986         glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_buffer);
987         glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
988         data = static_cast<GLuint *>(
989             glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 512 * sizeof(GLuint), GL_MAP_READ_BIT | GL_MAP_WRITE_BIT));
990 
991         std::sort(data, data + 512);
992         for (int i = 0; i < 512; i += 2)
993         {
994             if (data[i] != data[i + 1])
995             {
996                 m_context.getTestContext().getLog()
997                     << tcu::TestLog::Message << "Pair of values should be equal, got: " << data[i] << ", "
998                     << data[i + 1] << tcu::TestLog::EndMessage;
999                 error = ERROR;
1000             }
1001             if (i < 510 && data[i] == data[i + 2])
1002             {
1003                 m_context.getTestContext().getLog()
1004                     << tcu::TestLog::Message << "Too many same values found: " << data[i] << ", index: " << i
1005                     << tcu::TestLog::EndMessage;
1006                 error = ERROR;
1007             }
1008         }
1009 
1010         glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
1011         glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
1012         return error;
1013     }
1014 
Cleanup()1015     virtual long Cleanup()
1016     {
1017         glDeleteBuffers(1, &counter_buffer_);
1018         glDeleteBuffers(1, &m_buffer);
1019         glDeleteProgram(prog_);
1020         glUseProgram(0);
1021         return NO_ERROR;
1022     }
1023 };
1024 
1025 class BasicBufferOperations : public SACSubcaseBase
1026 {
Title()1027     virtual std::string Title()
1028     {
1029         return NL "Atomic Counter Buffer - basic operations";
1030     }
Purpose()1031     virtual std::string Purpose()
1032     {
1033         return NL
1034             "Verify that basic buffer operations work as expected with new buffer target." NL
1035             "Tested commands: BindBuffer, BufferData, BufferSubData, MapBuffer, MapBufferRange, UnmapBuffer and" NL
1036             "GetBufferSubData.";
1037     }
Method()1038     virtual std::string Method()
1039     {
1040         return NL "";
1041     }
PassCriteria()1042     virtual std::string PassCriteria()
1043     {
1044         return NL "";
1045     }
1046 
1047     GLuint buffer_;
1048 
Setup()1049     virtual long Setup()
1050     {
1051         buffer_ = 0;
1052         return NO_ERROR;
1053     }
Run()1054     virtual long Run()
1055     {
1056         glGenBuffers(1, &buffer_);
1057         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, buffer_);
1058         glBufferData(GL_ATOMIC_COUNTER_BUFFER, 8 * 4, NULL, GL_STATIC_DRAW);
1059         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
1060 
1061         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, buffer_);
1062         GLuint *ptr = static_cast<GLuint *>(glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 8 * 4, GL_MAP_WRITE_BIT));
1063         if (ptr == NULL)
1064         {
1065             return ERROR;
1066         }
1067         for (GLuint i = 0; i < 8; ++i)
1068             ptr[i] = i;
1069         glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
1070         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
1071 
1072         long res = NO_ERROR;
1073         GLuint *data;
1074         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, buffer_);
1075         data = static_cast<GLuint *>(glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 32, GL_MAP_READ_BIT));
1076         if (data == NULL)
1077         {
1078             return ERROR;
1079         }
1080         for (GLuint i = 0; i < 8; ++i)
1081         {
1082             if (data[i] != i)
1083             {
1084                 m_context.getTestContext().getLog() << tcu::TestLog::Message << "data[" << i << "] is: " << data[i]
1085                                                     << " should be: " << i << tcu::TestLog::EndMessage;
1086                 res = ERROR;
1087             }
1088         }
1089         glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
1090         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
1091         if (res != NO_ERROR)
1092             return res;
1093 
1094         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, buffer_);
1095         ptr = static_cast<GLuint *>(glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 32, GL_MAP_WRITE_BIT));
1096         if (ptr == NULL)
1097         {
1098             return ERROR;
1099         }
1100         for (GLuint i = 0; i < 8; ++i)
1101             ptr[i] = i * 2;
1102         glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
1103         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
1104 
1105         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, buffer_);
1106         data = static_cast<GLuint *>(glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 32, GL_MAP_READ_BIT));
1107         if (data == NULL)
1108         {
1109             return ERROR;
1110         }
1111         for (GLuint i = 0; i < 8; ++i)
1112         {
1113             if (data[i] != i * 2)
1114             {
1115                 m_context.getTestContext().getLog() << tcu::TestLog::Message << "data[" << i << "] is: " << data[i]
1116                                                     << " should be: " << i * 2 << tcu::TestLog::EndMessage;
1117                 res = ERROR;
1118             }
1119         }
1120         glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
1121         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
1122 
1123         GLuint data2[8];
1124         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, buffer_);
1125         for (GLuint i = 0; i < 8; ++i)
1126             data2[i] = i * 3;
1127         glBufferSubData(GL_ATOMIC_COUNTER_BUFFER, 0, 32, data2);
1128         for (GLuint i = 0; i < 8; ++i)
1129             data2[i] = 0;
1130         data = static_cast<GLuint *>(glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 32, GL_MAP_READ_BIT));
1131         for (GLuint i = 0; i < 8; ++i)
1132         {
1133             if (data[i] != i * 3)
1134             {
1135                 m_context.getTestContext().getLog() << tcu::TestLog::Message << "data[" << i << "] is: " << data[i]
1136                                                     << " should be: " << i * 3 << tcu::TestLog::EndMessage;
1137                 res = ERROR;
1138             }
1139         }
1140         glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
1141         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
1142 
1143         return res;
1144     }
Cleanup()1145     virtual long Cleanup()
1146     {
1147         glDeleteBuffers(1, &buffer_);
1148         return NO_ERROR;
1149     }
1150 };
1151 
1152 class BasicBufferState : public SACSubcaseBase
1153 {
Title()1154     virtual std::string Title()
1155     {
1156         return NL "Atomic Counter Buffer - state";
1157     }
Purpose()1158     virtual std::string Purpose()
1159     {
1160         return NL "Verify that setting and getting buffer state works as expected for new buffer target.";
1161     }
Method()1162     virtual std::string Method()
1163     {
1164         return NL "";
1165     }
PassCriteria()1166     virtual std::string PassCriteria()
1167     {
1168         return NL "";
1169     }
1170 
Run()1171     virtual long Run()
1172     {
1173         Buffer buffer;
1174         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, buffer.name());
1175 
1176         if (buffer.Verify() != NO_ERROR)
1177             return ERROR;
1178 
1179         buffer.Data(100, NULL, GL_DYNAMIC_COPY);
1180         if (buffer.Verify() != NO_ERROR)
1181             return ERROR;
1182 
1183         buffer.MapRange(10, 50, GL_MAP_WRITE_BIT);
1184         if (buffer.Verify() != NO_ERROR)
1185             return ERROR;
1186         buffer.Unmap();
1187         if (buffer.Verify() != NO_ERROR)
1188             return ERROR;
1189 
1190         return NO_ERROR;
1191     }
1192 };
1193 
1194 class BasicBufferBind : public SACSubcaseBase
1195 {
Title()1196     virtual std::string Title()
1197     {
1198         return NL "Atomic Counter Buffer - binding";
1199     }
Purpose()1200     virtual std::string Purpose()
1201     {
1202         return NL "Verify that binding buffer objects to ATOMIC_COUNTER_BUFFER (indexed) target" NL
1203                   "works as expected. In particualr make sure that binding with BindBufferBase and BindBufferRange" NL
1204                   "also bind to generic binding point and deleting buffer that is currently bound unbinds it. Tested" NL
1205                   "commands: BindBuffer, BindBufferBase and BindBufferRange.";
1206     }
Method()1207     virtual std::string Method()
1208     {
1209         return NL "";
1210     }
PassCriteria()1211     virtual std::string PassCriteria()
1212     {
1213         return NL "";
1214     }
1215 
1216     GLuint buffer_;
1217 
Setup()1218     virtual long Setup()
1219     {
1220         buffer_ = 0;
1221         return NO_ERROR;
1222     }
Run()1223     virtual long Run()
1224     {
1225         GLint bindings;
1226         glGetIntegerv(GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS, &bindings);
1227         m_context.getTestContext().getLog()
1228             << tcu::TestLog::Message << "MAX_ATOMIC_COUNTER_BUFFER_BINDINGS: " << bindings << tcu::TestLog::EndMessage;
1229 
1230         if (!CheckGetCommands(GL_ATOMIC_COUNTER_BUFFER_BINDING, 0))
1231             return ERROR;
1232         for (GLint index = 0; index < bindings; ++index)
1233         {
1234             if (!CheckBufferBindingState(static_cast<GLuint>(index), 0, 0, 0))
1235                 return ERROR;
1236         }
1237 
1238         glGenBuffers(1, &buffer_);
1239         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, buffer_);
1240 
1241         if (!CheckGetCommands(GL_ATOMIC_COUNTER_BUFFER_BINDING, static_cast<GLint>(buffer_)))
1242             return ERROR;
1243         for (GLint index = 0; index < bindings; ++index)
1244         {
1245             if (!CheckBufferBindingState(static_cast<GLuint>(index), 0, 0, 0))
1246                 return ERROR;
1247         }
1248 
1249         long res = NO_ERROR;
1250 
1251         glBufferData(GL_ATOMIC_COUNTER_BUFFER, 1000, NULL, GL_DYNAMIC_COPY);
1252         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
1253 
1254         glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, buffer_);
1255         if (!CheckBufferBindingState(0, static_cast<GLint>(buffer_), 0, 1000))
1256             res = ERROR;
1257         if (!CheckGetCommands(GL_ATOMIC_COUNTER_BUFFER_BINDING, static_cast<GLint>(buffer_)))
1258             res = ERROR;
1259 
1260         glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, static_cast<GLuint>(bindings / 2), buffer_);
1261         if (!CheckBufferBindingState(static_cast<GLuint>(bindings / 2), static_cast<GLint>(buffer_), 0, 1000))
1262             res = ERROR;
1263 
1264         glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, static_cast<GLuint>(bindings - 1), buffer_);
1265         if (!CheckBufferBindingState(static_cast<GLuint>(bindings - 1), static_cast<GLint>(buffer_), 0, 1000))
1266             res = ERROR;
1267         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
1268 
1269         glBindBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, buffer_, 8, 32);
1270         if (!CheckBufferBindingState(0, static_cast<GLint>(buffer_), 8, 32))
1271             res = ERROR;
1272         if (!CheckGetCommands(GL_ATOMIC_COUNTER_BUFFER_BINDING, static_cast<GLint>(buffer_)))
1273             res = ERROR;
1274 
1275         glBindBufferRange(GL_ATOMIC_COUNTER_BUFFER, static_cast<GLuint>(bindings / 2), buffer_, 512, 100);
1276         if (!CheckBufferBindingState(static_cast<GLuint>(bindings / 2), static_cast<GLint>(buffer_), 512, 100))
1277             res = ERROR;
1278 
1279         glBindBufferRange(GL_ATOMIC_COUNTER_BUFFER, static_cast<GLuint>(bindings - 1), buffer_, 12, 128);
1280         if (!CheckBufferBindingState(static_cast<GLuint>(bindings - 1), static_cast<GLint>(buffer_), 12, 128))
1281             res = ERROR;
1282 
1283         glDeleteBuffers(1, &buffer_);
1284         buffer_ = 0;
1285 
1286         GLint i;
1287         glGetIntegerv(GL_ATOMIC_COUNTER_BUFFER_BINDING, &i);
1288         if (i != 0)
1289         {
1290             m_context.getTestContext().getLog()
1291                 << tcu::TestLog::Message << "Generic binding point should be 0 after deleting bound buffer object."
1292                 << tcu::TestLog::EndMessage;
1293             res = ERROR;
1294         }
1295         for (GLint index = 0; index < bindings; ++index)
1296         {
1297             glGetIntegeri_v(GL_ATOMIC_COUNTER_BUFFER_BINDING, static_cast<GLuint>(index), &i);
1298             if (i != 0)
1299             {
1300                 m_context.getTestContext().getLog()
1301                     << tcu::TestLog::Message << "Binding point " << index
1302                     << " should be 0 after deleting bound buffer object." << tcu::TestLog::EndMessage;
1303                 res = ERROR;
1304             }
1305         }
1306 
1307         return res;
1308     }
Cleanup()1309     virtual long Cleanup()
1310     {
1311         glDeleteBuffers(1, &buffer_);
1312         return NO_ERROR;
1313     }
1314 };
1315 
1316 class BasicProgramMax : public SACSubcaseBase
1317 {
Title()1318     virtual std::string Title()
1319     {
1320         return NL "Program - max values";
1321     }
Purpose()1322     virtual std::string Purpose()
1323     {
1324         return NL "Verify all max values which deal with atomic counter buffers.";
1325     }
Method()1326     virtual std::string Method()
1327     {
1328         return NL "";
1329     }
PassCriteria()1330     virtual std::string PassCriteria()
1331     {
1332         return NL "";
1333     }
1334 
Run()1335     virtual long Run()
1336     {
1337         if (!CheckMaxValue(GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS, 1))
1338             return ERROR;
1339         if (!CheckMaxValue(GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE, 32))
1340             return ERROR;
1341         if (!CheckMaxValue(GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS, 1))
1342             return ERROR;
1343         if (!CheckMaxValue(GL_MAX_COMBINED_ATOMIC_COUNTERS, 8))
1344             return ERROR;
1345         if (!CheckMaxValue(GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS, 0))
1346             return ERROR;
1347         if (!CheckMaxValue(GL_MAX_VERTEX_ATOMIC_COUNTERS, 0))
1348             return ERROR;
1349         if (!CheckMaxValue(GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS, 1))
1350             return ERROR;
1351         if (!CheckMaxValue(GL_MAX_COMPUTE_ATOMIC_COUNTERS, 8))
1352             return ERROR;
1353         if (!CheckMaxValue(GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS, 0))
1354             return ERROR;
1355         if (!CheckMaxValue(GL_MAX_FRAGMENT_ATOMIC_COUNTERS, 0))
1356             return ERROR;
1357         return NO_ERROR;
1358     }
1359 };
1360 
1361 class BasicProgramQuery : public BasicUsageCS
1362 {
Title()1363     virtual std::string Title()
1364     {
1365         return NL "Program - atomic counters queries";
1366     }
Purpose()1367     virtual std::string Purpose()
1368     {
1369         return NL "Get all the information from the program object about atomic counters." NL
1370                   "Verify that all informations are correct. Tested commands:" NL
1371                   "GetProgramiv and GetUniform* with new enums.";
1372     }
Method()1373     virtual std::string Method()
1374     {
1375         return NL "";
1376     }
PassCriteria()1377     virtual std::string PassCriteria()
1378     {
1379         return NL "";
1380     }
1381 
1382     GLuint counter_buffer_, m_buffer;
1383     GLuint prog_;
1384 
Setup()1385     virtual long Setup()
1386     {
1387         counter_buffer_ = 0;
1388         m_buffer        = 0;
1389         prog_           = 0;
1390         return NO_ERROR;
1391     }
1392 
Run()1393     virtual long Run()
1394     {
1395 
1396         // create program
1397         const char *glsl_cs =
1398             NL "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;" NL "layout(std430) buffer Output {" NL
1399                "  mediump vec4 data;" NL "} g_out;" NL
1400                "layout(binding = 0, offset = 0)  uniform atomic_uint ac_counter0;" NL
1401                "layout(binding = 0, offset = 4)  uniform atomic_uint ac_counter1;" NL
1402                "layout(binding = 0)              uniform atomic_uint ac_counter2;" NL
1403                "layout(binding = 0)              uniform atomic_uint ac_counter67[2];" NL
1404                "layout(binding = 0)              uniform atomic_uint ac_counter3;" NL
1405                "layout(binding = 0)              uniform atomic_uint ac_counter4;" NL
1406                "layout(binding = 0)              uniform atomic_uint ac_counter5;" NL "void main() {" NL
1407                "  mediump uint c = 0u;" NL "  c += atomicCounterIncrement(ac_counter0);" NL
1408                "  c += atomicCounterIncrement(ac_counter1);" NL "  c += atomicCounterIncrement(ac_counter2);" NL
1409                "  c += atomicCounterIncrement(ac_counter3);" NL "  c += atomicCounterIncrement(ac_counter4);" NL
1410                "  c += atomicCounterIncrement(ac_counter5);" NL "  c += atomicCounterIncrement(ac_counter67[0]);" NL
1411                "  c += atomicCounterIncrement(ac_counter67[1]);" NL
1412                "  if (c > 10u) g_out.data = vec4(0.0, 1.0, 0.0, 1.0);" NL
1413                "  else g_out.data = vec4(1.0, float(c), 0.0, 1.0);" NL "}";
1414 
1415         prog_ = CreateComputeProgram(glsl_cs);
1416         glLinkProgram(prog_);
1417         if (!CheckProgram(prog_))
1418             return ERROR;
1419         glUseProgram(prog_);
1420 
1421         // get active buffers
1422         GLuint active_buffers;
1423         glGetProgramiv(prog_, GL_ACTIVE_ATOMIC_COUNTER_BUFFERS, reinterpret_cast<GLint *>(&active_buffers));
1424         if (active_buffers != 1)
1425         {
1426             m_context.getTestContext().getLog() << tcu::TestLog::Message << "GL_ACTIVE_ATOMIC_COUNTER_BUFFERS is "
1427                                                 << active_buffers << " should be 1." << tcu::TestLog::EndMessage;
1428             return ERROR;
1429         }
1430 
1431         // get active uniforms
1432         std::map<std::string, GLuint> uniforms_name_index;
1433         GLuint active_uniforms;
1434         glGetProgramiv(prog_, GL_ACTIVE_UNIFORMS, reinterpret_cast<GLint *>(&active_uniforms));
1435         if (active_uniforms != 7)
1436         {
1437             m_context.getTestContext().getLog() << tcu::TestLog::Message << "GL_ACTIVE_UNIFORMS is " << active_uniforms
1438                                                 << " should be 8." << tcu::TestLog::EndMessage;
1439             return ERROR;
1440         }
1441         for (GLuint index = 0; index < active_uniforms; ++index)
1442         {
1443             GLchar name[32];
1444             glGetProgramResourceName(prog_, GL_UNIFORM, index, sizeof(name), NULL, name);
1445             uniforms_name_index.insert(std::make_pair(name, index));
1446         }
1447 
1448         if (!CheckUniform(prog_, "ac_counter0", uniforms_name_index["ac_counter0"], GL_UNSIGNED_INT_ATOMIC_COUNTER, 1,
1449                           0, 0))
1450             return ERROR;
1451         if (!CheckUniform(prog_, "ac_counter1", uniforms_name_index["ac_counter1"], GL_UNSIGNED_INT_ATOMIC_COUNTER, 1,
1452                           4, 0))
1453             return ERROR;
1454         if (!CheckUniform(prog_, "ac_counter2", uniforms_name_index["ac_counter2"], GL_UNSIGNED_INT_ATOMIC_COUNTER, 1,
1455                           8, 0))
1456             return ERROR;
1457         if (!CheckUniform(prog_, "ac_counter3", uniforms_name_index["ac_counter3"], GL_UNSIGNED_INT_ATOMIC_COUNTER, 1,
1458                           20, 0))
1459             return ERROR;
1460         if (!CheckUniform(prog_, "ac_counter4", uniforms_name_index["ac_counter4"], GL_UNSIGNED_INT_ATOMIC_COUNTER, 1,
1461                           24, 0))
1462             return ERROR;
1463         if (!CheckUniform(prog_, "ac_counter5", uniforms_name_index["ac_counter5"], GL_UNSIGNED_INT_ATOMIC_COUNTER, 1,
1464                           28, 0))
1465             return ERROR;
1466         if (!CheckUniform(prog_, "ac_counter67[0]", uniforms_name_index["ac_counter67[0]"],
1467                           GL_UNSIGNED_INT_ATOMIC_COUNTER, 2, 12, 4))
1468             return ERROR;
1469 
1470         // create atomic counter buffer
1471         glGenBuffers(1, &counter_buffer_);
1472         glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, counter_buffer_);
1473         const unsigned int data[8] = {20, 20, 20, 20, 20, 20, 20, 20};
1474         glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(data), data, GL_DYNAMIC_DRAW);
1475         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
1476 
1477         glGenBuffers(1, &m_buffer);
1478         glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer);
1479         glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(Vec4), NULL, GL_DYNAMIC_DRAW);
1480         glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
1481 
1482         glDispatchCompute(1, 1, 1);
1483 
1484         long error = NO_ERROR;
1485         Vec4 *data_out;
1486         glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_buffer);
1487         glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT | GL_ATOMIC_COUNTER_BARRIER_BIT);
1488         data_out = static_cast<Vec4 *>(glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(Vec4), GL_MAP_READ_BIT));
1489         if (data_out[0].x() != 0.0 || data_out[0].y() != 1.0 || data_out[0].z() != 0.0 || data_out[0].w() != 1.0)
1490         {
1491             m_context.getTestContext().getLog()
1492                 << tcu::TestLog::Message << "Expected vec4(0, 1, 0, 1) in the buffer, got: " << data_out[0].x() << " "
1493                 << data_out[0].y() << " " << data_out[0].z() << " " << data_out[0].w() << tcu::TestLog::EndMessage;
1494             error = ERROR;
1495         }
1496         glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
1497         glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
1498 
1499         return error;
1500     }
1501 
Cleanup()1502     virtual long Cleanup()
1503     {
1504         glDeleteBuffers(1, &counter_buffer_);
1505         glDeleteBuffers(1, &m_buffer);
1506         glDeleteProgram(prog_);
1507         glUseProgram(0);
1508         return NO_ERROR;
1509     }
1510 };
1511 
1512 class BasicUsageSimple : public BasicUsageCS
1513 {
Title()1514     virtual std::string Title()
1515     {
1516         return NL "Simple Use Case";
1517     }
Purpose()1518     virtual std::string Purpose()
1519     {
1520         return NL "Verify that simple usage of atomic counters work as expected.";
1521     }
Method()1522     virtual std::string Method()
1523     {
1524         return NL "";
1525     }
PassCriteria()1526     virtual std::string PassCriteria()
1527     {
1528         return NL "";
1529     }
1530 
1531     GLuint counter_buffer_;
1532     GLuint storage_buffer_;
1533     GLuint prog_;
1534 
Setup()1535     virtual long Setup()
1536     {
1537         counter_buffer_ = 0;
1538         storage_buffer_ = 0;
1539         prog_           = 0;
1540         return NO_ERROR;
1541     }
1542 
Run()1543     virtual long Run()
1544     {
1545         const char *glsl_cs =
1546             NL "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;" NL "layout(std430) buffer Output {" NL
1547                "  mediump vec4 color;" NL "} g_out;" NL
1548                "layout(binding = 0, offset = 0) uniform atomic_uint ac_counter;" NL "void main() {" NL
1549                "  mediump uint c = atomicCounterIncrement(ac_counter);" NL
1550                "  mediump float r = float(c / 40u) / 255.0;" NL "  g_out.color = vec4(r, 0.0, 0.0, 1.0);" NL "}";
1551         prog_ = CreateComputeProgram(glsl_cs);
1552         glLinkProgram(prog_);
1553         if (!CheckProgram(prog_))
1554             return ERROR;
1555 
1556         // create atomic counter buffer
1557         glGenBuffers(1, &counter_buffer_);
1558         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_);
1559         glBufferData(GL_ATOMIC_COUNTER_BUFFER, 4, NULL, GL_DYNAMIC_COPY);
1560         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
1561 
1562         // clear counter buffer (set to 0)
1563         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_);
1564         unsigned int *ptr = static_cast<unsigned int *>(
1565             glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 4, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT));
1566         *ptr = 0;
1567         glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
1568 
1569         // create shader storage buffer
1570         glGenBuffers(1, &storage_buffer_);
1571         glBindBuffer(GL_SHADER_STORAGE_BUFFER, storage_buffer_);
1572         glBufferData(GL_SHADER_STORAGE_BUFFER, 16, NULL, GL_DYNAMIC_DRAW);
1573         glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
1574 
1575         glUseProgram(prog_);
1576         glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, counter_buffer_);
1577         glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, storage_buffer_);
1578         glDispatchCompute(1, 1, 1);
1579 
1580         if (glGetError() != GL_NO_ERROR)
1581         {
1582             return ERROR;
1583         }
1584         else
1585         {
1586             return NO_ERROR;
1587         }
1588     }
1589 
Cleanup()1590     virtual long Cleanup()
1591     {
1592         glDeleteBuffers(1, &counter_buffer_);
1593         glDeleteBuffers(1, &storage_buffer_);
1594         glDeleteProgram(prog_);
1595         glUseProgram(0);
1596         return NO_ERROR;
1597     }
1598 };
1599 
1600 class BasicUsageFS : public SACSubcaseBase
1601 {
Title()1602     virtual std::string Title()
1603     {
1604         return NL "Atomic Counters usage in the Fragment Shader stage";
1605     }
Purpose()1606     virtual std::string Purpose()
1607     {
1608         return NL "Verify that atomic counters work as expected in the Fragment Shader stage." NL
1609                   "In particular make sure that values returned by GLSL built-in functions" NL
1610                   "atomicCounterIncrement and atomicCounterDecrement are unique in every shader invocation." NL
1611                   "Also make sure that the final values in atomic counter buffer objects are as expected.";
1612     }
Method()1613     virtual std::string Method()
1614     {
1615         return NL "";
1616     }
PassCriteria()1617     virtual std::string PassCriteria()
1618     {
1619         return NL "";
1620     }
1621 
1622     GLuint counter_buffer_;
1623     GLuint vao_, vbo_;
1624     GLuint prog_;
1625     GLuint fbo_, rt_[2];
1626 
Setup()1627     virtual long Setup()
1628     {
1629         counter_buffer_ = 0;
1630         vao_ = vbo_ = 0;
1631         prog_       = 0;
1632         fbo_ = rt_[0] = rt_[1] = 0;
1633         return NO_ERROR;
1634     }
Run()1635     virtual long Run()
1636     {
1637 
1638         GLint p1, p2;
1639         glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS, &p1);
1640         glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTERS, &p2);
1641         if (p1 < 1 || p2 < 2)
1642         {
1643             OutputNotSupported(
1644                 "GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS or GL_MAX_FRAGMENT_ATOMIC_COUNTERS are less than required");
1645             return NOT_SUPPORTED;
1646         }
1647 
1648         // create program
1649         const char *src_vs = "#version 310 es" NL "layout(location = 0) in vec4 i_vertex;" NL "void main() {" NL
1650                              "  gl_Position = i_vertex;" NL "}";
1651 
1652         const char *src_fs = "#version 310 es" NL "layout(location = 0) out uvec4 o_color[2];" NL
1653                              "layout(binding = 0, offset = 0) uniform atomic_uint ac_counter_inc;" NL
1654                              "layout(binding = 0, offset = 4) uniform atomic_uint ac_counter_dec;" NL "void main() {" NL
1655                              "  o_color[0] = uvec4(atomicCounterIncrement(ac_counter_inc));" NL
1656                              "  o_color[1] = uvec4(atomicCounterDecrement(ac_counter_dec));" NL "}";
1657         prog_ = CreateProgram(src_vs, src_fs, true);
1658 
1659         // create atomic counter buffer
1660         glGenBuffers(1, &counter_buffer_);
1661         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_);
1662         glBufferData(GL_ATOMIC_COUNTER_BUFFER, 8, NULL, GL_DYNAMIC_COPY);
1663         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
1664 
1665         // create render targets
1666         const int s = 8;
1667         glGenTextures(2, rt_);
1668 
1669         for (int i = 0; i < 2; ++i)
1670         {
1671             glBindTexture(GL_TEXTURE_2D, rt_[i]);
1672             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1673             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1674             glTexImage2D(GL_TEXTURE_2D, 0, GL_R32UI, s, s, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, NULL);
1675             glBindTexture(GL_TEXTURE_2D, 0);
1676         }
1677 
1678         // create fbo
1679         glGenFramebuffers(1, &fbo_);
1680         glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
1681         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt_[0], 0);
1682         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, rt_[1], 0);
1683         const GLenum draw_buffers[2] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1};
1684         glDrawBuffers(2, draw_buffers);
1685         glBindFramebuffer(GL_FRAMEBUFFER, 0);
1686 
1687         // create geometry
1688         CreateQuad(&vao_, &vbo_, NULL);
1689 
1690         // init counter buffer
1691         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_);
1692         unsigned int *ptr = static_cast<unsigned int *>(
1693             glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 8, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT));
1694         *ptr++ = 0;
1695         *ptr++ = 80;
1696         glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
1697 
1698         // draw
1699         glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
1700         glViewport(0, 0, s, s);
1701         glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, counter_buffer_);
1702         glUseProgram(prog_);
1703         glBindVertexArray(vao_);
1704         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1705 
1706         // validate
1707         UVec4 data[s * s];
1708         glReadBuffer(GL_COLOR_ATTACHMENT0);
1709         glReadPixels(0, 0, s, s, GL_RGBA_INTEGER, GL_UNSIGNED_INT, data);
1710         if (!CheckCounterValues(s * s, data, 0))
1711             return ERROR;
1712 
1713         glReadBuffer(GL_COLOR_ATTACHMENT1);
1714         glReadPixels(0, 0, s, s, GL_RGBA_INTEGER, GL_UNSIGNED_INT, data);
1715         if (!CheckCounterValues(s * s, data, 16))
1716             return ERROR;
1717 
1718         if (!CheckFinalCounterValue(counter_buffer_, 0, 64))
1719             return ERROR;
1720         if (!CheckFinalCounterValue(counter_buffer_, 4, 16))
1721             return ERROR;
1722 
1723         return NO_ERROR;
1724     }
Cleanup()1725     virtual long Cleanup()
1726     {
1727         glDeleteFramebuffers(1, &fbo_);
1728         glDeleteTextures(2, rt_);
1729         glViewport(0, 0, getWindowWidth(), getWindowHeight());
1730         glDeleteBuffers(1, &counter_buffer_);
1731         glDeleteVertexArrays(1, &vao_);
1732         glDeleteBuffers(1, &vbo_);
1733         glDeleteProgram(prog_);
1734         glUseProgram(0);
1735         return NO_ERROR;
1736     }
1737 };
1738 
1739 class BasicUsageVS : public SACSubcaseBase
1740 {
Title()1741     virtual std::string Title()
1742     {
1743         return NL "Atomic Counters usage in the Vertex Shader stage";
1744     }
Purpose()1745     virtual std::string Purpose()
1746     {
1747         return NL "Verify that atomic counters work as expected in the Vertex Shader stage." NL
1748                   "In particular make sure that values returned by GLSL built-in functions" NL
1749                   "atomicCounterIncrement and atomicCounterDecrement are unique in every shader invocation." NL
1750                   "Also make sure that the final values in atomic counter buffer objects are as expected.";
1751     }
Method()1752     virtual std::string Method()
1753     {
1754         return NL "";
1755     }
PassCriteria()1756     virtual std::string PassCriteria()
1757     {
1758         return NL "";
1759     }
1760 
1761     GLuint counter_buffer_[2];
1762     GLuint xfb_buffer_[2];
1763     GLuint array_buffer_;
1764     GLuint vao_;
1765     GLuint prog_;
1766 
Setup()1767     virtual long Setup()
1768     {
1769         counter_buffer_[0] = counter_buffer_[1] = 0;
1770         xfb_buffer_[0] = xfb_buffer_[1] = 0;
1771         array_buffer_                   = 0;
1772         vao_                            = 0;
1773         prog_                           = 0;
1774         return NO_ERROR;
1775     }
Run()1776     virtual long Run()
1777     {
1778 
1779         GLint p1, p2;
1780         glGetIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS, &p1);
1781         glGetIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTERS, &p2);
1782         if (p1 < 2 || p2 < 2)
1783         {
1784             OutputNotSupported(
1785                 "GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS or GL_MAX_VERTEX_ATOMIC_COUNTERS are less than required");
1786             return NOT_SUPPORTED;
1787         }
1788 
1789         // create program
1790         const char *src_vs =
1791             "#version 310 es" NL "layout(location = 0) in uint i_zero;" NL "flat out uint o_atomic_inc;" NL
1792             "flat out uint o_atomic_dec;" NL "layout(binding = 0, offset = 0) uniform atomic_uint ac_counter_inc;" NL
1793             "layout(binding = 1, offset = 0) uniform atomic_uint ac_counter_dec;" NL "void main() {" NL
1794             "  o_atomic_inc = i_zero + atomicCounterIncrement(ac_counter_inc);" NL
1795             "  o_atomic_dec = i_zero + atomicCounterDecrement(ac_counter_dec);" NL "}";
1796 
1797         const char *src_fs = "#version 310 es                \n"
1798                              "out mediump vec4 color;        \n"
1799                              "void main() {                  \n"
1800                              "    color = vec4(0, 1, 0, 1);  \n"
1801                              "}";
1802 
1803         prog_                  = CreateProgram(src_vs, src_fs, false);
1804         const char *xfb_var[2] = {"o_atomic_inc", "o_atomic_dec"};
1805         glTransformFeedbackVaryings(prog_, 2, xfb_var, GL_SEPARATE_ATTRIBS);
1806         LinkProgram(prog_);
1807 
1808         // create array buffer
1809         const unsigned int array_buffer_data[32] = {0};
1810         glGenBuffers(1, &array_buffer_);
1811         glBindBuffer(GL_ARRAY_BUFFER, array_buffer_);
1812         glBufferData(GL_ARRAY_BUFFER, sizeof(array_buffer_data), array_buffer_data, GL_STATIC_DRAW);
1813         glBindBuffer(GL_ARRAY_BUFFER, 0);
1814 
1815         // create atomic counter buffers
1816         glGenBuffers(2, counter_buffer_);
1817         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_[0]);
1818         glBufferData(GL_ATOMIC_COUNTER_BUFFER, 4, NULL, GL_DYNAMIC_COPY);
1819         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_[1]);
1820         glBufferData(GL_ATOMIC_COUNTER_BUFFER, 4, NULL, GL_DYNAMIC_COPY);
1821         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
1822 
1823         // create transform feedback buffers
1824         glGenBuffers(2, xfb_buffer_);
1825         glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buffer_[0]);
1826         glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 1000, NULL, GL_STREAM_COPY);
1827         glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buffer_[1]);
1828         glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 1000, NULL, GL_STREAM_COPY);
1829         glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0);
1830 
1831         // init counter buffers
1832         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_[0]);
1833         unsigned int *ptr = static_cast<unsigned int *>(
1834             glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 4, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT));
1835         *ptr = 7;
1836         glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
1837 
1838         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_[1]);
1839         ptr = static_cast<unsigned int *>(
1840             glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 4, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT));
1841         *ptr = 77;
1842         glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
1843 
1844         // create vertex array object
1845         glGenVertexArrays(1, &vao_);
1846         glBindVertexArray(vao_);
1847         glBindBuffer(GL_ARRAY_BUFFER, array_buffer_);
1848         glVertexAttribIPointer(0, 1, GL_UNSIGNED_INT, 0, 0);
1849         glBindBuffer(GL_ARRAY_BUFFER, 0);
1850         glEnableVertexAttribArray(0);
1851         glBindVertexArray(0);
1852 
1853         // draw
1854         glEnable(GL_RASTERIZER_DISCARD);
1855         glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, counter_buffer_[0]);
1856         glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 1, counter_buffer_[1]);
1857         glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, xfb_buffer_[0]);
1858         glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 1, xfb_buffer_[1]);
1859         glUseProgram(prog_);
1860         glBindVertexArray(vao_);
1861         glBeginTransformFeedback(GL_POINTS);
1862         glDrawArrays(GL_POINTS, 0, 32);
1863         glEndTransformFeedback();
1864         glDisable(GL_RASTERIZER_DISCARD);
1865 
1866         // validate
1867         GLuint *data;
1868         glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buffer_[0]);
1869         // CheckCounterValues will sort in place, so map buffer for both read and write
1870         data = static_cast<GLuint *>(
1871             glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 32 * 4, GL_MAP_READ_BIT | GL_MAP_WRITE_BIT));
1872         if (!CheckCounterValues(32, data, 7))
1873             return ERROR;
1874         glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
1875         glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0);
1876 
1877         glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buffer_[1]);
1878         data = static_cast<GLuint *>(
1879             glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 32 * 4, GL_MAP_READ_BIT | GL_MAP_WRITE_BIT));
1880         if (!CheckCounterValues(32, data, 45))
1881             return ERROR;
1882         glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
1883         glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0);
1884 
1885         if (!CheckFinalCounterValue(counter_buffer_[0], 0, 39))
1886             return ERROR;
1887         if (!CheckFinalCounterValue(counter_buffer_[1], 0, 45))
1888             return ERROR;
1889 
1890         return NO_ERROR;
1891     }
Cleanup()1892     virtual long Cleanup()
1893     {
1894         glDeleteBuffers(2, counter_buffer_);
1895         glDeleteBuffers(2, xfb_buffer_);
1896         glDeleteBuffers(1, &array_buffer_);
1897         glDeleteVertexArrays(1, &vao_);
1898         glDeleteProgram(prog_);
1899         glUseProgram(0);
1900         return NO_ERROR;
1901     }
1902 };
1903 
1904 class AdvancedUsageMultiStage : public SACSubcaseBase
1905 {
Title()1906     virtual std::string Title()
1907     {
1908         return NL "Same atomic counter accessed from multiple shader stages";
1909     }
Purpose()1910     virtual std::string Purpose()
1911     {
1912         return NL "Same atomic counter is incremented (decremented) from two shader stages (VS and FS)." NL
1913                   "Verify that this scenario works as expected. In particular ensure that all generated values are "
1914                   "unique and" NL "final value in atomic counter buffer objects are as expected.";
1915     }
Method()1916     virtual std::string Method()
1917     {
1918         return NL "";
1919     }
PassCriteria()1920     virtual std::string PassCriteria()
1921     {
1922         return NL "";
1923     }
1924 
1925     GLuint counter_buffer_;
1926     GLuint xfb_buffer_[2];
1927     GLuint vao_, vbo_;
1928     GLuint prog_;
1929     GLuint fbo_, rt_[2];
1930 
Setup()1931     virtual long Setup()
1932     {
1933         counter_buffer_ = 0;
1934         xfb_buffer_[0] = xfb_buffer_[1] = 0;
1935         vao_ = vbo_ = 0;
1936         prog_       = 0;
1937         fbo_ = rt_[0] = rt_[1] = 0;
1938         return NO_ERROR;
1939     }
Run()1940     virtual long Run()
1941     {
1942 
1943         GLint p1, p2, p3, p4;
1944         glGetIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS, &p1);
1945         glGetIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTERS, &p2);
1946         glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS, &p3);
1947         glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTERS, &p4);
1948         if (p1 < 8 || p2 < 2 || p3 < 8 || p4 < 2)
1949         {
1950             OutputNotSupported("GL_MAX_FRAGMENT/VERTEX_ATOMIC_COUNTER_BUFFERS or"
1951                                "GL_MAX_FRAGMENT/VERTEX_ATOMIC_COUNTERS are less than required");
1952             return NOT_SUPPORTED;
1953         }
1954 
1955         // create program
1956         const char *src_vs =
1957             "#version 310 es" NL "layout(location = 0) in vec4 i_vertex;" NL "flat out uint o_atomic_inc;" NL
1958             "flat out uint o_atomic_dec;" NL "layout(binding = 1, offset = 16) uniform atomic_uint ac_counter_inc;" NL
1959             "layout(binding = 7, offset = 128) uniform atomic_uint ac_counter_dec;" NL "void main() {" NL
1960             "  gl_Position = i_vertex;" NL "  o_atomic_inc = atomicCounterIncrement(ac_counter_inc);" NL
1961             "  o_atomic_dec = atomicCounterDecrement(ac_counter_dec);" NL "}";
1962         const char *src_fs = "#version 310 es" NL "layout(location = 0) out uvec4 o_color[2];" NL
1963                              "layout(binding = 1, offset = 16) uniform atomic_uint ac_counter_inc;" NL
1964                              "layout(binding = 7, offset = 128) uniform atomic_uint ac_counter_dec;" NL
1965                              "void main() {" NL "  o_color[0] = uvec4(atomicCounterIncrement(ac_counter_inc));" NL
1966                              "  o_color[1] = uvec4(atomicCounterDecrement(ac_counter_dec));" NL "}";
1967         prog_                  = CreateProgram(src_vs, src_fs, false);
1968         const char *xfb_var[2] = {"o_atomic_inc", "o_atomic_dec"};
1969         glTransformFeedbackVaryings(prog_, 2, xfb_var, GL_SEPARATE_ATTRIBS);
1970         LinkProgram(prog_);
1971 
1972         // create atomic counter buffer
1973         std::vector<GLuint> init_data(256, 100);
1974         glGenBuffers(1, &counter_buffer_);
1975         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_);
1976         glBufferData(GL_ATOMIC_COUNTER_BUFFER, (GLsizeiptr)(init_data.size() * sizeof(GLuint)), &init_data[0],
1977                      GL_DYNAMIC_COPY);
1978         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
1979 
1980         // create transform feedback buffers
1981         glGenBuffers(2, xfb_buffer_);
1982         glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buffer_[0]);
1983         glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 1000, NULL, GL_STREAM_COPY);
1984         glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buffer_[1]);
1985         glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 1000, NULL, GL_STREAM_COPY);
1986         glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0);
1987 
1988         // create render targets
1989         const int s = 8;
1990         glGenTextures(2, rt_);
1991         for (int i = 0; i < 2; ++i)
1992         {
1993             glBindTexture(GL_TEXTURE_2D, rt_[i]);
1994             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1995             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1996             glTexImage2D(GL_TEXTURE_2D, 0, GL_R32UI, s, s, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, NULL);
1997             glBindTexture(GL_TEXTURE_2D, 0);
1998         }
1999 
2000         // create fbo
2001         glGenFramebuffers(1, &fbo_);
2002         glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
2003         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt_[0], 0);
2004         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, rt_[1], 0);
2005         const GLenum draw_buffers[2] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1};
2006         glDrawBuffers(2, draw_buffers);
2007         glBindFramebuffer(GL_FRAMEBUFFER, 0);
2008 
2009         // create geometry
2010         CreateTriangle(&vao_, &vbo_, NULL);
2011 
2012         // draw
2013         glBindBufferRange(GL_ATOMIC_COUNTER_BUFFER, 1, counter_buffer_, 16, 32);
2014         glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 7, counter_buffer_);
2015         glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, xfb_buffer_[0]);
2016         glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 1, xfb_buffer_[1]);
2017         glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
2018         glViewport(0, 0, s, s);
2019         glUseProgram(prog_);
2020         glBindVertexArray(vao_);
2021         glBeginTransformFeedback(GL_TRIANGLES);
2022         glDrawArrays(GL_TRIANGLES, 0, 3);
2023         glEndTransformFeedback();
2024 
2025         // validate
2026         UVec4 data[s * s + 3];
2027         glReadBuffer(GL_COLOR_ATTACHMENT0);
2028         glReadPixels(0, 0, s, s, GL_RGBA_INTEGER, GL_UNSIGNED_INT, data);
2029         glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buffer_[0]);
2030         GLuint *data2;
2031         data2 = static_cast<GLuint *>(
2032             glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 3 * sizeof(GLuint), GL_MAP_READ_BIT));
2033         data[s * s]     = UVec4(data2[0]);
2034         data[s * s + 1] = UVec4(data2[1]);
2035         data[s * s + 2] = UVec4(data2[2]);
2036         if (!CheckCounterValues(s * s + 3, data, 100))
2037             return ERROR;
2038         glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
2039         glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0);
2040 
2041         glReadBuffer(GL_COLOR_ATTACHMENT1);
2042         glReadPixels(0, 0, s, s, GL_RGBA_INTEGER, GL_UNSIGNED_INT, data);
2043         glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buffer_[1]);
2044         data2 = static_cast<GLuint *>(
2045             glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 3 * sizeof(GLuint), GL_MAP_READ_BIT));
2046         data[s * s]     = UVec4(data2[0]);
2047         data[s * s + 1] = UVec4(data2[1]);
2048         data[s * s + 2] = UVec4(data2[2]);
2049         if (!CheckCounterValues(s * s + 3, data, 33))
2050             return ERROR;
2051         glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
2052         glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0);
2053 
2054         if (!CheckFinalCounterValue(counter_buffer_, 32, 167))
2055             return ERROR;
2056         if (!CheckFinalCounterValue(counter_buffer_, 128, 33))
2057             return ERROR;
2058 
2059         return NO_ERROR;
2060     }
Cleanup()2061     virtual long Cleanup()
2062     {
2063         glDeleteFramebuffers(1, &fbo_);
2064         glDeleteTextures(2, rt_);
2065         glViewport(0, 0, getWindowWidth(), getWindowHeight());
2066         glDeleteBuffers(1, &counter_buffer_);
2067         glDeleteBuffers(2, xfb_buffer_);
2068         glDeleteVertexArrays(1, &vao_);
2069         glDeleteBuffers(1, &vbo_);
2070         glDeleteProgram(prog_);
2071         glUseProgram(0);
2072         return NO_ERROR;
2073     }
2074 };
2075 
2076 class AdvancedUsageDrawUpdateDraw : public SACSubcaseBase
2077 {
Title()2078     virtual std::string Title()
2079     {
2080         return NL "Update via Draw Call and update via MapBufferRange";
2081     }
Purpose()2082     virtual std::string Purpose()
2083     {
2084         return NL "1. Create atomic counter buffers and init them with start values." NL
2085                   "2. Increment (decrement) buffer values in the shader." NL
2086                   "3. Map buffers with MapBufferRange command. Increment (decrement) buffer values manually." NL
2087                   "4. Unmap buffers with UnmapBuffer command." NL
2088                   "5. Again increment (decrement) buffer values in the shader." NL
2089                   "Verify that this scenario works as expected and final values in the buffer objects are correct.";
2090     }
Method()2091     virtual std::string Method()
2092     {
2093         return NL "";
2094     }
PassCriteria()2095     virtual std::string PassCriteria()
2096     {
2097         return NL "";
2098     }
2099 
2100     GLuint counter_buffer_;
2101     GLuint vao_, vbo_;
2102     GLuint prog_, prog2_;
2103     GLuint fbo_, rt_[2];
2104 
Setup()2105     virtual long Setup()
2106     {
2107         counter_buffer_ = 0;
2108         vao_ = vbo_ = 0;
2109         prog_       = 0;
2110         prog2_      = 0;
2111         fbo_ = rt_[0] = rt_[1] = 0;
2112         return NO_ERROR;
2113     }
Run()2114     virtual long Run()
2115     {
2116 
2117         GLint p1, p2;
2118         glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS, &p1);
2119         glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTERS, &p2);
2120         if (p1 < 1 || p2 < 2)
2121         {
2122             OutputNotSupported(
2123                 "GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS or GL_MAX_FRAGMENT_ATOMIC_COUNTERS are less than required");
2124             return NOT_SUPPORTED;
2125         }
2126 
2127         // create program
2128         const char *src_vs = "#version 310 es" NL "layout(location = 0) in vec4 i_vertex;" NL "void main() {" NL
2129                              "  gl_Position = i_vertex;" NL "}";
2130         const char *src_fs = "#version 310 es" NL "layout(location = 0) out uvec4 o_color[2];" NL
2131                              "layout(binding = 0) uniform atomic_uint ac_counter[2];" NL "void main() {" NL
2132                              "  o_color[0] = uvec4(atomicCounterIncrement(ac_counter[0]));" NL
2133                              "  o_color[1] = uvec4(atomicCounterDecrement(ac_counter[1]));" NL "}";
2134         const char *src_fs2 = "#version 310 es" NL "layout(location = 0) out uvec4 o_color[2];" NL
2135                               "layout(binding = 0) uniform atomic_uint ac_counter[2];" NL "void main() {" NL
2136                               "  o_color[0] = uvec4(atomicCounter(ac_counter[0]));" NL
2137                               "  o_color[1] = uvec4(atomicCounter(ac_counter[1]));" NL "}";
2138         prog_  = CreateProgram(src_vs, src_fs, true);
2139         prog2_ = CreateProgram(src_vs, src_fs2, true);
2140 
2141         // create atomic counter buffer
2142         glGenBuffers(1, &counter_buffer_);
2143         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_);
2144         glBufferData(GL_ATOMIC_COUNTER_BUFFER, 8, NULL, GL_DYNAMIC_COPY);
2145         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
2146 
2147         // create render targets
2148         const int s = 8;
2149         glGenTextures(2, rt_);
2150 
2151         for (int i = 0; i < 2; ++i)
2152         {
2153             glBindTexture(GL_TEXTURE_2D, rt_[i]);
2154             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2155             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2156             glTexImage2D(GL_TEXTURE_2D, 0, GL_R32UI, s, s, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, NULL);
2157             glBindTexture(GL_TEXTURE_2D, 0);
2158         }
2159 
2160         // create fbo
2161         glGenFramebuffers(1, &fbo_);
2162         glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
2163         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt_[0], 0);
2164         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, rt_[1], 0);
2165         const GLenum draw_buffers[2] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1};
2166         glDrawBuffers(2, draw_buffers);
2167         glBindFramebuffer(GL_FRAMEBUFFER, 0);
2168 
2169         // create geometry
2170         CreateQuad(&vao_, &vbo_, NULL);
2171 
2172         // init counter buffer
2173         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_);
2174         unsigned int *ptr = static_cast<unsigned int *>(
2175             glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 8, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT));
2176         *ptr++ = 256;
2177         *ptr++ = 256;
2178         glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
2179 
2180         // draw
2181         glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
2182         glViewport(0, 0, s, s);
2183         glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, counter_buffer_);
2184         glUseProgram(prog_);
2185         glBindVertexArray(vao_);
2186         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
2187 
2188         // update counter buffer
2189         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_);
2190         ptr = static_cast<unsigned int *>(
2191             glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 8, GL_MAP_WRITE_BIT | GL_MAP_READ_BIT));
2192         *ptr++ += 512;
2193         *ptr++ += 1024;
2194         glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
2195 
2196         // draw
2197         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
2198         glMemoryBarrier(GL_ATOMIC_COUNTER_BARRIER_BIT);
2199 
2200         // draw
2201         glUseProgram(prog2_);
2202         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
2203 
2204         // validate
2205         UVec4 data[s * s];
2206         glReadBuffer(GL_COLOR_ATTACHMENT0);
2207         glReadPixels(0, 0, s, s, GL_RGBA_INTEGER, GL_UNSIGNED_INT, data);
2208         for (int i = 0; i < s * s; ++i)
2209         {
2210             if (data[i].x() != 896)
2211             {
2212                 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Counter value is " << data[i].x()
2213                                                     << " should be 896." << tcu::TestLog::EndMessage;
2214                 return ERROR;
2215             }
2216         }
2217 
2218         glReadBuffer(GL_COLOR_ATTACHMENT1);
2219         glReadPixels(0, 0, s, s, GL_RGBA_INTEGER, GL_UNSIGNED_INT, data);
2220         for (int i = 0; i < s * s; ++i)
2221         {
2222             if (data[i].x() != 1152)
2223             {
2224                 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Counter value is " << data[i].x()
2225                                                     << " should be 896." << tcu::TestLog::EndMessage;
2226                 return ERROR;
2227             }
2228         }
2229 
2230         if (!CheckFinalCounterValue(counter_buffer_, 0, 896))
2231             return ERROR;
2232         if (!CheckFinalCounterValue(counter_buffer_, 4, 1152))
2233             return ERROR;
2234 
2235         return NO_ERROR;
2236     }
Cleanup()2237     virtual long Cleanup()
2238     {
2239         glDeleteFramebuffers(1, &fbo_);
2240         glDeleteTextures(2, rt_);
2241         glViewport(0, 0, getWindowWidth(), getWindowHeight());
2242         glDeleteBuffers(1, &counter_buffer_);
2243         glDeleteVertexArrays(1, &vao_);
2244         glDeleteBuffers(1, &vbo_);
2245         glDeleteProgram(prog_);
2246         glDeleteProgram(prog2_);
2247         glUseProgram(0);
2248         return NO_ERROR;
2249     }
2250 };
2251 
2252 class AdvancedUsageManyCounters : public BasicUsageCS
2253 {
Title()2254     virtual std::string Title()
2255     {
2256         return NL "Large atomic counters array indexed with uniforms";
2257     }
Purpose()2258     virtual std::string Purpose()
2259     {
2260         return NL "Verify that large atomic counters array works as expected when indexed with dynamically uniform "
2261                   "expressions." NL
2262                   "Built-ins tested: atomicCounterIncrement, atomicCounterDecrement and atomicCounter.";
2263     }
Method()2264     virtual std::string Method()
2265     {
2266         return NL "";
2267     }
PassCriteria()2268     virtual std::string PassCriteria()
2269     {
2270         return NL "";
2271     }
2272 
2273     GLuint counter_buffer_, m_ssbo;
2274     GLuint prog_;
2275 
Setup()2276     virtual long Setup()
2277     {
2278         counter_buffer_ = 0;
2279         m_ssbo          = 0;
2280         prog_           = 0;
2281         return NO_ERROR;
2282     }
2283 
Run()2284     virtual long Run()
2285     {
2286         // create program
2287         const char *glsl_cs = NL
2288             "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;" NL "layout(std430) buffer Output {" NL
2289             "  mediump uvec4 data1[64];" NL "  mediump uvec4 data2[64];" NL "  mediump uvec4 data3[64];" NL
2290             "  mediump uvec4 data4[64];" NL "  mediump uvec4 data5[64];" NL "  mediump uvec4 data6[64];" NL
2291             "  mediump uvec4 data7[64];" NL "  mediump uvec4 data8[64];" NL "} g_out;" NL
2292             "uniform mediump int u_active_counters[8];" NL "layout(binding = 0) uniform atomic_uint ac_counter[8];" NL
2293             "void main() {" NL "  mediump uint offset = 8u * gl_GlobalInvocationID.y + gl_GlobalInvocationID.x;" NL
2294             "  g_out.data1[offset] = uvec4(atomicCounterIncrement(ac_counter[u_active_counters[0]]));" NL
2295             "  g_out.data2[offset] = uvec4(atomicCounterDecrement(ac_counter[u_active_counters[1]]));" NL
2296             "  g_out.data3[offset] = uvec4(atomicCounter(ac_counter[u_active_counters[2]]));" NL
2297             "  g_out.data4[offset] = uvec4(atomicCounterIncrement(ac_counter[u_active_counters[3]]));" NL
2298             "  g_out.data5[offset] = uvec4(atomicCounterDecrement(ac_counter[u_active_counters[4]]));" NL
2299             "  g_out.data6[offset] = uvec4(atomicCounter(ac_counter[u_active_counters[5]]));" NL
2300             "  g_out.data7[offset] = uvec4(atomicCounterIncrement(ac_counter[u_active_counters[6]]));" NL
2301             "  g_out.data8[offset] = uvec4(atomicCounterIncrement(ac_counter[u_active_counters[7]]));" NL "}";
2302 
2303         prog_ = CreateComputeProgram(glsl_cs);
2304         glLinkProgram(prog_);
2305         if (!CheckProgram(prog_))
2306             return ERROR;
2307 
2308         // create atomic counter buffer
2309         std::vector<GLuint> init_data(1024, 1000);
2310         glGenBuffers(1, &counter_buffer_);
2311         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_);
2312         glBufferData(GL_ATOMIC_COUNTER_BUFFER, 1024 * sizeof(GLuint), &init_data[0], GL_DYNAMIC_COPY);
2313         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
2314 
2315         glGenBuffers(1, &m_ssbo);
2316         glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_ssbo);
2317         glBufferData(GL_SHADER_STORAGE_BUFFER, 8 * 64 * sizeof(UVec4), NULL, GL_DYNAMIC_DRAW);
2318         glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
2319 
2320         // set uniforms
2321         glUseProgram(prog_);
2322         glUniform1i(glGetUniformLocation(prog_, "u_active_counters[0]"), 0);
2323         glUniform1i(glGetUniformLocation(prog_, "u_active_counters[1]"), 1);
2324         glUniform1i(glGetUniformLocation(prog_, "u_active_counters[2]"), 2);
2325         glUniform1i(glGetUniformLocation(prog_, "u_active_counters[3]"), 3);
2326         glUniform1i(glGetUniformLocation(prog_, "u_active_counters[4]"), 4);
2327         glUniform1i(glGetUniformLocation(prog_, "u_active_counters[5]"), 5);
2328         glUniform1i(glGetUniformLocation(prog_, "u_active_counters[6]"), 6);
2329         glUniform1i(glGetUniformLocation(prog_, "u_active_counters[7]"), 7);
2330 
2331         // dispatch
2332         glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, counter_buffer_);
2333         glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_ssbo);
2334         glDispatchCompute(8, 8, 1);
2335 
2336         // validate
2337         glMemoryBarrier(GL_ATOMIC_COUNTER_BARRIER_BIT | GL_SHADER_STORAGE_BARRIER_BIT);
2338         UVec4 *data;
2339         long error = NO_ERROR;
2340 
2341         glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_ssbo);
2342         data = static_cast<UVec4 *>(glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 64 * sizeof(UVec4), GL_MAP_READ_BIT));
2343         if (!CheckCounterValues(8 * 8, data, 1000))
2344             error = ERROR;
2345         glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
2346         if (!CheckFinalCounterValue(counter_buffer_, 0, 1064))
2347             error = ERROR;
2348 
2349         glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_ssbo);
2350         data = static_cast<UVec4 *>(
2351             glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 64 * sizeof(UVec4), 64 * sizeof(UVec4), GL_MAP_READ_BIT));
2352         if (!CheckCounterValues(8 * 8, data, 1000 - 64))
2353             error = ERROR;
2354         glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
2355         if (!CheckFinalCounterValue(counter_buffer_, 1 * sizeof(GLuint), 1000 - 64))
2356             error = ERROR;
2357 
2358         glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_ssbo);
2359         data = static_cast<UVec4 *>(
2360             glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 64 * sizeof(UVec4) * 2, 64 * sizeof(UVec4), GL_MAP_READ_BIT));
2361         for (int i = 0; i < 8 * 8; ++i)
2362             if (data[i].x() != 1000)
2363                 error = ERROR;
2364         glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
2365         if (!CheckFinalCounterValue(counter_buffer_, 2 * sizeof(GLuint), 1000))
2366             error = ERROR;
2367 
2368         glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_ssbo);
2369         data = static_cast<UVec4 *>(
2370             glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 64 * sizeof(UVec4) * 3, 64 * sizeof(UVec4), GL_MAP_READ_BIT));
2371         if (!CheckCounterValues(8 * 8, data, 1000))
2372             error = ERROR;
2373         glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
2374         if (!CheckFinalCounterValue(counter_buffer_, 3 * sizeof(GLuint), 1064))
2375             error = ERROR;
2376 
2377         glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_ssbo);
2378         data = static_cast<UVec4 *>(
2379             glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 64 * sizeof(UVec4) * 4, 64 * sizeof(UVec4), GL_MAP_READ_BIT));
2380         if (!CheckCounterValues(8 * 8, data, 1000 - 64))
2381             error = ERROR;
2382         glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
2383         if (!CheckFinalCounterValue(counter_buffer_, 4 * sizeof(GLuint), 1000 - 64))
2384             error = ERROR;
2385 
2386         glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_ssbo);
2387         data = static_cast<UVec4 *>(
2388             glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 64 * sizeof(UVec4) * 5, 64 * sizeof(UVec4), GL_MAP_READ_BIT));
2389         for (int i = 0; i < 8 * 8; ++i)
2390             if (data[i].x() != 1000)
2391                 error = ERROR;
2392         glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
2393         if (!CheckFinalCounterValue(counter_buffer_, 5 * sizeof(GLuint), 1000))
2394             error = ERROR;
2395 
2396         glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_ssbo);
2397         data = static_cast<UVec4 *>(
2398             glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 64 * sizeof(UVec4) * 6, 64 * sizeof(UVec4), GL_MAP_READ_BIT));
2399         if (!CheckCounterValues(8 * 8, data, 1000))
2400             error = ERROR;
2401         glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
2402         if (!CheckFinalCounterValue(counter_buffer_, 6 * sizeof(GLuint), 1064))
2403             error = ERROR;
2404 
2405         glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_ssbo);
2406         data = static_cast<UVec4 *>(
2407             glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 64 * sizeof(UVec4) * 7, 64 * sizeof(UVec4), GL_MAP_READ_BIT));
2408         if (!CheckCounterValues(8 * 8, data, 1000))
2409             error = ERROR;
2410         glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
2411         if (!CheckFinalCounterValue(counter_buffer_, 7 * sizeof(GLuint), 1064))
2412             error = ERROR;
2413 
2414         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
2415         glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
2416         return error;
2417     }
2418 
Cleanup()2419     virtual long Cleanup()
2420     {
2421         glDeleteBuffers(1, &counter_buffer_);
2422         glDeleteBuffers(1, &m_ssbo);
2423         glDeleteProgram(prog_);
2424         glUseProgram(0);
2425         return NO_ERROR;
2426     }
2427 };
2428 
2429 class AdvancedUsageMultiDimArray : public BasicUsageCS
2430 {
2431 public:
Title()2432     virtual std::string Title()
2433     {
2434         return NL "Multidimensional atomic counter array";
2435     }
Purpose()2436     virtual std::string Purpose()
2437     {
2438         return NL "Verify that multidimensional atomic counter array works as expected." NL
2439                   "Built-ins tested: atomicCounterIncrement.";
2440     }
Method()2441     virtual std::string Method()
2442     {
2443         return NL "";
2444     }
PassCriteria()2445     virtual std::string PassCriteria()
2446     {
2447         return NL "";
2448     }
2449 
Setup()2450     virtual long Setup()
2451     {
2452         DE_ASSERT(dim_x_ != 0 && dim_y_ != 0 && dim_z_ != 0);
2453         DE_ASSERT(!glsl_cs_.empty());
2454         return NO_ERROR;
2455     }
2456 
Run()2457     virtual long Run()
2458     {
2459         GLint maxAtomicCounters = 0;
2460         glGetIntegerv(GL_MAX_COMPUTE_ATOMIC_COUNTERS, &maxAtomicCounters);
2461         if (maxAtomicCounters < dim_x_ * dim_y_ * dim_z_)
2462         {
2463             OutputNotSupported("GL_MAX_COMPUTE_ATOMIC_COUNTERS is less than required");
2464             return NOT_SUPPORTED;
2465         }
2466 
2467         GLsizeiptr bufferSize = dim_x_ * dim_y_ * dim_z_ * sizeof(GLuint);
2468         GLint maxBufferSize   = 0;
2469         glGetIntegerv(GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE, &maxBufferSize);
2470         if (maxBufferSize < bufferSize)
2471         {
2472             OutputNotSupported("GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE is less than required");
2473             return NOT_SUPPORTED;
2474         }
2475 
2476         prog_ = CreateComputeProgram(glsl_cs_.c_str());
2477         glLinkProgram(prog_);
2478         if (!CheckProgram(prog_))
2479             return ERROR;
2480 
2481         // create atomic counter buffer
2482         std::vector<GLuint> init_data(bufferSize, 1000);
2483         glGenBuffers(1, &counter_buffer_);
2484         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_);
2485         glBufferData(GL_ATOMIC_COUNTER_BUFFER, bufferSize * sizeof(GLuint), &init_data[0], GL_DYNAMIC_COPY);
2486         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
2487 
2488         // dispatch
2489         glUseProgram(prog_);
2490         glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, counter_buffer_);
2491         glDispatchCompute(8, 8, 1);
2492 
2493         // validate
2494         glMemoryBarrier(GL_ATOMIC_COUNTER_BARRIER_BIT);
2495         long error = NO_ERROR;
2496 
2497         for (int x = 0; x < dim_x_; x++)
2498             for (int y = 0; y < dim_y_; y++)
2499                 for (int z = 0; z < dim_z_; z++)
2500                     if (!CheckFinalCounterValue(counter_buffer_,
2501                                                 (x * dim_y_ * dim_z_ + y * dim_z_ + z) * sizeof(GLuint), 1064))
2502                         error = ERROR;
2503 
2504         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
2505         return error;
2506     }
2507 
Cleanup()2508     virtual long Cleanup()
2509     {
2510         glDeleteBuffers(1, &counter_buffer_);
2511         glDeleteProgram(prog_);
2512         glUseProgram(0);
2513         return NO_ERROR;
2514     }
2515 
2516 protected:
2517     GLuint counter_buffer_ = 0;
2518     GLuint prog_           = 0;
2519     int dim_x_             = 0;
2520     int dim_y_             = 0;
2521     int dim_z_             = 0;
2522     std::string glsl_cs_;
2523 };
2524 
2525 class AdvancedUsageMultiDimArrayLarge : public AdvancedUsageMultiDimArray
2526 {
Setup()2527     virtual long Setup()
2528     {
2529         dim_x_ = 3;
2530         dim_y_ = 5;
2531         dim_z_ = 6;
2532 
2533         glsl_cs_ =
2534             NL "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;" NL
2535                "layout(binding = 0) uniform atomic_uint ac_counter[3][5][6];" NL
2536                "// Increments all the elements in a one dimensional array using different methods." NL
2537                "void incrementCounterArray1D(in atomic_uint arr[6]) {" NL "  for (int i = 1; i < 5; i++)" NL
2538                "    atomicCounterIncrement(arr[i]);" NL "  atomicCounterIncrement(arr[0]);" NL
2539                "  atomicCounterIncrement(arr[5]);" NL "}" NL
2540                "// Increments all the elements in a two dimensional counter array using different methods." NL
2541                "void incrementCounterArray2D(in atomic_uint arr[5][6]) {" NL "  incrementCounterArray1D(arr[1]);" NL
2542                "  for (int i = 2; i < 5; i++) {" NL "    for (int j = 0; j < 5; j++) {" NL
2543                "      atomicCounterIncrement(arr[i][j]);" NL "    }" NL "    atomicCounterIncrement(arr[i][5]);" NL
2544                "  }" NL "  for (int i = 0; i < 4; i++)" NL "     atomicCounterIncrement(arr[0][i]);" NL
2545                "  atomicCounterIncrement(arr[0][4]);" NL "  atomicCounterIncrement(arr[0][5]);" NL "}" NL
2546                "// Increments all the atomic counters once." NL "void main() {" NL "  for (int i = 0; i < 2; i++)" NL
2547                "    incrementCounterArray2D(ac_counter[i]);" NL "  for (int i = 0; i < 5; i++)" NL
2548                "    incrementCounterArray1D(ac_counter[2][i]);" NL "}";
2549 
2550         return AdvancedUsageMultiDimArray::Setup();
2551     }
2552 };
2553 
2554 class AdvancedUsageMultiDimArrayMedium : public AdvancedUsageMultiDimArray
2555 {
Setup()2556     virtual long Setup()
2557     {
2558         dim_x_ = 3;
2559         dim_y_ = 5;
2560         dim_z_ = 3;
2561 
2562         glsl_cs_ =
2563             NL "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;" NL
2564                "layout(binding = 0) uniform atomic_uint ac_counter[3][5][3];" NL
2565                "// Increments all the elements in a one dimensional array using different methods." NL
2566                "void incrementCounterArray1D(in atomic_uint arr[3]) {" NL "  for (int i = 1; i < 3; i++)" NL
2567                "    atomicCounterIncrement(arr[i]);" NL "  atomicCounterIncrement(arr[0]);" NL "}" NL
2568                "// Increments all the elements in a two dimensional counter array using different methods." NL
2569                "void incrementCounterArray2D(in atomic_uint arr[5][3]) {" NL "  incrementCounterArray1D(arr[1]);" NL
2570                "  for (int i = 2; i < 5; i++) {" NL "    for (int j = 0; j < 2; j++) {" NL
2571                "      atomicCounterIncrement(arr[i][j]);" NL "    }" NL "    atomicCounterIncrement(arr[i][2]);" NL
2572                "  }" NL "  for (int i = 0; i < 2; i++)" NL "     atomicCounterIncrement(arr[0][i]);" NL
2573                "  atomicCounterIncrement(arr[0][2]);" NL "}" NL "// Increments all the atomic counters once." NL
2574                "void main() {" NL "  for (int i = 0; i < 2; i++)" NL "    incrementCounterArray2D(ac_counter[i]);" NL
2575                "  for (int i = 0; i < 5; i++)" NL "    incrementCounterArray1D(ac_counter[2][i]);" NL "}";
2576 
2577         return AdvancedUsageMultiDimArray::Setup();
2578     }
2579 };
2580 
2581 class AdvancedUsageMultiDimArraySmall : public AdvancedUsageMultiDimArray
2582 {
Setup()2583     virtual long Setup()
2584     {
2585         dim_x_ = 2;
2586         dim_y_ = 2;
2587         dim_z_ = 2;
2588 
2589         glsl_cs_ =
2590             NL "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;" NL
2591                "layout(binding = 0) uniform atomic_uint ac_counter[2][2][2];" NL
2592                "// Increments all the elements in a one dimensional array." NL
2593                "void incrementCounterArray1D(in atomic_uint arr[2]) {" NL "  atomicCounterIncrement(arr[0]);" NL
2594                "  atomicCounterIncrement(arr[1]);" NL "}" NL
2595                "// Increments all the elements in a two dimensional counter array using different methods." NL
2596                "void incrementCounterArray2D(in atomic_uint arr[2][2]) {" NL "  incrementCounterArray1D(arr[1]);" NL
2597                "  for (int i = 0; i < 2; i++) {" NL "    atomicCounterIncrement(arr[0][i]);" NL "  }" NL "}" NL
2598                "// Increments all the atomic counters once." NL "void main() {" NL
2599                "  incrementCounterArray2D(ac_counter[0]);" NL "  for (int i = 0; i < 2; i++)" NL
2600                "    incrementCounterArray1D(ac_counter[1][i]);" NL "}";
2601 
2602         return AdvancedUsageMultiDimArray::Setup();
2603     }
2604 };
2605 
2606 class AdvancedUsageSwitchPrograms : public SACSubcaseBase
2607 {
Title()2608     virtual std::string Title()
2609     {
2610         return NL "Switching several program objects with different atomic counters with different bindings";
2611     }
Purpose()2612     virtual std::string Purpose()
2613     {
2614         return NL "Verify that each program upadate atomic counter buffer object in appropriate binding point.";
2615     }
Method()2616     virtual std::string Method()
2617     {
2618         return NL "";
2619     }
PassCriteria()2620     virtual std::string PassCriteria()
2621     {
2622         return NL "";
2623     }
2624 
2625     GLuint counter_buffer_[8];
2626     GLuint xfb_buffer_;
2627     GLuint vao_, vbo_;
2628     GLuint prog_[8];
2629     GLuint fbo_, rt_;
2630 
GenVSSrc(int binding,int offset)2631     std::string GenVSSrc(int binding, int offset)
2632     {
2633         std::ostringstream os;
2634         os << "#version 310 es" NL "layout(location = 0) in vec4 i_vertex;" NL "flat out uvec4 o_atomic_value;" NL
2635               "layout(binding = "
2636            << binding << ", offset = " << offset
2637            << ") uniform atomic_uint ac_counter_vs;" NL "void main() {" NL "  gl_Position = i_vertex;" NL
2638               "  o_atomic_value = uvec4(atomicCounterIncrement(ac_counter_vs));" NL "}";
2639         return os.str();
2640     }
GenFSSrc(int binding,int offset)2641     std::string GenFSSrc(int binding, int offset)
2642     {
2643         std::ostringstream os;
2644         os << "#version 310 es" NL "layout(location = 0) out uvec4 o_color;" NL "layout(binding = " << binding
2645            << ", offset = " << offset
2646            << ") uniform atomic_uint ac_counter_fs;" NL "void main() {" NL
2647               "  o_color = uvec4(atomicCounterIncrement(ac_counter_fs));" NL "}";
2648         return os.str();
2649     }
Setup()2650     virtual long Setup()
2651     {
2652         memset(counter_buffer_, 0, sizeof(counter_buffer_));
2653         xfb_buffer_ = 0;
2654         vao_ = vbo_ = 0;
2655         memset(prog_, 0, sizeof(prog_));
2656         fbo_ = rt_ = 0;
2657         return NO_ERROR;
2658     }
Run()2659     virtual long Run()
2660     {
2661 
2662         GLint p1, p2, p3, p4;
2663         glGetIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS, &p1);
2664         glGetIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTERS, &p2);
2665         glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS, &p3);
2666         glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTERS, &p4);
2667         if (p1 < 8 || p2 < 1 || p3 < 8 || p4 < 1)
2668         {
2669             OutputNotSupported("GL_MAX_*_ATOMIC_COUNTER_BUFFERS or GL_MAX_*_ATOMIC_COUNTERS are less than required");
2670             return NOT_SUPPORTED;
2671         }
2672 
2673         // create programs
2674         for (int i = 0; i < 8; ++i)
2675         {
2676             std::string vs_str  = GenVSSrc(i, i * 8);
2677             std::string fs_str  = GenFSSrc(7 - i, 128 + i * 16);
2678             const char *src_vs  = vs_str.c_str();
2679             const char *src_fs  = fs_str.c_str();
2680             prog_[i]            = CreateProgram(src_vs, src_fs, false);
2681             const char *xfb_var = "o_atomic_value";
2682             glTransformFeedbackVaryings(prog_[i], 1, &xfb_var, GL_SEPARATE_ATTRIBS);
2683             LinkProgram(prog_[i]);
2684         }
2685 
2686         // create atomic counter buffers
2687         glGenBuffers(8, counter_buffer_);
2688         for (int i = 0; i < 8; ++i)
2689         {
2690             std::vector<GLuint> init_data(256);
2691             glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_[i]);
2692             glBufferData(GL_ATOMIC_COUNTER_BUFFER, (GLsizeiptr)(init_data.size() * sizeof(GLuint)), &init_data[0],
2693                          GL_DYNAMIC_COPY);
2694         }
2695         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
2696 
2697         // create transform feedback buffer
2698         glGenBuffers(1, &xfb_buffer_);
2699         glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buffer_);
2700         glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 1000, NULL, GL_STREAM_COPY);
2701         glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0);
2702 
2703         // create render target
2704         const int s = 8;
2705         glGenTextures(1, &rt_);
2706         glBindTexture(GL_TEXTURE_2D, rt_);
2707         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2708         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2709         glTexImage2D(GL_TEXTURE_2D, 0, GL_R32UI, s, s, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, NULL);
2710         glBindTexture(GL_TEXTURE_2D, 0);
2711 
2712         // create fbo
2713         glGenFramebuffers(1, &fbo_);
2714         glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
2715         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt_, 0);
2716         glBindFramebuffer(GL_FRAMEBUFFER, 0);
2717 
2718         // create geometry
2719         CreateTriangle(&vao_, &vbo_, NULL);
2720 
2721         // draw
2722         for (GLuint i = 0; i < 8; ++i)
2723         {
2724             glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, i, counter_buffer_[i]);
2725         }
2726         glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, xfb_buffer_);
2727         glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
2728         glViewport(0, 0, s, s);
2729         glBindVertexArray(vao_);
2730 
2731         for (int i = 0; i < 8; ++i)
2732         {
2733             glUseProgram(prog_[i]);
2734             glBeginTransformFeedback(GL_TRIANGLES);
2735             glDrawArrays(GL_TRIANGLES, 0, 3);
2736             glEndTransformFeedback();
2737             glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
2738 
2739             if (!CheckFinalCounterValue(counter_buffer_[i], i * 8, 3))
2740                 return ERROR;
2741             if (!CheckFinalCounterValue(counter_buffer_[7 - i], 128 + i * 16, 64))
2742                 return ERROR;
2743         }
2744         return NO_ERROR;
2745     }
Cleanup()2746     virtual long Cleanup()
2747     {
2748         glDeleteFramebuffers(1, &fbo_);
2749         glDeleteTextures(1, &rt_);
2750         glViewport(0, 0, getWindowWidth(), getWindowHeight());
2751         glDeleteBuffers(8, counter_buffer_);
2752         glDeleteBuffers(1, &xfb_buffer_);
2753         glDeleteVertexArrays(1, &vao_);
2754         glDeleteBuffers(1, &vbo_);
2755         for (int i = 0; i < 8; ++i)
2756             glDeleteProgram(prog_[i]);
2757         glUseProgram(0);
2758         return NO_ERROR;
2759     }
2760 };
2761 
2762 class AdvancedUsageUBO : public BasicUsageCS
2763 {
Title()2764     virtual std::string Title()
2765     {
2766         return NL "Atomic Counters used to access Uniform Buffer Objects";
2767     }
Purpose()2768     virtual std::string Purpose()
2769     {
2770         return NL "Atomic counters are used to access UBOs. In that way each shader invocation can access UBO at "
2771                   "unique offset." NL
2772                   "This scenario is a base for some practical algorithms. Verify that it works as expected.";
2773     }
Method()2774     virtual std::string Method()
2775     {
2776         return NL "";
2777     }
PassCriteria()2778     virtual std::string PassCriteria()
2779     {
2780         return NL "";
2781     }
2782 
2783     GLuint counter_buffer_, m_ssbo;
2784     GLuint uniform_buffer_;
2785     GLuint prog_;
2786 
Setup()2787     virtual long Setup()
2788     {
2789         counter_buffer_ = 0;
2790         uniform_buffer_ = 0;
2791         m_ssbo          = 0;
2792         prog_           = 0;
2793         return NO_ERROR;
2794     }
2795 
Run()2796     virtual long Run()
2797     {
2798         // create program
2799         const char *glsl_cs =
2800             NL "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;" NL "layout(std430) buffer Output {" NL
2801                "  mediump uvec4 color[256];" NL "} g_out;" NL
2802                "layout(binding = 0, offset = 0) uniform atomic_uint ac_counter;" NL "layout(std140) uniform Data {" NL
2803                "  mediump uint index[256];" NL "} ub_data;" NL "void main() {" NL
2804                "  mediump uint offset = 16u * gl_GlobalInvocationID.y + gl_GlobalInvocationID.x;" NL
2805                "  g_out.color[offset] = uvec4(ub_data.index[atomicCounterIncrement(ac_counter)]);" NL "}";
2806         prog_ = CreateComputeProgram(glsl_cs);
2807         glLinkProgram(prog_);
2808         if (!CheckProgram(prog_))
2809             return ERROR;
2810         glUniformBlockBinding(prog_, glGetUniformBlockIndex(prog_, "Data"), 1);
2811 
2812         // create atomic counter buffer
2813         const unsigned int z = 0;
2814         glGenBuffers(1, &counter_buffer_);
2815         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_);
2816         glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(z), &z, GL_DYNAMIC_COPY);
2817         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
2818 
2819         // create uniform buffer
2820         std::vector<UVec4> init_data(256);
2821         for (GLuint i = 0; i < 256; ++i)
2822             init_data[i] = UVec4(i);
2823         glGenBuffers(1, &uniform_buffer_);
2824         glBindBuffer(GL_UNIFORM_BUFFER, uniform_buffer_);
2825         glBufferData(GL_UNIFORM_BUFFER, (GLsizeiptr)(sizeof(UVec4) * init_data.size()), &init_data[0], GL_DYNAMIC_COPY);
2826         glBindBuffer(GL_UNIFORM_BUFFER, 0);
2827 
2828         glGenBuffers(1, &m_ssbo);
2829         glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_ssbo);
2830         glBufferData(GL_SHADER_STORAGE_BUFFER, 256 * sizeof(UVec4), NULL, GL_DYNAMIC_DRAW);
2831         glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
2832 
2833         // draw
2834         glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, counter_buffer_);
2835         glBindBufferBase(GL_UNIFORM_BUFFER, 1, uniform_buffer_);
2836         glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_ssbo);
2837         glUseProgram(prog_);
2838         glDispatchCompute(16, 16, 1);
2839 
2840         // validate
2841         UVec4 *data;
2842         long error = NO_ERROR;
2843         glMemoryBarrier(GL_UNIFORM_BARRIER_BIT | GL_SHADER_STORAGE_BARRIER_BIT | GL_ATOMIC_COUNTER_BARRIER_BIT);
2844 
2845         glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_ssbo);
2846         data =
2847             static_cast<UVec4 *>(glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 256 * sizeof(UVec4), GL_MAP_READ_BIT));
2848         if (!CheckCounterValues(16 * 16, data, 0))
2849             error = ERROR;
2850         if (!CheckFinalCounterValue(counter_buffer_, 0, 256))
2851             error = ERROR;
2852         glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
2853 
2854         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
2855         glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
2856 
2857         return error;
2858     }
2859 
Cleanup()2860     virtual long Cleanup()
2861     {
2862         glDeleteBuffers(1, &counter_buffer_);
2863         glDeleteBuffers(1, &uniform_buffer_);
2864         glDeleteBuffers(1, &m_ssbo);
2865         glDeleteProgram(prog_);
2866         glUseProgram(0);
2867         return NO_ERROR;
2868     }
2869 };
2870 
2871 class NegativeAPI : public SACSubcaseBase
2872 {
Title()2873     virtual std::string Title()
2874     {
2875         return NL "NegativeAPI";
2876     }
Purpose()2877     virtual std::string Purpose()
2878     {
2879         return NL "Verify errors reported by BindBuffer* commands.";
2880     }
Method()2881     virtual std::string Method()
2882     {
2883         return NL "";
2884     }
PassCriteria()2885     virtual std::string PassCriteria()
2886     {
2887         return NL "";
2888     }
2889 
2890     GLuint buffer;
2891 
Setup()2892     virtual long Setup()
2893     {
2894         return NO_ERROR;
2895     }
Run()2896     virtual long Run()
2897     {
2898         long error = NO_ERROR;
2899         GLint res;
2900         glGetIntegerv(GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS, &res);
2901         glGenBuffers(1, &buffer);
2902         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, buffer);
2903         glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, res, buffer);
2904         if (glGetError() != GL_INVALID_VALUE)
2905         {
2906             m_context.getTestContext().getLog()
2907                 << tcu::TestLog::Message
2908                 << "glBindBufferBase should generate INVALID_VALUE when"
2909                    " index is greater than or equal GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS."
2910                 << tcu::TestLog::EndMessage;
2911             error = ERROR;
2912         }
2913         glBindBufferRange(GL_ATOMIC_COUNTER_BUFFER, res, buffer, 0, 4);
2914         if (glGetError() != GL_INVALID_VALUE)
2915         {
2916             m_context.getTestContext().getLog()
2917                 << tcu::TestLog::Message
2918                 << "glBindBufferRange should generate INVALID_VALUE when"
2919                    " index is greater than or equal GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS."
2920                 << tcu::TestLog::EndMessage;
2921             error = ERROR;
2922         }
2923         glBindBufferRange(GL_ATOMIC_COUNTER_BUFFER, res - 1, buffer, 3, 4);
2924         if (glGetError() != GL_INVALID_VALUE)
2925         {
2926             m_context.getTestContext().getLog() << tcu::TestLog::Message
2927                                                 << "glBindBufferRange should generate INVALID_VALUE when"
2928                                                    " <offset> is not a multiple of four"
2929                                                 << tcu::TestLog::EndMessage;
2930             error = ERROR;
2931         }
2932         return error;
2933     }
Cleanup()2934     virtual long Cleanup()
2935     {
2936         glDeleteBuffers(1, &buffer);
2937         return NO_ERROR;
2938     }
2939 };
2940 
2941 class NegativeGLSL : public BasicUsageCS
2942 {
Title()2943     virtual std::string Title()
2944     {
2945         return NL "GLSL errors";
2946     }
Purpose()2947     virtual std::string Purpose()
2948     {
2949         return NL "Verify that two different atomic counter uniforms with same binding cannot share same offset value.";
2950     }
Method()2951     virtual std::string Method()
2952     {
2953         return NL "";
2954     }
PassCriteria()2955     virtual std::string PassCriteria()
2956     {
2957         return NL "";
2958     }
2959 
2960     GLuint prog_;
2961 
Setup()2962     virtual long Setup()
2963     {
2964         prog_ = 0;
2965         return NO_ERROR;
2966     }
2967 
Run()2968     virtual long Run()
2969     {
2970         const char *const glsl_cs = NL
2971             "layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;" NL
2972             "layout(binding = 0, offset = 4) uniform atomic_uint ac_counter_inc;" NL
2973             "layout(binding = 0, offset = 4) uniform atomic_uint ac_counter_dec;" NL "layout(std430) buffer Output {" NL
2974             "  mediump uint data_inc[256];" NL "  mediump uint data_dec[256];" NL "} g_out;" NL "void main() {" NL
2975             "  mediump uint offset = 32u * gl_GlobalInvocationID.y + gl_GlobalInvocationID.x;" NL
2976             "  g_out.data_inc[offset] = atomicCounterIncrement(ac_counter_inc);" NL
2977             "  g_out.data_dec[offset] = atomicCounterDecrement(ac_counter_dec);" NL "}";
2978 
2979         prog_ = CreateComputeProgram(glsl_cs);
2980         glLinkProgram(prog_);
2981         if (CheckProgram(prog_))
2982         {
2983             m_context.getTestContext().getLog()
2984                 << tcu::TestLog::Message
2985                 << "Link should fail because ac_counter0 and ac_counter2 uses same binding and same offset."
2986                 << tcu::TestLog::EndMessage;
2987             return ERROR;
2988         }
2989         return NO_ERROR;
2990     }
Cleanup()2991     virtual long Cleanup()
2992     {
2993         glDeleteProgram(prog_);
2994         return NO_ERROR;
2995     }
2996 };
2997 
2998 class AdvancedManyDrawCalls : public SACSubcaseBase
2999 {
Title()3000     virtual std::string Title()
3001     {
3002         return NL "Atomic Counters usage in multiple draw calls";
3003     }
Purpose()3004     virtual std::string Purpose()
3005     {
3006         return NL "Verify atomic counters behaviour across multiple draw calls.";
3007     }
Method()3008     virtual std::string Method()
3009     {
3010         return NL "";
3011     }
PassCriteria()3012     virtual std::string PassCriteria()
3013     {
3014         return NL "";
3015     }
3016 
3017     GLuint counter_buffer_;
3018     GLuint vao_, vbo_;
3019     GLuint prog_;
3020     GLuint fbo_, rt_[2];
3021 
Setup()3022     virtual long Setup()
3023     {
3024         counter_buffer_ = 0;
3025         vao_ = vbo_ = 0;
3026         prog_       = 0;
3027         fbo_ = rt_[0] = rt_[1] = 0;
3028         return NO_ERROR;
3029     }
Run()3030     virtual long Run()
3031     {
3032 
3033         GLint p1, p2;
3034         glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS, &p1);
3035         glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTERS, &p2);
3036         if (p1 < 1 || p2 < 2)
3037         {
3038             OutputNotSupported(
3039                 "GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS or GL_MAX_FRAGMENT_ATOMIC_COUNTERS are less than required");
3040             return NOT_SUPPORTED;
3041         }
3042 
3043         // create program
3044         const char *src_vs = "#version 310 es" NL "layout(location = 0) in vec4 i_vertex;" NL "void main() {" NL
3045                              "  gl_Position = i_vertex;" NL "}";
3046         const char *src_fs = "#version 310 es" NL "layout(location = 0) out uvec4 o_color[2];" NL
3047                              "layout(binding = 0, offset = 0) uniform atomic_uint ac_counter_inc;" NL
3048                              "layout(binding = 0, offset = 4) uniform atomic_uint ac_counter_dec;" NL "void main() {" NL
3049                              "  o_color[0] = uvec4(atomicCounterIncrement(ac_counter_inc));" NL
3050                              "  o_color[1] = uvec4(atomicCounterDecrement(ac_counter_dec));" NL "}";
3051         prog_ = CreateProgram(src_vs, src_fs, true);
3052 
3053         // create atomic counter buffer
3054         glGenBuffers(1, &counter_buffer_);
3055         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_);
3056         glBufferData(GL_ATOMIC_COUNTER_BUFFER, 8, NULL, GL_DYNAMIC_COPY);
3057         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
3058 
3059         // create render targets
3060         const int s = 8;
3061         glGenTextures(2, rt_);
3062 
3063         for (int i = 0; i < 2; ++i)
3064         {
3065             glBindTexture(GL_TEXTURE_2D, rt_[i]);
3066             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3067             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3068             glTexImage2D(GL_TEXTURE_2D, 0, GL_R32UI, s, s, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, NULL);
3069             glBindTexture(GL_TEXTURE_2D, 0);
3070         }
3071 
3072         // create fbo
3073         glGenFramebuffers(1, &fbo_);
3074         glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
3075         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt_[0], 0);
3076         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, rt_[1], 0);
3077         const GLenum draw_buffers[2] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1};
3078         glDrawBuffers(2, draw_buffers);
3079         glBindFramebuffer(GL_FRAMEBUFFER, 0);
3080 
3081         // create geometry
3082         CreateQuad(&vao_, &vbo_, NULL);
3083 
3084         // init counter buffer
3085         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_);
3086         unsigned int *ptr = static_cast<unsigned int *>(
3087             glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 8, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT));
3088         *ptr++ = 0;
3089         *ptr++ = 256;
3090         glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
3091 
3092         // draw
3093         glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
3094         glViewport(0, 0, s, s);
3095         glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, counter_buffer_);
3096         glUseProgram(prog_);
3097         glBindVertexArray(vao_);
3098 
3099         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3100         glMemoryBarrier(GL_ATOMIC_COUNTER_BARRIER_BIT);
3101         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3102         glMemoryBarrier(GL_ATOMIC_COUNTER_BARRIER_BIT);
3103         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3104         glMemoryBarrier(GL_ATOMIC_COUNTER_BARRIER_BIT);
3105         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3106 
3107         // validate
3108         UVec4 data[s * s];
3109         glReadBuffer(GL_COLOR_ATTACHMENT0);
3110         glReadPixels(0, 0, s, s, GL_RGBA_INTEGER, GL_UNSIGNED_INT, data);
3111         if (!CheckCounterValues(s * s, data, s * s * 3))
3112             return ERROR;
3113 
3114         glReadBuffer(GL_COLOR_ATTACHMENT1);
3115         glReadPixels(0, 0, s, s, GL_RGBA_INTEGER, GL_UNSIGNED_INT, data);
3116         if (!CheckCounterValues(s * s, data, 0))
3117             return ERROR;
3118 
3119         if (!CheckFinalCounterValue(counter_buffer_, 0, 256))
3120             return ERROR;
3121         if (!CheckFinalCounterValue(counter_buffer_, 4, 0))
3122             return ERROR;
3123 
3124         return NO_ERROR;
3125     }
3126 
Cleanup()3127     virtual long Cleanup()
3128     {
3129         glDeleteFramebuffers(1, &fbo_);
3130         glDeleteTextures(2, rt_);
3131         glViewport(0, 0, getWindowWidth(), getWindowHeight());
3132         glDeleteBuffers(1, &counter_buffer_);
3133         glDeleteVertexArrays(1, &vao_);
3134         glDeleteBuffers(1, &vbo_);
3135         glDeleteProgram(prog_);
3136         glUseProgram(0);
3137         return NO_ERROR;
3138     }
3139 };
3140 
3141 class NegativeSSBO : public BasicUsageCS
3142 {
Title()3143     virtual std::string Title()
3144     {
3145         return NL "GLSL errors";
3146     }
Purpose()3147     virtual std::string Purpose()
3148     {
3149         return NL "Verify that atomic counters cannot be declared in the buffer block.";
3150     }
Method()3151     virtual std::string Method()
3152     {
3153         return NL "";
3154     }
PassCriteria()3155     virtual std::string PassCriteria()
3156     {
3157         return NL "";
3158     }
3159 
3160     GLuint prog_;
3161 
Setup()3162     virtual long Setup()
3163     {
3164         prog_ = 0;
3165         return NO_ERROR;
3166     }
Run()3167     virtual long Run()
3168     {
3169 
3170         const char *const glsl_cs =
3171             NL "layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;" NL
3172                "layout(binding = 0, offset = 0) uniform atomic_uint ac_counter_dec;" NL
3173                "layout(std430) buffer Output {" NL "  mediump uint data_inc[256];" NL "  mediump uint data_dec[256];" NL
3174                "  layout(binding = 0, offset = 16) uniform atomic_uint ac_counter0;" NL "} g_out;" NL "void main() {" NL
3175                "  mediump uint offset = 32u * gl_GlobalInvocationID.y + gl_GlobalInvocationID.x;" NL
3176                "  g_out.data_inc[offset] = atomicCounterIncrement(ac_counter0);" NL
3177                "  g_out.data_dec[offset] = atomicCounterDecrement(ac_counter_dec);" NL "}";
3178 
3179         prog_ = CreateComputeProgram(glsl_cs);
3180         glLinkProgram(prog_);
3181         if (CheckProgram(prog_))
3182         {
3183             m_context.getTestContext().getLog()
3184                 << tcu::TestLog::Message
3185                 << "Link should fail because atomic counters cannot be declared in the buffer block."
3186                 << tcu::TestLog::EndMessage;
3187             return ERROR;
3188         }
3189         return NO_ERROR;
3190     }
Cleanup()3191     virtual long Cleanup()
3192     {
3193         glDeleteProgram(prog_);
3194         return NO_ERROR;
3195     }
3196 };
3197 
3198 class NegativeUBO : public BasicUsageCS
3199 {
Title()3200     virtual std::string Title()
3201     {
3202         return NL "GLSL errors";
3203     }
Purpose()3204     virtual std::string Purpose()
3205     {
3206         return NL "Verify that atomic counters cannot be declared in uniform block.";
3207     }
Method()3208     virtual std::string Method()
3209     {
3210         return NL "";
3211     }
PassCriteria()3212     virtual std::string PassCriteria()
3213     {
3214         return NL "";
3215     }
3216 
3217     GLuint prog_;
3218 
Setup()3219     virtual long Setup()
3220     {
3221         prog_ = 0;
3222         return NO_ERROR;
3223     }
3224 
Run()3225     virtual long Run()
3226     {
3227         const char *const glsl_cs =
3228             NL "layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;" NL "uniform Block {" NL
3229                "  uniform atomic_uint ac_counter;" NL "};" NL "layout(std430) buffer Output {" NL
3230                "  mediump uint data_inc[256];" NL "} g_out;" NL "void main() {" NL
3231                "  mediump uint offset = 32u * gl_GlobalInvocationID.y + gl_GlobalInvocationID.x;" NL
3232                "  g_out.data_inc[offset] = atomicCounterIncrement(ac_counter);" NL "}";
3233 
3234         prog_ = CreateComputeProgram(glsl_cs);
3235         glLinkProgram(prog_);
3236         if (CheckProgram(prog_))
3237         {
3238             m_context.getTestContext().getLog()
3239                 << tcu::TestLog::Message
3240                 << "Link should fail because atomic counters cannot be declared in the uniform block."
3241                 << tcu::TestLog::EndMessage;
3242             return ERROR;
3243         }
3244         return NO_ERROR;
3245     }
3246 
Cleanup()3247     virtual long Cleanup()
3248     {
3249         glDeleteProgram(prog_);
3250         return NO_ERROR;
3251     }
3252 };
3253 
3254 class BasicUsageNoOffset : public BasicUsageCS
3255 {
Title()3256     virtual std::string Title()
3257     {
3258         return NL "Atomic Counters usage in the Compute Shader stage";
3259     }
Purpose()3260     virtual std::string Purpose()
3261     {
3262         return NL "Verify that atomic counters work as expected in the Compute Shader stage when decalred with no "
3263                   "offset qualifier." NL "In particular make sure that values returned by GLSL built-in functions" NL
3264                   "atomicCounterIncrement and atomicCounterDecrement are unique in every shader invocation." NL
3265                   "Also make sure that the final values in atomic counter buffer objects are as expected.";
3266     }
Method()3267     virtual std::string Method()
3268     {
3269         return NL "";
3270     }
PassCriteria()3271     virtual std::string PassCriteria()
3272     {
3273         return NL "";
3274     }
3275 
3276     GLuint counter_buffer_;
3277     GLuint prog_;
3278     GLuint m_buffer;
3279 
Setup()3280     virtual long Setup()
3281     {
3282         counter_buffer_ = 0;
3283         prog_           = 0;
3284         m_buffer        = 0;
3285         return NO_ERROR;
3286     }
3287 
Run()3288     virtual long Run()
3289     {
3290         // create program
3291         const char *const glsl_cs =
3292             NL "layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;" NL
3293                "layout(binding = 0) uniform atomic_uint ac_counter_inc;" NL
3294                "layout(binding = 0) uniform atomic_uint ac_counter_dec;" NL "layout(std430) buffer Output {" NL
3295                "  mediump uint data_inc[256];" NL "  mediump uint data_dec[256];" NL "} g_out;" NL "void main() {" NL
3296                "  mediump uint offset = 32u * gl_GlobalInvocationID.y + gl_GlobalInvocationID.x;" NL
3297                "  g_out.data_inc[offset] = atomicCounterIncrement(ac_counter_inc);" NL
3298                "  g_out.data_dec[offset] = atomicCounterDecrement(ac_counter_dec);" NL "}";
3299         prog_ = CreateComputeProgram(glsl_cs);
3300         glLinkProgram(prog_);
3301         if (!CheckProgram(prog_))
3302             return ERROR;
3303 
3304         // create atomic counter buffer
3305         glGenBuffers(1, &counter_buffer_);
3306         glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, counter_buffer_);
3307         glBufferData(GL_ATOMIC_COUNTER_BUFFER, 8, NULL, GL_DYNAMIC_COPY);
3308         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
3309 
3310         glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_);
3311         unsigned int *ptr = static_cast<unsigned int *>(
3312             glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 8, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT));
3313         *ptr++ = 0;
3314         *ptr++ = 256;
3315         glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
3316 
3317         glGenBuffers(1, &m_buffer);
3318         glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer);
3319         glBufferData(GL_SHADER_STORAGE_BUFFER, 512 * sizeof(GLuint), NULL, GL_DYNAMIC_DRAW);
3320         glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
3321 
3322         glUseProgram(prog_);
3323         glDispatchCompute(4, 1, 1);
3324 
3325         long error = NO_ERROR;
3326         GLuint *data;
3327         glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_buffer);
3328         glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
3329         data = static_cast<GLuint *>(
3330             glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 512 * sizeof(GLuint), GL_MAP_READ_BIT | GL_MAP_WRITE_BIT));
3331 
3332         std::sort(data, data + 512);
3333         for (int i = 0; i < 512; i += 2)
3334         {
3335             if (data[i] != data[i + 1])
3336             {
3337                 m_context.getTestContext().getLog()
3338                     << tcu::TestLog::Message << "Pair of values should be equal, got: " << data[i] << ", "
3339                     << data[i + 1] << tcu::TestLog::EndMessage;
3340                 error = ERROR;
3341             }
3342             if (i < 510 && data[i] == data[i + 2])
3343             {
3344                 m_context.getTestContext().getLog()
3345                     << tcu::TestLog::Message << "Too many same values found: " << data[i] << ", index: " << i
3346                     << tcu::TestLog::EndMessage;
3347                 error = ERROR;
3348             }
3349         }
3350 
3351         glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
3352         glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
3353         return error;
3354     }
3355 
Cleanup()3356     virtual long Cleanup()
3357     {
3358         glDeleteBuffers(1, &counter_buffer_);
3359         glDeleteBuffers(1, &m_buffer);
3360         glDeleteProgram(prog_);
3361         glUseProgram(0);
3362         return NO_ERROR;
3363     }
3364 };
3365 
3366 class NegativeUniform : public SACSubcaseBase
3367 {
Title()3368     virtual std::string Title()
3369     {
3370         return NL "GLSL errors";
3371     }
Purpose()3372     virtual std::string Purpose()
3373     {
3374         return NL "Verify that atomicCounterIncrement/atomicCounterDecrement "
3375                   "cannot be used on normal uniform.";
3376     }
Method()3377     virtual std::string Method()
3378     {
3379         return NL "";
3380     }
PassCriteria()3381     virtual std::string PassCriteria()
3382     {
3383         return NL "";
3384     }
3385 
3386     GLuint prog_;
3387 
Setup()3388     virtual long Setup()
3389     {
3390         prog_ = 0;
3391         return NO_ERROR;
3392     }
Run()3393     virtual long Run()
3394     {
3395 
3396         GLint p1, p2;
3397         glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS, &p1);
3398         glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTERS, &p2);
3399         if (p1 < 1 || p2 < 1)
3400         {
3401             OutputNotSupported(
3402                 "GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS or GL_MAX_FRAGMENT_ATOMIC_COUNTERS are less than required");
3403             return NOT_SUPPORTED;
3404         }
3405 
3406         // create program
3407         const char *glsl_vs = "#version 310 es" NL "layout(location = 0) in vec4 i_vertex;" NL "void main() {" NL
3408                               "  gl_Position = i_vertex;" NL "}";
3409 
3410         const char *glsl_fs1 =
3411             "#version 310 es" NL "layout(location = 0) out uvec4 o_color[4];" NL "uniform uint ac_counter0;" NL
3412             "void main() {" NL "  o_color[0] = uvec4(atomicCounterIncrement(ac_counter0));" NL "}";
3413 
3414         prog_ = glCreateProgram();
3415 
3416         GLuint sh = glCreateShader(GL_VERTEX_SHADER);
3417         glAttachShader(prog_, sh);
3418         glShaderSource(sh, 1, &glsl_vs, NULL);
3419         glCompileShader(sh);
3420         GLint status_comp;
3421         glGetShaderiv(sh, GL_COMPILE_STATUS, &status_comp);
3422         if (status_comp != GL_TRUE)
3423         {
3424             m_context.getTestContext().getLog()
3425                 << tcu::TestLog::Message << "Unexpected error during vertex shader compilation."
3426                 << tcu::TestLog::EndMessage;
3427             return ERROR;
3428         }
3429         glDeleteShader(sh);
3430 
3431         sh = glCreateShader(GL_FRAGMENT_SHADER);
3432         glAttachShader(prog_, sh);
3433         glShaderSource(sh, 1, &glsl_fs1, NULL);
3434         glCompileShader(sh);
3435         glGetShaderiv(sh, GL_COMPILE_STATUS, &status_comp);
3436         glDeleteShader(sh);
3437 
3438         GLint status;
3439         glLinkProgram(prog_);
3440         glGetProgramiv(prog_, GL_LINK_STATUS, &status);
3441         if (status_comp == GL_TRUE && status == GL_TRUE)
3442         {
3443             m_context.getTestContext().getLog()
3444                 << tcu::TestLog::Message << "Expected error during fragment shader compilation or linking."
3445                 << tcu::TestLog::EndMessage;
3446             return ERROR;
3447         }
3448         return NO_ERROR;
3449     }
Cleanup()3450     virtual long Cleanup()
3451     {
3452         glDeleteProgram(prog_);
3453         return NO_ERROR;
3454     }
3455 };
3456 
3457 class NegativeArray : public BasicUsageCS
3458 {
Title()3459     virtual std::string Title()
3460     {
3461         return NL "GLSL errors";
3462     }
Purpose()3463     virtual std::string Purpose()
3464     {
3465         return NL "Verify that atomicCounterIncrement/atomicCounterDecrement "
3466                   "cannot be used on array of atomic counters.";
3467     }
Method()3468     virtual std::string Method()
3469     {
3470         return NL "";
3471     }
PassCriteria()3472     virtual std::string PassCriteria()
3473     {
3474         return NL "";
3475     }
3476 
3477     GLuint prog_;
3478 
Setup()3479     virtual long Setup()
3480     {
3481         prog_ = 0;
3482         return NO_ERROR;
3483     }
Run()3484     virtual long Run()
3485     {
3486 
3487         const char *const glsl_cs =
3488             NL "layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;" NL
3489                "layout(binding = 0) uniform atomic_uint ac_counter[3];" NL "layout(std430) buffer Output {" NL
3490                "  mediump uint data_inc[256];" NL "} g_out;" NL "void main() {" NL
3491                "  mediump uint offset = 32u * gl_GlobalInvocationID.y + gl_GlobalInvocationID.x;" NL
3492                "  g_out.data_inc[offset] = atomicCounterIncrement(ac_counter);" NL "}";
3493 
3494         prog_ = CreateComputeProgram(glsl_cs);
3495         glLinkProgram(prog_);
3496         if (CheckProgram(prog_))
3497         {
3498             m_context.getTestContext().getLog()
3499                 << tcu::TestLog::Message
3500                 << "Link should fail because atomicCounterIncrement cannot be used on array of atomic counters."
3501                 << tcu::TestLog::EndMessage;
3502             return ERROR;
3503         }
3504         return NO_ERROR;
3505     }
Cleanup()3506     virtual long Cleanup()
3507     {
3508         glDeleteProgram(prog_);
3509         return NO_ERROR;
3510     }
3511 };
3512 
3513 class NegativeArithmetic : public BasicUsageCS
3514 {
Title()3515     virtual std::string Title()
3516     {
3517         return NL "GLSL errors";
3518     }
Purpose()3519     virtual std::string Purpose()
3520     {
3521         return NL "Verify that standard arithmetic operations \n"
3522                   "cannot be performed on atomic counters.";
3523     }
Method()3524     virtual std::string Method()
3525     {
3526         return NL "";
3527     }
PassCriteria()3528     virtual std::string PassCriteria()
3529     {
3530         return NL "";
3531     }
3532 
3533     GLuint prog_;
3534 
Setup()3535     virtual long Setup()
3536     {
3537         prog_ = 0;
3538         return NO_ERROR;
3539     }
Run()3540     virtual long Run()
3541     {
3542 
3543         const char *const glsl_cs =
3544             NL "layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;" NL
3545                "layout(binding = 0) uniform atomic_uint ac_counter;" NL "layout(std430) buffer Output {" NL
3546                "  mediump uint data_inc[256];" NL "} g_out;" NL "void main() {" NL
3547                "  mediump uint offset = 32u * gl_GlobalInvocationID.y + gl_GlobalInvocationID.x;" NL
3548                "  g_out.data_inc[offset] = ac_counter + 1;" NL "}";
3549 
3550         prog_ = CreateComputeProgram(glsl_cs);
3551         glLinkProgram(prog_);
3552         if (CheckProgram(prog_))
3553         {
3554             m_context.getTestContext().getLog()
3555                 << tcu::TestLog::Message
3556                 << "Link should fail because atomic counters cannot be incremented by standard arithmetic operations."
3557                 << tcu::TestLog::EndMessage;
3558             return ERROR;
3559         }
3560         return NO_ERROR;
3561     }
3562 
Cleanup()3563     virtual long Cleanup()
3564     {
3565         glDeleteProgram(prog_);
3566         return NO_ERROR;
3567     }
3568 };
3569 
3570 class NegativeUnsizedArray : public SACSubcaseBase
3571 {
Title()3572     virtual std::string Title()
3573     {
3574         return NL "GLSL errors";
3575     }
3576 
Purpose()3577     virtual std::string Purpose()
3578     {
3579         return NL "Verify that it is compile-time error to declare an unsized array of atomic_uint.";
3580     }
3581 
Method()3582     virtual std::string Method()
3583     {
3584         return NL "";
3585     }
3586 
PassCriteria()3587     virtual std::string PassCriteria()
3588     {
3589         return NL "";
3590     }
3591 
Run()3592     virtual long Run()
3593     {
3594         const char *glsl_fs1 = "#version 310 es" NL "layout(location = 0) out uvec4 o_color[4];"
3595                                "  layout(binding = 0, offset = 4) uniform atomic_uint ac_counter[];" NL
3596                                "void main() {" NL "  o_color[0] = uvec4(atomicCounterIncrement(ac_counter[0]));" NL "}";
3597 
3598         GLuint sh = glCreateShader(GL_FRAGMENT_SHADER);
3599         glShaderSource(sh, 1, &glsl_fs1, NULL);
3600         glCompileShader(sh);
3601         GLint status_comp;
3602         glGetShaderiv(sh, GL_COMPILE_STATUS, &status_comp);
3603         glDeleteShader(sh);
3604 
3605         if (status_comp == GL_TRUE)
3606         {
3607             m_context.getTestContext().getLog()
3608                 << tcu::TestLog::Message << "Expected error during fragment shader compilation."
3609                 << tcu::TestLog::EndMessage;
3610             return ERROR;
3611         }
3612 
3613         return NO_ERROR;
3614     }
3615 };
3616 
3617 class NegativeLargeOffset : public SACSubcaseBase
3618 {
Title()3619     virtual std::string Title()
3620     {
3621         return NL "GLSL errors";
3622     }
3623 
Purpose()3624     virtual std::string Purpose()
3625     {
3626         return NL "Verify that it is compile-time error to declare an atomic counter whose offset \n"
3627                   "is such that the buffer containing it would be larger than MaxAtomicCounterBufferSiz.";
3628     }
3629 
Run()3630     virtual long Run()
3631     {
3632         GLint maxSize;
3633         glGetIntegerv(GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE, &maxSize);
3634 
3635         std::ostringstream os;
3636         os << "#version 310 es" NL "layout(location = 0) out uvec4 o_color;" NL "layout(binding = 0, offset = "
3637            << maxSize
3638            << ") uniform atomic_uint ac_counter_fs;" NL "void main() {" NL
3639               "  o_color = uvec4(atomicCounterIncrement(ac_counter_fs)); " NL " }";
3640         std::string source  = os.str();
3641         const char *glsl_fs = source.c_str();
3642 
3643         GLuint sh = glCreateShader(GL_FRAGMENT_SHADER);
3644         glShaderSource(sh, 1, &glsl_fs, NULL);
3645         glCompileShader(sh);
3646         GLint status_comp;
3647         glGetShaderiv(sh, GL_COMPILE_STATUS, &status_comp);
3648         glDeleteShader(sh);
3649 
3650         if (status_comp == GL_TRUE)
3651         {
3652             m_context.getTestContext().getLog()
3653                 << tcu::TestLog::Message << "Expected error during fragment shader compilation."
3654                 << tcu::TestLog::EndMessage;
3655             return ERROR;
3656         }
3657 
3658         return NO_ERROR;
3659     }
3660 };
3661 
3662 class AdvancedManyDrawCalls2 : public SACSubcaseBase
3663 {
3664 
3665     GLuint m_acbo, m_ssbo;
3666     GLuint m_vao;
3667     GLuint m_ppo, m_vsp, m_fsp;
3668 
Setup()3669     virtual long Setup()
3670     {
3671         glGenBuffers(1, &m_acbo);
3672         glGenBuffers(1, &m_ssbo);
3673         glGenVertexArrays(1, &m_vao);
3674         glGenProgramPipelines(1, &m_ppo);
3675         m_vsp = m_fsp = 0;
3676         return NO_ERROR;
3677     }
3678 
Cleanup()3679     virtual long Cleanup()
3680     {
3681         glDeleteBuffers(1, &m_acbo);
3682         glDeleteBuffers(1, &m_ssbo);
3683         glDeleteVertexArrays(1, &m_vao);
3684         glDeleteProgramPipelines(1, &m_ppo);
3685         glDeleteProgram(m_vsp);
3686         glDeleteProgram(m_fsp);
3687         return NO_ERROR;
3688     }
3689 
Run()3690     virtual long Run()
3691     {
3692 
3693         GLint p1, p2;
3694         glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS, &p1);
3695         glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTERS, &p2);
3696         if (p1 < 1 || p2 < 1)
3697         {
3698             OutputNotSupported(
3699                 "GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS or GL_MAX_FRAGMENT_ATOMIC_COUNTERS are less than required");
3700             return NOT_SUPPORTED;
3701         }
3702 
3703         const char *const glsl_vs = "#version 310 es" NL "void main() {" NL "#ifdef GL_ES" NL
3704                                     "  gl_PointSize = 1.0f;" NL "#endif" NL "  gl_Position = vec4(0, 0, 0, 1);" NL "}";
3705         const char *const glsl_fs =
3706             "#version 310 es" NL "layout(binding = 0) uniform atomic_uint g_counter;" NL
3707             "layout(std430, binding = 0) buffer Output {" NL "  uint g_output[];" NL "};" NL "void main() {" NL
3708             "  uint c = atomicCounterIncrement(g_counter);" NL "  g_output[c] = c;" NL "}";
3709 
3710         m_vsp = glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &glsl_vs);
3711         m_fsp = glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, &glsl_fs);
3712         if (!CheckProgram(m_vsp) || !CheckProgram(m_fsp))
3713             return ERROR;
3714 
3715         glUseProgramStages(m_ppo, GL_VERTEX_SHADER_BIT, m_vsp);
3716         glUseProgramStages(m_ppo, GL_FRAGMENT_SHADER_BIT, m_fsp);
3717 
3718         glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, m_acbo);
3719         {
3720             GLuint data = 0;
3721             glBufferData(GL_ATOMIC_COUNTER_BUFFER, 4, &data, GL_DYNAMIC_COPY);
3722         }
3723 
3724         {
3725             std::vector<GLuint> data(1000, 0xffff);
3726             glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_ssbo);
3727             glBufferData(GL_SHADER_STORAGE_BUFFER, (GLsizeiptr)(data.size() * 4), &data[0], GL_DYNAMIC_READ);
3728         }
3729 
3730         // draw
3731         glViewport(0, 0, 1, 1);
3732         glBindProgramPipeline(m_ppo);
3733         glBindVertexArray(m_vao);
3734         for (int i = 0; i < 100; ++i)
3735         {
3736             glDrawArrays(GL_POINTS, 0, 1);
3737         }
3738 
3739         glViewport(0, 0, getWindowWidth(), getWindowHeight());
3740 
3741         long status = NO_ERROR;
3742 
3743         {
3744             GLuint *data;
3745 
3746             glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_acbo);
3747             glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
3748             data = static_cast<GLuint *>(glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 4, GL_MAP_READ_BIT));
3749             if (data[0] != 100)
3750             {
3751                 status = ERROR;
3752                 m_context.getTestContext().getLog() << tcu::TestLog::Message << "AC buffer content is " << data[0]
3753                                                     << ", sholud be 100." << tcu::TestLog::EndMessage;
3754             }
3755             glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
3756             glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
3757 
3758             glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_ssbo);
3759             glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
3760             data = static_cast<GLuint *>(
3761                 glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 100 * 4, GL_MAP_READ_BIT | GL_MAP_WRITE_BIT));
3762             std::sort(data, data + 100);
3763             for (GLuint i = 0; i < 100; ++i)
3764             {
3765                 if (data[i] != i)
3766                 {
3767                     status = ERROR;
3768                     m_context.getTestContext().getLog() << tcu::TestLog::Message << "data[" << i << " is " << data[i]
3769                                                         << ", sholud be " << i << tcu::TestLog::EndMessage;
3770                 }
3771             }
3772             glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
3773             glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
3774         }
3775 
3776         return status;
3777     }
3778 };
3779 
3780 class AdvancedUsageMultipleComputeDispatches : public SACSubcaseBase
3781 {
3782     GLuint m_acbo, m_ssbo;
3783     GLuint m_ppo, m_csp;
3784 
Setup()3785     virtual long Setup()
3786     {
3787         glGenBuffers(1, &m_acbo);
3788         glGenBuffers(1, &m_ssbo);
3789         glGenProgramPipelines(1, &m_ppo);
3790         m_csp = 0;
3791         return NO_ERROR;
3792     }
3793 
Cleanup()3794     virtual long Cleanup()
3795     {
3796         glDeleteBuffers(1, &m_acbo);
3797         glDeleteBuffers(1, &m_ssbo);
3798         glDeleteProgramPipelines(1, &m_ppo);
3799         glDeleteProgram(m_csp);
3800         return NO_ERROR;
3801     }
3802 
Run()3803     virtual long Run()
3804     {
3805         // create program
3806         const char *const glsl_cs =
3807             "#version 310 es" NL "layout(local_size_x = 1) in;" NL
3808             "layout(binding = 0) uniform atomic_uint g_counter;" NL "layout(std430, binding = 0) buffer Output {" NL
3809             "  mediump uint g_output[];" NL "};" NL "void main() {" NL
3810             "  mediump uint c = atomicCounterIncrement(g_counter);" NL "  g_output[c] = c;" NL "}";
3811 
3812         m_csp = glCreateShaderProgramv(GL_COMPUTE_SHADER, 1, &glsl_cs);
3813         if (!CheckProgram(m_csp))
3814             return ERROR;
3815         glUseProgramStages(m_ppo, GL_COMPUTE_SHADER_BIT, m_csp);
3816 
3817         glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, m_acbo);
3818         {
3819             GLuint data = 0;
3820             glBufferData(GL_ATOMIC_COUNTER_BUFFER, 4, &data, GL_DYNAMIC_COPY);
3821         }
3822 
3823         {
3824             std::vector<GLuint> data(1000, 0xffff);
3825             glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_ssbo);
3826             glBufferData(GL_SHADER_STORAGE_BUFFER, (GLsizeiptr)(data.size() * 4), &data[0], GL_DYNAMIC_READ);
3827         }
3828 
3829         glBindProgramPipeline(m_ppo);
3830         for (int i = 0; i < 100; ++i)
3831         {
3832             glDispatchCompute(1, 1, 1);
3833         }
3834 
3835         long status = NO_ERROR;
3836 
3837         {
3838             GLuint *data;
3839 
3840             glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_acbo);
3841             glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
3842             data = static_cast<GLuint *>(glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 4, GL_MAP_READ_BIT));
3843             if (data[0] != 100)
3844             {
3845                 status = ERROR;
3846                 m_context.getTestContext().getLog() << tcu::TestLog::Message << "AC buffer content is " << data[0]
3847                                                     << ", sholud be 100" << tcu::TestLog::EndMessage;
3848             }
3849             glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
3850             glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
3851 
3852             glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_ssbo);
3853             glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
3854             data = static_cast<GLuint *>(
3855                 glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 100 * 4, GL_MAP_READ_BIT | GL_MAP_WRITE_BIT));
3856             std::sort(data, data + 100);
3857             for (GLuint i = 0; i < 100; ++i)
3858             {
3859                 if (data[i] != i)
3860                 {
3861                     status = ERROR;
3862                     m_context.getTestContext().getLog() << tcu::TestLog::Message << "data[" << i << "] is " << data[i]
3863                                                         << ", sholud be " << i << tcu::TestLog::EndMessage;
3864                 }
3865             }
3866             glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
3867             glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
3868         }
3869 
3870         return status;
3871     }
3872 };
3873 
3874 class BasicGLSLBuiltIn : public BasicUsageCS
3875 {
3876 public:
Title()3877     virtual std::string Title()
3878     {
3879         return NL "gl_Max* Check";
3880     }
Purpose()3881     virtual std::string Purpose()
3882     {
3883         return NL "Verify that gl_Max*Counters and gl_Max*Bindings exist in glsl and their values are no lower" NL
3884                   "than minimum required by the spec and are no different from their GL_MAX_* counterparts.";
3885     }
3886 
3887     GLuint prog_;
3888     GLuint m_buffer;
3889 
Setup()3890     virtual long Setup()
3891     {
3892         prog_    = 0;
3893         m_buffer = 0;
3894         return NO_ERROR;
3895     }
3896 
Run()3897     virtual long Run()
3898     {
3899         // create program
3900         const char *const glsl_cs = NL
3901             "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;" NL "layout(std430) buffer Output {" NL
3902             "  mediump uint data;" NL "} g_out;" NL "uniform mediump int m_vac;" NL "uniform mediump int m_fac;" NL
3903             "uniform mediump int m_csac;" NL "uniform mediump int m_cac;" NL "uniform mediump int m_abuf;" NL
3904             "void main() {" NL "  mediump uint res = 1u;" NL
3905             "  if (gl_MaxVertexAtomicCounters < 0 || gl_MaxVertexAtomicCounters != m_vac)" NL "     res = res * 2u;" NL
3906             "  if (gl_MaxFragmentAtomicCounters < 0 || gl_MaxFragmentAtomicCounters != m_fac)" NL
3907             "     res = res * 3u;" NL
3908             "  if (gl_MaxComputeAtomicCounters < 8 || gl_MaxComputeAtomicCounters != m_csac)" NL
3909             "     res = res * 5u;" NL
3910             "  if (gl_MaxCombinedAtomicCounters < 8 || gl_MaxCombinedAtomicCounters != m_cac)" NL
3911             "     res = res * 7u;" NL
3912             "  if (gl_MaxAtomicCounterBindings < 1 || gl_MaxAtomicCounterBindings != m_abuf)" NL
3913             "     res = res * 11u;" NL "  g_out.data = res;" NL "}";
3914 
3915         prog_ = CreateComputeProgram(glsl_cs);
3916         glLinkProgram(prog_);
3917         if (!CheckProgram(prog_))
3918             return ERROR;
3919         glUseProgram(prog_);
3920 
3921         int m_vac;
3922         int m_fac;
3923         int m_csac;
3924         int m_cac;
3925         int m_abuf;
3926         glGetIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTERS, &m_vac);
3927         glUniform1i(glGetUniformLocation(prog_, "m_vac"), m_vac);
3928         glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTERS, &m_fac);
3929         glUniform1i(glGetUniformLocation(prog_, "m_fac"), m_fac);
3930         glGetIntegerv(GL_MAX_COMPUTE_ATOMIC_COUNTERS, &m_csac);
3931         glUniform1i(glGetUniformLocation(prog_, "m_csac"), m_csac);
3932         glGetIntegerv(GL_MAX_COMBINED_ATOMIC_COUNTERS, &m_cac);
3933         glUniform1i(glGetUniformLocation(prog_, "m_cac"), m_cac);
3934         glGetIntegerv(GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS, &m_abuf);
3935         glUniform1i(glGetUniformLocation(prog_, "m_abuf"), m_abuf);
3936 
3937         glGenBuffers(1, &m_buffer);
3938         glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer);
3939         glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLuint), NULL, GL_DYNAMIC_DRAW);
3940         glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
3941 
3942         glDispatchCompute(1, 1, 1);
3943 
3944         long error = NO_ERROR;
3945         GLuint *data;
3946         glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_buffer);
3947         glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
3948         data = static_cast<GLuint *>(glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(GLuint), GL_MAP_READ_BIT));
3949         if (data[0] != 1u)
3950         {
3951             m_context.getTestContext().getLog()
3952                 << tcu::TestLog::Message << "Expected 1, got: " << data[0] << tcu::TestLog::EndMessage;
3953             error = ERROR;
3954         }
3955         glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
3956         glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
3957 
3958         return error;
3959     }
3960 
Cleanup()3961     virtual long Cleanup()
3962     {
3963         glDeleteBuffers(1, &m_buffer);
3964         glDeleteProgram(prog_);
3965         glUseProgram(0);
3966         return NO_ERROR;
3967     }
3968 };
3969 
ShaderAtomicCountersTests(glcts::Context & context)3970 ShaderAtomicCountersTests::ShaderAtomicCountersTests(glcts::Context &context)
3971     : TestCaseGroup(context, "shader_atomic_counters", "")
3972 {
3973 }
3974 
~ShaderAtomicCountersTests(void)3975 ShaderAtomicCountersTests::~ShaderAtomicCountersTests(void)
3976 {
3977 }
3978 
init()3979 void ShaderAtomicCountersTests::init()
3980 {
3981     using namespace glcts;
3982     addChild(new TestSubcase(m_context, "basic-buffer-operations", TestSubcase::Create<BasicBufferOperations>));
3983     addChild(new TestSubcase(m_context, "basic-buffer-state", TestSubcase::Create<BasicBufferState>));
3984     addChild(new TestSubcase(m_context, "basic-buffer-bind", TestSubcase::Create<BasicBufferBind>));
3985     addChild(new TestSubcase(m_context, "basic-program-max", TestSubcase::Create<BasicProgramMax>));
3986     addChild(new TestSubcase(m_context, "basic-program-query", TestSubcase::Create<BasicProgramQuery>));
3987     addChild(new TestSubcase(m_context, "basic-usage-simple", TestSubcase::Create<BasicUsageSimple>));
3988     addChild(new TestSubcase(m_context, "basic-usage-no-offset", TestSubcase::Create<BasicUsageNoOffset>));
3989     addChild(new TestSubcase(m_context, "basic-usage-fs", TestSubcase::Create<BasicUsageFS>));
3990     addChild(new TestSubcase(m_context, "basic-usage-vs", TestSubcase::Create<BasicUsageVS>));
3991     addChild(new TestSubcase(m_context, "basic-usage-cs", TestSubcase::Create<BasicUsageCS>));
3992     addChild(new TestSubcase(m_context, "basic-glsl-built-in", TestSubcase::Create<BasicGLSLBuiltIn>));
3993     addChild(new TestSubcase(m_context, "advanced-usage-multi-stage", TestSubcase::Create<AdvancedUsageMultiStage>));
3994     addChild(new TestSubcase(m_context, "advanced-usage-draw-update-draw",
3995                              TestSubcase::Create<AdvancedUsageDrawUpdateDraw>));
3996     addChild(
3997         new TestSubcase(m_context, "advanced-usage-many-counters", TestSubcase::Create<AdvancedUsageManyCounters>));
3998     addChild(new TestSubcase(m_context, "advanced-usage-multidim-array-small",
3999                              TestSubcase::Create<AdvancedUsageMultiDimArraySmall>));
4000     addChild(new TestSubcase(m_context, "advanced-usage-multidim-array-medium",
4001                              TestSubcase::Create<AdvancedUsageMultiDimArrayMedium>));
4002     addChild(new TestSubcase(m_context, "advanced-usage-multidim-array-large",
4003                              TestSubcase::Create<AdvancedUsageMultiDimArrayLarge>));
4004     addChild(
4005         new TestSubcase(m_context, "advanced-usage-switch-programs", TestSubcase::Create<AdvancedUsageSwitchPrograms>));
4006     addChild(new TestSubcase(m_context, "advanced-usage-ubo", TestSubcase::Create<AdvancedUsageUBO>));
4007     addChild(new TestSubcase(m_context, "advanced-usage-many-draw-calls", TestSubcase::Create<AdvancedManyDrawCalls>));
4008     addChild(
4009         new TestSubcase(m_context, "advanced-usage-many-draw-calls2", TestSubcase::Create<AdvancedManyDrawCalls2>));
4010     addChild(new TestSubcase(m_context, "advanced-usage-many-dispatches",
4011                              TestSubcase::Create<AdvancedUsageMultipleComputeDispatches>));
4012     addChild(new TestSubcase(m_context, "negative-api", TestSubcase::Create<NegativeAPI>));
4013     addChild(new TestSubcase(m_context, "negative-glsl", TestSubcase::Create<NegativeGLSL>));
4014     addChild(new TestSubcase(m_context, "negative-ssbo", TestSubcase::Create<NegativeSSBO>));
4015     addChild(new TestSubcase(m_context, "negative-ubo", TestSubcase::Create<NegativeUBO>));
4016     addChild(new TestSubcase(m_context, "negative-uniform", TestSubcase::Create<NegativeUniform>));
4017     addChild(new TestSubcase(m_context, "negative-array", TestSubcase::Create<NegativeArray>));
4018     addChild(new TestSubcase(m_context, "negative-arithmetic", TestSubcase::Create<NegativeArithmetic>));
4019     addChild(new TestSubcase(m_context, "negative-large-offset", TestSubcase::Create<NegativeLargeOffset>));
4020     addChild(new TestSubcase(m_context, "negative-unsized-array", TestSubcase::Create<NegativeUnsizedArray>));
4021 }
4022 } // namespace glcts
4023