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
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 AdvancedUsageSwitchPrograms : public SACSubcaseBase
2422 {
Title()2423 	virtual std::string Title()
2424 	{
2425 		return NL "Switching several program objects with different atomic counters with different bindings";
2426 	}
Purpose()2427 	virtual std::string Purpose()
2428 	{
2429 		return NL "Verify that each program upadate atomic counter buffer object in appropriate binding point.";
2430 	}
Method()2431 	virtual std::string Method()
2432 	{
2433 		return NL "";
2434 	}
PassCriteria()2435 	virtual std::string PassCriteria()
2436 	{
2437 		return NL "";
2438 	}
2439 
2440 	GLuint counter_buffer_[8];
2441 	GLuint xfb_buffer_;
2442 	GLuint vao_, vbo_;
2443 	GLuint prog_[8];
2444 	GLuint fbo_, rt_;
2445 
GenVSSrc(int binding,int offset)2446 	std::string GenVSSrc(int binding, int offset)
2447 	{
2448 		std::ostringstream os;
2449 		os << "#version 310 es" NL "layout(location = 0) in vec4 i_vertex;" NL "flat out uvec4 o_atomic_value;" NL
2450 			  "layout(binding = "
2451 		   << binding << ", offset = " << offset
2452 		   << ") uniform atomic_uint ac_counter_vs;" NL "void main() {" NL "  gl_Position = i_vertex;" NL
2453 			  "  o_atomic_value = uvec4(atomicCounterIncrement(ac_counter_vs));" NL "}";
2454 		return os.str();
2455 	}
GenFSSrc(int binding,int offset)2456 	std::string GenFSSrc(int binding, int offset)
2457 	{
2458 		std::ostringstream os;
2459 		os << "#version 310 es" NL "layout(location = 0) out uvec4 o_color;" NL "layout(binding = " << binding
2460 		   << ", offset = " << offset << ") uniform atomic_uint ac_counter_fs;" NL "void main() {" NL
2461 										 "  o_color = uvec4(atomicCounterIncrement(ac_counter_fs));" NL "}";
2462 		return os.str();
2463 	}
Setup()2464 	virtual long Setup()
2465 	{
2466 		memset(counter_buffer_, 0, sizeof(counter_buffer_));
2467 		xfb_buffer_ = 0;
2468 		vao_ = vbo_ = 0;
2469 		memset(prog_, 0, sizeof(prog_));
2470 		fbo_ = rt_ = 0;
2471 		return NO_ERROR;
2472 	}
Run()2473 	virtual long Run()
2474 	{
2475 
2476 		GLint p1, p2, p3, p4;
2477 		glGetIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS, &p1);
2478 		glGetIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTERS, &p2);
2479 		glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS, &p3);
2480 		glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTERS, &p4);
2481 		if (p1 < 8 || p2 < 1 || p3 < 8 || p4 < 1)
2482 		{
2483 			OutputNotSupported("GL_MAX_*_ATOMIC_COUNTER_BUFFERS or GL_MAX_*_ATOMIC_COUNTERS are less than required");
2484 			return NOT_SUPPORTED;
2485 		}
2486 
2487 		// create programs
2488 		for (int i = 0; i < 8; ++i)
2489 		{
2490 			std::string vs_str  = GenVSSrc(i, i * 8);
2491 			std::string fs_str  = GenFSSrc(7 - i, 128 + i * 16);
2492 			const char* src_vs  = vs_str.c_str();
2493 			const char* src_fs  = fs_str.c_str();
2494 			prog_[i]			= CreateProgram(src_vs, src_fs, false);
2495 			const char* xfb_var = "o_atomic_value";
2496 			glTransformFeedbackVaryings(prog_[i], 1, &xfb_var, GL_SEPARATE_ATTRIBS);
2497 			LinkProgram(prog_[i]);
2498 		}
2499 
2500 		// create atomic counter buffers
2501 		glGenBuffers(8, counter_buffer_);
2502 		for (int i = 0; i < 8; ++i)
2503 		{
2504 			std::vector<GLuint> init_data(256);
2505 			glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_[i]);
2506 			glBufferData(GL_ATOMIC_COUNTER_BUFFER, (GLsizeiptr)(init_data.size() * sizeof(GLuint)), &init_data[0],
2507 						 GL_DYNAMIC_COPY);
2508 		}
2509 		glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
2510 
2511 		// create transform feedback buffer
2512 		glGenBuffers(1, &xfb_buffer_);
2513 		glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, xfb_buffer_);
2514 		glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 1000, NULL, GL_STREAM_COPY);
2515 		glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0);
2516 
2517 		// create render target
2518 		const int s = 8;
2519 		glGenTextures(1, &rt_);
2520 		glBindTexture(GL_TEXTURE_2D, rt_);
2521 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2522 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2523 		glTexImage2D(GL_TEXTURE_2D, 0, GL_R32UI, s, s, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, NULL);
2524 		glBindTexture(GL_TEXTURE_2D, 0);
2525 
2526 		// create fbo
2527 		glGenFramebuffers(1, &fbo_);
2528 		glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
2529 		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt_, 0);
2530 		glBindFramebuffer(GL_FRAMEBUFFER, 0);
2531 
2532 		// create geometry
2533 		CreateTriangle(&vao_, &vbo_, NULL);
2534 
2535 		// draw
2536 		for (GLuint i = 0; i < 8; ++i)
2537 		{
2538 			glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, i, counter_buffer_[i]);
2539 		}
2540 		glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, xfb_buffer_);
2541 		glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
2542 		glViewport(0, 0, s, s);
2543 		glBindVertexArray(vao_);
2544 
2545 		for (int i = 0; i < 8; ++i)
2546 		{
2547 			glUseProgram(prog_[i]);
2548 			glBeginTransformFeedback(GL_TRIANGLES);
2549 			glDrawArrays(GL_TRIANGLES, 0, 3);
2550 			glEndTransformFeedback();
2551 			glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
2552 
2553 			if (!CheckFinalCounterValue(counter_buffer_[i], i * 8, 3))
2554 				return ERROR;
2555 			if (!CheckFinalCounterValue(counter_buffer_[7 - i], 128 + i * 16, 64))
2556 				return ERROR;
2557 		}
2558 		return NO_ERROR;
2559 	}
Cleanup()2560 	virtual long Cleanup()
2561 	{
2562 		glDeleteFramebuffers(1, &fbo_);
2563 		glDeleteTextures(1, &rt_);
2564 		glViewport(0, 0, getWindowWidth(), getWindowHeight());
2565 		glDeleteBuffers(8, counter_buffer_);
2566 		glDeleteBuffers(1, &xfb_buffer_);
2567 		glDeleteVertexArrays(1, &vao_);
2568 		glDeleteBuffers(1, &vbo_);
2569 		for (int i = 0; i < 8; ++i)
2570 			glDeleteProgram(prog_[i]);
2571 		glUseProgram(0);
2572 		return NO_ERROR;
2573 	}
2574 };
2575 
2576 class AdvancedUsageUBO : public BasicUsageCS
2577 {
Title()2578 	virtual std::string Title()
2579 	{
2580 		return NL "Atomic Counters used to access Uniform Buffer Objects";
2581 	}
Purpose()2582 	virtual std::string Purpose()
2583 	{
2584 		return NL "Atomic counters are used to access UBOs. In that way each shader invocation can access UBO at "
2585 				  "unique offset." NL
2586 				  "This scenario is a base for some practical algorithms. Verify that it works as expected.";
2587 	}
Method()2588 	virtual std::string Method()
2589 	{
2590 		return NL "";
2591 	}
PassCriteria()2592 	virtual std::string PassCriteria()
2593 	{
2594 		return NL "";
2595 	}
2596 
2597 	GLuint counter_buffer_, m_ssbo;
2598 	GLuint uniform_buffer_;
2599 	GLuint prog_;
2600 
Setup()2601 	virtual long Setup()
2602 	{
2603 		counter_buffer_ = 0;
2604 		uniform_buffer_ = 0;
2605 		m_ssbo			= 0;
2606 		prog_			= 0;
2607 		return NO_ERROR;
2608 	}
2609 
Run()2610 	virtual long Run()
2611 	{
2612 		// create program
2613 		const char* glsl_cs =
2614 			NL "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;" NL "layout(std430) buffer Output {" NL
2615 			   "  mediump uvec4 color[256];" NL "} g_out;" NL
2616 			   "layout(binding = 0, offset = 0) uniform atomic_uint ac_counter;" NL "layout(std140) uniform Data {" NL
2617 			   "  mediump uint index[256];" NL "} ub_data;" NL "void main() {" NL
2618 			   "  mediump uint offset = 16u * gl_GlobalInvocationID.y + gl_GlobalInvocationID.x;" NL
2619 			   "  g_out.color[offset] = uvec4(ub_data.index[atomicCounterIncrement(ac_counter)]);" NL "}";
2620 		prog_ = CreateComputeProgram(glsl_cs);
2621 		glLinkProgram(prog_);
2622 		if (!CheckProgram(prog_))
2623 			return ERROR;
2624 		glUniformBlockBinding(prog_, glGetUniformBlockIndex(prog_, "Data"), 1);
2625 
2626 		// create atomic counter buffer
2627 		const unsigned int z = 0;
2628 		glGenBuffers(1, &counter_buffer_);
2629 		glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_);
2630 		glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(z), &z, GL_DYNAMIC_COPY);
2631 		glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
2632 
2633 		// create uniform buffer
2634 		std::vector<UVec4> init_data(256);
2635 		for (GLuint i	= 0; i < 256; ++i)
2636 			init_data[i] = UVec4(i);
2637 		glGenBuffers(1, &uniform_buffer_);
2638 		glBindBuffer(GL_UNIFORM_BUFFER, uniform_buffer_);
2639 		glBufferData(GL_UNIFORM_BUFFER, (GLsizeiptr)(sizeof(UVec4) * init_data.size()), &init_data[0], GL_DYNAMIC_COPY);
2640 		glBindBuffer(GL_UNIFORM_BUFFER, 0);
2641 
2642 		glGenBuffers(1, &m_ssbo);
2643 		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_ssbo);
2644 		glBufferData(GL_SHADER_STORAGE_BUFFER, 256 * sizeof(UVec4), NULL, GL_DYNAMIC_DRAW);
2645 		glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
2646 
2647 		// draw
2648 		glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, counter_buffer_);
2649 		glBindBufferBase(GL_UNIFORM_BUFFER, 1, uniform_buffer_);
2650 		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_ssbo);
2651 		glUseProgram(prog_);
2652 		glDispatchCompute(16, 16, 1);
2653 
2654 		// validate
2655 		UVec4* data;
2656 		long   error = NO_ERROR;
2657 		glMemoryBarrier(GL_UNIFORM_BARRIER_BIT | GL_SHADER_STORAGE_BARRIER_BIT | GL_ATOMIC_COUNTER_BARRIER_BIT);
2658 
2659 		glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_ssbo);
2660 		data = static_cast<UVec4*>(glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 256 * sizeof(UVec4), GL_MAP_READ_BIT));
2661 		if (!CheckCounterValues(16 * 16, data, 0))
2662 			error = ERROR;
2663 		if (!CheckFinalCounterValue(counter_buffer_, 0, 256))
2664 			error = ERROR;
2665 		glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
2666 
2667 		glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
2668 		glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
2669 
2670 		return error;
2671 	}
2672 
Cleanup()2673 	virtual long Cleanup()
2674 	{
2675 		glDeleteBuffers(1, &counter_buffer_);
2676 		glDeleteBuffers(1, &uniform_buffer_);
2677 		glDeleteBuffers(1, &m_ssbo);
2678 		glDeleteProgram(prog_);
2679 		glUseProgram(0);
2680 		return NO_ERROR;
2681 	}
2682 };
2683 
2684 class NegativeAPI : public SACSubcaseBase
2685 {
Title()2686 	virtual std::string Title()
2687 	{
2688 		return NL "NegativeAPI";
2689 	}
Purpose()2690 	virtual std::string Purpose()
2691 	{
2692 		return NL "Verify errors reported by BindBuffer* commands.";
2693 	}
Method()2694 	virtual std::string Method()
2695 	{
2696 		return NL "";
2697 	}
PassCriteria()2698 	virtual std::string PassCriteria()
2699 	{
2700 		return NL "";
2701 	}
2702 
2703 	GLuint buffer;
2704 
Setup()2705 	virtual long Setup()
2706 	{
2707 		return NO_ERROR;
2708 	}
Run()2709 	virtual long Run()
2710 	{
2711 		long  error = NO_ERROR;
2712 		GLint res;
2713 		glGetIntegerv(GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS, &res);
2714 		glGenBuffers(1, &buffer);
2715 		glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, buffer);
2716 		glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, res, buffer);
2717 		if (glGetError() != GL_INVALID_VALUE)
2718 		{
2719 			m_context.getTestContext().getLog()
2720 				<< tcu::TestLog::Message << "glBindBufferBase should generate INVALID_VALUE when"
2721 											" index is greater than or equal GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS."
2722 				<< tcu::TestLog::EndMessage;
2723 			error = ERROR;
2724 		}
2725 		glBindBufferRange(GL_ATOMIC_COUNTER_BUFFER, res, buffer, 0, 4);
2726 		if (glGetError() != GL_INVALID_VALUE)
2727 		{
2728 			m_context.getTestContext().getLog()
2729 				<< tcu::TestLog::Message << "glBindBufferRange should generate INVALID_VALUE when"
2730 											" index is greater than or equal GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS."
2731 				<< tcu::TestLog::EndMessage;
2732 			error = ERROR;
2733 		}
2734 		glBindBufferRange(GL_ATOMIC_COUNTER_BUFFER, res - 1, buffer, 3, 4);
2735 		if (glGetError() != GL_INVALID_VALUE)
2736 		{
2737 			m_context.getTestContext().getLog()
2738 				<< tcu::TestLog::Message << "glBindBufferRange should generate INVALID_VALUE when"
2739 											" <offset> is not a multiple of four"
2740 				<< tcu::TestLog::EndMessage;
2741 			error = ERROR;
2742 		}
2743 		return error;
2744 	}
Cleanup()2745 	virtual long Cleanup()
2746 	{
2747 		glDeleteBuffers(1, &buffer);
2748 		return NO_ERROR;
2749 	}
2750 };
2751 
2752 class NegativeGLSL : public BasicUsageCS
2753 {
Title()2754 	virtual std::string Title()
2755 	{
2756 		return NL "GLSL errors";
2757 	}
Purpose()2758 	virtual std::string Purpose()
2759 	{
2760 		return NL "Verify that two different atomic counter uniforms with same binding cannot share same offset value.";
2761 	}
Method()2762 	virtual std::string Method()
2763 	{
2764 		return NL "";
2765 	}
PassCriteria()2766 	virtual std::string PassCriteria()
2767 	{
2768 		return NL "";
2769 	}
2770 
2771 	GLuint prog_;
2772 
Setup()2773 	virtual long Setup()
2774 	{
2775 		prog_ = 0;
2776 		return NO_ERROR;
2777 	}
2778 
Run()2779 	virtual long Run()
2780 	{
2781 		const char* const glsl_cs = NL
2782 			"layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;" NL
2783 			"layout(binding = 0, offset = 4) uniform atomic_uint ac_counter_inc;" NL
2784 			"layout(binding = 0, offset = 4) uniform atomic_uint ac_counter_dec;" NL "layout(std430) buffer Output {" NL
2785 			"  mediump uint data_inc[256];" NL "  mediump uint data_dec[256];" NL "} g_out;" NL "void main() {" NL
2786 			"  mediump uint offset = 32u * gl_GlobalInvocationID.y + gl_GlobalInvocationID.x;" NL
2787 			"  g_out.data_inc[offset] = atomicCounterIncrement(ac_counter_inc);" NL
2788 			"  g_out.data_dec[offset] = atomicCounterDecrement(ac_counter_dec);" NL "}";
2789 
2790 		prog_ = CreateComputeProgram(glsl_cs);
2791 		glLinkProgram(prog_);
2792 		if (CheckProgram(prog_))
2793 		{
2794 			m_context.getTestContext().getLog()
2795 				<< tcu::TestLog::Message
2796 				<< "Link should fail because ac_counter0 and ac_counter2 uses same binding and same offset."
2797 				<< tcu::TestLog::EndMessage;
2798 			return ERROR;
2799 		}
2800 		return NO_ERROR;
2801 	}
Cleanup()2802 	virtual long Cleanup()
2803 	{
2804 		glDeleteProgram(prog_);
2805 		return NO_ERROR;
2806 	}
2807 };
2808 
2809 class AdvancedManyDrawCalls : public SACSubcaseBase
2810 {
Title()2811 	virtual std::string Title()
2812 	{
2813 		return NL "Atomic Counters usage in multiple draw calls";
2814 	}
Purpose()2815 	virtual std::string Purpose()
2816 	{
2817 		return NL "Verify atomic counters behaviour across multiple draw calls.";
2818 	}
Method()2819 	virtual std::string Method()
2820 	{
2821 		return NL "";
2822 	}
PassCriteria()2823 	virtual std::string PassCriteria()
2824 	{
2825 		return NL "";
2826 	}
2827 
2828 	GLuint counter_buffer_;
2829 	GLuint vao_, vbo_;
2830 	GLuint prog_;
2831 	GLuint fbo_, rt_[2];
2832 
Setup()2833 	virtual long Setup()
2834 	{
2835 		counter_buffer_ = 0;
2836 		vao_ = vbo_ = 0;
2837 		prog_		= 0;
2838 		fbo_ = rt_[0] = rt_[1] = 0;
2839 		return NO_ERROR;
2840 	}
Run()2841 	virtual long Run()
2842 	{
2843 
2844 		GLint p1, p2;
2845 		glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS, &p1);
2846 		glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTERS, &p2);
2847 		if (p1 < 1 || p2 < 2)
2848 		{
2849 			OutputNotSupported(
2850 				"GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS or GL_MAX_FRAGMENT_ATOMIC_COUNTERS are less than required");
2851 			return NOT_SUPPORTED;
2852 		}
2853 
2854 		// create program
2855 		const char* src_vs = "#version 310 es" NL "layout(location = 0) in vec4 i_vertex;" NL "void main() {" NL
2856 							 "  gl_Position = i_vertex;" NL "}";
2857 		const char* src_fs = "#version 310 es" NL "layout(location = 0) out uvec4 o_color[2];" NL
2858 							 "layout(binding = 0, offset = 0) uniform atomic_uint ac_counter_inc;" NL
2859 							 "layout(binding = 0, offset = 4) uniform atomic_uint ac_counter_dec;" NL "void main() {" NL
2860 							 "  o_color[0] = uvec4(atomicCounterIncrement(ac_counter_inc));" NL
2861 							 "  o_color[1] = uvec4(atomicCounterDecrement(ac_counter_dec));" NL "}";
2862 		prog_ = CreateProgram(src_vs, src_fs, true);
2863 
2864 		// create atomic counter buffer
2865 		glGenBuffers(1, &counter_buffer_);
2866 		glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_);
2867 		glBufferData(GL_ATOMIC_COUNTER_BUFFER, 8, NULL, GL_DYNAMIC_COPY);
2868 		glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
2869 
2870 		// create render targets
2871 		const int s = 8;
2872 		glGenTextures(2, rt_);
2873 
2874 		for (int i = 0; i < 2; ++i)
2875 		{
2876 			glBindTexture(GL_TEXTURE_2D, rt_[i]);
2877 			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2878 			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2879 			glTexImage2D(GL_TEXTURE_2D, 0, GL_R32UI, s, s, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, NULL);
2880 			glBindTexture(GL_TEXTURE_2D, 0);
2881 		}
2882 
2883 		// create fbo
2884 		glGenFramebuffers(1, &fbo_);
2885 		glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
2886 		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt_[0], 0);
2887 		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, rt_[1], 0);
2888 		const GLenum draw_buffers[2] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 };
2889 		glDrawBuffers(2, draw_buffers);
2890 		glBindFramebuffer(GL_FRAMEBUFFER, 0);
2891 
2892 		// create geometry
2893 		CreateQuad(&vao_, &vbo_, NULL);
2894 
2895 		// init counter buffer
2896 		glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_);
2897 		unsigned int* ptr = static_cast<unsigned int*>(
2898 			glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 8, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT));
2899 		*ptr++ = 0;
2900 		*ptr++ = 256;
2901 		glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
2902 
2903 		// draw
2904 		glBindFramebuffer(GL_FRAMEBUFFER, fbo_);
2905 		glViewport(0, 0, s, s);
2906 		glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, counter_buffer_);
2907 		glUseProgram(prog_);
2908 		glBindVertexArray(vao_);
2909 
2910 		glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
2911 		glMemoryBarrier(GL_ATOMIC_COUNTER_BARRIER_BIT);
2912 		glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
2913 		glMemoryBarrier(GL_ATOMIC_COUNTER_BARRIER_BIT);
2914 		glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
2915 		glMemoryBarrier(GL_ATOMIC_COUNTER_BARRIER_BIT);
2916 		glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
2917 
2918 		// validate
2919 		UVec4 data[s * s];
2920 		glReadBuffer(GL_COLOR_ATTACHMENT0);
2921 		glReadPixels(0, 0, s, s, GL_RGBA_INTEGER, GL_UNSIGNED_INT, data);
2922 		if (!CheckCounterValues(s * s, data, s * s * 3))
2923 			return ERROR;
2924 
2925 		glReadBuffer(GL_COLOR_ATTACHMENT1);
2926 		glReadPixels(0, 0, s, s, GL_RGBA_INTEGER, GL_UNSIGNED_INT, data);
2927 		if (!CheckCounterValues(s * s, data, 0))
2928 			return ERROR;
2929 
2930 		if (!CheckFinalCounterValue(counter_buffer_, 0, 256))
2931 			return ERROR;
2932 		if (!CheckFinalCounterValue(counter_buffer_, 4, 0))
2933 			return ERROR;
2934 
2935 		return NO_ERROR;
2936 	}
2937 
Cleanup()2938 	virtual long Cleanup()
2939 	{
2940 		glDeleteFramebuffers(1, &fbo_);
2941 		glDeleteTextures(2, rt_);
2942 		glViewport(0, 0, getWindowWidth(), getWindowHeight());
2943 		glDeleteBuffers(1, &counter_buffer_);
2944 		glDeleteVertexArrays(1, &vao_);
2945 		glDeleteBuffers(1, &vbo_);
2946 		glDeleteProgram(prog_);
2947 		glUseProgram(0);
2948 		return NO_ERROR;
2949 	}
2950 };
2951 
2952 class NegativeSSBO : public BasicUsageCS
2953 {
Title()2954 	virtual std::string Title()
2955 	{
2956 		return NL "GLSL errors";
2957 	}
Purpose()2958 	virtual std::string Purpose()
2959 	{
2960 		return NL "Verify that atomic counters cannot be declared in the buffer block.";
2961 	}
Method()2962 	virtual std::string Method()
2963 	{
2964 		return NL "";
2965 	}
PassCriteria()2966 	virtual std::string PassCriteria()
2967 	{
2968 		return NL "";
2969 	}
2970 
2971 	GLuint prog_;
2972 
Setup()2973 	virtual long Setup()
2974 	{
2975 		prog_ = 0;
2976 		return NO_ERROR;
2977 	}
Run()2978 	virtual long Run()
2979 	{
2980 
2981 		const char* const glsl_cs =
2982 			NL "layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;" NL
2983 			   "layout(binding = 0, offset = 0) uniform atomic_uint ac_counter_dec;" NL
2984 			   "layout(std430) buffer Output {" NL "  mediump uint data_inc[256];" NL "  mediump uint data_dec[256];" NL
2985 			   "  layout(binding = 0, offset = 16) uniform atomic_uint ac_counter0;" NL "} g_out;" NL "void main() {" NL
2986 			   "  mediump uint offset = 32u * gl_GlobalInvocationID.y + gl_GlobalInvocationID.x;" NL
2987 			   "  g_out.data_inc[offset] = atomicCounterIncrement(ac_counter0);" NL
2988 			   "  g_out.data_dec[offset] = atomicCounterDecrement(ac_counter_dec);" NL "}";
2989 
2990 		prog_ = CreateComputeProgram(glsl_cs);
2991 		glLinkProgram(prog_);
2992 		if (CheckProgram(prog_))
2993 		{
2994 			m_context.getTestContext().getLog()
2995 				<< tcu::TestLog::Message
2996 				<< "Link should fail because atomic counters cannot be declared in the buffer block."
2997 				<< tcu::TestLog::EndMessage;
2998 			return ERROR;
2999 		}
3000 		return NO_ERROR;
3001 	}
Cleanup()3002 	virtual long Cleanup()
3003 	{
3004 		glDeleteProgram(prog_);
3005 		return NO_ERROR;
3006 	}
3007 };
3008 
3009 class NegativeUBO : public BasicUsageCS
3010 {
Title()3011 	virtual std::string Title()
3012 	{
3013 		return NL "GLSL errors";
3014 	}
Purpose()3015 	virtual std::string Purpose()
3016 	{
3017 		return NL "Verify that atomic counters cannot be declared in uniform block.";
3018 	}
Method()3019 	virtual std::string Method()
3020 	{
3021 		return NL "";
3022 	}
PassCriteria()3023 	virtual std::string PassCriteria()
3024 	{
3025 		return NL "";
3026 	}
3027 
3028 	GLuint prog_;
3029 
Setup()3030 	virtual long Setup()
3031 	{
3032 		prog_ = 0;
3033 		return NO_ERROR;
3034 	}
3035 
Run()3036 	virtual long Run()
3037 	{
3038 		const char* const glsl_cs =
3039 			NL "layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;" NL "uniform Block {" NL
3040 			   "  uniform atomic_uint ac_counter;" NL "};" NL "layout(std430) buffer Output {" NL
3041 			   "  mediump uint data_inc[256];" NL "} g_out;" NL "void main() {" NL
3042 			   "  mediump uint offset = 32u * gl_GlobalInvocationID.y + gl_GlobalInvocationID.x;" NL
3043 			   "  g_out.data_inc[offset] = atomicCounterIncrement(ac_counter);" NL "}";
3044 
3045 		prog_ = CreateComputeProgram(glsl_cs);
3046 		glLinkProgram(prog_);
3047 		if (CheckProgram(prog_))
3048 		{
3049 			m_context.getTestContext().getLog()
3050 				<< tcu::TestLog::Message
3051 				<< "Link should fail because atomic counters cannot be declared in the uniform block."
3052 				<< tcu::TestLog::EndMessage;
3053 			return ERROR;
3054 		}
3055 		return NO_ERROR;
3056 	}
3057 
Cleanup()3058 	virtual long Cleanup()
3059 	{
3060 		glDeleteProgram(prog_);
3061 		return NO_ERROR;
3062 	}
3063 };
3064 
3065 class BasicUsageNoOffset : public BasicUsageCS
3066 {
Title()3067 	virtual std::string Title()
3068 	{
3069 		return NL "Atomic Counters usage in the Compute Shader stage";
3070 	}
Purpose()3071 	virtual std::string Purpose()
3072 	{
3073 		return NL "Verify that atomic counters work as expected in the Compute Shader stage when decalred with no "
3074 				  "offset qualifier." NL "In particular make sure that values returned by GLSL built-in functions" NL
3075 				  "atomicCounterIncrement and atomicCounterDecrement are unique in every shader invocation." NL
3076 				  "Also make sure that the final values in atomic counter buffer objects are as expected.";
3077 	}
Method()3078 	virtual std::string Method()
3079 	{
3080 		return NL "";
3081 	}
PassCriteria()3082 	virtual std::string PassCriteria()
3083 	{
3084 		return NL "";
3085 	}
3086 
3087 	GLuint counter_buffer_;
3088 	GLuint prog_;
3089 	GLuint m_buffer;
3090 
Setup()3091 	virtual long Setup()
3092 	{
3093 		counter_buffer_ = 0;
3094 		prog_			= 0;
3095 		m_buffer		= 0;
3096 		return NO_ERROR;
3097 	}
3098 
Run()3099 	virtual long Run()
3100 	{
3101 		// create program
3102 		const char* const glsl_cs =
3103 			NL "layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;" NL
3104 			   "layout(binding = 0) uniform atomic_uint ac_counter_inc;" NL
3105 			   "layout(binding = 0) uniform atomic_uint ac_counter_dec;" NL "layout(std430) buffer Output {" NL
3106 			   "  mediump uint data_inc[256];" NL "  mediump uint data_dec[256];" NL "} g_out;" NL "void main() {" NL
3107 			   "  mediump uint offset = 32u * gl_GlobalInvocationID.y + gl_GlobalInvocationID.x;" NL
3108 			   "  g_out.data_inc[offset] = atomicCounterIncrement(ac_counter_inc);" NL
3109 			   "  g_out.data_dec[offset] = atomicCounterDecrement(ac_counter_dec);" NL "}";
3110 		prog_ = CreateComputeProgram(glsl_cs);
3111 		glLinkProgram(prog_);
3112 		if (!CheckProgram(prog_))
3113 			return ERROR;
3114 
3115 		// create atomic counter buffer
3116 		glGenBuffers(1, &counter_buffer_);
3117 		glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, counter_buffer_);
3118 		glBufferData(GL_ATOMIC_COUNTER_BUFFER, 8, NULL, GL_DYNAMIC_COPY);
3119 		glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
3120 
3121 		glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, counter_buffer_);
3122 		unsigned int* ptr = static_cast<unsigned int*>(
3123 			glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 8, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT));
3124 		*ptr++ = 0;
3125 		*ptr++ = 256;
3126 		glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
3127 
3128 		glGenBuffers(1, &m_buffer);
3129 		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer);
3130 		glBufferData(GL_SHADER_STORAGE_BUFFER, 512 * sizeof(GLuint), NULL, GL_DYNAMIC_DRAW);
3131 		glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
3132 
3133 		glUseProgram(prog_);
3134 		glDispatchCompute(4, 1, 1);
3135 
3136 		long	error = NO_ERROR;
3137 		GLuint* data;
3138 		glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_buffer);
3139 		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
3140 		data = static_cast<GLuint*>(
3141 			glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 512 * sizeof(GLuint), GL_MAP_READ_BIT | GL_MAP_WRITE_BIT));
3142 
3143 		std::sort(data, data + 512);
3144 		for (int i = 0; i < 512; i += 2)
3145 		{
3146 			if (data[i] != data[i + 1])
3147 			{
3148 				m_context.getTestContext().getLog()
3149 					<< tcu::TestLog::Message << "Pair of values should be equal, got: " << data[i] << ", "
3150 					<< data[i + 1] << tcu::TestLog::EndMessage;
3151 				error = ERROR;
3152 			}
3153 			if (i < 510 && data[i] == data[i + 2])
3154 			{
3155 				m_context.getTestContext().getLog()
3156 					<< tcu::TestLog::Message << "Too many same values found: " << data[i] << ", index: " << i
3157 					<< tcu::TestLog::EndMessage;
3158 				error = ERROR;
3159 			}
3160 		}
3161 
3162 		glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
3163 		glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
3164 		return error;
3165 	}
3166 
Cleanup()3167 	virtual long Cleanup()
3168 	{
3169 		glDeleteBuffers(1, &counter_buffer_);
3170 		glDeleteBuffers(1, &m_buffer);
3171 		glDeleteProgram(prog_);
3172 		glUseProgram(0);
3173 		return NO_ERROR;
3174 	}
3175 };
3176 
3177 class NegativeUniform : public SACSubcaseBase
3178 {
Title()3179 	virtual std::string Title()
3180 	{
3181 		return NL "GLSL errors";
3182 	}
Purpose()3183 	virtual std::string Purpose()
3184 	{
3185 		return NL "Verify that atomicCounterIncrement/atomicCounterDecrement "
3186 				  "cannot be used on normal uniform.";
3187 	}
Method()3188 	virtual std::string Method()
3189 	{
3190 		return NL "";
3191 	}
PassCriteria()3192 	virtual std::string PassCriteria()
3193 	{
3194 		return NL "";
3195 	}
3196 
3197 	GLuint prog_;
3198 
Setup()3199 	virtual long Setup()
3200 	{
3201 		prog_ = 0;
3202 		return NO_ERROR;
3203 	}
Run()3204 	virtual long Run()
3205 	{
3206 
3207 		GLint p1, p2;
3208 		glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS, &p1);
3209 		glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTERS, &p2);
3210 		if (p1 < 1 || p2 < 1)
3211 		{
3212 			OutputNotSupported(
3213 				"GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS or GL_MAX_FRAGMENT_ATOMIC_COUNTERS are less than required");
3214 			return NOT_SUPPORTED;
3215 		}
3216 
3217 		// create program
3218 		const char* glsl_vs = "#version 310 es" NL "layout(location = 0) in vec4 i_vertex;" NL "void main() {" NL
3219 							  "  gl_Position = i_vertex;" NL "}";
3220 
3221 		const char* glsl_fs1 =
3222 			"#version 310 es" NL "layout(location = 0) out uvec4 o_color[4];" NL "uniform uint ac_counter0;" NL
3223 			"void main() {" NL "  o_color[0] = uvec4(atomicCounterIncrement(ac_counter0));" NL "}";
3224 
3225 		prog_ = glCreateProgram();
3226 
3227 		GLuint sh = glCreateShader(GL_VERTEX_SHADER);
3228 		glAttachShader(prog_, sh);
3229 		glShaderSource(sh, 1, &glsl_vs, NULL);
3230 		glCompileShader(sh);
3231 		GLint status_comp;
3232 		glGetShaderiv(sh, GL_COMPILE_STATUS, &status_comp);
3233 		if (status_comp != GL_TRUE)
3234 		{
3235 			m_context.getTestContext().getLog()
3236 				<< tcu::TestLog::Message << "Unexpected error during vertex shader compilation."
3237 				<< tcu::TestLog::EndMessage;
3238 			return ERROR;
3239 		}
3240 		glDeleteShader(sh);
3241 
3242 		sh = glCreateShader(GL_FRAGMENT_SHADER);
3243 		glAttachShader(prog_, sh);
3244 		glShaderSource(sh, 1, &glsl_fs1, NULL);
3245 		glCompileShader(sh);
3246 		glGetShaderiv(sh, GL_COMPILE_STATUS, &status_comp);
3247 		glDeleteShader(sh);
3248 
3249 		GLint status;
3250 		glLinkProgram(prog_);
3251 		glGetProgramiv(prog_, GL_LINK_STATUS, &status);
3252 		if (status_comp == GL_TRUE && status == GL_TRUE)
3253 		{
3254 			m_context.getTestContext().getLog()
3255 				<< tcu::TestLog::Message << "Expected error during fragment shader compilation or linking."
3256 				<< tcu::TestLog::EndMessage;
3257 			return ERROR;
3258 		}
3259 		return NO_ERROR;
3260 	}
Cleanup()3261 	virtual long Cleanup()
3262 	{
3263 		glDeleteProgram(prog_);
3264 		return NO_ERROR;
3265 	}
3266 };
3267 
3268 class NegativeArray : public BasicUsageCS
3269 {
Title()3270 	virtual std::string Title()
3271 	{
3272 		return NL "GLSL errors";
3273 	}
Purpose()3274 	virtual std::string Purpose()
3275 	{
3276 		return NL "Verify that atomicCounterIncrement/atomicCounterDecrement "
3277 				  "cannot be used on array of atomic counters.";
3278 	}
Method()3279 	virtual std::string Method()
3280 	{
3281 		return NL "";
3282 	}
PassCriteria()3283 	virtual std::string PassCriteria()
3284 	{
3285 		return NL "";
3286 	}
3287 
3288 	GLuint prog_;
3289 
Setup()3290 	virtual long Setup()
3291 	{
3292 		prog_ = 0;
3293 		return NO_ERROR;
3294 	}
Run()3295 	virtual long Run()
3296 	{
3297 
3298 		const char* const glsl_cs =
3299 			NL "layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;" NL
3300 			   "layout(binding = 0) uniform atomic_uint ac_counter[3];" NL "layout(std430) buffer Output {" NL
3301 			   "  mediump uint data_inc[256];" NL "} g_out;" NL "void main() {" NL
3302 			   "  mediump uint offset = 32u * gl_GlobalInvocationID.y + gl_GlobalInvocationID.x;" NL
3303 			   "  g_out.data_inc[offset] = atomicCounterIncrement(ac_counter);" NL "}";
3304 
3305 		prog_ = CreateComputeProgram(glsl_cs);
3306 		glLinkProgram(prog_);
3307 		if (CheckProgram(prog_))
3308 		{
3309 			m_context.getTestContext().getLog()
3310 				<< tcu::TestLog::Message
3311 				<< "Link should fail because atomicCounterIncrement cannot be used on array of atomic counters."
3312 				<< tcu::TestLog::EndMessage;
3313 			return ERROR;
3314 		}
3315 		return NO_ERROR;
3316 	}
Cleanup()3317 	virtual long Cleanup()
3318 	{
3319 		glDeleteProgram(prog_);
3320 		return NO_ERROR;
3321 	}
3322 };
3323 
3324 class NegativeArithmetic : public BasicUsageCS
3325 {
Title()3326 	virtual std::string Title()
3327 	{
3328 		return NL "GLSL errors";
3329 	}
Purpose()3330 	virtual std::string Purpose()
3331 	{
3332 		return NL "Verify that standard arithmetic operations \n"
3333 				  "cannot be performed on atomic counters.";
3334 	}
Method()3335 	virtual std::string Method()
3336 	{
3337 		return NL "";
3338 	}
PassCriteria()3339 	virtual std::string PassCriteria()
3340 	{
3341 		return NL "";
3342 	}
3343 
3344 	GLuint prog_;
3345 
Setup()3346 	virtual long Setup()
3347 	{
3348 		prog_ = 0;
3349 		return NO_ERROR;
3350 	}
Run()3351 	virtual long Run()
3352 	{
3353 
3354 		const char* const glsl_cs =
3355 			NL "layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;" NL
3356 			   "layout(binding = 0) uniform atomic_uint ac_counter;" NL "layout(std430) buffer Output {" NL
3357 			   "  mediump uint data_inc[256];" NL "} g_out;" NL "void main() {" NL
3358 			   "  mediump uint offset = 32u * gl_GlobalInvocationID.y + gl_GlobalInvocationID.x;" NL
3359 			   "  g_out.data_inc[offset] = ac_counter + 1;" NL "}";
3360 
3361 		prog_ = CreateComputeProgram(glsl_cs);
3362 		glLinkProgram(prog_);
3363 		if (CheckProgram(prog_))
3364 		{
3365 			m_context.getTestContext().getLog()
3366 				<< tcu::TestLog::Message
3367 				<< "Link should fail because atomic counters cannot be incremented by standard arithmetic operations."
3368 				<< tcu::TestLog::EndMessage;
3369 			return ERROR;
3370 		}
3371 		return NO_ERROR;
3372 	}
3373 
Cleanup()3374 	virtual long Cleanup()
3375 	{
3376 		glDeleteProgram(prog_);
3377 		return NO_ERROR;
3378 	}
3379 };
3380 
3381 class NegativeUnsizedArray : public SACSubcaseBase
3382 {
Title()3383 	virtual std::string Title()
3384 	{
3385 		return NL "GLSL errors";
3386 	}
3387 
Purpose()3388 	virtual std::string Purpose()
3389 	{
3390 		return NL "Verify that it is compile-time error to declare an unsized array of atomic_uint..";
3391 	}
3392 
Method()3393 	virtual std::string Method()
3394 	{
3395 		return NL "";
3396 	}
3397 
PassCriteria()3398 	virtual std::string PassCriteria()
3399 	{
3400 		return NL "";
3401 	}
3402 
Run()3403 	virtual long Run()
3404 	{
3405 		const char* glsl_fs1 = "#version 310 es" NL "layout(location = 0) out uvec4 o_color[4];"
3406 							   "  layout(binding = 0, offset = 4) uniform atomic_uint ac_counter[];" NL
3407 							   "void main() {" NL "  o_color[0] = uvec4(atomicCounterIncrement(ac_counter[0]));" NL "}";
3408 
3409 		GLuint sh = glCreateShader(GL_FRAGMENT_SHADER);
3410 		glShaderSource(sh, 1, &glsl_fs1, NULL);
3411 		glCompileShader(sh);
3412 		GLint status_comp;
3413 		glGetShaderiv(sh, GL_COMPILE_STATUS, &status_comp);
3414 		glDeleteShader(sh);
3415 
3416 		if (status_comp == GL_TRUE)
3417 		{
3418 			m_context.getTestContext().getLog()
3419 				<< tcu::TestLog::Message << "Expected error during fragment shader compilation."
3420 				<< tcu::TestLog::EndMessage;
3421 			return ERROR;
3422 		}
3423 
3424 		return NO_ERROR;
3425 	}
3426 };
3427 
3428 class AdvancedManyDrawCalls2 : public SACSubcaseBase
3429 {
3430 
3431 	GLuint m_acbo, m_ssbo;
3432 	GLuint m_vao;
3433 	GLuint m_ppo, m_vsp, m_fsp;
3434 
Setup()3435 	virtual long Setup()
3436 	{
3437 		glGenBuffers(1, &m_acbo);
3438 		glGenBuffers(1, &m_ssbo);
3439 		glGenVertexArrays(1, &m_vao);
3440 		glGenProgramPipelines(1, &m_ppo);
3441 		m_vsp = m_fsp = 0;
3442 		return NO_ERROR;
3443 	}
3444 
Cleanup()3445 	virtual long Cleanup()
3446 	{
3447 		glDeleteBuffers(1, &m_acbo);
3448 		glDeleteBuffers(1, &m_ssbo);
3449 		glDeleteVertexArrays(1, &m_vao);
3450 		glDeleteProgramPipelines(1, &m_ppo);
3451 		glDeleteProgram(m_vsp);
3452 		glDeleteProgram(m_fsp);
3453 		return NO_ERROR;
3454 	}
3455 
Run()3456 	virtual long Run()
3457 	{
3458 
3459 		GLint p1, p2;
3460 		glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS, &p1);
3461 		glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTERS, &p2);
3462 		if (p1 < 1 || p2 < 1)
3463 		{
3464 			OutputNotSupported(
3465 				"GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS or GL_MAX_FRAGMENT_ATOMIC_COUNTERS are less than required");
3466 			return NOT_SUPPORTED;
3467 		}
3468 
3469 		const char* const glsl_vs = "#version 310 es" NL "void main() {" NL "#ifdef GL_ES" NL
3470 									"  gl_PointSize = 1.0f;" NL "#endif" NL "  gl_Position = vec4(0, 0, 0, 1);" NL "}";
3471 		const char* const glsl_fs =
3472 			"#version 310 es" NL "layout(binding = 0) uniform atomic_uint g_counter;" NL
3473 			"layout(std430, binding = 0) buffer Output {" NL "  uint g_output[];" NL "};" NL "void main() {" NL
3474 			"  uint c = atomicCounterIncrement(g_counter);" NL "  g_output[c] = c;" NL "}";
3475 
3476 		m_vsp = glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &glsl_vs);
3477 		m_fsp = glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, &glsl_fs);
3478 		if (!CheckProgram(m_vsp) || !CheckProgram(m_fsp))
3479 			return ERROR;
3480 
3481 		glUseProgramStages(m_ppo, GL_VERTEX_SHADER_BIT, m_vsp);
3482 		glUseProgramStages(m_ppo, GL_FRAGMENT_SHADER_BIT, m_fsp);
3483 
3484 		glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, m_acbo);
3485 		{
3486 			GLuint data = 0;
3487 			glBufferData(GL_ATOMIC_COUNTER_BUFFER, 4, &data, GL_DYNAMIC_COPY);
3488 		}
3489 
3490 		{
3491 			std::vector<GLuint> data(1000, 0xffff);
3492 			glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_ssbo);
3493 			glBufferData(GL_SHADER_STORAGE_BUFFER, (GLsizeiptr)(data.size() * 4), &data[0], GL_DYNAMIC_READ);
3494 		}
3495 
3496 		// draw
3497 		glViewport(0, 0, 1, 1);
3498 		glBindProgramPipeline(m_ppo);
3499 		glBindVertexArray(m_vao);
3500 		for (int i = 0; i < 100; ++i)
3501 		{
3502 			glDrawArrays(GL_POINTS, 0, 1);
3503 		}
3504 
3505 		glViewport(0, 0, getWindowWidth(), getWindowHeight());
3506 
3507 		long status = NO_ERROR;
3508 
3509 		{
3510 			GLuint* data;
3511 
3512 			glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_acbo);
3513 			glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
3514 			data = static_cast<GLuint*>(glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 4, GL_MAP_READ_BIT));
3515 			if (data[0] != 100)
3516 			{
3517 				status = ERROR;
3518 				m_context.getTestContext().getLog() << tcu::TestLog::Message << "AC buffer content is " << data[0]
3519 													<< ", sholud be 100." << tcu::TestLog::EndMessage;
3520 			}
3521 			glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
3522 			glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
3523 
3524 			glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_ssbo);
3525 			glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
3526 			data = static_cast<GLuint*>(
3527 				glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 100 * 4, GL_MAP_READ_BIT | GL_MAP_WRITE_BIT));
3528 			std::sort(data, data + 100);
3529 			for (GLuint i = 0; i < 100; ++i)
3530 			{
3531 				if (data[i] != i)
3532 				{
3533 					status = ERROR;
3534 					m_context.getTestContext().getLog() << tcu::TestLog::Message << "data[" << i << " is " << data[i]
3535 														<< ", sholud be " << i << tcu::TestLog::EndMessage;
3536 				}
3537 			}
3538 			glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
3539 			glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
3540 		}
3541 
3542 		return status;
3543 	}
3544 };
3545 
3546 class AdvancedUsageMultipleComputeDispatches : public SACSubcaseBase
3547 {
3548 	GLuint m_acbo, m_ssbo;
3549 	GLuint m_ppo, m_csp;
3550 
Setup()3551 	virtual long Setup()
3552 	{
3553 		glGenBuffers(1, &m_acbo);
3554 		glGenBuffers(1, &m_ssbo);
3555 		glGenProgramPipelines(1, &m_ppo);
3556 		m_csp = 0;
3557 		return NO_ERROR;
3558 	}
3559 
Cleanup()3560 	virtual long Cleanup()
3561 	{
3562 		glDeleteBuffers(1, &m_acbo);
3563 		glDeleteBuffers(1, &m_ssbo);
3564 		glDeleteProgramPipelines(1, &m_ppo);
3565 		glDeleteProgram(m_csp);
3566 		return NO_ERROR;
3567 	}
3568 
Run()3569 	virtual long Run()
3570 	{
3571 		// create program
3572 		const char* const glsl_cs =
3573 			"#version 310 es" NL "layout(local_size_x = 1) in;" NL
3574 			"layout(binding = 0) uniform atomic_uint g_counter;" NL "layout(std430, binding = 0) buffer Output {" NL
3575 			"  mediump uint g_output[];" NL "};" NL "void main() {" NL
3576 			"  mediump uint c = atomicCounterIncrement(g_counter);" NL "  g_output[c] = c;" NL "}";
3577 
3578 		m_csp = glCreateShaderProgramv(GL_COMPUTE_SHADER, 1, &glsl_cs);
3579 		if (!CheckProgram(m_csp))
3580 			return ERROR;
3581 		glUseProgramStages(m_ppo, GL_COMPUTE_SHADER_BIT, m_csp);
3582 
3583 		glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, m_acbo);
3584 		{
3585 			GLuint data = 0;
3586 			glBufferData(GL_ATOMIC_COUNTER_BUFFER, 4, &data, GL_DYNAMIC_COPY);
3587 		}
3588 
3589 		{
3590 			std::vector<GLuint> data(1000, 0xffff);
3591 			glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_ssbo);
3592 			glBufferData(GL_SHADER_STORAGE_BUFFER, (GLsizeiptr)(data.size() * 4), &data[0], GL_DYNAMIC_READ);
3593 		}
3594 
3595 		glBindProgramPipeline(m_ppo);
3596 		for (int i = 0; i < 100; ++i)
3597 		{
3598 			glDispatchCompute(1, 1, 1);
3599 		}
3600 
3601 		long status = NO_ERROR;
3602 
3603 		{
3604 			GLuint* data;
3605 
3606 			glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_acbo);
3607 			glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
3608 			data = static_cast<GLuint*>(glMapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, 4, GL_MAP_READ_BIT));
3609 			if (data[0] != 100)
3610 			{
3611 				status = ERROR;
3612 				m_context.getTestContext().getLog() << tcu::TestLog::Message << "AC buffer content is " << data[0]
3613 													<< ", sholud be 100" << tcu::TestLog::EndMessage;
3614 			}
3615 			glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
3616 			glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, 0);
3617 
3618 			glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_ssbo);
3619 			glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
3620 			data = static_cast<GLuint*>(
3621 				glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, 100 * 4, GL_MAP_READ_BIT | GL_MAP_WRITE_BIT));
3622 			std::sort(data, data + 100);
3623 			for (GLuint i = 0; i < 100; ++i)
3624 			{
3625 				if (data[i] != i)
3626 				{
3627 					status = ERROR;
3628 					m_context.getTestContext().getLog() << tcu::TestLog::Message << "data[" << i << "] is " << data[i]
3629 														<< ", sholud be " << i << tcu::TestLog::EndMessage;
3630 				}
3631 			}
3632 			glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
3633 			glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
3634 		}
3635 
3636 		return status;
3637 	}
3638 };
3639 
3640 class BasicGLSLBuiltIn : public BasicUsageCS
3641 {
3642 public:
Title()3643 	virtual std::string Title()
3644 	{
3645 		return NL "gl_Max* Check";
3646 	}
Purpose()3647 	virtual std::string Purpose()
3648 	{
3649 		return NL "Verify that gl_Max*Counters and gl_Max*Bindings exist in glsl and their values are no lower" NL
3650 				  "than minimum required by the spec and are no different from their GL_MAX_* counterparts.";
3651 	}
3652 
3653 	GLuint prog_;
3654 	GLuint m_buffer;
3655 
Setup()3656 	virtual long Setup()
3657 	{
3658 		prog_	= 0;
3659 		m_buffer = 0;
3660 		return NO_ERROR;
3661 	}
3662 
Run()3663 	virtual long Run()
3664 	{
3665 		// create program
3666 		const char* const glsl_cs = NL
3667 			"layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;" NL "layout(std430) buffer Output {" NL
3668 			"  mediump uint data;" NL "} g_out;" NL "uniform mediump int m_vac;" NL "uniform mediump int m_fac;" NL
3669 			"uniform mediump int m_csac;" NL "uniform mediump int m_cac;" NL "uniform mediump int m_abuf;" NL
3670 			"void main() {" NL "  mediump uint res = 1u;" NL
3671 			"  if (gl_MaxVertexAtomicCounters < 0 || gl_MaxVertexAtomicCounters != m_vac)" NL "     res = res * 2u;" NL
3672 			"  if (gl_MaxFragmentAtomicCounters < 0 || gl_MaxFragmentAtomicCounters != m_fac)" NL
3673 			"     res = res * 3u;" NL
3674 			"  if (gl_MaxComputeAtomicCounters < 8 || gl_MaxComputeAtomicCounters != m_csac)" NL
3675 			"     res = res * 5u;" NL
3676 			"  if (gl_MaxCombinedAtomicCounters < 8 || gl_MaxCombinedAtomicCounters != m_cac)" NL
3677 			"     res = res * 7u;" NL
3678 			"  if (gl_MaxAtomicCounterBindings < 1 || gl_MaxAtomicCounterBindings != m_abuf)" NL
3679 			"     res = res * 11u;" NL "  g_out.data = res;" NL "}";
3680 
3681 		prog_ = CreateComputeProgram(glsl_cs);
3682 		glLinkProgram(prog_);
3683 		if (!CheckProgram(prog_))
3684 			return ERROR;
3685 		glUseProgram(prog_);
3686 
3687 		int m_vac;
3688 		int m_fac;
3689 		int m_csac;
3690 		int m_cac;
3691 		int m_abuf;
3692 		glGetIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTERS, &m_vac);
3693 		glUniform1i(glGetUniformLocation(prog_, "m_vac"), m_vac);
3694 		glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTERS, &m_fac);
3695 		glUniform1i(glGetUniformLocation(prog_, "m_fac"), m_fac);
3696 		glGetIntegerv(GL_MAX_COMPUTE_ATOMIC_COUNTERS, &m_csac);
3697 		glUniform1i(glGetUniformLocation(prog_, "m_csac"), m_csac);
3698 		glGetIntegerv(GL_MAX_COMBINED_ATOMIC_COUNTERS, &m_cac);
3699 		glUniform1i(glGetUniformLocation(prog_, "m_cac"), m_cac);
3700 		glGetIntegerv(GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS, &m_abuf);
3701 		glUniform1i(glGetUniformLocation(prog_, "m_abuf"), m_abuf);
3702 
3703 		glGenBuffers(1, &m_buffer);
3704 		glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_buffer);
3705 		glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(GLuint), NULL, GL_DYNAMIC_DRAW);
3706 		glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
3707 
3708 		glDispatchCompute(1, 1, 1);
3709 
3710 		long	error = NO_ERROR;
3711 		GLuint* data;
3712 		glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_buffer);
3713 		glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
3714 		data = static_cast<GLuint*>(glMapBufferRange(GL_SHADER_STORAGE_BUFFER, 0, sizeof(GLuint), GL_MAP_READ_BIT));
3715 		if (data[0] != 1u)
3716 		{
3717 			m_context.getTestContext().getLog()
3718 				<< tcu::TestLog::Message << "Expected 1, got: " << data[0] << tcu::TestLog::EndMessage;
3719 			error = ERROR;
3720 		}
3721 		glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
3722 		glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
3723 
3724 		return error;
3725 	}
3726 
Cleanup()3727 	virtual long Cleanup()
3728 	{
3729 		glDeleteBuffers(1, &m_buffer);
3730 		glDeleteProgram(prog_);
3731 		glUseProgram(0);
3732 		return NO_ERROR;
3733 	}
3734 };
3735 
ShaderAtomicCountersTests(glcts::Context & context)3736 ShaderAtomicCountersTests::ShaderAtomicCountersTests(glcts::Context& context)
3737 	: TestCaseGroup(context, "shader_atomic_counters", "")
3738 {
3739 }
3740 
~ShaderAtomicCountersTests(void)3741 ShaderAtomicCountersTests::~ShaderAtomicCountersTests(void)
3742 {
3743 }
3744 
init()3745 void ShaderAtomicCountersTests::init()
3746 {
3747 	using namespace glcts;
3748 	addChild(new TestSubcase(m_context, "basic-buffer-operations", TestSubcase::Create<BasicBufferOperations>));
3749 	addChild(new TestSubcase(m_context, "basic-buffer-state", TestSubcase::Create<BasicBufferState>));
3750 	addChild(new TestSubcase(m_context, "basic-buffer-bind", TestSubcase::Create<BasicBufferBind>));
3751 	addChild(new TestSubcase(m_context, "basic-program-max", TestSubcase::Create<BasicProgramMax>));
3752 	addChild(new TestSubcase(m_context, "basic-program-query", TestSubcase::Create<BasicProgramQuery>));
3753 	addChild(new TestSubcase(m_context, "basic-usage-simple", TestSubcase::Create<BasicUsageSimple>));
3754 	addChild(new TestSubcase(m_context, "basic-usage-no-offset", TestSubcase::Create<BasicUsageNoOffset>));
3755 	addChild(new TestSubcase(m_context, "basic-usage-fs", TestSubcase::Create<BasicUsageFS>));
3756 	addChild(new TestSubcase(m_context, "basic-usage-vs", TestSubcase::Create<BasicUsageVS>));
3757 	addChild(new TestSubcase(m_context, "basic-usage-cs", TestSubcase::Create<BasicUsageCS>));
3758 	addChild(new TestSubcase(m_context, "basic-glsl-built-in", TestSubcase::Create<BasicGLSLBuiltIn>));
3759 	addChild(new TestSubcase(m_context, "advanced-usage-multi-stage", TestSubcase::Create<AdvancedUsageMultiStage>));
3760 	addChild(new TestSubcase(m_context, "advanced-usage-draw-update-draw",
3761 							 TestSubcase::Create<AdvancedUsageDrawUpdateDraw>));
3762 	addChild(
3763 		new TestSubcase(m_context, "advanced-usage-many-counters", TestSubcase::Create<AdvancedUsageManyCounters>));
3764 	addChild(
3765 		new TestSubcase(m_context, "advanced-usage-switch-programs", TestSubcase::Create<AdvancedUsageSwitchPrograms>));
3766 	addChild(new TestSubcase(m_context, "advanced-usage-ubo", TestSubcase::Create<AdvancedUsageUBO>));
3767 	addChild(new TestSubcase(m_context, "advanced-usage-many-draw-calls", TestSubcase::Create<AdvancedManyDrawCalls>));
3768 	addChild(
3769 		new TestSubcase(m_context, "advanced-usage-many-draw-calls2", TestSubcase::Create<AdvancedManyDrawCalls2>));
3770 	addChild(new TestSubcase(m_context, "advanced-usage-many-dispatches",
3771 							 TestSubcase::Create<AdvancedUsageMultipleComputeDispatches>));
3772 	addChild(new TestSubcase(m_context, "negative-api", TestSubcase::Create<NegativeAPI>));
3773 	addChild(new TestSubcase(m_context, "negative-glsl", TestSubcase::Create<NegativeGLSL>));
3774 	addChild(new TestSubcase(m_context, "negative-ssbo", TestSubcase::Create<NegativeSSBO>));
3775 	addChild(new TestSubcase(m_context, "negative-ubo", TestSubcase::Create<NegativeUBO>));
3776 	addChild(new TestSubcase(m_context, "negative-uniform", TestSubcase::Create<NegativeUniform>));
3777 	addChild(new TestSubcase(m_context, "negative-array", TestSubcase::Create<NegativeArray>));
3778 	addChild(new TestSubcase(m_context, "negative-arithmetic", TestSubcase::Create<NegativeArithmetic>));
3779 	addChild(new TestSubcase(m_context, "negative-unsized-array", TestSubcase::Create<NegativeUnsizedArray>));
3780 }
3781 }
3782