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