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