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