1 /*-------------------------------------------------------------------------
2 * OpenGL Conformance Test Suite
3 * -----------------------------
5 * Copyright (c) 2014-2016 The Khronos Group Inc.
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
22 */ /*-------------------------------------------------------------------*/
24 #include "es31cShaderAtomicCountersTests.hpp"
25 #include "gluContextInfo.hpp"
26 #include "gluPixelTransfer.hpp"
27 #include "glwEnums.hpp"
28 #include "glwFunctions.hpp"
29 #include "tcuImageCompare.hpp"
30 #include "tcuRenderTarget.hpp"
31 #include "tcuSurface.hpp"
32 #include "tcuVector.hpp"
46 static tcu::TestLog* currentLog;
48 void setOutput(tcu::TestLog& log)
53 void Output(const char* format, ...)
56 va_start(args, format);
58 const int MAX_OUTPUT_STRING_SIZE = 40000;
59 static char temp[MAX_OUTPUT_STRING_SIZE];
61 vsnprintf(temp, MAX_OUTPUT_STRING_SIZE - 1, format, args);
62 temp[MAX_OUTPUT_STRING_SIZE - 1] = '\0';
64 char* logLine = strtok(temp, "\n");
65 while (logLine != NULL)
67 currentLog->writeMessage(logLine);
68 logLine = strtok(NULL, "\n");
73 class SACSubcaseBase : public glcts::SubcaseBase
76 virtual std::string Title()
80 virtual std::string Purpose()
84 virtual std::string Method()
88 virtual std::string PassCriteria()
93 virtual ~SACSubcaseBase()
97 bool CheckProgram(GLuint program)
100 glGetProgramiv(program, GL_LINK_STATUS, &status);
102 glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length);
105 std::vector<GLchar> log(length);
106 glGetProgramInfoLog(program, length, NULL, &log[0]);
107 Output("%s\n", &log[0]);
109 return status == GL_TRUE;
114 const tcu::RenderTarget& renderTarget = m_context.getRenderContext().getRenderTarget();
115 return renderTarget.getWidth();
118 int getWindowHeight()
120 const tcu::RenderTarget& renderTarget = m_context.getRenderContext().getRenderTarget();
121 return renderTarget.getHeight();
124 long ValidateReadBuffer(const Vec4& expected)
126 const tcu::RenderTarget& renderTarget = m_context.getRenderContext().getRenderTarget();
127 int viewportW = renderTarget.getWidth();
128 int viewportH = renderTarget.getHeight();
129 tcu::Surface renderedFrame(viewportW, viewportH);
130 tcu::Surface referenceFrame(viewportW, viewportH);
132 glu::readPixels(m_context.getRenderContext(), 0, 0, renderedFrame.getAccess());
134 for (int y = 0; y < viewportH; ++y)
136 for (int x = 0; x < viewportW; ++x)
138 referenceFrame.setPixel(
139 x, y, tcu::RGBA(static_cast<int>(expected[0] * 255), static_cast<int>(expected[1] * 255),
140 static_cast<int>(expected[2] * 255), static_cast<int>(expected[3] * 255)));
143 tcu::TestLog& log = m_context.getTestContext().getLog();
144 bool isOk = tcu::fuzzyCompare(log, "Result", "Image comparison result", referenceFrame, renderedFrame, 0.05f,
145 tcu::COMPARE_LOG_RESULT);
146 return (isOk ? NO_ERROR : ERROR);
149 void LinkProgram(GLuint program)
151 glLinkProgram(program);
154 glGetProgramInfoLog(program, sizeof(log), &length, log);
157 Output("Program Info Log:\n%s\n", log);
161 GLuint CreateProgram(const char* src_vs, const char* src_fs, bool link)
163 const GLuint p = glCreateProgram();
167 GLuint sh = glCreateShader(GL_VERTEX_SHADER);
168 glAttachShader(p, sh);
170 glShaderSource(sh, 1, &src_vs, NULL);
175 GLuint sh = glCreateShader(GL_FRAGMENT_SHADER);
176 glAttachShader(p, sh);
178 glShaderSource(sh, 1, &src_fs, NULL);
188 GLuint CreateShaderProgram(GLenum type, GLsizei count, const GLchar** strings)
190 GLuint program = glCreateShaderProgramv(type, count, strings);
191 GLint status = GL_TRUE;
192 glGetProgramiv(program, GL_LINK_STATUS, &status);
193 if (status == GL_FALSE)
197 glGetProgramInfoLog(program, sizeof(log), &length, log);
200 Output("Program Info Log:\n%s\n", log);
206 void CreateQuad(GLuint* vao, GLuint* vbo, GLuint* ebo)
210 // interleaved data (vertex, color0 (green), color1 (blue), color2 (red))
212 -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,
213 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,
214 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,
216 glGenBuffers(1, vbo);
217 glBindBuffer(GL_ARRAY_BUFFER, *vbo);
218 glBufferData(GL_ARRAY_BUFFER, sizeof(v), v, GL_STATIC_DRAW);
219 glBindBuffer(GL_ARRAY_BUFFER, 0);
223 std::vector<GLushort> index_data(4);
224 for (int i = 0; i < 4; ++i)
226 index_data[i] = static_cast<GLushort>(i);
228 glGenBuffers(1, ebo);
229 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, *ebo);
230 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort) * 4, &index_data[0], GL_STATIC_DRAW);
231 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
234 glGenVertexArrays(1, vao);
235 glBindVertexArray(*vao);
236 glBindBuffer(GL_ARRAY_BUFFER, *vbo);
237 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 11, 0);
238 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 11, reinterpret_cast<void*>(sizeof(float) * 2));
239 glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 11, reinterpret_cast<void*>(sizeof(float) * 5));
240 glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 11, reinterpret_cast<void*>(sizeof(float) * 8));
241 glBindBuffer(GL_ARRAY_BUFFER, 0);
242 glEnableVertexAttribArray(0);
243 glEnableVertexAttribArray(1);
244 glEnableVertexAttribArray(2);
245 glEnableVertexAttribArray(3);
248 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, *ebo);
250 glBindVertexArray(0);
253 void CreateTriangle(GLuint* vao, GLuint* vbo, GLuint* ebo)
257 // interleaved data (vertex, color0 (green), color1 (blue), color2 (red))
259 -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,
260 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,
262 glGenBuffers(1, vbo);
263 glBindBuffer(GL_ARRAY_BUFFER, *vbo);
264 glBufferData(GL_ARRAY_BUFFER, sizeof(v), v, GL_STATIC_DRAW);
265 glBindBuffer(GL_ARRAY_BUFFER, 0);
269 std::vector<GLushort> index_data(3);
270 for (int i = 0; i < 3; ++i)
272 index_data[i] = static_cast<GLushort>(i);
274 glGenBuffers(1, ebo);
275 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, *ebo);
276 glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort) * 4, &index_data[0], GL_STATIC_DRAW);
277 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
280 glGenVertexArrays(1, vao);
281 glBindVertexArray(*vao);
282 glBindBuffer(GL_ARRAY_BUFFER, *vbo);
283 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 11, 0);
284 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 11, reinterpret_cast<void*>(sizeof(float) * 2));
285 glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 11, reinterpret_cast<void*>(sizeof(float) * 5));
286 glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 11, reinterpret_cast<void*>(sizeof(float) * 8));
287 glBindBuffer(GL_ARRAY_BUFFER, 0);
288 glEnableVertexAttribArray(0);
289 glEnableVertexAttribArray(1);
290 glEnableVertexAttribArray(2);
291 glEnableVertexAttribArray(3);
294 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, *ebo);
296 glBindVertexArray(0);
299 const char* GLenumToString(GLenum e)
303 case GL_ATOMIC_COUNTER_BUFFER_BINDING:
304 return "GL_ATOMIC_COUNTER_BUFFER_BINDING";
305 case GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS:
306 return "GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS";
307 case GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS:
308 return "GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS";
309 case GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS:
310 return "GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS";
311 case GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS:
312 return "GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS";
314 case GL_MAX_VERTEX_ATOMIC_COUNTERS:
315 return "GL_MAX_VERTEX_ATOMIC_COUNTERS";
316 case GL_MAX_COMPUTE_ATOMIC_COUNTERS:
317 return "GL_MAX_GEOMETRY_ATOMIC_COUNTERS";
318 case GL_MAX_FRAGMENT_ATOMIC_COUNTERS:
319 return "GL_MAX_FRAGMENT_ATOMIC_COUNTERS";
320 case GL_MAX_COMBINED_ATOMIC_COUNTERS:
321 return "GL_MAX_COMBINED_ATOMIC_COUNTERS";
323 case GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE:
324 return "GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE";
325 case GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS:
326 return "GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS";
335 bool CheckMaxValue(GLenum e, GLint expected)
340 glGetIntegerv(e, &i);
341 Output("%s = %d\n", GLenumToString(e), i);
345 Output("%s state is incorrect (GetIntegerv, is: %d, expected: %d)\n", GLenumToString(e), i, expected);
349 glGetInteger64v(e, &i64);
350 if (i64 < static_cast<GLint64>(expected))
353 Output("%s state is incorrect (GetInteger64v, is: %d, expected: %d)\n", GLenumToString(e),
354 static_cast<GLint>(i64), expected);
359 if (f < static_cast<GLfloat>(expected))
362 Output("%s state is incorrect (GetFloatv, is: %f, expected: %d)\n", GLenumToString(e), f, expected);
366 glGetBooleanv(e, &b);
371 bool CheckGetCommands(GLenum e, GLint expected)
376 glGetIntegerv(e, &i);
380 Output("%s state is incorrect (GetIntegerv, is: %d, expected: %d)\n", GLenumToString(e), i, expected);
384 glGetInteger64v(e, &i64);
385 if (i64 != static_cast<GLint64>(expected))
388 Output("%s state is incorrect (GetInteger64v, is: %d, expected: %d)\n", GLenumToString(e),
389 static_cast<GLint>(i64), expected);
394 if (f != static_cast<GLfloat>(expected))
397 Output("%s state is incorrect (GetFloatv, is: %f, expected: %d)\n", GLenumToString(e), f, expected);
401 glGetBooleanv(e, &b);
402 if (b != (expected ? GL_TRUE : GL_FALSE))
405 Output("%s state is incorrect (GetBooleanv, is: %d, expected: %d)\n", GLenumToString(e), b,
406 expected ? GL_TRUE : GL_FALSE);
412 bool CheckBufferBindingState(GLuint index, GLint binding, GLint64 start, GLint64 size)
417 glGetIntegeri_v(GL_ATOMIC_COUNTER_BUFFER_BINDING, index, &i);
421 Output("GL_ATOMIC_COUNTER_BUFFER_BINDING state is incorrect (GetIntegeri_v, is: %d, expected: %d, index: "
427 glGetInteger64i_v(GL_ATOMIC_COUNTER_BUFFER_BINDING, index, &i64);
428 if (i64 != static_cast<GLint64>(binding))
431 Output("GL_ATOMIC_COUNTER_BUFFER_BINDING state is incorrect (GetInteger64i_v, is: %d, expected: %d, index: "
433 static_cast<GLint>(i64), binding, index);
436 glGetInteger64i_v(GL_ATOMIC_COUNTER_BUFFER_START, index, &i64);
440 Output("GL_ATOMIC_COUNTER_BUFFER_START state is incorrect (GetInteger64i_v, is: %d, expected: %d, index: "
442 static_cast<GLint>(i64), static_cast<GLint>(start), index);
444 glGetInteger64i_v(GL_ATOMIC_COUNTER_BUFFER_SIZE, index, &i64);
445 if (i64 != size && i64 != 0)
448 Output("GL_ATOMIC_COUNTER_BUFFER_SIZE state is incorrect (GetInteger64i_v, is: %d, expected: (%d or 0), "
450 static_cast<GLint>(i64), static_cast<GLint>(size), index);
456 bool CheckUniform(GLuint prog, const GLchar* uniform_name, GLuint uniform_index, GLint uniform_type,
457 GLint uniform_size, GLint uniform_offset, GLint uniform_array_stride)
462 glGetUniformIndices(prog, 1, &uniform_name, &index);
463 if (index != uniform_index)
465 Output("Uniform: %s: Bad index returned by glGetUniformIndices.\n", uniform_name);
469 const GLsizei uniform_length = static_cast<GLsizei>(strlen(uniform_name));
476 glGetProgramResourceName(prog, GL_UNIFORM, uniform_index, sizeof(name), &length, name);
477 if (length != uniform_length)
479 Output("Uniform: %s: Length is %d should be %d.\n", uniform_name, length, uniform_length);
482 glGetActiveUniform(prog, uniform_index, sizeof(name), &length, &size, &type, name);
483 if (strcmp(name, uniform_name))
485 Output("Uniform: %s: Bad name returned by glGetActiveUniform.\n", uniform_name);
488 if (length != uniform_length)
490 Output("Uniform: %s: Length is %d should be %d.\n", uniform_name, length, uniform_length);
493 if (size != uniform_size)
495 Output("Uniform: %s: Size is %d should be %d.\n", uniform_name, size, uniform_size);
498 if (type != static_cast<GLenum>(uniform_type))
500 Output("Uniform: %s: Type is %d should be %d.\n", uniform_name, type, uniform_type);
505 glGetActiveUniformsiv(prog, 1, &uniform_index, GL_UNIFORM_TYPE, ¶m);
506 if (param != uniform_type)
508 Output("Uniform: %s: Type is %d should be %d.\n", uniform_name, param, uniform_type);
511 glGetActiveUniformsiv(prog, 1, &uniform_index, GL_UNIFORM_SIZE, ¶m);
512 if (param != uniform_size)
514 Output("Uniform: %s: GL_UNIFORM_SIZE is %d should be %d.\n", uniform_name, param, uniform_size);
517 glGetActiveUniformsiv(prog, 1, &uniform_index, GL_UNIFORM_NAME_LENGTH, ¶m);
518 if (param != (uniform_length + 1))
520 Output("Uniform: %s: GL_UNIFORM_NAME_LENGTH is %d should be %d.\n", uniform_name, param,
524 glGetActiveUniformsiv(prog, 1, &uniform_index, GL_UNIFORM_BLOCK_INDEX, ¶m);
527 Output("Uniform: %s: GL_UNIFORM_BLOCK_INDEX should be -1.\n", uniform_name);
530 glGetActiveUniformsiv(prog, 1, &uniform_index, GL_UNIFORM_OFFSET, ¶m);
531 if (param != uniform_offset)
533 Output("Uniform: %s: GL_UNIFORM_OFFSET is %d should be %d.\n", uniform_name, param, uniform_offset);
536 glGetActiveUniformsiv(prog, 1, &uniform_index, GL_UNIFORM_ARRAY_STRIDE, ¶m);
537 if (param != uniform_array_stride)
539 Output("Uniform: %s: GL_UNIFORM_ARRAY_STRIDE is %d should be %d.\n", uniform_name, param,
540 uniform_array_stride);
543 glGetActiveUniformsiv(prog, 1, &uniform_index, GL_UNIFORM_MATRIX_STRIDE, ¶m);
546 Output("Uniform: %s: GL_UNIFORM_MATRIX_STRIDE should be 0 is %d.\n", uniform_name, param);
549 glGetActiveUniformsiv(prog, 1, &uniform_index, GL_UNIFORM_IS_ROW_MAJOR, ¶m);
552 Output("Uniform: %s: GL_UNIFORM_IS_ROW_MAJOR should be 0 is %d.\n", uniform_name, param);
559 bool CheckCounterValues(GLuint size, GLuint* values, GLuint min_value)
561 std::sort(values, values + size);
562 for (GLuint i = 0; i < size; ++i)
564 Output("%u\n", values[i]);
565 if (values[i] != i + min_value)
567 Output("Counter value is %u should be %u.\n", values[i], i + min_value);
574 bool CheckCounterValues(GLuint size, UVec4* data, GLuint min_value)
576 std::vector<GLuint> values(size);
577 for (GLuint j = 0; j < size; ++j)
579 values[j] = data[j].x();
581 std::sort(values.begin(), values.end());
582 for (GLuint i = 0; i < size; ++i)
584 Output("%u\n", values[i]);
585 if (values[i] != i + min_value)
587 Output("Counter value is %u should be %u.\n", values[i], i + min_value);
594 bool CheckFinalCounterValue(GLuint buffer, GLintptr offset, GLuint expected_value)
596 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, buffer);
597 GLuint* value = static_cast<GLuint*>(glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, offset, 4, GL_MAP_READ_BIT));
598 if (value[0] != expected_value)
600 Output("Counter value is %u should be %u.\n", value, expected_value);
601 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
602 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
605 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
606 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
611 class Buffer : public glcts::GLWrapper
616 , usage_(GL_STATIC_DRAW)
617 , access_(GL_WRITE_ONLY)
624 glGenBuffers(1, &name_);
625 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, name_);
626 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
630 glDeleteBuffers(1, &name_);
641 glGetBufferParameteri64v(GL_ATOMIC_COUNTER_BUFFER, GL_BUFFER_SIZE, &i64);
644 Output("BUFFER_SIZE is %d should be %d.\n", static_cast<GLint>(i64), static_cast<GLint>(size_));
647 glGetBufferParameteriv(GL_ATOMIC_COUNTER_BUFFER, GL_BUFFER_USAGE, &i);
648 if (i != static_cast<GLint>(usage_))
650 Output("BUFFER_USAGE is %d should be %d.\n", i, usage_);
653 if (this->m_context.getContextInfo().isExtensionSupported("GL_OES_mapbuffer"))
655 glGetBufferParameteriv(GL_ATOMIC_COUNTER_BUFFER, GL_BUFFER_ACCESS, &i);
656 if (i != static_cast<GLint>(access_))
658 Output("BUFFER_ACCESS is %d should be %d.\n", i, access_);
664 Output("GL_OES_mapbuffer not supported, skipping GL_BUFFER_ACCESS enum");
666 glGetBufferParameteriv(GL_ATOMIC_COUNTER_BUFFER, GL_BUFFER_ACCESS_FLAGS, &i);
667 if (i != access_flags_)
669 Output("BUFFER_ACCESS_FLAGS is %d should be %d.\n", i, access_flags_);
672 glGetBufferParameteriv(GL_ATOMIC_COUNTER_BUFFER, GL_BUFFER_MAPPED, &i);
675 Output("BUFFER_MAPPED is %d should be %d.\n", i, mapped_);
678 glGetBufferParameteri64v(GL_ATOMIC_COUNTER_BUFFER, GL_BUFFER_MAP_OFFSET, &i64);
679 if (i64 != map_offset_)
681 Output("BUFFER_MAP_OFFSET is %d should be %d.\n", static_cast<GLint>(i64), static_cast<GLint>(map_offset_));
684 glGetBufferParameteri64v(GL_ATOMIC_COUNTER_BUFFER, GL_BUFFER_MAP_LENGTH, &i64);
685 if (i64 != map_length_)
687 Output("BUFFER_MAP_LENGTH is %d should be %d.\n", static_cast<GLint>(i64), static_cast<GLint>(map_length_));
691 glGetBufferPointerv(GL_ATOMIC_COUNTER_BUFFER, GL_BUFFER_MAP_POINTER, &ptr);
692 if (ptr != map_pointer_)
694 Output("BUFFER_MAP_POINTER is %p should be %p.\n", ptr, map_pointer_);
699 void Data(GLsizeiptr size, const void* data, GLenum usage)
703 glBufferData(GL_ATOMIC_COUNTER_BUFFER, size, data, usage);
705 void* MapRange(GLintptr offset, GLsizeiptr length, GLbitfield access)
707 assert(mapped_ == GL_FALSE);
709 map_pointer_ = glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, offset, length, access);
712 map_offset_ = offset;
713 map_length_ = length;
714 access_flags_ = access;
715 if (access & GL_MAP_READ_BIT)
716 access_ = GL_READ_ONLY;
717 else if (access & GL_MAP_WRITE_BIT)
718 access_ = GL_WRITE_ONLY;
725 assert(mapped_ == GL_TRUE);
727 if (glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER))
733 access_ = GL_WRITE_ONLY;
753 class BasicUsageCS : public SACSubcaseBase
756 virtual std::string Title()
758 return NL "Atomic Counters usage in the Compute Shader stage";
760 virtual std::string Purpose()
762 return NL "Verify that atomic counters work as expected in the Compute Shader stage." NL
763 "In particular make sure that values returned by GLSL built-in functions" NL
764 "atomicCounterIncrement and atomicCounterDecrement are unique in every shader invocation." NL
765 "Also make sure that the final values in atomic counter buffer objects are as expected.";
767 virtual std::string Method()
771 virtual std::string PassCriteria()
776 GLuint counter_buffer_;
788 GLuint CreateComputeProgram(const std::string& cs)
790 const GLuint p = glCreateProgram();
792 const char* const kGLSLVer = "#version 310 es\n";
796 const GLuint sh = glCreateShader(GL_COMPUTE_SHADER);
797 glAttachShader(p, sh);
799 const char* const src[2] = { kGLSLVer, cs.c_str() };
800 glShaderSource(sh, 2, src, NULL);
807 bool CheckProgram(GLuint program, bool* compile_error = NULL)
809 GLint compile_status = GL_TRUE;
811 glGetProgramiv(program, GL_LINK_STATUS, &status);
813 if (status == GL_FALSE)
815 GLint attached_shaders;
816 glGetProgramiv(program, GL_ATTACHED_SHADERS, &attached_shaders);
818 if (attached_shaders > 0)
820 std::vector<GLuint> shaders(attached_shaders);
821 glGetAttachedShaders(program, attached_shaders, NULL, &shaders[0]);
823 for (GLint i = 0; i < attached_shaders; ++i)
826 glGetShaderiv(shaders[i], GL_SHADER_TYPE, reinterpret_cast<GLint*>(&type));
829 case GL_VERTEX_SHADER:
830 Output("*** Vertex Shader ***\n");
832 case GL_TESS_CONTROL_SHADER:
833 Output("*** Tessellation Control Shader ***\n");
835 case GL_TESS_EVALUATION_SHADER:
836 Output("*** Tessellation Evaluation Shader ***\n");
838 case GL_GEOMETRY_SHADER:
839 Output("*** Geometry Shader ***\n");
841 case GL_FRAGMENT_SHADER:
842 Output("*** Fragment Shader ***\n");
844 case GL_COMPUTE_SHADER:
845 Output("*** Compute Shader ***\n");
848 Output("*** Unknown Shader ***\n");
853 glGetShaderiv(shaders[i], GL_COMPILE_STATUS, &res);
855 compile_status = res;
859 glGetShaderiv(shaders[i], GL_SHADER_SOURCE_LENGTH, &length);
862 std::vector<GLchar> source(length);
863 glGetShaderSource(shaders[i], length, NULL, &source[0]);
864 Output("%s\n", &source[0]);
868 glGetShaderiv(shaders[i], GL_INFO_LOG_LENGTH, &length);
871 std::vector<GLchar> log(length);
872 glGetShaderInfoLog(shaders[i], length, NULL, &log[0]);
873 Output("%s\n", &log[0]);
880 glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length);
883 std::vector<GLchar> log(length);
884 glGetProgramInfoLog(program, length, NULL, &log[0]);
885 Output("%s\n", &log[0]);
890 *compile_error = (compile_status == GL_TRUE ? false : true);
891 if (compile_status != GL_TRUE)
893 return status == GL_TRUE ? true : false;
899 const char* const glsl_cs = NL
900 "layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;" NL
901 "layout(binding = 0, offset = 0) uniform atomic_uint ac_counter_inc;" NL
902 "layout(binding = 0, offset = 4) uniform atomic_uint ac_counter_dec;" NL "layout(std430) buffer Output {" NL
903 " mediump uint data_inc[256];" NL " mediump uint data_dec[256];" NL "} g_out;" NL "void main() {" NL
904 " mediump uint offset = 32u * gl_GlobalInvocationID.y + gl_GlobalInvocationID.x;" NL
905 " g_out.data_inc[offset] = atomicCounterIncrement(ac_counter_inc);" NL
906 " g_out.data_dec[offset] = atomicCounterDecrement(ac_counter_dec);" NL "}";
907 prog_ = CreateComputeProgram(glsl_cs);
908 glLinkProgram(prog_);
909 if (!CheckProgram(prog_))
912 // create atomic counter buffer
913 glGenBuffers(1, &counter_buffer_);
914 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, counter_buffer_);
915 glBufferData(GL_ATOMIC_COUNTER_BUFFER, 8, NULL, GL_DYNAMIC_COPY);
916 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
918 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_);
919 unsigned int* ptr = static_cast<unsigned int*>(
920 glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 8, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT));
923 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
925 glGenBuffers(1, &m_buffer);
926 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer);
927 glBufferData(GL_SHADER_STORAGE_BUFFER, 512 * sizeof(GLuint), NULL, GL_DYNAMIC_DRAW);
928 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
931 glDispatchCompute(4, 1, 1);
933 long error = NO_ERROR;
935 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_buffer);
936 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
937 data = static_cast<GLuint*>(
938 glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 512 * sizeof(GLuint), GL_MAP_READ_BIT | GL_MAP_WRITE_BIT));
940 std::sort(data, data + 512);
941 for (int i = 0; i < 512; i += 2)
943 if (data[i] != data[i + 1])
945 Output("Pair of values should be equal, got: %d, %d\n", data[i], data[i + 1]);
948 if (i < 510 && data[i] == data[i + 2])
950 Output("Too many same values found: %d, index: %d\n", data[i], i);
955 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
956 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
960 virtual long Cleanup()
962 glDeleteBuffers(1, &counter_buffer_);
963 glDeleteBuffers(1, &m_buffer);
964 glDeleteProgram(prog_);
970 class BasicBufferOperations : public SACSubcaseBase
972 virtual std::string Title()
974 return NL "Atomic Counter Buffer - basic operations";
976 virtual std::string Purpose()
979 "Verify that basic buffer operations work as expected with new buffer target." NL
980 "Tested commands: BindBuffer, BufferData, BufferSubData, MapBuffer, MapBufferRange, UnmapBuffer and" NL
983 virtual std::string Method()
987 virtual std::string PassCriteria()
1001 glGenBuffers(1, &buffer_);
1002 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, buffer_);
1003 glBufferData(GL_ATOMIC_COUNTER_BUFFER, 8 * 4, NULL, GL_STATIC_DRAW);
1004 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
1006 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, buffer_);
1007 GLuint* ptr = static_cast<GLuint*>(glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 8 * 4, GL_MAP_WRITE_BIT));
1012 for (GLuint i = 0; i < 8; ++i)
1014 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
1015 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
1017 long res = NO_ERROR;
1019 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, buffer_);
1020 data = static_cast<GLuint*>(glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 32, GL_MAP_READ_BIT));
1025 for (GLuint i = 0; i < 8; ++i)
1029 Output("data[%u] is: %u should be: %u\n", i, data[i], i);
1033 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
1034 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
1035 if (res != NO_ERROR)
1038 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, buffer_);
1039 ptr = static_cast<GLuint*>(glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 32, GL_MAP_WRITE_BIT));
1044 for (GLuint i = 0; i < 8; ++i)
1046 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
1047 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
1049 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, buffer_);
1050 data = static_cast<GLuint*>(glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 32, GL_MAP_READ_BIT));
1055 for (GLuint i = 0; i < 8; ++i)
1057 if (data[i] != i * 2)
1059 Output("data[%u] is: %u should be: %u\n", i, data[i], i * 2);
1063 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
1064 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
1067 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, buffer_);
1068 for (GLuint i = 0; i < 8; ++i)
1070 glBufferSubData(GL_ATOMIC_COUNTER_BUFFER, 0, 32, data2);
1071 for (GLuint i = 0; i < 8; ++i)
1073 data = static_cast<GLuint*>(glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 32, GL_MAP_READ_BIT));
1074 for (GLuint i = 0; i < 8; ++i)
1076 if (data[i] != i * 3)
1078 Output("data[%u] is: %u should be: %u\n", i, data[i], i * 3);
1082 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
1083 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
1087 virtual long Cleanup()
1089 glDeleteBuffers(1, &buffer_);
1094 class BasicBufferState : public SACSubcaseBase
1096 virtual std::string Title()
1098 return NL "Atomic Counter Buffer - state";
1100 virtual std::string Purpose()
1102 return NL "Verify that setting and getting buffer state works as expected for new buffer target.";
1104 virtual std::string Method()
1108 virtual std::string PassCriteria()
1116 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, buffer.name());
1118 if (buffer.Verify() != NO_ERROR)
1121 buffer.Data(100, NULL, GL_DYNAMIC_COPY);
1122 if (buffer.Verify() != NO_ERROR)
1125 buffer.MapRange(10, 50, GL_MAP_WRITE_BIT);
1126 if (buffer.Verify() != NO_ERROR)
1129 if (buffer.Verify() != NO_ERROR)
1136 class BasicBufferBind : public SACSubcaseBase
1138 virtual std::string Title()
1140 return NL "Atomic Counter Buffer - binding";
1142 virtual std::string Purpose()
1144 return NL "Verify that binding buffer objects to ATOMIC_COUNTER_BUFFER (indexed) target" NL
1145 "works as expected. In particualr make sure that binding with BindBufferBase and BindBufferRange" NL
1146 "also bind to generic binding point and deleting buffer that is currently bound unbinds it. Tested" NL
1147 "commands: BindBuffer, BindBufferBase and BindBufferRange.";
1149 virtual std::string Method()
1153 virtual std::string PassCriteria()
1160 virtual long Setup()
1168 glGetIntegerv(GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS, &bindings);
1169 Output("MAX_ATOMIC_COUNTER_BUFFER_BINDINGS: %d\n", bindings);
1171 if (!CheckGetCommands(GL_ATOMIC_COUNTER_BUFFER_BINDING, 0))
1173 for (GLint index = 0; index < bindings; ++index)
1175 if (!CheckBufferBindingState(static_cast<GLuint>(index), 0, 0, 0))
1179 glGenBuffers(1, &buffer_);
1180 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, buffer_);
1182 if (!CheckGetCommands(GL_ATOMIC_COUNTER_BUFFER_BINDING, static_cast<GLint>(buffer_)))
1184 for (GLint index = 0; index < bindings; ++index)
1186 if (!CheckBufferBindingState(static_cast<GLuint>(index), 0, 0, 0))
1190 long res = NO_ERROR;
1192 glBufferData(GL_ATOMIC_COUNTER_BUFFER, 1000, NULL, GL_DYNAMIC_COPY);
1193 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
1195 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, buffer_);
1196 if (!CheckBufferBindingState(0, static_cast<GLint>(buffer_), 0, 1000))
1198 if (!CheckGetCommands(GL_ATOMIC_COUNTER_BUFFER_BINDING, static_cast<GLint>(buffer_)))
1201 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, static_cast<GLuint>(bindings / 2), buffer_);
1202 if (!CheckBufferBindingState(static_cast<GLuint>(bindings / 2), static_cast<GLint>(buffer_), 0, 1000))
1205 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, static_cast<GLuint>(bindings - 1), buffer_);
1206 if (!CheckBufferBindingState(static_cast<GLuint>(bindings - 1), static_cast<GLint>(buffer_), 0, 1000))
1208 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
1210 glBindBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, buffer_, 8, 32);
1211 if (!CheckBufferBindingState(0, static_cast<GLint>(buffer_), 8, 32))
1213 if (!CheckGetCommands(GL_ATOMIC_COUNTER_BUFFER_BINDING, static_cast<GLint>(buffer_)))
1216 glBindBufferRange(GL_ATOMIC_COUNTER_BUFFER, static_cast<GLuint>(bindings / 2), buffer_, 512, 100);
1217 if (!CheckBufferBindingState(static_cast<GLuint>(bindings / 2), static_cast<GLint>(buffer_), 512, 100))
1220 glBindBufferRange(GL_ATOMIC_COUNTER_BUFFER, static_cast<GLuint>(bindings - 1), buffer_, 12, 128);
1221 if (!CheckBufferBindingState(static_cast<GLuint>(bindings - 1), static_cast<GLint>(buffer_), 12, 128))
1224 glDeleteBuffers(1, &buffer_);
1228 glGetIntegerv(GL_ATOMIC_COUNTER_BUFFER_BINDING, &i);
1231 Output("Generic binding point should be 0 after deleting bound buffer object.\n");
1234 for (GLint index = 0; index < bindings; ++index)
1236 glGetIntegeri_v(GL_ATOMIC_COUNTER_BUFFER_BINDING, static_cast<GLuint>(index), &i);
1239 Output("Binding point %u should be 0 after deleting bound buffer object.\n", index);
1246 virtual long Cleanup()
1248 glDeleteBuffers(1, &buffer_);
1253 class BasicProgramMax : public SACSubcaseBase
1255 virtual std::string Title()
1257 return NL "Program - max values";
1259 virtual std::string Purpose()
1261 return NL "Verify all max values which deal with atomic counter buffers.";
1263 virtual std::string Method()
1267 virtual std::string PassCriteria()
1274 if (!CheckMaxValue(GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS, 1))
1276 if (!CheckMaxValue(GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE, 32))
1278 if (!CheckMaxValue(GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS, 1))
1280 if (!CheckMaxValue(GL_MAX_COMBINED_ATOMIC_COUNTERS, 8))
1282 if (!CheckMaxValue(GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS, 0))
1284 if (!CheckMaxValue(GL_MAX_VERTEX_ATOMIC_COUNTERS, 0))
1286 if (!CheckMaxValue(GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS, 1))
1288 if (!CheckMaxValue(GL_MAX_COMPUTE_ATOMIC_COUNTERS, 8))
1290 if (!CheckMaxValue(GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS, 0))
1292 if (!CheckMaxValue(GL_MAX_FRAGMENT_ATOMIC_COUNTERS, 0))
1298 class BasicProgramQuery : public BasicUsageCS
1300 virtual std::string Title()
1302 return NL "Program - atomic counters queries";
1304 virtual std::string Purpose()
1306 return NL "Get all the information from the program object about atomic counters." NL
1307 "Verify that all informations are correct. Tested commands:" NL
1308 "GetProgramiv and GetUniform* with new enums.";
1310 virtual std::string Method()
1314 virtual std::string PassCriteria()
1319 GLuint counter_buffer_, m_buffer;
1322 virtual long Setup()
1324 counter_buffer_ = 0;
1334 const char* glsl_cs =
1335 NL "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;" NL "layout(std430) buffer Output {" NL
1336 " mediump vec4 data;" NL "} g_out;" NL
1337 "layout(binding = 0, offset = 0) uniform atomic_uint ac_counter0;" NL
1338 "layout(binding = 0, offset = 4) uniform atomic_uint ac_counter1;" NL
1339 "layout(binding = 0) uniform atomic_uint ac_counter2;" NL
1340 "layout(binding = 0) uniform atomic_uint ac_counter67[2];" NL
1341 "layout(binding = 0) uniform atomic_uint ac_counter3;" NL
1342 "layout(binding = 0) uniform atomic_uint ac_counter4;" NL
1343 "layout(binding = 0) uniform atomic_uint ac_counter5;" NL "void main() {" NL
1344 " mediump uint c = 0u;" NL " c += atomicCounterIncrement(ac_counter0);" NL
1345 " c += atomicCounterIncrement(ac_counter1);" NL " c += atomicCounterIncrement(ac_counter2);" NL
1346 " c += atomicCounterIncrement(ac_counter3);" NL " c += atomicCounterIncrement(ac_counter4);" NL
1347 " c += atomicCounterIncrement(ac_counter5);" NL " c += atomicCounterIncrement(ac_counter67[0]);" NL
1348 " c += atomicCounterIncrement(ac_counter67[1]);" NL
1349 " if (c > 10u) g_out.data = vec4(0.0, 1.0, 0.0, 1.0);" NL
1350 " else g_out.data = vec4(1.0, float(c), 0.0, 1.0);" NL "}";
1352 prog_ = CreateComputeProgram(glsl_cs);
1353 glLinkProgram(prog_);
1354 if (!CheckProgram(prog_))
1356 glUseProgram(prog_);
1358 // get active buffers
1359 GLuint active_buffers;
1360 glGetProgramiv(prog_, GL_ACTIVE_ATOMIC_COUNTER_BUFFERS, reinterpret_cast<GLint*>(&active_buffers));
1361 if (active_buffers != 1)
1363 Output("GL_ACTIVE_ATOMIC_COUNTER_BUFFERS is %u should be %d.\n", active_buffers, 1);
1367 // get active uniforms
1368 std::map<std::string, GLuint> uniforms_name_index;
1369 GLuint active_uniforms;
1370 glGetProgramiv(prog_, GL_ACTIVE_UNIFORMS, reinterpret_cast<GLint*>(&active_uniforms));
1371 if (active_uniforms != 7)
1373 Output("GL_ACTIVE_UNIFORMS is %u should be %d.\n", active_uniforms, 8);
1376 for (GLuint index = 0; index < active_uniforms; ++index)
1379 glGetProgramResourceName(prog_, GL_UNIFORM, index, sizeof(name), NULL, name);
1380 uniforms_name_index.insert(std::make_pair(name, index));
1383 if (!CheckUniform(prog_, "ac_counter0", uniforms_name_index["ac_counter0"], GL_UNSIGNED_INT_ATOMIC_COUNTER, 1,
1386 if (!CheckUniform(prog_, "ac_counter1", uniforms_name_index["ac_counter1"], GL_UNSIGNED_INT_ATOMIC_COUNTER, 1,
1389 if (!CheckUniform(prog_, "ac_counter2", uniforms_name_index["ac_counter2"], GL_UNSIGNED_INT_ATOMIC_COUNTER, 1,
1392 if (!CheckUniform(prog_, "ac_counter3", uniforms_name_index["ac_counter3"], GL_UNSIGNED_INT_ATOMIC_COUNTER, 1,
1395 if (!CheckUniform(prog_, "ac_counter4", uniforms_name_index["ac_counter4"], GL_UNSIGNED_INT_ATOMIC_COUNTER, 1,
1398 if (!CheckUniform(prog_, "ac_counter5", uniforms_name_index["ac_counter5"], GL_UNSIGNED_INT_ATOMIC_COUNTER, 1,
1401 if (!CheckUniform(prog_, "ac_counter67[0]", uniforms_name_index["ac_counter67[0]"],
1402 GL_UNSIGNED_INT_ATOMIC_COUNTER, 2, 12, 4))
1405 // create atomic counter buffer
1406 glGenBuffers(1, &counter_buffer_);
1407 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, counter_buffer_);
1408 const unsigned int data[8] = { 20, 20, 20, 20, 20, 20, 20, 20 };
1409 glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(data), data, GL_DYNAMIC_DRAW);
1410 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
1412 glGenBuffers(1, &m_buffer);
1413 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer);
1414 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(Vec4), NULL, GL_DYNAMIC_DRAW);
1415 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
1417 glDispatchCompute(1, 1, 1);
1419 long error = NO_ERROR;
1421 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_buffer);
1422 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT | GL_ATOMIC_COUNTER_BARRIER_BIT);
1423 data_out = static_cast<Vec4*>(glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(Vec4), GL_MAP_READ_BIT));
1424 if (data_out[0].x() != 0.0 || data_out[0].y() != 1.0 || data_out[0].z() != 0.0 || data_out[0].w() != 1.0)
1426 Output("Expected vec4(0, 1, 0, 1) in the buffer, got: %f %f %f %f\n", data_out[0].x(), data_out[0].y(),
1427 data_out[0].z(), data_out[0].w());
1430 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
1431 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
1436 virtual long Cleanup()
1438 glDeleteBuffers(1, &counter_buffer_);
1439 glDeleteBuffers(1, &m_buffer);
1440 glDeleteProgram(prog_);
1446 class BasicUsageSimple : public BasicUsageCS
1448 virtual std::string Title()
1450 return NL "Simple Use Case";
1452 virtual std::string Purpose()
1454 return NL "Verify that simple usage of atomic counters work as expected.";
1456 virtual std::string Method()
1460 virtual std::string PassCriteria()
1465 GLuint counter_buffer_;
1466 GLuint storage_buffer_;
1469 virtual long Setup()
1471 counter_buffer_ = 0;
1472 storage_buffer_ = 0;
1479 const char* glsl_cs =
1480 NL "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;" NL "layout(std430) buffer Output {" NL
1481 " mediump vec4 color;" NL "} g_out;" NL
1482 "layout(binding = 0, offset = 0) uniform atomic_uint ac_counter;" NL "void main() {" NL
1483 " mediump uint c = atomicCounterIncrement(ac_counter);" NL
1484 " mediump float r = float(c / 40u) / 255.0;" NL " g_out.color = vec4(r, 0.0, 0.0, 1.0);" NL "}";
1485 prog_ = CreateComputeProgram(glsl_cs);
1486 glLinkProgram(prog_);
1487 if (!CheckProgram(prog_))
1490 // create atomic counter buffer
1491 glGenBuffers(1, &counter_buffer_);
1492 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_);
1493 glBufferData(GL_ATOMIC_COUNTER_BUFFER, 4, NULL, GL_DYNAMIC_COPY);
1494 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
1496 // clear counter buffer (set to 0)
1497 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_);
1498 unsigned int* ptr = static_cast<unsigned int*>(
1499 glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 4, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT));
1501 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
1503 // create shader storage buffer
1504 glGenBuffers(1, &storage_buffer_);
1505 glBindBuffer(GL_SHADER_STORAGE_BUFFER, storage_buffer_);
1506 glBufferData(GL_SHADER_STORAGE_BUFFER, 16, NULL, GL_DYNAMIC_DRAW);
1507 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
1509 glUseProgram(prog_);
1510 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, counter_buffer_);
1511 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, storage_buffer_);
1512 glDispatchCompute(1, 1, 1);
1514 if (glGetError() != GL_NO_ERROR)
1524 virtual long Cleanup()
1526 glDeleteBuffers(1, &counter_buffer_);
1527 glDeleteBuffers(1, &storage_buffer_);
1528 glDeleteProgram(prog_);
1534 class BasicUsageFS : public SACSubcaseBase
1536 virtual std::string Title()
1538 return NL "Atomic Counters usage in the Fragment Shader stage";
1540 virtual std::string Purpose()
1542 return NL "Verify that atomic counters work as expected in the Fragment Shader stage." NL
1543 "In particular make sure that values returned by GLSL built-in functions" NL
1544 "atomicCounterIncrement and atomicCounterDecrement are unique in every shader invocation." NL
1545 "Also make sure that the final values in atomic counter buffer objects are as expected.";
1547 virtual std::string Method()
1551 virtual std::string PassCriteria()
1556 GLuint counter_buffer_;
1559 GLuint fbo_, rt_[2];
1561 virtual long Setup()
1563 counter_buffer_ = 0;
1566 fbo_ = rt_[0] = rt_[1] = 0;
1573 glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS, &p1);
1574 glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTERS, &p2);
1575 if (p1 < 1 || p2 < 2)
1578 "GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS or GL_MAX_FRAGMENT_ATOMIC_COUNTERS are less than required");
1579 return NOT_SUPPORTED;
1583 const char* src_vs = "#version 310 es" NL "layout(location = 0) in vec4 i_vertex;" NL "void main() {" NL
1584 " gl_Position = i_vertex;" NL "}";
1586 const char* src_fs = "#version 310 es" NL "layout(location = 0) out uvec4 o_color[2];" NL
1587 "layout(binding = 0, offset = 0) uniform atomic_uint ac_counter_inc;" NL
1588 "layout(binding = 0, offset = 4) uniform atomic_uint ac_counter_dec;" NL "void main() {" NL
1589 " o_color[0] = uvec4(atomicCounterIncrement(ac_counter_inc));" NL
1590 " o_color[1] = uvec4(atomicCounterDecrement(ac_counter_dec));" NL "}";
1591 prog_ = CreateProgram(src_vs, src_fs, true);
1593 // create atomic counter buffer
1594 glGenBuffers(1, &counter_buffer_);
1595 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_);
1596 glBufferData(GL_ATOMIC_COUNTER_BUFFER, 8, NULL, GL_DYNAMIC_COPY);
1597 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
1599 // create render targets
1601 glGenTextures(2, rt_);
1603 for (int i = 0; i < 2; ++i)
1605 glBindTexture(GL_TEXTURE_2D, rt_[i]);
1606 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1607 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1608 glTexImage2D(GL_TEXTURE_2D, 0, GL_R32UI, s, s, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, NULL);
1609 glBindTexture(GL_TEXTURE_2D, 0);
1613 glGenFramebuffers(1, &fbo_);
1614 glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
1615 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt_[0], 0);
1616 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, rt_[1], 0);
1617 const GLenum draw_buffers[2] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 };
1618 glDrawBuffers(2, draw_buffers);
1619 glBindFramebuffer(GL_FRAMEBUFFER, 0);
1622 CreateQuad(&vao_, &vbo_, NULL);
1624 // init counter buffer
1625 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_);
1626 unsigned int* ptr = static_cast<unsigned int*>(
1627 glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 8, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT));
1630 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
1633 glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
1634 glViewport(0, 0, s, s);
1635 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, counter_buffer_);
1636 glUseProgram(prog_);
1637 glBindVertexArray(vao_);
1638 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
1642 glReadBuffer(GL_COLOR_ATTACHMENT0);
1643 glReadPixels(0, 0, s, s, GL_RGBA_INTEGER, GL_UNSIGNED_INT, data);
1644 if (!CheckCounterValues(s * s, data, 0))
1647 glReadBuffer(GL_COLOR_ATTACHMENT1);
1648 glReadPixels(0, 0, s, s, GL_RGBA_INTEGER, GL_UNSIGNED_INT, data);
1649 if (!CheckCounterValues(s * s, data, 16))
1652 if (!CheckFinalCounterValue(counter_buffer_, 0, 64))
1654 if (!CheckFinalCounterValue(counter_buffer_, 4, 16))
1659 virtual long Cleanup()
1661 glDeleteFramebuffers(1, &fbo_);
1662 glDeleteTextures(2, rt_);
1663 glViewport(0, 0, getWindowWidth(), getWindowHeight());
1664 glDeleteBuffers(1, &counter_buffer_);
1665 glDeleteVertexArrays(1, &vao_);
1666 glDeleteBuffers(1, &vbo_);
1667 glDeleteProgram(prog_);
1673 class BasicUsageVS : public SACSubcaseBase
1675 virtual std::string Title()
1677 return NL "Atomic Counters usage in the Vertex Shader stage";
1679 virtual std::string Purpose()
1681 return NL "Verify that atomic counters work as expected in the Vertex Shader stage." NL
1682 "In particular make sure that values returned by GLSL built-in functions" NL
1683 "atomicCounterIncrement and atomicCounterDecrement are unique in every shader invocation." NL
1684 "Also make sure that the final values in atomic counter buffer objects are as expected.";
1686 virtual std::string Method()
1690 virtual std::string PassCriteria()
1695 GLuint counter_buffer_[2];
1696 GLuint xfb_buffer_[2];
1697 GLuint array_buffer_;
1701 virtual long Setup()
1703 counter_buffer_[0] = counter_buffer_[1] = 0;
1704 xfb_buffer_[0] = xfb_buffer_[1] = 0;
1714 glGetIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS, &p1);
1715 glGetIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTERS, &p2);
1716 if (p1 < 2 || p2 < 2)
1719 "GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS or GL_MAX_VERTEX_ATOMIC_COUNTERS are less than required");
1720 return NOT_SUPPORTED;
1724 const char* src_vs =
1725 "#version 310 es" NL "layout(location = 0) in uint i_zero;" NL "flat out uint o_atomic_inc;" NL
1726 "flat out uint o_atomic_dec;" NL "layout(binding = 0, offset = 0) uniform atomic_uint ac_counter_inc;" NL
1727 "layout(binding = 1, offset = 0) uniform atomic_uint ac_counter_dec;" NL "void main() {" NL
1728 " o_atomic_inc = i_zero + atomicCounterIncrement(ac_counter_inc);" NL
1729 " o_atomic_dec = i_zero + atomicCounterDecrement(ac_counter_dec);" NL "}";
1731 const char* src_fs = "#version 310 es \n"
1732 "out mediump vec4 color; \n"
1734 " color = vec4(0, 1, 0, 1); \n"
1737 prog_ = CreateProgram(src_vs, src_fs, false);
1738 const char* xfb_var[2] = { "o_atomic_inc", "o_atomic_dec" };
1739 glTransformFeedbackVaryings(prog_, 2, xfb_var, GL_SEPARATE_ATTRIBS);
1742 // create array buffer
1743 const unsigned int array_buffer_data[32] = { 0 };
1744 glGenBuffers(1, &array_buffer_);
1745 glBindBuffer(GL_ARRAY_BUFFER, array_buffer_);
1746 glBufferData(GL_ARRAY_BUFFER, sizeof(array_buffer_data), array_buffer_data, GL_STATIC_DRAW);
1747 glBindBuffer(GL_ARRAY_BUFFER, 0);
1749 // create atomic counter buffers
1750 glGenBuffers(2, counter_buffer_);
1751 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_[0]);
1752 glBufferData(GL_ATOMIC_COUNTER_BUFFER, 4, NULL, GL_DYNAMIC_COPY);
1753 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_[1]);
1754 glBufferData(GL_ATOMIC_COUNTER_BUFFER, 4, NULL, GL_DYNAMIC_COPY);
1755 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
1757 // create transform feedback buffers
1758 glGenBuffers(2, xfb_buffer_);
1759 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buffer_[0]);
1760 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 1000, NULL, GL_STREAM_COPY);
1761 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buffer_[1]);
1762 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 1000, NULL, GL_STREAM_COPY);
1763 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0);
1765 // init counter buffers
1766 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_[0]);
1767 unsigned int* ptr = static_cast<unsigned int*>(
1768 glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 4, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT));
1770 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
1772 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_[1]);
1773 ptr = static_cast<unsigned int*>(
1774 glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 4, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT));
1776 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
1778 // create vertex array object
1779 glGenVertexArrays(1, &vao_);
1780 glBindVertexArray(vao_);
1781 glBindBuffer(GL_ARRAY_BUFFER, array_buffer_);
1782 glVertexAttribIPointer(0, 1, GL_UNSIGNED_INT, 0, 0);
1783 glBindBuffer(GL_ARRAY_BUFFER, 0);
1784 glEnableVertexAttribArray(0);
1785 glBindVertexArray(0);
1788 glEnable(GL_RASTERIZER_DISCARD);
1789 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, counter_buffer_[0]);
1790 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 1, counter_buffer_[1]);
1791 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, xfb_buffer_[0]);
1792 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 1, xfb_buffer_[1]);
1793 glUseProgram(prog_);
1794 glBindVertexArray(vao_);
1795 glBeginTransformFeedback(GL_POINTS);
1796 glDrawArrays(GL_POINTS, 0, 32);
1797 glEndTransformFeedback();
1798 glDisable(GL_RASTERIZER_DISCARD);
1802 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buffer_[0]);
1803 // CheckCounterValues will sort in place, so map buffer for both read and write
1804 data = static_cast<GLuint*>(
1805 glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 32 * 4, GL_MAP_READ_BIT | GL_MAP_WRITE_BIT));
1806 if (!CheckCounterValues(32, data, 7))
1808 glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
1809 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0);
1811 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buffer_[1]);
1812 data = static_cast<GLuint*>(
1813 glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 32 * 4, GL_MAP_READ_BIT | GL_MAP_WRITE_BIT));
1814 if (!CheckCounterValues(32, data, 45))
1816 glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
1817 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0);
1819 if (!CheckFinalCounterValue(counter_buffer_[0], 0, 39))
1821 if (!CheckFinalCounterValue(counter_buffer_[1], 0, 45))
1826 virtual long Cleanup()
1828 glDeleteBuffers(2, counter_buffer_);
1829 glDeleteBuffers(2, xfb_buffer_);
1830 glDeleteBuffers(1, &array_buffer_);
1831 glDeleteVertexArrays(1, &vao_);
1832 glDeleteProgram(prog_);
1838 class AdvancedUsageMultiStage : public SACSubcaseBase
1840 virtual std::string Title()
1842 return NL "Same atomic counter accessed from multiple shader stages";
1844 virtual std::string Purpose()
1846 return NL "Same atomic counter is incremented (decremented) from two shader stages (VS and FS)." NL
1847 "Verify that this scenario works as expected. In particular ensure that all generated values are "
1848 "unique and" NL "final value in atomic counter buffer objects are as expected.";
1850 virtual std::string Method()
1854 virtual std::string PassCriteria()
1859 GLuint counter_buffer_;
1860 GLuint xfb_buffer_[2];
1863 GLuint fbo_, rt_[2];
1865 virtual long Setup()
1867 counter_buffer_ = 0;
1868 xfb_buffer_[0] = xfb_buffer_[1] = 0;
1871 fbo_ = rt_[0] = rt_[1] = 0;
1877 GLint p1, p2, p3, p4;
1878 glGetIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS, &p1);
1879 glGetIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTERS, &p2);
1880 glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS, &p3);
1881 glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTERS, &p4);
1882 if (p1 < 8 || p2 < 2 || p3 < 8 || p4 < 2)
1884 OutputNotSupported("GL_MAX_FRAGMENT/VERTEX_ATOMIC_COUNTER_BUFFERS or"
1885 "GL_MAX_FRAGMENT/VERTEX_ATOMIC_COUNTERS are less than required");
1886 return NOT_SUPPORTED;
1890 const char* src_vs =
1891 "#version 310 es" NL "layout(location = 0) in vec4 i_vertex;" NL "flat out uint o_atomic_inc;" NL
1892 "flat out uint o_atomic_dec;" NL "layout(binding = 1, offset = 16) uniform atomic_uint ac_counter_inc;" NL
1893 "layout(binding = 7, offset = 128) uniform atomic_uint ac_counter_dec;" NL "void main() {" NL
1894 " gl_Position = i_vertex;" NL " o_atomic_inc = atomicCounterIncrement(ac_counter_inc);" NL
1895 " o_atomic_dec = atomicCounterDecrement(ac_counter_dec);" NL "}";
1896 const char* src_fs = "#version 310 es" NL "layout(location = 0) out uvec4 o_color[2];" NL
1897 "layout(binding = 1, offset = 16) uniform atomic_uint ac_counter_inc;" NL
1898 "layout(binding = 7, offset = 128) uniform atomic_uint ac_counter_dec;" NL
1899 "void main() {" NL " o_color[0] = uvec4(atomicCounterIncrement(ac_counter_inc));" NL
1900 " o_color[1] = uvec4(atomicCounterDecrement(ac_counter_dec));" NL "}";
1901 prog_ = CreateProgram(src_vs, src_fs, false);
1902 const char* xfb_var[2] = { "o_atomic_inc", "o_atomic_dec" };
1903 glTransformFeedbackVaryings(prog_, 2, xfb_var, GL_SEPARATE_ATTRIBS);
1906 // create atomic counter buffer
1907 std::vector<GLuint> init_data(256, 100);
1908 glGenBuffers(1, &counter_buffer_);
1909 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_);
1910 glBufferData(GL_ATOMIC_COUNTER_BUFFER, (GLsizeiptr)(init_data.size() * sizeof(GLuint)), &init_data[0],
1912 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
1914 // create transform feedback buffers
1915 glGenBuffers(2, xfb_buffer_);
1916 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buffer_[0]);
1917 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 1000, NULL, GL_STREAM_COPY);
1918 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buffer_[1]);
1919 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 1000, NULL, GL_STREAM_COPY);
1920 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0);
1922 // create render targets
1924 glGenTextures(2, rt_);
1925 for (int i = 0; i < 2; ++i)
1927 glBindTexture(GL_TEXTURE_2D, rt_[i]);
1928 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1929 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1930 glTexImage2D(GL_TEXTURE_2D, 0, GL_R32UI, s, s, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, NULL);
1931 glBindTexture(GL_TEXTURE_2D, 0);
1935 glGenFramebuffers(1, &fbo_);
1936 glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
1937 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt_[0], 0);
1938 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, rt_[1], 0);
1939 const GLenum draw_buffers[2] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 };
1940 glDrawBuffers(2, draw_buffers);
1941 glBindFramebuffer(GL_FRAMEBUFFER, 0);
1944 CreateTriangle(&vao_, &vbo_, NULL);
1947 glBindBufferRange(GL_ATOMIC_COUNTER_BUFFER, 1, counter_buffer_, 16, 32);
1948 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 7, counter_buffer_);
1949 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, xfb_buffer_[0]);
1950 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 1, xfb_buffer_[1]);
1951 glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
1952 glViewport(0, 0, s, s);
1953 glUseProgram(prog_);
1954 glBindVertexArray(vao_);
1955 glBeginTransformFeedback(GL_TRIANGLES);
1956 glDrawArrays(GL_TRIANGLES, 0, 3);
1957 glEndTransformFeedback();
1960 UVec4 data[s * s + 3];
1961 glReadBuffer(GL_COLOR_ATTACHMENT0);
1962 glReadPixels(0, 0, s, s, GL_RGBA_INTEGER, GL_UNSIGNED_INT, data);
1963 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buffer_[0]);
1965 data2 = static_cast<GLuint*>(
1966 glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 3 * sizeof(GLuint), GL_MAP_READ_BIT));
1967 data[s * s] = UVec4(data2[0]);
1968 data[s * s + 1] = UVec4(data2[1]);
1969 data[s * s + 2] = UVec4(data2[2]);
1970 if (!CheckCounterValues(s * s + 3, data, 100))
1972 glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
1973 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0);
1975 glReadBuffer(GL_COLOR_ATTACHMENT1);
1976 glReadPixels(0, 0, s, s, GL_RGBA_INTEGER, GL_UNSIGNED_INT, data);
1977 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buffer_[1]);
1978 data2 = static_cast<GLuint*>(
1979 glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 3 * sizeof(GLuint), GL_MAP_READ_BIT));
1980 data[s * s] = UVec4(data2[0]);
1981 data[s * s + 1] = UVec4(data2[1]);
1982 data[s * s + 2] = UVec4(data2[2]);
1983 if (!CheckCounterValues(s * s + 3, data, 33))
1985 glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
1986 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0);
1988 if (!CheckFinalCounterValue(counter_buffer_, 32, 167))
1990 if (!CheckFinalCounterValue(counter_buffer_, 128, 33))
1995 virtual long Cleanup()
1997 glDeleteFramebuffers(1, &fbo_);
1998 glDeleteTextures(2, rt_);
1999 glViewport(0, 0, getWindowWidth(), getWindowHeight());
2000 glDeleteBuffers(1, &counter_buffer_);
2001 glDeleteBuffers(2, xfb_buffer_);
2002 glDeleteVertexArrays(1, &vao_);
2003 glDeleteBuffers(1, &vbo_);
2004 glDeleteProgram(prog_);
2010 class AdvancedUsageDrawUpdateDraw : public SACSubcaseBase
2012 virtual std::string Title()
2014 return NL "Update via Draw Call and update via MapBufferRange";
2016 virtual std::string Purpose()
2018 return NL "1. Create atomic counter buffers and init them with start values." NL
2019 "2. Increment (decrement) buffer values in the shader." NL
2020 "3. Map buffers with MapBufferRange command. Increment (decrement) buffer values manually." NL
2021 "4. Unmap buffers with UnmapBuffer command." NL
2022 "5. Again increment (decrement) buffer values in the shader." NL
2023 "Verify that this scenario works as expected and final values in the buffer objects are correct.";
2025 virtual std::string Method()
2029 virtual std::string PassCriteria()
2034 GLuint counter_buffer_;
2036 GLuint prog_, prog2_;
2037 GLuint fbo_, rt_[2];
2039 virtual long Setup()
2041 counter_buffer_ = 0;
2045 fbo_ = rt_[0] = rt_[1] = 0;
2052 glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS, &p1);
2053 glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTERS, &p2);
2054 if (p1 < 1 || p2 < 2)
2057 "GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS or GL_MAX_FRAGMENT_ATOMIC_COUNTERS are less than required");
2058 return NOT_SUPPORTED;
2062 const char* src_vs = "#version 310 es" NL "layout(location = 0) in vec4 i_vertex;" NL "void main() {" NL
2063 " gl_Position = i_vertex;" NL "}";
2064 const char* src_fs = "#version 310 es" NL "layout(location = 0) out uvec4 o_color[2];" NL
2065 "layout(binding = 0) uniform atomic_uint ac_counter[2];" NL "void main() {" NL
2066 " o_color[0] = uvec4(atomicCounterIncrement(ac_counter[0]));" NL
2067 " o_color[1] = uvec4(atomicCounterDecrement(ac_counter[1]));" NL "}";
2068 const char* src_fs2 = "#version 310 es" NL "layout(location = 0) out uvec4 o_color[2];" NL
2069 "layout(binding = 0) uniform atomic_uint ac_counter[2];" NL "void main() {" NL
2070 " o_color[0] = uvec4(atomicCounter(ac_counter[0]));" NL
2071 " o_color[1] = uvec4(atomicCounter(ac_counter[1]));" NL "}";
2072 prog_ = CreateProgram(src_vs, src_fs, true);
2073 prog2_ = CreateProgram(src_vs, src_fs2, true);
2075 // create atomic counter buffer
2076 glGenBuffers(1, &counter_buffer_);
2077 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_);
2078 glBufferData(GL_ATOMIC_COUNTER_BUFFER, 8, NULL, GL_DYNAMIC_COPY);
2079 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
2081 // create render targets
2083 glGenTextures(2, rt_);
2085 for (int i = 0; i < 2; ++i)
2087 glBindTexture(GL_TEXTURE_2D, rt_[i]);
2088 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2089 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2090 glTexImage2D(GL_TEXTURE_2D, 0, GL_R32UI, s, s, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, NULL);
2091 glBindTexture(GL_TEXTURE_2D, 0);
2095 glGenFramebuffers(1, &fbo_);
2096 glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
2097 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt_[0], 0);
2098 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, rt_[1], 0);
2099 const GLenum draw_buffers[2] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 };
2100 glDrawBuffers(2, draw_buffers);
2101 glBindFramebuffer(GL_FRAMEBUFFER, 0);
2104 CreateQuad(&vao_, &vbo_, NULL);
2106 // init counter buffer
2107 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_);
2108 unsigned int* ptr = static_cast<unsigned int*>(
2109 glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 8, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT));
2112 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
2115 glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
2116 glViewport(0, 0, s, s);
2117 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, counter_buffer_);
2118 glUseProgram(prog_);
2119 glBindVertexArray(vao_);
2120 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
2122 // update counter buffer
2123 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_);
2124 ptr = static_cast<unsigned int*>(
2125 glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 8, GL_MAP_WRITE_BIT | GL_MAP_READ_BIT));
2128 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
2131 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
2132 glMemoryBarrier(GL_ATOMIC_COUNTER_BARRIER_BIT);
2135 glUseProgram(prog2_);
2136 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
2140 glReadBuffer(GL_COLOR_ATTACHMENT0);
2141 glReadPixels(0, 0, s, s, GL_RGBA_INTEGER, GL_UNSIGNED_INT, data);
2142 for (int i = 0; i < s * s; ++i)
2144 if (data[i].x() != 896)
2146 Output("Counter value is %u should be %u.\n", data[i].x(), 896);
2151 glReadBuffer(GL_COLOR_ATTACHMENT1);
2152 glReadPixels(0, 0, s, s, GL_RGBA_INTEGER, GL_UNSIGNED_INT, data);
2153 for (int i = 0; i < s * s; ++i)
2155 if (data[i].x() != 1152)
2157 Output("Counter value is %u should be %u.\n", data[i].x(), 896);
2162 if (!CheckFinalCounterValue(counter_buffer_, 0, 896))
2164 if (!CheckFinalCounterValue(counter_buffer_, 4, 1152))
2169 virtual long Cleanup()
2171 glDeleteFramebuffers(1, &fbo_);
2172 glDeleteTextures(2, rt_);
2173 glViewport(0, 0, getWindowWidth(), getWindowHeight());
2174 glDeleteBuffers(1, &counter_buffer_);
2175 glDeleteVertexArrays(1, &vao_);
2176 glDeleteBuffers(1, &vbo_);
2177 glDeleteProgram(prog_);
2178 glDeleteProgram(prog2_);
2184 class AdvancedUsageManyCounters : public BasicUsageCS
2186 virtual std::string Title()
2188 return NL "Large atomic counters array indexed with uniforms";
2190 virtual std::string Purpose()
2192 return NL "Verify that large atomic counters array works as expected when indexed with dynamically uniform "
2194 "Built-ins tested: atomicCounterIncrement, atomicCounterDecrement and atomicCounter.";
2196 virtual std::string Method()
2200 virtual std::string PassCriteria()
2205 GLuint counter_buffer_, m_ssbo;
2208 virtual long Setup()
2210 counter_buffer_ = 0;
2219 const char* glsl_cs = NL
2220 "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;" NL "layout(std430) buffer Output {" NL
2221 " mediump uvec4 data1[64];" NL " mediump uvec4 data2[64];" NL " mediump uvec4 data3[64];" NL
2222 " mediump uvec4 data4[64];" NL " mediump uvec4 data5[64];" NL " mediump uvec4 data6[64];" NL
2223 " mediump uvec4 data7[64];" NL " mediump uvec4 data8[64];" NL "} g_out;" NL
2224 "uniform mediump int u_active_counters[8];" NL "layout(binding = 0) uniform atomic_uint ac_counter[8];" NL
2225 "void main() {" NL " mediump uint offset = 8u * gl_GlobalInvocationID.y + gl_GlobalInvocationID.x;" NL
2226 " g_out.data1[offset] = uvec4(atomicCounterIncrement(ac_counter[u_active_counters[0]]));" NL
2227 " g_out.data2[offset] = uvec4(atomicCounterDecrement(ac_counter[u_active_counters[1]]));" NL
2228 " g_out.data3[offset] = uvec4(atomicCounter(ac_counter[u_active_counters[2]]));" NL
2229 " g_out.data4[offset] = uvec4(atomicCounterIncrement(ac_counter[u_active_counters[3]]));" NL
2230 " g_out.data5[offset] = uvec4(atomicCounterDecrement(ac_counter[u_active_counters[4]]));" NL
2231 " g_out.data6[offset] = uvec4(atomicCounter(ac_counter[u_active_counters[5]]));" NL
2232 " g_out.data7[offset] = uvec4(atomicCounterIncrement(ac_counter[u_active_counters[6]]));" NL
2233 " g_out.data8[offset] = uvec4(atomicCounterIncrement(ac_counter[u_active_counters[7]]));" NL "}";
2235 prog_ = CreateComputeProgram(glsl_cs);
2236 glLinkProgram(prog_);
2237 if (!CheckProgram(prog_))
2240 // create atomic counter buffer
2241 std::vector<GLuint> init_data(1024, 1000);
2242 glGenBuffers(1, &counter_buffer_);
2243 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_);
2244 glBufferData(GL_ATOMIC_COUNTER_BUFFER, 1024 * sizeof(GLuint), &init_data[0], GL_DYNAMIC_COPY);
2245 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
2247 glGenBuffers(1, &m_ssbo);
2248 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_ssbo);
2249 glBufferData(GL_SHADER_STORAGE_BUFFER, 8 * 64 * sizeof(UVec4), NULL, GL_DYNAMIC_DRAW);
2250 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
2253 glUseProgram(prog_);
2254 glUniform1i(glGetUniformLocation(prog_, "u_active_counters[0]"), 0);
2255 glUniform1i(glGetUniformLocation(prog_, "u_active_counters[1]"), 1);
2256 glUniform1i(glGetUniformLocation(prog_, "u_active_counters[2]"), 2);
2257 glUniform1i(glGetUniformLocation(prog_, "u_active_counters[3]"), 3);
2258 glUniform1i(glGetUniformLocation(prog_, "u_active_counters[4]"), 4);
2259 glUniform1i(glGetUniformLocation(prog_, "u_active_counters[5]"), 5);
2260 glUniform1i(glGetUniformLocation(prog_, "u_active_counters[6]"), 6);
2261 glUniform1i(glGetUniformLocation(prog_, "u_active_counters[7]"), 7);
2264 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, counter_buffer_);
2265 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_ssbo);
2266 glDispatchCompute(8, 8, 1);
2269 glMemoryBarrier(GL_ATOMIC_COUNTER_BARRIER_BIT | GL_SHADER_STORAGE_BARRIER_BIT);
2271 long error = NO_ERROR;
2273 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_ssbo);
2274 data = static_cast<UVec4*>(glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 64 * sizeof(UVec4), GL_MAP_READ_BIT));
2275 if (!CheckCounterValues(8 * 8, data, 1000))
2277 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
2278 if (!CheckFinalCounterValue(counter_buffer_, 0, 1064))
2281 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_ssbo);
2282 data = static_cast<UVec4*>(
2283 glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 64 * sizeof(UVec4), 64 * sizeof(UVec4), GL_MAP_READ_BIT));
2284 if (!CheckCounterValues(8 * 8, data, 1000 - 64))
2286 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
2287 if (!CheckFinalCounterValue(counter_buffer_, 1 * sizeof(GLuint), 1000 - 64))
2290 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_ssbo);
2291 data = static_cast<UVec4*>(
2292 glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 64 * sizeof(UVec4) * 2, 64 * sizeof(UVec4), GL_MAP_READ_BIT));
2293 for (int i = 0; i < 8 * 8; ++i)
2294 if (data[i].x() != 1000)
2296 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
2297 if (!CheckFinalCounterValue(counter_buffer_, 2 * sizeof(GLuint), 1000))
2300 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_ssbo);
2301 data = static_cast<UVec4*>(
2302 glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 64 * sizeof(UVec4) * 3, 64 * sizeof(UVec4), GL_MAP_READ_BIT));
2303 if (!CheckCounterValues(8 * 8, data, 1000))
2305 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
2306 if (!CheckFinalCounterValue(counter_buffer_, 3 * sizeof(GLuint), 1064))
2309 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_ssbo);
2310 data = static_cast<UVec4*>(
2311 glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 64 * sizeof(UVec4) * 4, 64 * sizeof(UVec4), GL_MAP_READ_BIT));
2312 if (!CheckCounterValues(8 * 8, data, 1000 - 64))
2314 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
2315 if (!CheckFinalCounterValue(counter_buffer_, 4 * sizeof(GLuint), 1000 - 64))
2318 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_ssbo);
2319 data = static_cast<UVec4*>(
2320 glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 64 * sizeof(UVec4) * 5, 64 * sizeof(UVec4), GL_MAP_READ_BIT));
2321 for (int i = 0; i < 8 * 8; ++i)
2322 if (data[i].x() != 1000)
2324 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
2325 if (!CheckFinalCounterValue(counter_buffer_, 5 * sizeof(GLuint), 1000))
2328 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_ssbo);
2329 data = static_cast<UVec4*>(
2330 glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 64 * sizeof(UVec4) * 6, 64 * sizeof(UVec4), GL_MAP_READ_BIT));
2331 if (!CheckCounterValues(8 * 8, data, 1000))
2333 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
2334 if (!CheckFinalCounterValue(counter_buffer_, 6 * sizeof(GLuint), 1064))
2337 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_ssbo);
2338 data = static_cast<UVec4*>(
2339 glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 64 * sizeof(UVec4) * 7, 64 * sizeof(UVec4), GL_MAP_READ_BIT));
2340 if (!CheckCounterValues(8 * 8, data, 1000))
2342 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
2343 if (!CheckFinalCounterValue(counter_buffer_, 7 * sizeof(GLuint), 1064))
2346 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
2347 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
2351 virtual long Cleanup()
2353 glDeleteBuffers(1, &counter_buffer_);
2354 glDeleteBuffers(1, &m_ssbo);
2355 glDeleteProgram(prog_);
2361 class AdvancedUsageSwitchPrograms : public SACSubcaseBase
2363 virtual std::string Title()
2365 return NL "Switching several program objects with different atomic counters with different bindings";
2367 virtual std::string Purpose()
2369 return NL "Verify that each program upadate atomic counter buffer object in appropriate binding point.";
2371 virtual std::string Method()
2375 virtual std::string PassCriteria()
2380 GLuint counter_buffer_[8];
2386 std::string GenVSSrc(int binding, int offset)
2388 std::ostringstream os;
2389 os << "#version 310 es" NL "layout(location = 0) in vec4 i_vertex;" NL "flat out uvec4 o_atomic_value;" NL
2391 << binding << ", offset = " << offset
2392 << ") uniform atomic_uint ac_counter_vs;" NL "void main() {" NL " gl_Position = i_vertex;" NL
2393 " o_atomic_value = uvec4(atomicCounterIncrement(ac_counter_vs));" NL "}";
2396 std::string GenFSSrc(int binding, int offset)
2398 std::ostringstream os;
2399 os << "#version 310 es" NL "layout(location = 0) out uvec4 o_color;" NL "layout(binding = " << binding
2400 << ", offset = " << offset << ") uniform atomic_uint ac_counter_fs;" NL "void main() {" NL
2401 " o_color = uvec4(atomicCounterIncrement(ac_counter_fs));" NL "}";
2404 virtual long Setup()
2406 memset(counter_buffer_, 0, sizeof(counter_buffer_));
2409 memset(prog_, 0, sizeof(prog_));
2416 GLint p1, p2, p3, p4;
2417 glGetIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS, &p1);
2418 glGetIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTERS, &p2);
2419 glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS, &p3);
2420 glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTERS, &p4);
2421 if (p1 < 8 || p2 < 1 || p3 < 8 || p4 < 1)
2423 OutputNotSupported("GL_MAX_*_ATOMIC_COUNTER_BUFFERS or GL_MAX_*_ATOMIC_COUNTERS are less than required");
2424 return NOT_SUPPORTED;
2428 for (int i = 0; i < 8; ++i)
2430 std::string vs_str = GenVSSrc(i, i * 8);
2431 std::string fs_str = GenFSSrc(7 - i, 128 + i * 16);
2432 const char* src_vs = vs_str.c_str();
2433 const char* src_fs = fs_str.c_str();
2434 prog_[i] = CreateProgram(src_vs, src_fs, false);
2435 const char* xfb_var = "o_atomic_value";
2436 glTransformFeedbackVaryings(prog_[i], 1, &xfb_var, GL_SEPARATE_ATTRIBS);
2437 LinkProgram(prog_[i]);
2440 // create atomic counter buffers
2441 glGenBuffers(8, counter_buffer_);
2442 for (int i = 0; i < 8; ++i)
2444 std::vector<GLuint> init_data(256);
2445 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_[i]);
2446 glBufferData(GL_ATOMIC_COUNTER_BUFFER, (GLsizeiptr)(init_data.size() * sizeof(GLuint)), &init_data[0],
2449 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
2451 // create transform feedback buffer
2452 glGenBuffers(1, &xfb_buffer_);
2453 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buffer_);
2454 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 1000, NULL, GL_STREAM_COPY);
2455 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0);
2457 // create render target
2459 glGenTextures(1, &rt_);
2460 glBindTexture(GL_TEXTURE_2D, rt_);
2461 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2462 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2463 glTexImage2D(GL_TEXTURE_2D, 0, GL_R32UI, s, s, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, NULL);
2464 glBindTexture(GL_TEXTURE_2D, 0);
2467 glGenFramebuffers(1, &fbo_);
2468 glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
2469 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt_, 0);
2470 glBindFramebuffer(GL_FRAMEBUFFER, 0);
2473 CreateTriangle(&vao_, &vbo_, NULL);
2476 for (GLuint i = 0; i < 8; ++i)
2478 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, i, counter_buffer_[i]);
2480 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, xfb_buffer_);
2481 glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
2482 glViewport(0, 0, s, s);
2483 glBindVertexArray(vao_);
2485 for (int i = 0; i < 8; ++i)
2487 glUseProgram(prog_[i]);
2488 glBeginTransformFeedback(GL_TRIANGLES);
2489 glDrawArrays(GL_TRIANGLES, 0, 3);
2490 glEndTransformFeedback();
2491 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
2493 if (!CheckFinalCounterValue(counter_buffer_[i], i * 8, 3))
2495 if (!CheckFinalCounterValue(counter_buffer_[7 - i], 128 + i * 16, 64))
2500 virtual long Cleanup()
2502 glDeleteFramebuffers(1, &fbo_);
2503 glDeleteTextures(1, &rt_);
2504 glViewport(0, 0, getWindowWidth(), getWindowHeight());
2505 glDeleteBuffers(8, counter_buffer_);
2506 glDeleteBuffers(1, &xfb_buffer_);
2507 glDeleteVertexArrays(1, &vao_);
2508 glDeleteBuffers(1, &vbo_);
2509 for (int i = 0; i < 8; ++i)
2510 glDeleteProgram(prog_[i]);
2516 class AdvancedUsageUBO : public BasicUsageCS
2518 virtual std::string Title()
2520 return NL "Atomic Counters used to access Uniform Buffer Objects";
2522 virtual std::string Purpose()
2524 return NL "Atomic counters are used to access UBOs. In that way each shader invocation can access UBO at "
2526 "This scenario is a base for some practical algorithms. Verify that it works as expected.";
2528 virtual std::string Method()
2532 virtual std::string PassCriteria()
2537 GLuint counter_buffer_, m_ssbo;
2538 GLuint uniform_buffer_;
2541 virtual long Setup()
2543 counter_buffer_ = 0;
2544 uniform_buffer_ = 0;
2553 const char* glsl_cs =
2554 NL "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;" NL "layout(std430) buffer Output {" NL
2555 " mediump uvec4 color[256];" NL "} g_out;" NL
2556 "layout(binding = 0, offset = 0) uniform atomic_uint ac_counter;" NL "layout(std140) uniform Data {" NL
2557 " mediump uint index[256];" NL "} ub_data;" NL "void main() {" NL
2558 " mediump uint offset = 16u * gl_GlobalInvocationID.y + gl_GlobalInvocationID.x;" NL
2559 " g_out.color[offset] = uvec4(ub_data.index[atomicCounterIncrement(ac_counter)]);" NL "}";
2560 prog_ = CreateComputeProgram(glsl_cs);
2561 glLinkProgram(prog_);
2562 if (!CheckProgram(prog_))
2564 glUniformBlockBinding(prog_, glGetUniformBlockIndex(prog_, "Data"), 1);
2566 // create atomic counter buffer
2567 const unsigned int z = 0;
2568 glGenBuffers(1, &counter_buffer_);
2569 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_);
2570 glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(z), &z, GL_DYNAMIC_COPY);
2571 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
2573 // create uniform buffer
2574 std::vector<UVec4> init_data(256);
2575 for (GLuint i = 0; i < 256; ++i)
2576 init_data[i] = UVec4(i);
2577 glGenBuffers(1, &uniform_buffer_);
2578 glBindBuffer(GL_UNIFORM_BUFFER, uniform_buffer_);
2579 glBufferData(GL_UNIFORM_BUFFER, (GLsizeiptr)(sizeof(UVec4) * init_data.size()), &init_data[0], GL_DYNAMIC_COPY);
2580 glBindBuffer(GL_UNIFORM_BUFFER, 0);
2582 glGenBuffers(1, &m_ssbo);
2583 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_ssbo);
2584 glBufferData(GL_SHADER_STORAGE_BUFFER, 256 * sizeof(UVec4), NULL, GL_DYNAMIC_DRAW);
2585 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
2588 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, counter_buffer_);
2589 glBindBufferBase(GL_UNIFORM_BUFFER, 1, uniform_buffer_);
2590 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_ssbo);
2591 glUseProgram(prog_);
2592 glDispatchCompute(16, 16, 1);
2596 long error = NO_ERROR;
2597 glMemoryBarrier(GL_UNIFORM_BARRIER_BIT | GL_SHADER_STORAGE_BARRIER_BIT | GL_ATOMIC_COUNTER_BARRIER_BIT);
2599 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_ssbo);
2600 data = static_cast<UVec4*>(glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 256 * sizeof(UVec4), GL_MAP_READ_BIT));
2601 if (!CheckCounterValues(16 * 16, data, 0))
2603 if (!CheckFinalCounterValue(counter_buffer_, 0, 256))
2605 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
2607 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
2608 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
2613 virtual long Cleanup()
2615 glDeleteBuffers(1, &counter_buffer_);
2616 glDeleteBuffers(1, &uniform_buffer_);
2617 glDeleteBuffers(1, &m_ssbo);
2618 glDeleteProgram(prog_);
2624 class NegativeAPI : public SACSubcaseBase
2626 virtual std::string Title()
2628 return NL "NegativeAPI";
2630 virtual std::string Purpose()
2632 return NL "Verify errors reported by BindBuffer* commands.";
2634 virtual std::string Method()
2638 virtual std::string PassCriteria()
2645 virtual long Setup()
2651 long error = NO_ERROR;
2653 glGetIntegerv(GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS, &res);
2654 glGenBuffers(1, &buffer);
2655 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, buffer);
2656 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, res, buffer);
2657 if (glGetError() != GL_INVALID_VALUE)
2659 Output("glBindBufferBase should generate INVALID_VALUE when"
2660 " index is greater than or equal GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS.\n");
2663 glBindBufferRange(GL_ATOMIC_COUNTER_BUFFER, res, buffer, 0, 4);
2664 if (glGetError() != GL_INVALID_VALUE)
2666 Output("glBindBufferRange should generate INVALID_VALUE when"
2667 " index is greater than or equal GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS.\n");
2670 glBindBufferRange(GL_ATOMIC_COUNTER_BUFFER, res - 1, buffer, 3, 4);
2671 if (glGetError() != GL_INVALID_VALUE)
2673 Output("glBindBufferRange should generate INVALID_VALUE when"
2674 " <offset> is not a multiple of four\n");
2679 virtual long Cleanup()
2681 glDeleteBuffers(1, &buffer);
2686 class NegativeGLSL : public BasicUsageCS
2688 virtual std::string Title()
2690 return NL "GLSL errors";
2692 virtual std::string Purpose()
2694 return NL "Verify that two different atomic counter uniforms with same binding cannot share same offset value.";
2696 virtual std::string Method()
2700 virtual std::string PassCriteria()
2707 virtual long Setup()
2715 const char* const glsl_cs = NL
2716 "layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;" NL
2717 "layout(binding = 0, offset = 4) uniform atomic_uint ac_counter_inc;" NL
2718 "layout(binding = 0, offset = 4) uniform atomic_uint ac_counter_dec;" NL "layout(std430) buffer Output {" NL
2719 " mediump uint data_inc[256];" NL " mediump uint data_dec[256];" NL "} g_out;" NL "void main() {" NL
2720 " mediump uint offset = 32u * gl_GlobalInvocationID.y + gl_GlobalInvocationID.x;" NL
2721 " g_out.data_inc[offset] = atomicCounterIncrement(ac_counter_inc);" NL
2722 " g_out.data_dec[offset] = atomicCounterDecrement(ac_counter_dec);" NL "}";
2724 prog_ = CreateComputeProgram(glsl_cs);
2725 glLinkProgram(prog_);
2726 if (CheckProgram(prog_))
2728 Output("Link should fail because ac_counter0 and ac_counter2 uses same binding and same offset.\n");
2733 virtual long Cleanup()
2735 glDeleteProgram(prog_);
2740 class AdvancedManyDrawCalls : public SACSubcaseBase
2742 virtual std::string Title()
2744 return NL "Atomic Counters usage in multiple draw calls";
2746 virtual std::string Purpose()
2748 return NL "Verify atomic counters behaviour across multiple draw calls.";
2750 virtual std::string Method()
2754 virtual std::string PassCriteria()
2759 GLuint counter_buffer_;
2762 GLuint fbo_, rt_[2];
2764 virtual long Setup()
2766 counter_buffer_ = 0;
2769 fbo_ = rt_[0] = rt_[1] = 0;
2776 glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS, &p1);
2777 glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTERS, &p2);
2778 if (p1 < 1 || p2 < 2)
2781 "GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS or GL_MAX_FRAGMENT_ATOMIC_COUNTERS are less than required");
2782 return NOT_SUPPORTED;
2786 const char* src_vs = "#version 310 es" NL "layout(location = 0) in vec4 i_vertex;" NL "void main() {" NL
2787 " gl_Position = i_vertex;" NL "}";
2788 const char* src_fs = "#version 310 es" NL "layout(location = 0) out uvec4 o_color[2];" NL
2789 "layout(binding = 0, offset = 0) uniform atomic_uint ac_counter_inc;" NL
2790 "layout(binding = 0, offset = 4) uniform atomic_uint ac_counter_dec;" NL "void main() {" NL
2791 " o_color[0] = uvec4(atomicCounterIncrement(ac_counter_inc));" NL
2792 " o_color[1] = uvec4(atomicCounterDecrement(ac_counter_dec));" NL "}";
2793 prog_ = CreateProgram(src_vs, src_fs, true);
2795 // create atomic counter buffer
2796 glGenBuffers(1, &counter_buffer_);
2797 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_);
2798 glBufferData(GL_ATOMIC_COUNTER_BUFFER, 8, NULL, GL_DYNAMIC_COPY);
2799 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
2801 // create render targets
2803 glGenTextures(2, rt_);
2805 for (int i = 0; i < 2; ++i)
2807 glBindTexture(GL_TEXTURE_2D, rt_[i]);
2808 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2809 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2810 glTexImage2D(GL_TEXTURE_2D, 0, GL_R32UI, s, s, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, NULL);
2811 glBindTexture(GL_TEXTURE_2D, 0);
2815 glGenFramebuffers(1, &fbo_);
2816 glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
2817 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt_[0], 0);
2818 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, rt_[1], 0);
2819 const GLenum draw_buffers[2] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 };
2820 glDrawBuffers(2, draw_buffers);
2821 glBindFramebuffer(GL_FRAMEBUFFER, 0);
2824 CreateQuad(&vao_, &vbo_, NULL);
2826 // init counter buffer
2827 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_);
2828 unsigned int* ptr = static_cast<unsigned int*>(
2829 glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 8, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT));
2832 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
2835 glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
2836 glViewport(0, 0, s, s);
2837 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, counter_buffer_);
2838 glUseProgram(prog_);
2839 glBindVertexArray(vao_);
2841 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
2842 glMemoryBarrier(GL_ATOMIC_COUNTER_BARRIER_BIT);
2843 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
2844 glMemoryBarrier(GL_ATOMIC_COUNTER_BARRIER_BIT);
2845 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
2846 glMemoryBarrier(GL_ATOMIC_COUNTER_BARRIER_BIT);
2847 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
2851 glReadBuffer(GL_COLOR_ATTACHMENT0);
2852 glReadPixels(0, 0, s, s, GL_RGBA_INTEGER, GL_UNSIGNED_INT, data);
2853 if (!CheckCounterValues(s * s, data, s * s * 3))
2856 glReadBuffer(GL_COLOR_ATTACHMENT1);
2857 glReadPixels(0, 0, s, s, GL_RGBA_INTEGER, GL_UNSIGNED_INT, data);
2858 if (!CheckCounterValues(s * s, data, 0))
2861 if (!CheckFinalCounterValue(counter_buffer_, 0, 256))
2863 if (!CheckFinalCounterValue(counter_buffer_, 4, 0))
2869 virtual long Cleanup()
2871 glDeleteFramebuffers(1, &fbo_);
2872 glDeleteTextures(2, rt_);
2873 glViewport(0, 0, getWindowWidth(), getWindowHeight());
2874 glDeleteBuffers(1, &counter_buffer_);
2875 glDeleteVertexArrays(1, &vao_);
2876 glDeleteBuffers(1, &vbo_);
2877 glDeleteProgram(prog_);
2883 class NegativeSSBO : public BasicUsageCS
2885 virtual std::string Title()
2887 return NL "GLSL errors";
2889 virtual std::string Purpose()
2891 return NL "Verify that atomic counters cannot be declared in the buffer block.";
2893 virtual std::string Method()
2897 virtual std::string PassCriteria()
2904 virtual long Setup()
2912 const char* const glsl_cs =
2913 NL "layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;" NL
2914 "layout(binding = 0, offset = 0) uniform atomic_uint ac_counter_dec;" NL
2915 "layout(std430) buffer Output {" NL " mediump uint data_inc[256];" NL " mediump uint data_dec[256];" NL
2916 " layout(binding = 0, offset = 16) uniform atomic_uint ac_counter0;" NL "} g_out;" NL "void main() {" NL
2917 " mediump uint offset = 32u * gl_GlobalInvocationID.y + gl_GlobalInvocationID.x;" NL
2918 " g_out.data_inc[offset] = atomicCounterIncrement(ac_counter0);" NL
2919 " g_out.data_dec[offset] = atomicCounterDecrement(ac_counter_dec);" NL "}";
2921 prog_ = CreateComputeProgram(glsl_cs);
2922 glLinkProgram(prog_);
2923 if (CheckProgram(prog_))
2925 Output("Link should fail because atomic counters cannot be declared in the buffer block.\n");
2930 virtual long Cleanup()
2932 glDeleteProgram(prog_);
2937 class NegativeUBO : public BasicUsageCS
2939 virtual std::string Title()
2941 return NL "GLSL errors";
2943 virtual std::string Purpose()
2945 return NL "Verify that atomic counters cannot be declared in uniform block.";
2947 virtual std::string Method()
2951 virtual std::string PassCriteria()
2958 virtual long Setup()
2966 const char* const glsl_cs =
2967 NL "layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;" NL "uniform Block {" NL
2968 " uniform atomic_uint ac_counter;" NL "};" NL "layout(std430) buffer Output {" NL
2969 " mediump uint data_inc[256];" NL "} g_out;" NL "void main() {" NL
2970 " mediump uint offset = 32u * gl_GlobalInvocationID.y + gl_GlobalInvocationID.x;" NL
2971 " g_out.data_inc[offset] = atomicCounterIncrement(ac_counter);" NL "}";
2973 prog_ = CreateComputeProgram(glsl_cs);
2974 glLinkProgram(prog_);
2975 if (CheckProgram(prog_))
2977 Output("Link should fail because atomic counters cannot be declared in the uniform block.\n");
2983 virtual long Cleanup()
2985 glDeleteProgram(prog_);
2990 class BasicUsageNoOffset : public BasicUsageCS
2992 virtual std::string Title()
2994 return NL "Atomic Counters usage in the Compute Shader stage";
2996 virtual std::string Purpose()
2998 return NL "Verify that atomic counters work as expected in the Compute Shader stage when decalred with no "
2999 "offset qualifier." NL "In particular make sure that values returned by GLSL built-in functions" NL
3000 "atomicCounterIncrement and atomicCounterDecrement are unique in every shader invocation." NL
3001 "Also make sure that the final values in atomic counter buffer objects are as expected.";
3003 virtual std::string Method()
3007 virtual std::string PassCriteria()
3012 GLuint counter_buffer_;
3016 virtual long Setup()
3018 counter_buffer_ = 0;
3027 const char* const glsl_cs =
3028 NL "layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;" NL
3029 "layout(binding = 0) uniform atomic_uint ac_counter_inc;" NL
3030 "layout(binding = 0) uniform atomic_uint ac_counter_dec;" NL "layout(std430) buffer Output {" NL
3031 " mediump uint data_inc[256];" NL " mediump uint data_dec[256];" NL "} g_out;" NL "void main() {" NL
3032 " mediump uint offset = 32u * gl_GlobalInvocationID.y + gl_GlobalInvocationID.x;" NL
3033 " g_out.data_inc[offset] = atomicCounterIncrement(ac_counter_inc);" NL
3034 " g_out.data_dec[offset] = atomicCounterDecrement(ac_counter_dec);" NL "}";
3035 prog_ = CreateComputeProgram(glsl_cs);
3036 glLinkProgram(prog_);
3037 if (!CheckProgram(prog_))
3040 // create atomic counter buffer
3041 glGenBuffers(1, &counter_buffer_);
3042 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, counter_buffer_);
3043 glBufferData(GL_ATOMIC_COUNTER_BUFFER, 8, NULL, GL_DYNAMIC_COPY);
3044 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
3046 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_);
3047 unsigned int* ptr = static_cast<unsigned int*>(
3048 glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 8, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT));
3051 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
3053 glGenBuffers(1, &m_buffer);
3054 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer);
3055 glBufferData(GL_SHADER_STORAGE_BUFFER, 512 * sizeof(GLuint), NULL, GL_DYNAMIC_DRAW);
3056 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
3058 glUseProgram(prog_);
3059 glDispatchCompute(4, 1, 1);
3061 long error = NO_ERROR;
3063 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_buffer);
3064 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
3065 data = static_cast<GLuint*>(
3066 glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 512 * sizeof(GLuint), GL_MAP_READ_BIT | GL_MAP_WRITE_BIT));
3068 std::sort(data, data + 512);
3069 for (int i = 0; i < 512; i += 2)
3071 if (data[i] != data[i + 1])
3073 Output("Pair of values should be equal, got: %d, %d\n", data[i], data[i + 1]);
3076 if (i < 510 && data[i] == data[i + 2])
3078 Output("Too many same values found: %d, index: %d\n", data[i], i);
3083 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
3084 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
3088 virtual long Cleanup()
3090 glDeleteBuffers(1, &counter_buffer_);
3091 glDeleteBuffers(1, &m_buffer);
3092 glDeleteProgram(prog_);
3098 class NegativeUniform : public SACSubcaseBase
3100 virtual std::string Title()
3102 return NL "GLSL errors";
3104 virtual std::string Purpose()
3106 return NL "Verify that atomicCounterIncrement/atomicCounterDecrement "
3107 "cannot be used on normal uniform.";
3109 virtual std::string Method()
3113 virtual std::string PassCriteria()
3120 virtual long Setup()
3129 glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS, &p1);
3130 glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTERS, &p2);
3131 if (p1 < 1 || p2 < 1)
3134 "GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS or GL_MAX_FRAGMENT_ATOMIC_COUNTERS are less than required");
3135 return NOT_SUPPORTED;
3139 const char* glsl_vs = "#version 310 es" NL "layout(location = 0) in vec4 i_vertex;" NL "void main() {" NL
3140 " gl_Position = i_vertex;" NL "}";
3142 const char* glsl_fs1 =
3143 "#version 310 es" NL "layout(location = 0) out uvec4 o_color[4];" NL "uniform uint ac_counter0;" NL
3144 "void main() {" NL " o_color[0] = uvec4(atomicCounterIncrement(ac_counter0));" NL "}";
3146 prog_ = glCreateProgram();
3148 GLuint sh = glCreateShader(GL_VERTEX_SHADER);
3149 glAttachShader(prog_, sh);
3150 glShaderSource(sh, 1, &glsl_vs, NULL);
3151 glCompileShader(sh);
3153 glGetShaderiv(sh, GL_COMPILE_STATUS, &status_comp);
3154 if (status_comp != GL_TRUE)
3156 Output("Unexpected error during vertex shader compilation.");
3161 sh = glCreateShader(GL_FRAGMENT_SHADER);
3162 glAttachShader(prog_, sh);
3163 glShaderSource(sh, 1, &glsl_fs1, NULL);
3164 glCompileShader(sh);
3165 glGetShaderiv(sh, GL_COMPILE_STATUS, &status_comp);
3169 glLinkProgram(prog_);
3170 glGetProgramiv(prog_, GL_LINK_STATUS, &status);
3171 if (status_comp == GL_TRUE && status == GL_TRUE)
3173 Output("Expected error during fragment shader compilation or linking.");
3178 virtual long Cleanup()
3180 glDeleteProgram(prog_);
3185 class NegativeArray : public BasicUsageCS
3187 virtual std::string Title()
3189 return NL "GLSL errors";
3191 virtual std::string Purpose()
3193 return NL "Verify that atomicCounterIncrement/atomicCounterDecrement "
3194 "cannot be used on array of atomic counters.";
3196 virtual std::string Method()
3200 virtual std::string PassCriteria()
3207 virtual long Setup()
3215 const char* const glsl_cs =
3216 NL "layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;" NL
3217 "layout(binding = 0) uniform atomic_uint ac_counter[3];" NL "layout(std430) buffer Output {" NL
3218 " mediump uint data_inc[256];" NL "} g_out;" NL "void main() {" NL
3219 " mediump uint offset = 32u * gl_GlobalInvocationID.y + gl_GlobalInvocationID.x;" NL
3220 " g_out.data_inc[offset] = atomicCounterIncrement(ac_counter);" NL "}";
3222 prog_ = CreateComputeProgram(glsl_cs);
3223 glLinkProgram(prog_);
3224 if (CheckProgram(prog_))
3226 Output("Link should fail because atomicCounterIncrement cannot be used on array of atomic counters.\n");
3231 virtual long Cleanup()
3233 glDeleteProgram(prog_);
3238 class NegativeArithmetic : public BasicUsageCS
3240 virtual std::string Title()
3242 return NL "GLSL errors";
3244 virtual std::string Purpose()
3246 return NL "Verify that standard arithmetic operations \n"
3247 "cannot be performed on atomic counters.";
3249 virtual std::string Method()
3253 virtual std::string PassCriteria()
3260 virtual long Setup()
3268 const char* const glsl_cs =
3269 NL "layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;" NL
3270 "layout(binding = 0) uniform atomic_uint ac_counter;" NL "layout(std430) buffer Output {" NL
3271 " mediump uint data_inc[256];" NL "} g_out;" NL "void main() {" NL
3272 " mediump uint offset = 32u * gl_GlobalInvocationID.y + gl_GlobalInvocationID.x;" NL
3273 " g_out.data_inc[offset] = ac_counter + 1;" NL "}";
3275 prog_ = CreateComputeProgram(glsl_cs);
3276 glLinkProgram(prog_);
3277 if (CheckProgram(prog_))
3280 "Link should fail because atomic counters cannot be incremented by standard arithmetic operations.\n");
3286 virtual long Cleanup()
3288 glDeleteProgram(prog_);
3293 class AdvancedManyDrawCalls2 : public SACSubcaseBase
3296 GLuint m_acbo, m_ssbo;
3298 GLuint m_ppo, m_vsp, m_fsp;
3300 virtual long Setup()
3302 glGenBuffers(1, &m_acbo);
3303 glGenBuffers(1, &m_ssbo);
3304 glGenVertexArrays(1, &m_vao);
3305 glGenProgramPipelines(1, &m_ppo);
3310 virtual long Cleanup()
3312 glDeleteBuffers(1, &m_acbo);
3313 glDeleteBuffers(1, &m_ssbo);
3314 glDeleteVertexArrays(1, &m_vao);
3315 glDeleteProgramPipelines(1, &m_ppo);
3316 glDeleteProgram(m_vsp);
3317 glDeleteProgram(m_fsp);
3325 glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS, &p1);
3326 glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTERS, &p2);
3327 if (p1 < 1 || p2 < 1)
3330 "GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS or GL_MAX_FRAGMENT_ATOMIC_COUNTERS are less than required");
3331 return NOT_SUPPORTED;
3334 const char* const glsl_vs = "#version 310 es" NL "void main() {" NL "#ifdef GL_ES" NL
3335 " gl_PointSize = 1.0f;" NL "#endif" NL " gl_Position = vec4(0, 0, 0, 1);" NL "}";
3336 const char* const glsl_fs =
3337 "#version 310 es" NL "layout(binding = 0) uniform atomic_uint g_counter;" NL
3338 "layout(std430, binding = 0) buffer Output {" NL " uint g_output[];" NL "};" NL "void main() {" NL
3339 " uint c = atomicCounterIncrement(g_counter);" NL " g_output[c] = c;" NL "}";
3341 m_vsp = glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &glsl_vs);
3342 m_fsp = glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, &glsl_fs);
3343 if (!CheckProgram(m_vsp) || !CheckProgram(m_fsp))
3346 glUseProgramStages(m_ppo, GL_VERTEX_SHADER_BIT, m_vsp);
3347 glUseProgramStages(m_ppo, GL_FRAGMENT_SHADER_BIT, m_fsp);
3349 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, m_acbo);
3352 glBufferData(GL_ATOMIC_COUNTER_BUFFER, 4, &data, GL_DYNAMIC_COPY);
3356 std::vector<GLuint> data(1000, 0xffff);
3357 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_ssbo);
3358 glBufferData(GL_SHADER_STORAGE_BUFFER, (GLsizeiptr)(data.size() * 4), &data[0], GL_DYNAMIC_READ);
3362 glViewport(0, 0, 1, 1);
3363 glBindProgramPipeline(m_ppo);
3364 glBindVertexArray(m_vao);
3365 for (int i = 0; i < 100; ++i)
3367 glDrawArrays(GL_POINTS, 0, 1);
3370 glViewport(0, 0, getWindowWidth(), getWindowHeight());
3372 long status = NO_ERROR;
3377 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_acbo);
3378 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
3379 data = static_cast<GLuint*>(glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 4, GL_MAP_READ_BIT));
3383 Output("AC buffer content is %u, sholud be 100.\n", data[0]);
3385 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
3386 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
3388 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_ssbo);
3389 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
3390 data = static_cast<GLuint*>(
3391 glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 100 * 4, GL_MAP_READ_BIT | GL_MAP_WRITE_BIT));
3392 std::sort(data, data + 100);
3393 for (GLuint i = 0; i < 100; ++i)
3398 Output("data[%u] is %u, should be %u.\n", i, data[i], i);
3401 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
3402 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
3409 class AdvancedUsageMultipleComputeDispatches : public SACSubcaseBase
3411 GLuint m_acbo, m_ssbo;
3412 GLuint m_ppo, m_csp;
3414 virtual long Setup()
3416 glGenBuffers(1, &m_acbo);
3417 glGenBuffers(1, &m_ssbo);
3418 glGenProgramPipelines(1, &m_ppo);
3423 virtual long Cleanup()
3425 glDeleteBuffers(1, &m_acbo);
3426 glDeleteBuffers(1, &m_ssbo);
3427 glDeleteProgramPipelines(1, &m_ppo);
3428 glDeleteProgram(m_csp);
3435 const char* const glsl_cs =
3436 "#version 310 es" NL "layout(local_size_x = 1) in;" NL
3437 "layout(binding = 0) uniform atomic_uint g_counter;" NL "layout(std430, binding = 0) buffer Output {" NL
3438 " mediump uint g_output[];" NL "};" NL "void main() {" NL
3439 " mediump uint c = atomicCounterIncrement(g_counter);" NL " g_output[c] = c;" NL "}";
3441 m_csp = glCreateShaderProgramv(GL_COMPUTE_SHADER, 1, &glsl_cs);
3442 if (!CheckProgram(m_csp))
3444 glUseProgramStages(m_ppo, GL_COMPUTE_SHADER_BIT, m_csp);
3446 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, m_acbo);
3449 glBufferData(GL_ATOMIC_COUNTER_BUFFER, 4, &data, GL_DYNAMIC_COPY);
3453 std::vector<GLuint> data(1000, 0xffff);
3454 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_ssbo);
3455 glBufferData(GL_SHADER_STORAGE_BUFFER, (GLsizeiptr)(data.size() * 4), &data[0], GL_DYNAMIC_READ);
3458 glBindProgramPipeline(m_ppo);
3459 for (int i = 0; i < 100; ++i)
3461 glDispatchCompute(1, 1, 1);
3464 long status = NO_ERROR;
3469 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_acbo);
3470 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
3471 data = static_cast<GLuint*>(glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 4, GL_MAP_READ_BIT));
3475 Output("AC buffer content is %u, sholud be 100.\n", data[0]);
3477 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
3478 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
3480 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_ssbo);
3481 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
3482 data = static_cast<GLuint*>(
3483 glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 100 * 4, GL_MAP_READ_BIT | GL_MAP_WRITE_BIT));
3484 std::sort(data, data + 100);
3485 for (GLuint i = 0; i < 100; ++i)
3490 Output("data[%u] is %u, should be %u.\n", i, data[i], i);
3493 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
3494 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
3501 class BasicGLSLBuiltIn : public BasicUsageCS
3504 virtual std::string Title()
3506 return NL "gl_Max* Check";
3508 virtual std::string Purpose()
3510 return NL "Verify that gl_Max*Counters and gl_Max*Bindings exist in glsl and their values are no lower" NL
3511 "than minimum required by the spec and are no different from their GL_MAX_* counterparts.";
3517 virtual long Setup()
3527 const char* const glsl_cs = NL
3528 "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;" NL "layout(std430) buffer Output {" NL
3529 " mediump uint data;" NL "} g_out;" NL "uniform mediump int m_vac;" NL "uniform mediump int m_fac;" NL
3530 "uniform mediump int m_csac;" NL "uniform mediump int m_cac;" NL "uniform mediump int m_abuf;" NL
3531 "void main() {" NL " mediump uint res = 1u;" NL
3532 " if (gl_MaxVertexAtomicCounters < 0 || gl_MaxVertexAtomicCounters != m_vac)" NL " res = res * 2u;" NL
3533 " if (gl_MaxFragmentAtomicCounters < 0 || gl_MaxFragmentAtomicCounters != m_fac)" NL
3534 " res = res * 3u;" NL
3535 " if (gl_MaxComputeAtomicCounters < 8 || gl_MaxComputeAtomicCounters != m_csac)" NL
3536 " res = res * 5u;" NL
3537 " if (gl_MaxCombinedAtomicCounters < 8 || gl_MaxCombinedAtomicCounters != m_cac)" NL
3538 " res = res * 7u;" NL
3539 " if (gl_MaxAtomicCounterBindings < 1 || gl_MaxAtomicCounterBindings != m_abuf)" NL
3540 " res = res * 11u;" NL " g_out.data = res;" NL "}";
3542 prog_ = CreateComputeProgram(glsl_cs);
3543 glLinkProgram(prog_);
3544 if (!CheckProgram(prog_))
3546 glUseProgram(prog_);
3553 glGetIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTERS, &m_vac);
3554 glUniform1i(glGetUniformLocation(prog_, "m_vac"), m_vac);
3555 glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTERS, &m_fac);
3556 glUniform1i(glGetUniformLocation(prog_, "m_fac"), m_fac);
3557 glGetIntegerv(GL_MAX_COMPUTE_ATOMIC_COUNTERS, &m_csac);
3558 glUniform1i(glGetUniformLocation(prog_, "m_csac"), m_csac);
3559 glGetIntegerv(GL_MAX_COMBINED_ATOMIC_COUNTERS, &m_cac);
3560 glUniform1i(glGetUniformLocation(prog_, "m_cac"), m_cac);
3561 glGetIntegerv(GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS, &m_abuf);
3562 glUniform1i(glGetUniformLocation(prog_, "m_abuf"), m_abuf);
3564 glGenBuffers(1, &m_buffer);
3565 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer);
3566 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLuint), NULL, GL_DYNAMIC_DRAW);
3567 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
3569 glDispatchCompute(1, 1, 1);
3571 long error = NO_ERROR;
3573 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_buffer);
3574 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
3575 data = static_cast<GLuint*>(glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(GLuint), GL_MAP_READ_BIT));
3578 Output("Expected 1, got: %d", data[0]);
3581 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
3582 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
3587 virtual long Cleanup()
3589 glDeleteBuffers(1, &m_buffer);
3590 glDeleteProgram(prog_);
3596 ShaderAtomicCountersTests::ShaderAtomicCountersTests(glcts::Context& context)
3597 : TestCaseGroup(context, "shader_atomic_counters", "")
3601 ShaderAtomicCountersTests::~ShaderAtomicCountersTests(void)
3605 void ShaderAtomicCountersTests::init()
3607 using namespace glcts;
3608 setOutput(m_context.getTestContext().getLog());
3609 addChild(new TestSubcase(m_context, "basic-buffer-operations", TestSubcase::Create<BasicBufferOperations>));
3610 addChild(new TestSubcase(m_context, "basic-buffer-state", TestSubcase::Create<BasicBufferState>));
3611 addChild(new TestSubcase(m_context, "basic-buffer-bind", TestSubcase::Create<BasicBufferBind>));
3612 addChild(new TestSubcase(m_context, "basic-program-max", TestSubcase::Create<BasicProgramMax>));
3613 addChild(new TestSubcase(m_context, "basic-program-query", TestSubcase::Create<BasicProgramQuery>));
3614 addChild(new TestSubcase(m_context, "basic-usage-simple", TestSubcase::Create<BasicUsageSimple>));
3615 addChild(new TestSubcase(m_context, "basic-usage-no-offset", TestSubcase::Create<BasicUsageNoOffset>));
3616 addChild(new TestSubcase(m_context, "basic-usage-fs", TestSubcase::Create<BasicUsageFS>));
3617 addChild(new TestSubcase(m_context, "basic-usage-vs", TestSubcase::Create<BasicUsageVS>));
3618 addChild(new TestSubcase(m_context, "basic-usage-cs", TestSubcase::Create<BasicUsageCS>));
3619 addChild(new TestSubcase(m_context, "basic-glsl-built-in", TestSubcase::Create<BasicGLSLBuiltIn>));
3620 addChild(new TestSubcase(m_context, "advanced-usage-multi-stage", TestSubcase::Create<AdvancedUsageMultiStage>));
3621 addChild(new TestSubcase(m_context, "advanced-usage-draw-update-draw",
3622 TestSubcase::Create<AdvancedUsageDrawUpdateDraw>));
3624 new TestSubcase(m_context, "advanced-usage-many-counters", TestSubcase::Create<AdvancedUsageManyCounters>));
3626 new TestSubcase(m_context, "advanced-usage-switch-programs", TestSubcase::Create<AdvancedUsageSwitchPrograms>));
3627 addChild(new TestSubcase(m_context, "advanced-usage-ubo", TestSubcase::Create<AdvancedUsageUBO>));
3628 addChild(new TestSubcase(m_context, "advanced-usage-many-draw-calls", TestSubcase::Create<AdvancedManyDrawCalls>));
3630 new TestSubcase(m_context, "advanced-usage-many-draw-calls2", TestSubcase::Create<AdvancedManyDrawCalls2>));
3631 addChild(new TestSubcase(m_context, "advanced-usage-many-dispatches",
3632 TestSubcase::Create<AdvancedUsageMultipleComputeDispatches>));
3633 addChild(new TestSubcase(m_context, "negative-api", TestSubcase::Create<NegativeAPI>));
3634 addChild(new TestSubcase(m_context, "negative-glsl", TestSubcase::Create<NegativeGLSL>));
3635 addChild(new TestSubcase(m_context, "negative-ssbo", TestSubcase::Create<NegativeSSBO>));
3636 addChild(new TestSubcase(m_context, "negative-ubo", TestSubcase::Create<NegativeUBO>));
3637 addChild(new TestSubcase(m_context, "negative-uniform", TestSubcase::Create<NegativeUniform>));
3638 addChild(new TestSubcase(m_context, "negative-array", TestSubcase::Create<NegativeArray>));
3639 addChild(new TestSubcase(m_context, "negative-arithmetic", TestSubcase::Create<NegativeArithmetic>));