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);
938 static_cast<GLuint*>(glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 512 * sizeof(GLuint), GL_MAP_READ_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 data = static_cast<GLuint*>(glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 32 * 4, GL_MAP_READ_BIT));
1804 if (!CheckCounterValues(32, data, 7))
1806 glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
1807 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0);
1809 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buffer_[1]);
1810 data = static_cast<GLuint*>(glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 32 * 4, GL_MAP_READ_BIT));
1811 if (!CheckCounterValues(32, data, 45))
1813 glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
1814 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0);
1816 if (!CheckFinalCounterValue(counter_buffer_[0], 0, 39))
1818 if (!CheckFinalCounterValue(counter_buffer_[1], 0, 45))
1823 virtual long Cleanup()
1825 glDeleteBuffers(2, counter_buffer_);
1826 glDeleteBuffers(2, xfb_buffer_);
1827 glDeleteBuffers(1, &array_buffer_);
1828 glDeleteVertexArrays(1, &vao_);
1829 glDeleteProgram(prog_);
1835 class AdvancedUsageMultiStage : public SACSubcaseBase
1837 virtual std::string Title()
1839 return NL "Same atomic counter accessed from multiple shader stages";
1841 virtual std::string Purpose()
1843 return NL "Same atomic counter is incremented (decremented) from two shader stages (VS and FS)." NL
1844 "Verify that this scenario works as expected. In particular ensure that all generated values are "
1845 "unique and" NL "final value in atomic counter buffer objects are as expected.";
1847 virtual std::string Method()
1851 virtual std::string PassCriteria()
1856 GLuint counter_buffer_;
1857 GLuint xfb_buffer_[2];
1860 GLuint fbo_, rt_[2];
1862 virtual long Setup()
1864 counter_buffer_ = 0;
1865 xfb_buffer_[0] = xfb_buffer_[1] = 0;
1868 fbo_ = rt_[0] = rt_[1] = 0;
1874 GLint p1, p2, p3, p4;
1875 glGetIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS, &p1);
1876 glGetIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTERS, &p2);
1877 glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS, &p3);
1878 glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTERS, &p4);
1879 if (p1 < 8 || p2 < 2 || p3 < 8 || p4 < 2)
1881 OutputNotSupported("GL_MAX_FRAGMENT/VERTEX_ATOMIC_COUNTER_BUFFERS or"
1882 "GL_MAX_FRAGMENT/VERTEX_ATOMIC_COUNTERS are less than required");
1883 return NOT_SUPPORTED;
1887 const char* src_vs =
1888 "#version 310 es" NL "layout(location = 0) in vec4 i_vertex;" NL "flat out uint o_atomic_inc;" NL
1889 "flat out uint o_atomic_dec;" NL "layout(binding = 1, offset = 16) uniform atomic_uint ac_counter_inc;" NL
1890 "layout(binding = 7, offset = 128) uniform atomic_uint ac_counter_dec;" NL "void main() {" NL
1891 " gl_Position = i_vertex;" NL " o_atomic_inc = atomicCounterIncrement(ac_counter_inc);" NL
1892 " o_atomic_dec = atomicCounterDecrement(ac_counter_dec);" NL "}";
1893 const char* src_fs = "#version 310 es" NL "layout(location = 0) out uvec4 o_color[2];" NL
1894 "layout(binding = 1, offset = 16) uniform atomic_uint ac_counter_inc;" NL
1895 "layout(binding = 7, offset = 128) uniform atomic_uint ac_counter_dec;" NL
1896 "void main() {" NL " o_color[0] = uvec4(atomicCounterIncrement(ac_counter_inc));" NL
1897 " o_color[1] = uvec4(atomicCounterDecrement(ac_counter_dec));" NL "}";
1898 prog_ = CreateProgram(src_vs, src_fs, false);
1899 const char* xfb_var[2] = { "o_atomic_inc", "o_atomic_dec" };
1900 glTransformFeedbackVaryings(prog_, 2, xfb_var, GL_SEPARATE_ATTRIBS);
1903 // create atomic counter buffer
1904 std::vector<GLuint> init_data(256, 100);
1905 glGenBuffers(1, &counter_buffer_);
1906 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_);
1907 glBufferData(GL_ATOMIC_COUNTER_BUFFER, (GLsizeiptr)(init_data.size() * sizeof(GLuint)), &init_data[0],
1909 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
1911 // create transform feedback buffers
1912 glGenBuffers(2, xfb_buffer_);
1913 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buffer_[0]);
1914 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 1000, NULL, GL_STREAM_COPY);
1915 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buffer_[1]);
1916 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 1000, NULL, GL_STREAM_COPY);
1917 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0);
1919 // create render targets
1921 glGenTextures(2, rt_);
1922 for (int i = 0; i < 2; ++i)
1924 glBindTexture(GL_TEXTURE_2D, rt_[i]);
1925 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1926 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1927 glTexImage2D(GL_TEXTURE_2D, 0, GL_R32UI, s, s, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, NULL);
1928 glBindTexture(GL_TEXTURE_2D, 0);
1932 glGenFramebuffers(1, &fbo_);
1933 glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
1934 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt_[0], 0);
1935 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, rt_[1], 0);
1936 const GLenum draw_buffers[2] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 };
1937 glDrawBuffers(2, draw_buffers);
1938 glBindFramebuffer(GL_FRAMEBUFFER, 0);
1941 CreateTriangle(&vao_, &vbo_, NULL);
1944 glBindBufferRange(GL_ATOMIC_COUNTER_BUFFER, 1, counter_buffer_, 16, 32);
1945 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 7, counter_buffer_);
1946 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, xfb_buffer_[0]);
1947 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 1, xfb_buffer_[1]);
1948 glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
1949 glViewport(0, 0, s, s);
1950 glUseProgram(prog_);
1951 glBindVertexArray(vao_);
1952 glBeginTransformFeedback(GL_TRIANGLES);
1953 glDrawArrays(GL_TRIANGLES, 0, 3);
1954 glEndTransformFeedback();
1957 UVec4 data[s * s + 3];
1958 glReadBuffer(GL_COLOR_ATTACHMENT0);
1959 glReadPixels(0, 0, s, s, GL_RGBA_INTEGER, GL_UNSIGNED_INT, data);
1960 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buffer_[0]);
1962 data2 = static_cast<GLuint*>(
1963 glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 3 * sizeof(GLuint), GL_MAP_READ_BIT));
1964 data[s * s] = UVec4(data2[0]);
1965 data[s * s + 1] = UVec4(data2[1]);
1966 data[s * s + 2] = UVec4(data2[2]);
1967 if (!CheckCounterValues(s * s + 3, data, 100))
1969 glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
1970 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0);
1972 glReadBuffer(GL_COLOR_ATTACHMENT1);
1973 glReadPixels(0, 0, s, s, GL_RGBA_INTEGER, GL_UNSIGNED_INT, data);
1974 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buffer_[1]);
1975 data2 = static_cast<GLuint*>(
1976 glMapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 3 * sizeof(GLuint), GL_MAP_READ_BIT));
1977 data[s * s] = UVec4(data2[0]);
1978 data[s * s + 1] = UVec4(data2[1]);
1979 data[s * s + 2] = UVec4(data2[2]);
1980 if (!CheckCounterValues(s * s + 3, data, 33))
1982 glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
1983 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0);
1985 if (!CheckFinalCounterValue(counter_buffer_, 32, 167))
1987 if (!CheckFinalCounterValue(counter_buffer_, 128, 33))
1992 virtual long Cleanup()
1994 glDeleteFramebuffers(1, &fbo_);
1995 glDeleteTextures(2, rt_);
1996 glViewport(0, 0, getWindowWidth(), getWindowHeight());
1997 glDeleteBuffers(1, &counter_buffer_);
1998 glDeleteBuffers(2, xfb_buffer_);
1999 glDeleteVertexArrays(1, &vao_);
2000 glDeleteBuffers(1, &vbo_);
2001 glDeleteProgram(prog_);
2007 class AdvancedUsageDrawUpdateDraw : public SACSubcaseBase
2009 virtual std::string Title()
2011 return NL "Update via Draw Call and update via MapBufferRange";
2013 virtual std::string Purpose()
2015 return NL "1. Create atomic counter buffers and init them with start values." NL
2016 "2. Increment (decrement) buffer values in the shader." NL
2017 "3. Map buffers with MapBufferRange command. Increment (decrement) buffer values manually." NL
2018 "4. Unmap buffers with UnmapBuffer command." NL
2019 "5. Again increment (decrement) buffer values in the shader." NL
2020 "Verify that this scenario works as expected and final values in the buffer objects are correct.";
2022 virtual std::string Method()
2026 virtual std::string PassCriteria()
2031 GLuint counter_buffer_;
2033 GLuint prog_, prog2_;
2034 GLuint fbo_, rt_[2];
2036 virtual long Setup()
2038 counter_buffer_ = 0;
2042 fbo_ = rt_[0] = rt_[1] = 0;
2049 glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS, &p1);
2050 glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTERS, &p2);
2051 if (p1 < 1 || p2 < 2)
2054 "GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS or GL_MAX_FRAGMENT_ATOMIC_COUNTERS are less than required");
2055 return NOT_SUPPORTED;
2059 const char* src_vs = "#version 310 es" NL "layout(location = 0) in vec4 i_vertex;" NL "void main() {" NL
2060 " gl_Position = i_vertex;" NL "}";
2061 const char* src_fs = "#version 310 es" NL "layout(location = 0) out uvec4 o_color[2];" NL
2062 "layout(binding = 0) uniform atomic_uint ac_counter[2];" NL "void main() {" NL
2063 " o_color[0] = uvec4(atomicCounterIncrement(ac_counter[0]));" NL
2064 " o_color[1] = uvec4(atomicCounterDecrement(ac_counter[1]));" NL "}";
2065 const char* src_fs2 = "#version 310 es" NL "layout(location = 0) out uvec4 o_color[2];" NL
2066 "layout(binding = 0) uniform atomic_uint ac_counter[2];" NL "void main() {" NL
2067 " o_color[0] = uvec4(atomicCounter(ac_counter[0]));" NL
2068 " o_color[1] = uvec4(atomicCounter(ac_counter[1]));" NL "}";
2069 prog_ = CreateProgram(src_vs, src_fs, true);
2070 prog2_ = CreateProgram(src_vs, src_fs2, true);
2072 // create atomic counter buffer
2073 glGenBuffers(1, &counter_buffer_);
2074 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_);
2075 glBufferData(GL_ATOMIC_COUNTER_BUFFER, 8, NULL, GL_DYNAMIC_COPY);
2076 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
2078 // create render targets
2080 glGenTextures(2, rt_);
2082 for (int i = 0; i < 2; ++i)
2084 glBindTexture(GL_TEXTURE_2D, rt_[i]);
2085 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2086 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2087 glTexImage2D(GL_TEXTURE_2D, 0, GL_R32UI, s, s, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, NULL);
2088 glBindTexture(GL_TEXTURE_2D, 0);
2092 glGenFramebuffers(1, &fbo_);
2093 glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
2094 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt_[0], 0);
2095 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, rt_[1], 0);
2096 const GLenum draw_buffers[2] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 };
2097 glDrawBuffers(2, draw_buffers);
2098 glBindFramebuffer(GL_FRAMEBUFFER, 0);
2101 CreateQuad(&vao_, &vbo_, NULL);
2103 // init counter buffer
2104 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_);
2105 unsigned int* ptr = static_cast<unsigned int*>(
2106 glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 8, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT));
2109 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
2112 glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
2113 glViewport(0, 0, s, s);
2114 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, counter_buffer_);
2115 glUseProgram(prog_);
2116 glBindVertexArray(vao_);
2117 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
2119 // update counter buffer
2120 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_);
2121 ptr = static_cast<unsigned int*>(
2122 glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 8, GL_MAP_WRITE_BIT | GL_MAP_READ_BIT));
2125 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
2128 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
2129 glMemoryBarrier(GL_ATOMIC_COUNTER_BARRIER_BIT);
2132 glUseProgram(prog2_);
2133 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
2137 glReadBuffer(GL_COLOR_ATTACHMENT0);
2138 glReadPixels(0, 0, s, s, GL_RGBA_INTEGER, GL_UNSIGNED_INT, data);
2139 for (int i = 0; i < s * s; ++i)
2141 if (data[i].x() != 896)
2143 Output("Counter value is %u should be %u.\n", data[i].x(), 896);
2148 glReadBuffer(GL_COLOR_ATTACHMENT1);
2149 glReadPixels(0, 0, s, s, GL_RGBA_INTEGER, GL_UNSIGNED_INT, data);
2150 for (int i = 0; i < s * s; ++i)
2152 if (data[i].x() != 1152)
2154 Output("Counter value is %u should be %u.\n", data[i].x(), 896);
2159 if (!CheckFinalCounterValue(counter_buffer_, 0, 896))
2161 if (!CheckFinalCounterValue(counter_buffer_, 4, 1152))
2166 virtual long Cleanup()
2168 glDeleteFramebuffers(1, &fbo_);
2169 glDeleteTextures(2, rt_);
2170 glViewport(0, 0, getWindowWidth(), getWindowHeight());
2171 glDeleteBuffers(1, &counter_buffer_);
2172 glDeleteVertexArrays(1, &vao_);
2173 glDeleteBuffers(1, &vbo_);
2174 glDeleteProgram(prog_);
2175 glDeleteProgram(prog2_);
2181 class AdvancedUsageManyCounters : public BasicUsageCS
2183 virtual std::string Title()
2185 return NL "Large atomic counters array indexed with uniforms";
2187 virtual std::string Purpose()
2189 return NL "Verify that large atomic counters array works as expected when indexed with dynamically uniform "
2191 "Built-ins tested: atomicCounterIncrement, atomicCounterDecrement and atomicCounter.";
2193 virtual std::string Method()
2197 virtual std::string PassCriteria()
2202 GLuint counter_buffer_, m_ssbo;
2205 virtual long Setup()
2207 counter_buffer_ = 0;
2216 const char* glsl_cs = NL
2217 "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;" NL "layout(std430) buffer Output {" NL
2218 " mediump uvec4 data1[64];" NL " mediump uvec4 data2[64];" NL " mediump uvec4 data3[64];" NL
2219 " mediump uvec4 data4[64];" NL " mediump uvec4 data5[64];" NL " mediump uvec4 data6[64];" NL
2220 " mediump uvec4 data7[64];" NL " mediump uvec4 data8[64];" NL "} g_out;" NL
2221 "uniform mediump int u_active_counters[8];" NL "layout(binding = 0) uniform atomic_uint ac_counter[8];" NL
2222 "void main() {" NL " mediump uint offset = 8u * gl_GlobalInvocationID.y + gl_GlobalInvocationID.x;" NL
2223 " g_out.data1[offset] = uvec4(atomicCounterIncrement(ac_counter[u_active_counters[0]]));" NL
2224 " g_out.data2[offset] = uvec4(atomicCounterDecrement(ac_counter[u_active_counters[1]]));" NL
2225 " g_out.data3[offset] = uvec4(atomicCounter(ac_counter[u_active_counters[2]]));" NL
2226 " g_out.data4[offset] = uvec4(atomicCounterIncrement(ac_counter[u_active_counters[3]]));" NL
2227 " g_out.data5[offset] = uvec4(atomicCounterDecrement(ac_counter[u_active_counters[4]]));" NL
2228 " g_out.data6[offset] = uvec4(atomicCounter(ac_counter[u_active_counters[5]]));" NL
2229 " g_out.data7[offset] = uvec4(atomicCounterIncrement(ac_counter[u_active_counters[6]]));" NL
2230 " g_out.data8[offset] = uvec4(atomicCounterIncrement(ac_counter[u_active_counters[7]]));" NL "}";
2232 prog_ = CreateComputeProgram(glsl_cs);
2233 glLinkProgram(prog_);
2234 if (!CheckProgram(prog_))
2237 // create atomic counter buffer
2238 std::vector<GLuint> init_data(1024, 1000);
2239 glGenBuffers(1, &counter_buffer_);
2240 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_);
2241 glBufferData(GL_ATOMIC_COUNTER_BUFFER, 1024 * sizeof(GLuint), &init_data[0], GL_DYNAMIC_COPY);
2242 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
2244 glGenBuffers(1, &m_ssbo);
2245 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_ssbo);
2246 glBufferData(GL_SHADER_STORAGE_BUFFER, 8 * 64 * sizeof(UVec4), NULL, GL_DYNAMIC_DRAW);
2247 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
2250 glUseProgram(prog_);
2251 glUniform1i(glGetUniformLocation(prog_, "u_active_counters[0]"), 0);
2252 glUniform1i(glGetUniformLocation(prog_, "u_active_counters[1]"), 1);
2253 glUniform1i(glGetUniformLocation(prog_, "u_active_counters[2]"), 2);
2254 glUniform1i(glGetUniformLocation(prog_, "u_active_counters[3]"), 3);
2255 glUniform1i(glGetUniformLocation(prog_, "u_active_counters[4]"), 4);
2256 glUniform1i(glGetUniformLocation(prog_, "u_active_counters[5]"), 5);
2257 glUniform1i(glGetUniformLocation(prog_, "u_active_counters[6]"), 6);
2258 glUniform1i(glGetUniformLocation(prog_, "u_active_counters[7]"), 7);
2261 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, counter_buffer_);
2262 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_ssbo);
2263 glDispatchCompute(8, 8, 1);
2266 glMemoryBarrier(GL_ATOMIC_COUNTER_BARRIER_BIT | GL_SHADER_STORAGE_BARRIER_BIT);
2268 long error = NO_ERROR;
2270 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_ssbo);
2271 data = static_cast<UVec4*>(glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 64 * sizeof(UVec4), GL_MAP_READ_BIT));
2272 if (!CheckCounterValues(8 * 8, data, 1000))
2274 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
2275 if (!CheckFinalCounterValue(counter_buffer_, 0, 1064))
2278 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_ssbo);
2279 data = static_cast<UVec4*>(
2280 glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 64 * sizeof(UVec4), 64 * sizeof(UVec4), GL_MAP_READ_BIT));
2281 if (!CheckCounterValues(8 * 8, data, 1000 - 64))
2283 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
2284 if (!CheckFinalCounterValue(counter_buffer_, 1 * sizeof(GLuint), 1000 - 64))
2287 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_ssbo);
2288 data = static_cast<UVec4*>(
2289 glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 64 * sizeof(UVec4) * 2, 64 * sizeof(UVec4), GL_MAP_READ_BIT));
2290 for (int i = 0; i < 8 * 8; ++i)
2291 if (data[i].x() != 1000)
2293 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
2294 if (!CheckFinalCounterValue(counter_buffer_, 2 * sizeof(GLuint), 1000))
2297 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_ssbo);
2298 data = static_cast<UVec4*>(
2299 glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 64 * sizeof(UVec4) * 3, 64 * sizeof(UVec4), GL_MAP_READ_BIT));
2300 if (!CheckCounterValues(8 * 8, data, 1000))
2302 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
2303 if (!CheckFinalCounterValue(counter_buffer_, 3 * sizeof(GLuint), 1064))
2306 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_ssbo);
2307 data = static_cast<UVec4*>(
2308 glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 64 * sizeof(UVec4) * 4, 64 * sizeof(UVec4), GL_MAP_READ_BIT));
2309 if (!CheckCounterValues(8 * 8, data, 1000 - 64))
2311 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
2312 if (!CheckFinalCounterValue(counter_buffer_, 4 * sizeof(GLuint), 1000 - 64))
2315 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_ssbo);
2316 data = static_cast<UVec4*>(
2317 glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 64 * sizeof(UVec4) * 5, 64 * sizeof(UVec4), GL_MAP_READ_BIT));
2318 for (int i = 0; i < 8 * 8; ++i)
2319 if (data[i].x() != 1000)
2321 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
2322 if (!CheckFinalCounterValue(counter_buffer_, 5 * sizeof(GLuint), 1000))
2325 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_ssbo);
2326 data = static_cast<UVec4*>(
2327 glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 64 * sizeof(UVec4) * 6, 64 * sizeof(UVec4), GL_MAP_READ_BIT));
2328 if (!CheckCounterValues(8 * 8, data, 1000))
2330 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
2331 if (!CheckFinalCounterValue(counter_buffer_, 6 * sizeof(GLuint), 1064))
2334 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_ssbo);
2335 data = static_cast<UVec4*>(
2336 glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 64 * sizeof(UVec4) * 7, 64 * sizeof(UVec4), GL_MAP_READ_BIT));
2337 if (!CheckCounterValues(8 * 8, data, 1000))
2339 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
2340 if (!CheckFinalCounterValue(counter_buffer_, 7 * sizeof(GLuint), 1064))
2343 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
2344 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
2348 virtual long Cleanup()
2350 glDeleteBuffers(1, &counter_buffer_);
2351 glDeleteBuffers(1, &m_ssbo);
2352 glDeleteProgram(prog_);
2358 class AdvancedUsageSwitchPrograms : public SACSubcaseBase
2360 virtual std::string Title()
2362 return NL "Switching several program objects with different atomic counters with different bindings";
2364 virtual std::string Purpose()
2366 return NL "Verify that each program upadate atomic counter buffer object in appropriate binding point.";
2368 virtual std::string Method()
2372 virtual std::string PassCriteria()
2377 GLuint counter_buffer_[8];
2383 std::string GenVSSrc(int binding, int offset)
2385 std::ostringstream os;
2386 os << "#version 310 es" NL "layout(location = 0) in vec4 i_vertex;" NL "flat out uvec4 o_atomic_value;" NL
2388 << binding << ", offset = " << offset
2389 << ") uniform atomic_uint ac_counter_vs;" NL "void main() {" NL " gl_Position = i_vertex;" NL
2390 " o_atomic_value = uvec4(atomicCounterIncrement(ac_counter_vs));" NL "}";
2393 std::string GenFSSrc(int binding, int offset)
2395 std::ostringstream os;
2396 os << "#version 310 es" NL "layout(location = 0) out uvec4 o_color;" NL "layout(binding = " << binding
2397 << ", offset = " << offset << ") uniform atomic_uint ac_counter_fs;" NL "void main() {" NL
2398 " o_color = uvec4(atomicCounterIncrement(ac_counter_fs));" NL "}";
2401 virtual long Setup()
2403 memset(counter_buffer_, 0, sizeof(counter_buffer_));
2406 memset(prog_, 0, sizeof(prog_));
2413 GLint p1, p2, p3, p4;
2414 glGetIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS, &p1);
2415 glGetIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTERS, &p2);
2416 glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS, &p3);
2417 glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTERS, &p4);
2418 if (p1 < 8 || p2 < 1 || p3 < 8 || p4 < 1)
2420 OutputNotSupported("GL_MAX_*_ATOMIC_COUNTER_BUFFERS or GL_MAX_*_ATOMIC_COUNTERS are less than required");
2421 return NOT_SUPPORTED;
2425 for (int i = 0; i < 8; ++i)
2427 std::string vs_str = GenVSSrc(i, i * 8);
2428 std::string fs_str = GenFSSrc(7 - i, 128 + i * 16);
2429 const char* src_vs = vs_str.c_str();
2430 const char* src_fs = fs_str.c_str();
2431 prog_[i] = CreateProgram(src_vs, src_fs, false);
2432 const char* xfb_var = "o_atomic_value";
2433 glTransformFeedbackVaryings(prog_[i], 1, &xfb_var, GL_SEPARATE_ATTRIBS);
2434 LinkProgram(prog_[i]);
2437 // create atomic counter buffers
2438 glGenBuffers(8, counter_buffer_);
2439 for (int i = 0; i < 8; ++i)
2441 std::vector<GLuint> init_data(256);
2442 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_[i]);
2443 glBufferData(GL_ATOMIC_COUNTER_BUFFER, (GLsizeiptr)(init_data.size() * sizeof(GLuint)), &init_data[0],
2446 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
2448 // create transform feedback buffer
2449 glGenBuffers(1, &xfb_buffer_);
2450 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buffer_);
2451 glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 1000, NULL, GL_STREAM_COPY);
2452 glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0);
2454 // create render target
2456 glGenTextures(1, &rt_);
2457 glBindTexture(GL_TEXTURE_2D, rt_);
2458 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2459 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2460 glTexImage2D(GL_TEXTURE_2D, 0, GL_R32UI, s, s, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, NULL);
2461 glBindTexture(GL_TEXTURE_2D, 0);
2464 glGenFramebuffers(1, &fbo_);
2465 glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
2466 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt_, 0);
2467 glBindFramebuffer(GL_FRAMEBUFFER, 0);
2470 CreateTriangle(&vao_, &vbo_, NULL);
2473 for (GLuint i = 0; i < 8; ++i)
2475 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, i, counter_buffer_[i]);
2477 glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, xfb_buffer_);
2478 glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
2479 glViewport(0, 0, s, s);
2480 glBindVertexArray(vao_);
2482 for (int i = 0; i < 8; ++i)
2484 glUseProgram(prog_[i]);
2485 glBeginTransformFeedback(GL_TRIANGLES);
2486 glDrawArrays(GL_TRIANGLES, 0, 3);
2487 glEndTransformFeedback();
2488 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
2490 if (!CheckFinalCounterValue(counter_buffer_[i], i * 8, 3))
2492 if (!CheckFinalCounterValue(counter_buffer_[7 - i], 128 + i * 16, 64))
2497 virtual long Cleanup()
2499 glDeleteFramebuffers(1, &fbo_);
2500 glDeleteTextures(1, &rt_);
2501 glViewport(0, 0, getWindowWidth(), getWindowHeight());
2502 glDeleteBuffers(8, counter_buffer_);
2503 glDeleteBuffers(1, &xfb_buffer_);
2504 glDeleteVertexArrays(1, &vao_);
2505 glDeleteBuffers(1, &vbo_);
2506 for (int i = 0; i < 8; ++i)
2507 glDeleteProgram(prog_[i]);
2513 class AdvancedUsageUBO : public BasicUsageCS
2515 virtual std::string Title()
2517 return NL "Atomic Counters used to access Uniform Buffer Objects";
2519 virtual std::string Purpose()
2521 return NL "Atomic counters are used to access UBOs. In that way each shader invocation can access UBO at "
2523 "This scenario is a base for some practical algorithms. Verify that it works as expected.";
2525 virtual std::string Method()
2529 virtual std::string PassCriteria()
2534 GLuint counter_buffer_, m_ssbo;
2535 GLuint uniform_buffer_;
2538 virtual long Setup()
2540 counter_buffer_ = 0;
2541 uniform_buffer_ = 0;
2550 const char* glsl_cs =
2551 NL "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;" NL "layout(std430) buffer Output {" NL
2552 " mediump uvec4 color[256];" NL "} g_out;" NL
2553 "layout(binding = 0, offset = 0) uniform atomic_uint ac_counter;" NL "layout(std140) uniform Data {" NL
2554 " mediump uint index[256];" NL "} ub_data;" NL "void main() {" NL
2555 " mediump uint offset = 16u * gl_GlobalInvocationID.y + gl_GlobalInvocationID.x;" NL
2556 " g_out.color[offset] = uvec4(ub_data.index[atomicCounterIncrement(ac_counter)]);" NL "}";
2557 prog_ = CreateComputeProgram(glsl_cs);
2558 glLinkProgram(prog_);
2559 if (!CheckProgram(prog_))
2561 glUniformBlockBinding(prog_, glGetUniformBlockIndex(prog_, "Data"), 1);
2563 // create atomic counter buffer
2564 const unsigned int z = 0;
2565 glGenBuffers(1, &counter_buffer_);
2566 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_);
2567 glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(z), &z, GL_DYNAMIC_COPY);
2568 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
2570 // create uniform buffer
2571 std::vector<UVec4> init_data(256);
2572 for (GLuint i = 0; i < 256; ++i)
2573 init_data[i] = UVec4(i);
2574 glGenBuffers(1, &uniform_buffer_);
2575 glBindBuffer(GL_UNIFORM_BUFFER, uniform_buffer_);
2576 glBufferData(GL_UNIFORM_BUFFER, (GLsizeiptr)(sizeof(UVec4) * init_data.size()), &init_data[0], GL_DYNAMIC_COPY);
2577 glBindBuffer(GL_UNIFORM_BUFFER, 0);
2579 glGenBuffers(1, &m_ssbo);
2580 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_ssbo);
2581 glBufferData(GL_SHADER_STORAGE_BUFFER, 256 * sizeof(UVec4), NULL, GL_DYNAMIC_DRAW);
2582 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
2585 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, counter_buffer_);
2586 glBindBufferBase(GL_UNIFORM_BUFFER, 1, uniform_buffer_);
2587 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_ssbo);
2588 glUseProgram(prog_);
2589 glDispatchCompute(16, 16, 1);
2593 long error = NO_ERROR;
2594 glMemoryBarrier(GL_UNIFORM_BARRIER_BIT | GL_SHADER_STORAGE_BARRIER_BIT | GL_ATOMIC_COUNTER_BARRIER_BIT);
2596 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_ssbo);
2597 data = static_cast<UVec4*>(glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 256 * sizeof(UVec4), GL_MAP_READ_BIT));
2598 if (!CheckCounterValues(16 * 16, data, 0))
2600 if (!CheckFinalCounterValue(counter_buffer_, 0, 256))
2602 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
2604 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
2605 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
2610 virtual long Cleanup()
2612 glDeleteBuffers(1, &counter_buffer_);
2613 glDeleteBuffers(1, &uniform_buffer_);
2614 glDeleteBuffers(1, &m_ssbo);
2615 glDeleteProgram(prog_);
2621 class NegativeAPI : public SACSubcaseBase
2623 virtual std::string Title()
2625 return NL "NegativeAPI";
2627 virtual std::string Purpose()
2629 return NL "Verify errors reported by BindBuffer* commands.";
2631 virtual std::string Method()
2635 virtual std::string PassCriteria()
2642 virtual long Setup()
2648 long error = NO_ERROR;
2650 glGetIntegerv(GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS, &res);
2651 glGenBuffers(1, &buffer);
2652 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, buffer);
2653 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, res, buffer);
2654 if (glGetError() != GL_INVALID_VALUE)
2656 Output("glBindBufferBase should generate INVALID_VALUE when"
2657 " index is greater than or equal GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS.\n");
2660 glBindBufferRange(GL_ATOMIC_COUNTER_BUFFER, res, buffer, 0, 4);
2661 if (glGetError() != GL_INVALID_VALUE)
2663 Output("glBindBufferRange should generate INVALID_VALUE when"
2664 " index is greater than or equal GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS.\n");
2667 glBindBufferRange(GL_ATOMIC_COUNTER_BUFFER, res - 1, buffer, 3, 4);
2668 if (glGetError() != GL_INVALID_VALUE)
2670 Output("glBindBufferRange should generate INVALID_VALUE when"
2671 " <offset> is not a multiple of four\n");
2676 virtual long Cleanup()
2678 glDeleteBuffers(1, &buffer);
2683 class NegativeGLSL : public BasicUsageCS
2685 virtual std::string Title()
2687 return NL "GLSL errors";
2689 virtual std::string Purpose()
2691 return NL "Verify that two different atomic counter uniforms with same binding cannot share same offset value.";
2693 virtual std::string Method()
2697 virtual std::string PassCriteria()
2704 virtual long Setup()
2712 const char* const glsl_cs = NL
2713 "layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;" NL
2714 "layout(binding = 0, offset = 4) uniform atomic_uint ac_counter_inc;" NL
2715 "layout(binding = 0, offset = 4) uniform atomic_uint ac_counter_dec;" NL "layout(std430) buffer Output {" NL
2716 " mediump uint data_inc[256];" NL " mediump uint data_dec[256];" NL "} g_out;" NL "void main() {" NL
2717 " mediump uint offset = 32u * gl_GlobalInvocationID.y + gl_GlobalInvocationID.x;" NL
2718 " g_out.data_inc[offset] = atomicCounterIncrement(ac_counter_inc);" NL
2719 " g_out.data_dec[offset] = atomicCounterDecrement(ac_counter_dec);" NL "}";
2721 prog_ = CreateComputeProgram(glsl_cs);
2722 glLinkProgram(prog_);
2723 if (CheckProgram(prog_))
2725 Output("Link should fail because ac_counter0 and ac_counter2 uses same binding and same offset.\n");
2730 virtual long Cleanup()
2732 glDeleteProgram(prog_);
2737 class AdvancedManyDrawCalls : public SACSubcaseBase
2739 virtual std::string Title()
2741 return NL "Atomic Counters usage in multiple draw calls";
2743 virtual std::string Purpose()
2745 return NL "Verify atomic counters behaviour across multiple draw calls.";
2747 virtual std::string Method()
2751 virtual std::string PassCriteria()
2756 GLuint counter_buffer_;
2759 GLuint fbo_, rt_[2];
2761 virtual long Setup()
2763 counter_buffer_ = 0;
2766 fbo_ = rt_[0] = rt_[1] = 0;
2773 glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS, &p1);
2774 glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTERS, &p2);
2775 if (p1 < 1 || p2 < 2)
2778 "GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS or GL_MAX_FRAGMENT_ATOMIC_COUNTERS are less than required");
2779 return NOT_SUPPORTED;
2783 const char* src_vs = "#version 310 es" NL "layout(location = 0) in vec4 i_vertex;" NL "void main() {" NL
2784 " gl_Position = i_vertex;" NL "}";
2785 const char* src_fs = "#version 310 es" NL "layout(location = 0) out uvec4 o_color[2];" NL
2786 "layout(binding = 0, offset = 0) uniform atomic_uint ac_counter_inc;" NL
2787 "layout(binding = 0, offset = 4) uniform atomic_uint ac_counter_dec;" NL "void main() {" NL
2788 " o_color[0] = uvec4(atomicCounterIncrement(ac_counter_inc));" NL
2789 " o_color[1] = uvec4(atomicCounterDecrement(ac_counter_dec));" NL "}";
2790 prog_ = CreateProgram(src_vs, src_fs, true);
2792 // create atomic counter buffer
2793 glGenBuffers(1, &counter_buffer_);
2794 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_);
2795 glBufferData(GL_ATOMIC_COUNTER_BUFFER, 8, NULL, GL_DYNAMIC_COPY);
2796 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
2798 // create render targets
2800 glGenTextures(2, rt_);
2802 for (int i = 0; i < 2; ++i)
2804 glBindTexture(GL_TEXTURE_2D, rt_[i]);
2805 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2806 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2807 glTexImage2D(GL_TEXTURE_2D, 0, GL_R32UI, s, s, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, NULL);
2808 glBindTexture(GL_TEXTURE_2D, 0);
2812 glGenFramebuffers(1, &fbo_);
2813 glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
2814 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt_[0], 0);
2815 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, rt_[1], 0);
2816 const GLenum draw_buffers[2] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 };
2817 glDrawBuffers(2, draw_buffers);
2818 glBindFramebuffer(GL_FRAMEBUFFER, 0);
2821 CreateQuad(&vao_, &vbo_, NULL);
2823 // init counter buffer
2824 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_);
2825 unsigned int* ptr = static_cast<unsigned int*>(
2826 glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 8, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT));
2829 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
2832 glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
2833 glViewport(0, 0, s, s);
2834 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, counter_buffer_);
2835 glUseProgram(prog_);
2836 glBindVertexArray(vao_);
2838 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
2839 glMemoryBarrier(GL_ATOMIC_COUNTER_BARRIER_BIT);
2840 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
2841 glMemoryBarrier(GL_ATOMIC_COUNTER_BARRIER_BIT);
2842 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
2843 glMemoryBarrier(GL_ATOMIC_COUNTER_BARRIER_BIT);
2844 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
2848 glReadBuffer(GL_COLOR_ATTACHMENT0);
2849 glReadPixels(0, 0, s, s, GL_RGBA_INTEGER, GL_UNSIGNED_INT, data);
2850 if (!CheckCounterValues(s * s, data, s * s * 3))
2853 glReadBuffer(GL_COLOR_ATTACHMENT1);
2854 glReadPixels(0, 0, s, s, GL_RGBA_INTEGER, GL_UNSIGNED_INT, data);
2855 if (!CheckCounterValues(s * s, data, 0))
2858 if (!CheckFinalCounterValue(counter_buffer_, 0, 256))
2860 if (!CheckFinalCounterValue(counter_buffer_, 4, 0))
2866 virtual long Cleanup()
2868 glDeleteFramebuffers(1, &fbo_);
2869 glDeleteTextures(2, rt_);
2870 glViewport(0, 0, getWindowWidth(), getWindowHeight());
2871 glDeleteBuffers(1, &counter_buffer_);
2872 glDeleteVertexArrays(1, &vao_);
2873 glDeleteBuffers(1, &vbo_);
2874 glDeleteProgram(prog_);
2880 class NegativeSSBO : public BasicUsageCS
2882 virtual std::string Title()
2884 return NL "GLSL errors";
2886 virtual std::string Purpose()
2888 return NL "Verify that atomic counters cannot be declared in the buffer block.";
2890 virtual std::string Method()
2894 virtual std::string PassCriteria()
2901 virtual long Setup()
2909 const char* const glsl_cs =
2910 NL "layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;" NL
2911 "layout(binding = 0, offset = 0) uniform atomic_uint ac_counter_dec;" NL
2912 "layout(std430) buffer Output {" NL " mediump uint data_inc[256];" NL " mediump uint data_dec[256];" NL
2913 " layout(binding = 0, offset = 16) uniform atomic_uint ac_counter0;" NL "} g_out;" NL "void main() {" NL
2914 " mediump uint offset = 32u * gl_GlobalInvocationID.y + gl_GlobalInvocationID.x;" NL
2915 " g_out.data_inc[offset] = atomicCounterIncrement(ac_counter0);" NL
2916 " g_out.data_dec[offset] = atomicCounterDecrement(ac_counter_dec);" NL "}";
2918 prog_ = CreateComputeProgram(glsl_cs);
2919 glLinkProgram(prog_);
2920 if (CheckProgram(prog_))
2922 Output("Link should fail because atomic counters cannot be declared in the buffer block.\n");
2927 virtual long Cleanup()
2929 glDeleteProgram(prog_);
2934 class NegativeUBO : public BasicUsageCS
2936 virtual std::string Title()
2938 return NL "GLSL errors";
2940 virtual std::string Purpose()
2942 return NL "Verify that atomic counters cannot be declared in uniform block.";
2944 virtual std::string Method()
2948 virtual std::string PassCriteria()
2955 virtual long Setup()
2963 const char* const glsl_cs =
2964 NL "layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;" NL "uniform Block {" NL
2965 " uniform atomic_uint ac_counter;" NL "};" NL "layout(std430) buffer Output {" NL
2966 " mediump uint data_inc[256];" NL "} g_out;" NL "void main() {" NL
2967 " mediump uint offset = 32u * gl_GlobalInvocationID.y + gl_GlobalInvocationID.x;" NL
2968 " g_out.data_inc[offset] = atomicCounterIncrement(ac_counter);" NL "}";
2970 prog_ = CreateComputeProgram(glsl_cs);
2971 glLinkProgram(prog_);
2972 if (CheckProgram(prog_))
2974 Output("Link should fail because atomic counters cannot be declared in the uniform block.\n");
2980 virtual long Cleanup()
2982 glDeleteProgram(prog_);
2987 class BasicUsageNoOffset : public BasicUsageCS
2989 virtual std::string Title()
2991 return NL "Atomic Counters usage in the Compute Shader stage";
2993 virtual std::string Purpose()
2995 return NL "Verify that atomic counters work as expected in the Compute Shader stage when decalred with no "
2996 "offset qualifier." NL "In particular make sure that values returned by GLSL built-in functions" NL
2997 "atomicCounterIncrement and atomicCounterDecrement are unique in every shader invocation." NL
2998 "Also make sure that the final values in atomic counter buffer objects are as expected.";
3000 virtual std::string Method()
3004 virtual std::string PassCriteria()
3009 GLuint counter_buffer_;
3013 virtual long Setup()
3015 counter_buffer_ = 0;
3024 const char* const glsl_cs =
3025 NL "layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;" NL
3026 "layout(binding = 0) uniform atomic_uint ac_counter_inc;" NL
3027 "layout(binding = 0) uniform atomic_uint ac_counter_dec;" NL "layout(std430) buffer Output {" NL
3028 " mediump uint data_inc[256];" NL " mediump uint data_dec[256];" NL "} g_out;" NL "void main() {" NL
3029 " mediump uint offset = 32u * gl_GlobalInvocationID.y + gl_GlobalInvocationID.x;" NL
3030 " g_out.data_inc[offset] = atomicCounterIncrement(ac_counter_inc);" NL
3031 " g_out.data_dec[offset] = atomicCounterDecrement(ac_counter_dec);" NL "}";
3032 prog_ = CreateComputeProgram(glsl_cs);
3033 glLinkProgram(prog_);
3034 if (!CheckProgram(prog_))
3037 // create atomic counter buffer
3038 glGenBuffers(1, &counter_buffer_);
3039 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, counter_buffer_);
3040 glBufferData(GL_ATOMIC_COUNTER_BUFFER, 8, NULL, GL_DYNAMIC_COPY);
3041 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
3043 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_);
3044 unsigned int* ptr = static_cast<unsigned int*>(
3045 glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 8, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT));
3048 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
3050 glGenBuffers(1, &m_buffer);
3051 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer);
3052 glBufferData(GL_SHADER_STORAGE_BUFFER, 512 * sizeof(GLuint), NULL, GL_DYNAMIC_DRAW);
3053 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
3055 glUseProgram(prog_);
3056 glDispatchCompute(4, 1, 1);
3058 long error = NO_ERROR;
3060 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_buffer);
3061 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
3063 static_cast<GLuint*>(glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 512 * sizeof(GLuint), GL_MAP_READ_BIT));
3065 std::sort(data, data + 512);
3066 for (int i = 0; i < 512; i += 2)
3068 if (data[i] != data[i + 1])
3070 Output("Pair of values should be equal, got: %d, %d\n", data[i], data[i + 1]);
3073 if (i < 510 && data[i] == data[i + 2])
3075 Output("Too many same values found: %d, index: %d\n", data[i], i);
3080 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
3081 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
3085 virtual long Cleanup()
3087 glDeleteBuffers(1, &counter_buffer_);
3088 glDeleteBuffers(1, &m_buffer);
3089 glDeleteProgram(prog_);
3095 class NegativeUniform : public SACSubcaseBase
3097 virtual std::string Title()
3099 return NL "GLSL errors";
3101 virtual std::string Purpose()
3103 return NL "Verify that atomicCounterIncrement/atomicCounterDecrement "
3104 "cannot be used on normal uniform.";
3106 virtual std::string Method()
3110 virtual std::string PassCriteria()
3117 virtual long Setup()
3126 glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS, &p1);
3127 glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTERS, &p2);
3128 if (p1 < 1 || p2 < 1)
3131 "GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS or GL_MAX_FRAGMENT_ATOMIC_COUNTERS are less than required");
3132 return NOT_SUPPORTED;
3136 const char* glsl_vs = "#version 310 es" NL "layout(location = 0) in vec4 i_vertex;" NL "void main() {" NL
3137 " gl_Position = i_vertex;" NL "}";
3139 const char* glsl_fs1 =
3140 "#version 310 es" NL "layout(location = 0) out uvec4 o_color[4];" NL "uniform uint ac_counter0;" NL
3141 "void main() {" NL " o_color[0] = uvec4(atomicCounterIncrement(ac_counter0));" NL "}";
3143 prog_ = glCreateProgram();
3145 GLuint sh = glCreateShader(GL_VERTEX_SHADER);
3146 glAttachShader(prog_, sh);
3147 glShaderSource(sh, 1, &glsl_vs, NULL);
3148 glCompileShader(sh);
3150 glGetShaderiv(sh, GL_COMPILE_STATUS, &status_comp);
3151 if (status_comp != GL_TRUE)
3153 Output("Unexpected error during vertex shader compilation.");
3158 sh = glCreateShader(GL_FRAGMENT_SHADER);
3159 glAttachShader(prog_, sh);
3160 glShaderSource(sh, 1, &glsl_fs1, NULL);
3161 glCompileShader(sh);
3162 glGetShaderiv(sh, GL_COMPILE_STATUS, &status_comp);
3166 glLinkProgram(prog_);
3167 glGetProgramiv(prog_, GL_LINK_STATUS, &status);
3168 if (status_comp == GL_TRUE && status == GL_TRUE)
3170 Output("Expected error during fragment shader compilation or linking.");
3175 virtual long Cleanup()
3177 glDeleteProgram(prog_);
3182 class NegativeArray : public BasicUsageCS
3184 virtual std::string Title()
3186 return NL "GLSL errors";
3188 virtual std::string Purpose()
3190 return NL "Verify that atomicCounterIncrement/atomicCounterDecrement "
3191 "cannot be used on array of atomic counters.";
3193 virtual std::string Method()
3197 virtual std::string PassCriteria()
3204 virtual long Setup()
3212 const char* const glsl_cs =
3213 NL "layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;" NL
3214 "layout(binding = 0) uniform atomic_uint ac_counter[3];" NL "layout(std430) buffer Output {" NL
3215 " mediump uint data_inc[256];" NL "} g_out;" NL "void main() {" NL
3216 " mediump uint offset = 32u * gl_GlobalInvocationID.y + gl_GlobalInvocationID.x;" NL
3217 " g_out.data_inc[offset] = atomicCounterIncrement(ac_counter);" NL "}";
3219 prog_ = CreateComputeProgram(glsl_cs);
3220 glLinkProgram(prog_);
3221 if (CheckProgram(prog_))
3223 Output("Link should fail because atomicCounterIncrement cannot be used on array of atomic counters.\n");
3228 virtual long Cleanup()
3230 glDeleteProgram(prog_);
3235 class NegativeArithmetic : public BasicUsageCS
3237 virtual std::string Title()
3239 return NL "GLSL errors";
3241 virtual std::string Purpose()
3243 return NL "Verify that standard arithmetic operations \n"
3244 "cannot be performed on atomic counters.";
3246 virtual std::string Method()
3250 virtual std::string PassCriteria()
3257 virtual long Setup()
3265 const char* const glsl_cs =
3266 NL "layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;" NL
3267 "layout(binding = 0) uniform atomic_uint ac_counter;" NL "layout(std430) buffer Output {" NL
3268 " mediump uint data_inc[256];" NL "} g_out;" NL "void main() {" NL
3269 " mediump uint offset = 32u * gl_GlobalInvocationID.y + gl_GlobalInvocationID.x;" NL
3270 " g_out.data_inc[offset] = ac_counter + 1;" NL "}";
3272 prog_ = CreateComputeProgram(glsl_cs);
3273 glLinkProgram(prog_);
3274 if (CheckProgram(prog_))
3277 "Link should fail because atomic counters cannot be incremented by standard arithmetic operations.\n");
3283 virtual long Cleanup()
3285 glDeleteProgram(prog_);
3290 class AdvancedManyDrawCalls2 : public SACSubcaseBase
3293 GLuint m_acbo, m_ssbo;
3295 GLuint m_ppo, m_vsp, m_fsp;
3297 virtual long Setup()
3299 glGenBuffers(1, &m_acbo);
3300 glGenBuffers(1, &m_ssbo);
3301 glGenVertexArrays(1, &m_vao);
3302 glGenProgramPipelines(1, &m_ppo);
3307 virtual long Cleanup()
3309 glDeleteBuffers(1, &m_acbo);
3310 glDeleteBuffers(1, &m_ssbo);
3311 glDeleteVertexArrays(1, &m_vao);
3312 glDeleteProgramPipelines(1, &m_ppo);
3313 glDeleteProgram(m_vsp);
3314 glDeleteProgram(m_fsp);
3322 glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS, &p1);
3323 glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTERS, &p2);
3324 if (p1 < 1 || p2 < 1)
3327 "GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS or GL_MAX_FRAGMENT_ATOMIC_COUNTERS are less than required");
3328 return NOT_SUPPORTED;
3331 const char* const glsl_vs = "#version 310 es" NL "void main() {" NL "#ifdef GL_ES" NL
3332 " gl_PointSize = 1.0f;" NL "#endif" NL " gl_Position = vec4(0, 0, 0, 1);" NL "}";
3333 const char* const glsl_fs =
3334 "#version 310 es" NL "layout(binding = 0) uniform atomic_uint g_counter;" NL
3335 "layout(std430, binding = 0) buffer Output {" NL " uint g_output[];" NL "};" NL "void main() {" NL
3336 " uint c = atomicCounterIncrement(g_counter);" NL " g_output[c] = c;" NL "}";
3338 m_vsp = glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &glsl_vs);
3339 m_fsp = glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, &glsl_fs);
3340 if (!CheckProgram(m_vsp) || !CheckProgram(m_fsp))
3343 glUseProgramStages(m_ppo, GL_VERTEX_SHADER_BIT, m_vsp);
3344 glUseProgramStages(m_ppo, GL_FRAGMENT_SHADER_BIT, m_fsp);
3346 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, m_acbo);
3349 glBufferData(GL_ATOMIC_COUNTER_BUFFER, 4, &data, GL_DYNAMIC_COPY);
3353 std::vector<GLuint> data(1000, 0xffff);
3354 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_ssbo);
3355 glBufferData(GL_SHADER_STORAGE_BUFFER, (GLsizeiptr)(data.size() * 4), &data[0], GL_DYNAMIC_READ);
3359 glViewport(0, 0, 1, 1);
3360 glBindProgramPipeline(m_ppo);
3361 glBindVertexArray(m_vao);
3362 for (int i = 0; i < 100; ++i)
3364 glDrawArrays(GL_POINTS, 0, 1);
3367 glViewport(0, 0, getWindowWidth(), getWindowHeight());
3369 long status = NO_ERROR;
3374 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_acbo);
3375 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
3376 data = static_cast<GLuint*>(glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 4, GL_MAP_READ_BIT));
3380 Output("AC buffer content is %u, sholud be 100.\n", data[0]);
3382 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
3383 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
3385 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_ssbo);
3386 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
3387 data = static_cast<GLuint*>(glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 100 * 4, GL_MAP_READ_BIT));
3388 std::sort(data, data + 100);
3389 for (GLuint i = 0; i < 100; ++i)
3394 Output("data[%u] is %u, should be %u.\n", i, data[i], i);
3397 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
3398 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
3405 class AdvancedUsageMultipleComputeDispatches : public SACSubcaseBase
3407 GLuint m_acbo, m_ssbo;
3408 GLuint m_ppo, m_csp;
3410 virtual long Setup()
3412 glGenBuffers(1, &m_acbo);
3413 glGenBuffers(1, &m_ssbo);
3414 glGenProgramPipelines(1, &m_ppo);
3419 virtual long Cleanup()
3421 glDeleteBuffers(1, &m_acbo);
3422 glDeleteBuffers(1, &m_ssbo);
3423 glDeleteProgramPipelines(1, &m_ppo);
3424 glDeleteProgram(m_csp);
3431 const char* const glsl_cs =
3432 "#version 310 es" NL "layout(local_size_x = 1) in;" NL
3433 "layout(binding = 0) uniform atomic_uint g_counter;" NL "layout(std430, binding = 0) buffer Output {" NL
3434 " mediump uint g_output[];" NL "};" NL "void main() {" NL
3435 " mediump uint c = atomicCounterIncrement(g_counter);" NL " g_output[c] = c;" NL "}";
3437 m_csp = glCreateShaderProgramv(GL_COMPUTE_SHADER, 1, &glsl_cs);
3438 if (!CheckProgram(m_csp))
3440 glUseProgramStages(m_ppo, GL_COMPUTE_SHADER_BIT, m_csp);
3442 glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, m_acbo);
3445 glBufferData(GL_ATOMIC_COUNTER_BUFFER, 4, &data, GL_DYNAMIC_COPY);
3449 std::vector<GLuint> data(1000, 0xffff);
3450 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_ssbo);
3451 glBufferData(GL_SHADER_STORAGE_BUFFER, (GLsizeiptr)(data.size() * 4), &data[0], GL_DYNAMIC_READ);
3454 glBindProgramPipeline(m_ppo);
3455 for (int i = 0; i < 100; ++i)
3457 glDispatchCompute(1, 1, 1);
3460 long status = NO_ERROR;
3465 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_acbo);
3466 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
3467 data = static_cast<GLuint*>(glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 4, GL_MAP_READ_BIT));
3471 Output("AC buffer content is %u, sholud be 100.\n", data[0]);
3473 glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
3474 glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
3476 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_ssbo);
3477 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
3478 data = static_cast<GLuint*>(glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 100 * 4, GL_MAP_READ_BIT));
3479 std::sort(data, data + 100);
3480 for (GLuint i = 0; i < 100; ++i)
3485 Output("data[%u] is %u, should be %u.\n", i, data[i], i);
3488 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
3489 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
3496 class BasicGLSLBuiltIn : public BasicUsageCS
3499 virtual std::string Title()
3501 return NL "gl_Max* Check";
3503 virtual std::string Purpose()
3505 return NL "Verify that gl_Max*Counters and gl_Max*Bindings exist in glsl and their values are no lower" NL
3506 "than minimum required by the spec and are no different from their GL_MAX_* counterparts.";
3512 virtual long Setup()
3522 const char* const glsl_cs = NL
3523 "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;" NL "layout(std430) buffer Output {" NL
3524 " mediump uint data;" NL "} g_out;" NL "uniform mediump int m_vac;" NL "uniform mediump int m_fac;" NL
3525 "uniform mediump int m_csac;" NL "uniform mediump int m_cac;" NL "uniform mediump int m_abuf;" NL
3526 "void main() {" NL " mediump uint res = 1u;" NL
3527 " if (gl_MaxVertexAtomicCounters < 0 || gl_MaxVertexAtomicCounters != m_vac)" NL " res = res * 2u;" NL
3528 " if (gl_MaxFragmentAtomicCounters < 0 || gl_MaxFragmentAtomicCounters != m_fac)" NL
3529 " res = res * 3u;" NL
3530 " if (gl_MaxComputeAtomicCounters < 8 || gl_MaxComputeAtomicCounters != m_csac)" NL
3531 " res = res * 5u;" NL
3532 " if (gl_MaxCombinedAtomicCounters < 8 || gl_MaxCombinedAtomicCounters != m_cac)" NL
3533 " res = res * 7u;" NL
3534 " if (gl_MaxAtomicCounterBindings < 1 || gl_MaxAtomicCounterBindings != m_abuf)" NL
3535 " res = res * 11u;" NL " g_out.data = res;" NL "}";
3537 prog_ = CreateComputeProgram(glsl_cs);
3538 glLinkProgram(prog_);
3539 if (!CheckProgram(prog_))
3541 glUseProgram(prog_);
3548 glGetIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTERS, &m_vac);
3549 glUniform1i(glGetUniformLocation(prog_, "m_vac"), m_vac);
3550 glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTERS, &m_fac);
3551 glUniform1i(glGetUniformLocation(prog_, "m_fac"), m_fac);
3552 glGetIntegerv(GL_MAX_COMPUTE_ATOMIC_COUNTERS, &m_csac);
3553 glUniform1i(glGetUniformLocation(prog_, "m_csac"), m_csac);
3554 glGetIntegerv(GL_MAX_COMBINED_ATOMIC_COUNTERS, &m_cac);
3555 glUniform1i(glGetUniformLocation(prog_, "m_cac"), m_cac);
3556 glGetIntegerv(GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS, &m_abuf);
3557 glUniform1i(glGetUniformLocation(prog_, "m_abuf"), m_abuf);
3559 glGenBuffers(1, &m_buffer);
3560 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer);
3561 glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLuint), NULL, GL_DYNAMIC_DRAW);
3562 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
3564 glDispatchCompute(1, 1, 1);
3566 long error = NO_ERROR;
3568 glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_buffer);
3569 glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
3570 data = static_cast<GLuint*>(glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(GLuint), GL_MAP_READ_BIT));
3573 Output("Expected 1, got: %d", data[0]);
3576 glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
3577 glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
3582 virtual long Cleanup()
3584 glDeleteBuffers(1, &m_buffer);
3585 glDeleteProgram(prog_);
3591 ShaderAtomicCountersTests::ShaderAtomicCountersTests(glcts::Context& context)
3592 : TestCaseGroup(context, "shader_atomic_counters", "")
3596 ShaderAtomicCountersTests::~ShaderAtomicCountersTests(void)
3600 void ShaderAtomicCountersTests::init()
3602 using namespace glcts;
3603 setOutput(m_context.getTestContext().getLog());
3604 addChild(new TestSubcase(m_context, "basic-buffer-operations", TestSubcase::Create<BasicBufferOperations>));
3605 addChild(new TestSubcase(m_context, "basic-buffer-state", TestSubcase::Create<BasicBufferState>));
3606 addChild(new TestSubcase(m_context, "basic-buffer-bind", TestSubcase::Create<BasicBufferBind>));
3607 addChild(new TestSubcase(m_context, "basic-program-max", TestSubcase::Create<BasicProgramMax>));
3608 addChild(new TestSubcase(m_context, "basic-program-query", TestSubcase::Create<BasicProgramQuery>));
3609 addChild(new TestSubcase(m_context, "basic-usage-simple", TestSubcase::Create<BasicUsageSimple>));
3610 addChild(new TestSubcase(m_context, "basic-usage-no-offset", TestSubcase::Create<BasicUsageNoOffset>));
3611 addChild(new TestSubcase(m_context, "basic-usage-fs", TestSubcase::Create<BasicUsageFS>));
3612 addChild(new TestSubcase(m_context, "basic-usage-vs", TestSubcase::Create<BasicUsageVS>));
3613 addChild(new TestSubcase(m_context, "basic-usage-cs", TestSubcase::Create<BasicUsageCS>));
3614 addChild(new TestSubcase(m_context, "basic-glsl-built-in", TestSubcase::Create<BasicGLSLBuiltIn>));
3615 addChild(new TestSubcase(m_context, "advanced-usage-multi-stage", TestSubcase::Create<AdvancedUsageMultiStage>));
3616 addChild(new TestSubcase(m_context, "advanced-usage-draw-update-draw",
3617 TestSubcase::Create<AdvancedUsageDrawUpdateDraw>));
3619 new TestSubcase(m_context, "advanced-usage-many-counters", TestSubcase::Create<AdvancedUsageManyCounters>));
3621 new TestSubcase(m_context, "advanced-usage-switch-programs", TestSubcase::Create<AdvancedUsageSwitchPrograms>));
3622 addChild(new TestSubcase(m_context, "advanced-usage-ubo", TestSubcase::Create<AdvancedUsageUBO>));
3623 addChild(new TestSubcase(m_context, "advanced-usage-many-draw-calls", TestSubcase::Create<AdvancedManyDrawCalls>));
3625 new TestSubcase(m_context, "advanced-usage-many-draw-calls2", TestSubcase::Create<AdvancedManyDrawCalls2>));
3626 addChild(new TestSubcase(m_context, "advanced-usage-many-dispatches",
3627 TestSubcase::Create<AdvancedUsageMultipleComputeDispatches>));
3628 addChild(new TestSubcase(m_context, "negative-api", TestSubcase::Create<NegativeAPI>));
3629 addChild(new TestSubcase(m_context, "negative-glsl", TestSubcase::Create<NegativeGLSL>));
3630 addChild(new TestSubcase(m_context, "negative-ssbo", TestSubcase::Create<NegativeSSBO>));
3631 addChild(new TestSubcase(m_context, "negative-ubo", TestSubcase::Create<NegativeUBO>));
3632 addChild(new TestSubcase(m_context, "negative-uniform", TestSubcase::Create<NegativeUniform>));
3633 addChild(new TestSubcase(m_context, "negative-array", TestSubcase::Create<NegativeArray>));
3634 addChild(new TestSubcase(m_context, "negative-arithmetic", TestSubcase::Create<NegativeArithmetic>));