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