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