• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*-------------------------------------------------------------------------
2  * OpenGL Conformance Test Suite
3  * -----------------------------
4  *
5  * Copyright (c) 2017 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  gl4cShaderAtomicCounterOpsTests.cpp
21  * \brief Conformance tests for the ARB_shader_atomic_counter_ops functionality.
22  */ /*-------------------------------------------------------------------*/
23 
24 #include "gl4cShaderAtomicCounterOpsTests.hpp"
25 #include "gluContextInfo.hpp"
26 #include "gluDefs.hpp"
27 #include "gluDrawUtil.hpp"
28 #include "gluObjectWrapper.hpp"
29 #include "gluShaderProgram.hpp"
30 #include "glwEnums.hpp"
31 #include "glwFunctions.hpp"
32 #include "tcuRenderTarget.hpp"
33 
34 #include <algorithm>
35 #include <sstream>
36 #include <string>
37 
38 using namespace glw;
39 
40 namespace gl4cts
41 {
42 
ShaderPipeline(glu::ShaderType testedShader,AtomicOperation * newOp,bool contextGL46)43 ShaderAtomicCounterOpsTestBase::ShaderPipeline::ShaderPipeline(glu::ShaderType testedShader, AtomicOperation* newOp,
44 															   bool contextGL46)
45 	: m_program(NULL), m_programCompute(NULL), m_testedShader(testedShader), m_atomicOp(newOp)
46 {
47 	m_shaders[glu::SHADERTYPE_VERTEX] = "<version>\n"
48 										"<head>"
49 										"in highp vec2 inPosition;\n"
50 										"out highp vec3 vsPosition;\n"
51 										"out highp vec4 vsColor;\n"
52 										"void main()\n"
53 										"{\n"
54 										"	gl_Position = vec4(inPosition, 0.0, 1.0);\n"
55 										"	vsPosition = vec3(inPosition, 0.0);\n"
56 										"	vec4 outColor = vec4(1.0);\n"
57 										"<atomic_operation>"
58 										"	vsColor = outColor;\n"
59 										"}\n";
60 
61 	m_shaders[glu::SHADERTYPE_FRAGMENT] = "<version>\n"
62 										  "<head>"
63 										  "in highp vec4 gsColor;\n"
64 										  "out highp vec4 fsColor;\n"
65 										  "void main()\n"
66 										  "{\n"
67 										  "	vec4 outColor = gsColor; \n"
68 										  "<atomic_operation>"
69 										  "	fsColor = outColor;\n"
70 										  "}\n";
71 
72 	m_shaders[glu::SHADERTYPE_TESSELLATION_CONTROL] = "<version>\n"
73 													  "<head>"
74 													  "layout(vertices = 3) out;\n"
75 													  "in highp vec4 vsColor[];\n"
76 													  "in highp vec3 vsPosition[];\n"
77 													  "out highp vec3 tcsPosition[];\n"
78 													  "out highp vec4 tcsColor[];\n"
79 													  "void main()\n"
80 													  "{\n"
81 													  "	tcsPosition[gl_InvocationID] = vsPosition[gl_InvocationID];\n"
82 													  "	vec4 outColor = vsColor[gl_InvocationID];\n"
83 													  "<atomic_operation>"
84 													  "	tcsColor[gl_InvocationID] = outColor;\n"
85 													  "	gl_TessLevelInner[0] = 3;\n"
86 													  "	gl_TessLevelOuter[0] = 3;\n"
87 													  "	gl_TessLevelOuter[1] = 3;\n"
88 													  "	gl_TessLevelOuter[2] = 3;\n"
89 													  "}\n";
90 
91 	m_shaders[glu::SHADERTYPE_TESSELLATION_EVALUATION] = "<version>\n"
92 														 "<head>"
93 														 "layout(triangles, equal_spacing, cw) in;\n"
94 														 "in highp vec3 tcsPosition[];\n"
95 														 "in highp vec4 tcsColor[];\n"
96 														 "out highp vec4 tesColor;\n"
97 														 "void main()\n"
98 														 "{\n"
99 														 "	vec3 p0 = gl_TessCoord.x * tcsPosition[0];\n"
100 														 "	vec3 p1 = gl_TessCoord.y * tcsPosition[1];\n"
101 														 "	vec3 p2 = gl_TessCoord.z * tcsPosition[2];\n"
102 														 "	vec4 outColor = tcsColor[0];\n"
103 														 "<atomic_operation>"
104 														 "	tesColor = outColor;\n"
105 														 "	gl_Position = vec4(normalize(p0 + p1 + p2), 1.0);\n"
106 														 "}\n";
107 
108 	m_shaders[glu::SHADERTYPE_GEOMETRY] = "<version>\n"
109 										  "<head>"
110 										  "layout(triangles) in;\n"
111 										  "layout(triangle_strip, max_vertices = 3) out;\n"
112 										  "in highp vec4 tesColor[];\n"
113 										  "out highp vec4 gsColor;\n"
114 										  "void main()\n"
115 										  "{\n"
116 										  "	for (int i = 0; i<3; i++)\n"
117 										  "	{\n"
118 										  "		gl_Position = gl_in[i].gl_Position;\n"
119 										  "		vec4 outColor = tesColor[i];\n"
120 										  "<atomic_operation>"
121 										  "		gsColor = outColor;\n"
122 										  "		EmitVertex();\n"
123 										  "	}\n"
124 										  "	EndPrimitive();\n"
125 										  "}\n";
126 
127 	m_shaders[glu::SHADERTYPE_COMPUTE] = "<version>\n"
128 										 "<head>"
129 										 "layout(rgba32f, binding = 2) writeonly uniform highp image2D destImage;\n"
130 										 "layout (local_size_x = 16, local_size_y = 16) in;\n"
131 										 "void main (void)\n"
132 										 "{\n"
133 										 "	vec4 outColor = vec4(1.0);\n"
134 										 "<atomic_operation>"
135 										 "	imageStore(destImage, ivec2(gl_GlobalInvocationID.xy), outColor);\n"
136 										 "}\n";
137 
138 	// prepare shaders
139 
140 	std::string		  postfix(contextGL46 ? "" : "ARB");
141 	std::stringstream atomicOperationStream;
142 	atomicOperationStream << "uint returned = " << m_atomicOp->getFunction() + postfix + "(counter, ";
143 	if (m_atomicOp->getCompareValue() != 0)
144 	{
145 		atomicOperationStream << m_atomicOp->getCompareValue();
146 		atomicOperationStream << "u, ";
147 	}
148 	atomicOperationStream << m_atomicOp->getParamValue();
149 	atomicOperationStream << "u);\n";
150 	atomicOperationStream << "uint after = atomicCounter(counter);\n";
151 
152 	if (m_atomicOp->shouldTestReturnValue())
153 	{
154 		atomicOperationStream << "if(after == returned) outColor = vec4(0.0f);\n";
155 	}
156 
157 	atomicOperationStream << "atomicCounterIncrement(calls);\n";
158 
159 	std::string versionString;
160 	std::string headString;
161 	if (contextGL46)
162 	{
163 		versionString = "#version 460 core";
164 		headString	= "layout (binding=0) uniform atomic_uint counter;\n"
165 					 "layout (binding=1) uniform atomic_uint calls;\n";
166 	}
167 	else
168 	{
169 		versionString = "#version 450 core";
170 		headString	= "#extension GL_ARB_shader_atomic_counters: enable\n"
171 					 "#extension GL_ARB_shader_atomic_counter_ops: enable\n"
172 					 "layout (binding=0) uniform atomic_uint counter;\n"
173 					 "layout (binding=1) uniform atomic_uint calls;\n";
174 	}
175 
176 	for (unsigned int i = 0; i < glu::SHADERTYPE_LAST; ++i)
177 	{
178 		prepareShader(m_shaders[i], "<version>", versionString);
179 		prepareShader(m_shaders[i], "<head>", i == testedShader ? headString : "");
180 		prepareShader(m_shaders[i], "<atomic_operation>", i == testedShader ? atomicOperationStream.str() : "");
181 	}
182 }
183 
~ShaderPipeline()184 ShaderAtomicCounterOpsTestBase::ShaderPipeline::~ShaderPipeline()
185 {
186 	if (m_program)
187 	{
188 		delete m_program;
189 	}
190 
191 	if (m_programCompute)
192 	{
193 		delete m_programCompute;
194 	}
195 }
196 
prepareShader(std::string & shader,const std::string & tag,const std::string & value)197 void ShaderAtomicCounterOpsTestBase::ShaderPipeline::prepareShader(std::string& shader, const std::string& tag,
198 																   const std::string& value)
199 {
200 	size_t tagPos = shader.find(tag);
201 
202 	if (tagPos != std::string::npos)
203 		shader.replace(tagPos, tag.length(), value);
204 }
205 
create(deqp::Context & context)206 void ShaderAtomicCounterOpsTestBase::ShaderPipeline::create(deqp::Context& context)
207 {
208 	glu::ProgramSources sources;
209 	for (unsigned int i = 0; i < glu::SHADERTYPE_COMPUTE; ++i)
210 	{
211 		if (!m_shaders[i].empty())
212 		{
213 			sources.sources[i].push_back(m_shaders[i]);
214 		}
215 	}
216 	m_program = new glu::ShaderProgram(context.getRenderContext(), sources);
217 
218 	if (!m_program->isOk())
219 	{
220 		TCU_FAIL("Shader compilation failed");
221 	}
222 
223 	glu::ProgramSources sourcesCompute;
224 	sourcesCompute.sources[glu::SHADERTYPE_COMPUTE].push_back(m_shaders[glu::SHADERTYPE_COMPUTE]);
225 	m_programCompute = new glu::ShaderProgram(context.getRenderContext(), sourcesCompute);
226 
227 	if (!m_programCompute->isOk())
228 	{
229 		TCU_FAIL("Shader compilation failed");
230 	}
231 }
232 
use(deqp::Context & context)233 void ShaderAtomicCounterOpsTestBase::ShaderPipeline::use(deqp::Context& context)
234 {
235 	const glw::Functions& gl = context.getRenderContext().getFunctions();
236 	gl.useProgram(m_program->getProgram());
237 	GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram failed");
238 }
239 
test(deqp::Context & context)240 void ShaderAtomicCounterOpsTestBase::ShaderPipeline::test(deqp::Context& context)
241 {
242 	const glw::Functions& gl = context.getRenderContext().getFunctions();
243 
244 	gl.clearColor(0.5f, 0.5f, 0.5f, 1.0f);
245 	gl.clear(GL_COLOR_BUFFER_BIT);
246 
247 	if (m_testedShader == glu::SHADERTYPE_COMPUTE)
248 	{
249 		executeComputeShader(context);
250 	}
251 	else
252 	{
253 		renderQuad(context);
254 	}
255 
256 	gl.flush();
257 }
258 
renderQuad(deqp::Context & context)259 void ShaderAtomicCounterOpsTestBase::ShaderPipeline::renderQuad(deqp::Context& context)
260 {
261 	const glw::Functions& gl = context.getRenderContext().getFunctions();
262 
263 	deUint16 const quadIndices[] = { 0, 1, 2, 2, 1, 3 };
264 
265 	float const position[] = { -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f };
266 
267 	glu::VertexArrayBinding vertexArrays[] = { glu::va::Float("inPosition", 2, 4, 0, position) };
268 
269 	this->use(context);
270 
271 	glu::PrimitiveList primitiveList = glu::pr::Patches(DE_LENGTH_OF_ARRAY(quadIndices), quadIndices);
272 
273 	glu::draw(context.getRenderContext(), this->getShaderProgram()->getProgram(), DE_LENGTH_OF_ARRAY(vertexArrays),
274 			  vertexArrays, primitiveList);
275 
276 	GLU_EXPECT_NO_ERROR(gl.getError(), "glu::draw error");
277 
278 	gl.memoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
279 	GLU_EXPECT_NO_ERROR(gl.getError(), "glMemoryBarrier() error");
280 }
281 
executeComputeShader(deqp::Context & context)282 void ShaderAtomicCounterOpsTestBase::ShaderPipeline::executeComputeShader(deqp::Context& context)
283 {
284 	const glw::Functions& gl = context.getRenderContext().getFunctions();
285 
286 	const glu::Texture outputTexture(context.getRenderContext());
287 
288 	gl.useProgram(m_programCompute->getProgram());
289 
290 	// output image
291 	gl.bindTexture(GL_TEXTURE_2D, *outputTexture);
292 	gl.texStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32UI, 16, 16);
293 	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
294 	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
295 	GLU_EXPECT_NO_ERROR(gl.getError(), "Uploading image data failed");
296 
297 	// bind image
298 	gl.bindImageTexture(2, *outputTexture, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32F);
299 	GLU_EXPECT_NO_ERROR(gl.getError(), "Image setup failed");
300 
301 	// dispatch compute
302 	gl.dispatchCompute(1, 1, 1);
303 	GLU_EXPECT_NO_ERROR(gl.getError(), "glDispatchCompute() error");
304 	gl.memoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT);
305 	GLU_EXPECT_NO_ERROR(gl.getError(), "glMemoryBarrier() error");
306 
307 	// render output texture
308 
309 	std::string vs = "#version 450 core\n"
310 					 "in highp vec2 position;\n"
311 					 "in vec2 inTexcoord;\n"
312 					 "out vec2 texcoord;\n"
313 					 "void main()\n"
314 					 "{\n"
315 					 "	texcoord = inTexcoord;\n"
316 					 "	gl_Position = vec4(position, 0.0, 1.0);\n"
317 					 "}\n";
318 
319 	std::string fs = "#version 450 core\n"
320 					 "uniform sampler2D sampler;\n"
321 					 "in vec2 texcoord;\n"
322 					 "out vec4 color;\n"
323 					 "void main()\n"
324 					 "{\n"
325 					 "	color = texture(sampler, texcoord);\n"
326 					 "}\n";
327 
328 	glu::ProgramSources sources;
329 	sources.sources[glu::SHADERTYPE_VERTEX].push_back(vs);
330 	sources.sources[glu::SHADERTYPE_FRAGMENT].push_back(fs);
331 	glu::ShaderProgram renderShader(context.getRenderContext(), sources);
332 
333 	if (!m_program->isOk())
334 	{
335 		TCU_FAIL("Shader compilation failed");
336 	}
337 
338 	gl.bindTexture(GL_TEXTURE_2D, *outputTexture);
339 	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed.");
340 
341 	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
342 	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
343 	GLU_EXPECT_NO_ERROR(gl.getError(), "texParameteri failed");
344 
345 	gl.useProgram(renderShader.getProgram());
346 	GLU_EXPECT_NO_ERROR(gl.getError(), "useProgram failed");
347 
348 	gl.uniform1i(gl.getUniformLocation(renderShader.getProgram(), "sampler"), 0);
349 	GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform1i failed");
350 
351 	deUint16 const quadIndices[] = { 0, 1, 2, 2, 1, 3 };
352 
353 	float const position[] = { -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f };
354 
355 	float const texCoord[] = { 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f };
356 
357 	glu::VertexArrayBinding vertexArrays[] = { glu::va::Float("position", 2, 4, 0, position),
358 											   glu::va::Float("inTexcoord", 2, 4, 0, texCoord) };
359 
360 	glu::draw(context.getRenderContext(), renderShader.getProgram(), DE_LENGTH_OF_ARRAY(vertexArrays), vertexArrays,
361 			  glu::pr::TriangleStrip(DE_LENGTH_OF_ARRAY(quadIndices), quadIndices));
362 
363 	GLU_EXPECT_NO_ERROR(gl.getError(), "glu::draw error");
364 }
365 
fillAtomicCounterBuffer(AtomicOperation * atomicOp)366 void ShaderAtomicCounterOpsTestBase::fillAtomicCounterBuffer(AtomicOperation* atomicOp)
367 {
368 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
369 
370 	GLuint* dataPtr;
371 
372 	// fill values buffer
373 
374 	GLuint inputValue = atomicOp->getInputValue();
375 
376 	gl.bindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_atomicCounterBuffer);
377 	GLU_EXPECT_NO_ERROR(gl.getError(), "bindBuffer() call failed.");
378 
379 	dataPtr = (GLuint*)gl.mapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint),
380 										 GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
381 	GLU_EXPECT_NO_ERROR(gl.getError(), "mapBufferRange() call failed.");
382 
383 	*dataPtr = inputValue;
384 
385 	gl.unmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
386 	GLU_EXPECT_NO_ERROR(gl.getError(), "unmapBuffer() call failed.");
387 
388 	// fill calls buffer
389 
390 	gl.bindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_atomicCounterCallsBuffer);
391 	GLU_EXPECT_NO_ERROR(gl.getError(), "bindBuffer() call failed.");
392 
393 	dataPtr = (GLuint*)gl.mapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint),
394 										 GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
395 	GLU_EXPECT_NO_ERROR(gl.getError(), "mapBufferRange() call failed.");
396 
397 	*dataPtr = 0;
398 
399 	gl.unmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
400 	GLU_EXPECT_NO_ERROR(gl.getError(), "unmapBuffer() call failed.");
401 }
402 
checkAtomicCounterBuffer(AtomicOperation * atomicOp)403 bool ShaderAtomicCounterOpsTestBase::checkAtomicCounterBuffer(AtomicOperation* atomicOp)
404 {
405 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
406 
407 	GLuint* dataPtr;
408 
409 	// get value
410 
411 	gl.bindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_atomicCounterBuffer);
412 	GLU_EXPECT_NO_ERROR(gl.getError(), "bindBuffer() call failed.");
413 
414 	dataPtr = (GLuint*)gl.mapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint), GL_MAP_READ_BIT);
415 	GLU_EXPECT_NO_ERROR(gl.getError(), "mapBufferRange() call failed.");
416 
417 	GLuint finalValue = *dataPtr;
418 
419 	gl.unmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
420 	GLU_EXPECT_NO_ERROR(gl.getError(), "unmapBuffer() call failed.");
421 
422 	// get calls
423 
424 	gl.bindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_atomicCounterCallsBuffer);
425 	GLU_EXPECT_NO_ERROR(gl.getError(), "bindBuffer() call failed.");
426 
427 	dataPtr = (GLuint*)gl.mapBufferRange(GL_ATOMIC_COUNTER_BUFFER, 0, sizeof(GLuint), GL_MAP_READ_BIT);
428 	GLU_EXPECT_NO_ERROR(gl.getError(), "mapBufferRange() call failed.");
429 
430 	GLuint numberOfCalls = *dataPtr;
431 
432 	gl.unmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
433 	GLU_EXPECT_NO_ERROR(gl.getError(), "unmapBuffer() call failed.");
434 
435 	// validate
436 
437 	GLuint expectedValue = atomicOp->getResult(numberOfCalls);
438 
439 	return finalValue == expectedValue;
440 }
441 
bindBuffers()442 void ShaderAtomicCounterOpsTestBase::bindBuffers()
443 {
444 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
445 
446 	gl.bindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, m_atomicCounterBuffer);
447 	GLU_EXPECT_NO_ERROR(gl.getError(), "bindBufferBase() call failed.");
448 
449 	gl.bindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 1, m_atomicCounterCallsBuffer);
450 	GLU_EXPECT_NO_ERROR(gl.getError(), "bindBufferBase() call failed.");
451 }
452 
validateColor(tcu::Vec4 testedColor,tcu::Vec4 desiredColor)453 bool ShaderAtomicCounterOpsTestBase::validateColor(tcu::Vec4 testedColor, tcu::Vec4 desiredColor)
454 {
455 	const float epsilon = 1.1f / 31.0f; // Accommodate framebuffers with 5-bit channels.
456 	return de::abs(testedColor.x() - desiredColor.x()) < epsilon &&
457 		   de::abs(testedColor.y() - desiredColor.y()) < epsilon &&
458 		   de::abs(testedColor.z() - desiredColor.z()) < epsilon;
459 }
460 
validateScreenPixels(tcu::Vec4 desiredColor,tcu::Vec4 ignoredColor)461 bool ShaderAtomicCounterOpsTestBase::validateScreenPixels(tcu::Vec4 desiredColor, tcu::Vec4 ignoredColor)
462 {
463 	const glw::Functions&   gl			 = m_context.getRenderContext().getFunctions();
464 	const tcu::RenderTarget renderTarget = m_context.getRenderContext().getRenderTarget();
465 	tcu::IVec2				size(renderTarget.getWidth(), renderTarget.getHeight());
466 
467 	glw::GLfloat* pixels = new glw::GLfloat[size.x() * size.y() * 4];
468 
469 	// clear buffer
470 	for (int x = 0; x < size.x(); ++x)
471 	{
472 		for (int y = 0; y < size.y(); ++y)
473 		{
474 			int mappedPixelPosition = y * size.x() + x;
475 
476 			pixels[mappedPixelPosition * 4 + 0] = -1.0f;
477 			pixels[mappedPixelPosition * 4 + 1] = -1.0f;
478 			pixels[mappedPixelPosition * 4 + 2] = -1.0f;
479 			pixels[mappedPixelPosition * 4 + 3] = -1.0f;
480 		}
481 	}
482 
483 	// read pixels
484 	gl.readPixels(0, 0, size.x(), size.y(), GL_RGBA, GL_FLOAT, pixels);
485 
486 	// validate pixels
487 	bool rendered = false;
488 	for (int x = 0; x < size.x(); ++x)
489 	{
490 		for (int y = 0; y < size.y(); ++y)
491 		{
492 			int mappedPixelPosition = y * size.x() + x;
493 
494 			tcu::Vec4 color(pixels[mappedPixelPosition * 4 + 0], pixels[mappedPixelPosition * 4 + 1],
495 							pixels[mappedPixelPosition * 4 + 2], pixels[mappedPixelPosition * 4 + 3]);
496 
497 			if (!validateColor(color, ignoredColor))
498 			{
499 				rendered = true;
500 				if (!validateColor(color, desiredColor))
501 				{
502 					delete[] pixels;
503 					return false;
504 				}
505 			}
506 		}
507 	}
508 
509 	delete[] pixels;
510 
511 	return rendered;
512 }
513 
ShaderAtomicCounterOpsTestBase(deqp::Context & context,const char * name,const char * description)514 ShaderAtomicCounterOpsTestBase::ShaderAtomicCounterOpsTestBase(deqp::Context& context, const char* name,
515 															   const char* description)
516 	: TestCase(context, name, description), m_atomicCounterBuffer(0), m_atomicCounterCallsBuffer(0)
517 {
518 	glu::ContextType contextType = m_context.getRenderContext().getType();
519 	m_contextSupportsGL46		 = glu::contextSupports(contextType, glu::ApiType::core(4, 6));
520 }
521 
init()522 void ShaderAtomicCounterOpsTestBase::init()
523 {
524 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
525 
526 	// generate atomic counter buffer
527 
528 	gl.genBuffers(1, &m_atomicCounterBuffer);
529 	GLU_EXPECT_NO_ERROR(gl.getError(), "genBuffers() call failed.");
530 
531 	gl.bindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_atomicCounterBuffer);
532 	GLU_EXPECT_NO_ERROR(gl.getError(), "bindBuffer() call failed.");
533 
534 	gl.bufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(GLuint), NULL, GL_DYNAMIC_DRAW);
535 	GLU_EXPECT_NO_ERROR(gl.getError(), "bufferData() call failed.");
536 
537 	// generate atomic counter calls buffer
538 
539 	gl.genBuffers(1, &m_atomicCounterCallsBuffer);
540 	GLU_EXPECT_NO_ERROR(gl.getError(), "genBuffers() call failed.");
541 
542 	gl.bindBuffer(GL_ATOMIC_COUNTER_BUFFER, m_atomicCounterCallsBuffer);
543 	GLU_EXPECT_NO_ERROR(gl.getError(), "bindBuffer() call failed.");
544 
545 	gl.bufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(GLuint), NULL, GL_DYNAMIC_DRAW);
546 	GLU_EXPECT_NO_ERROR(gl.getError(), "bufferData() call failed.");
547 
548 	// setup tested atomic operations
549 
550 	setOperations();
551 
552 	// setup shaders
553 
554 	for (ShaderPipelineIter iter = m_shaderPipelines.begin(); iter != m_shaderPipelines.end(); ++iter)
555 	{
556 		iter->create(m_context);
557 	}
558 }
559 
deinit()560 void ShaderAtomicCounterOpsTestBase::deinit()
561 {
562 	const glw::Functions& gl = m_context.getRenderContext().getFunctions();
563 
564 	// delete atomic counter buffer
565 
566 	gl.deleteBuffers(1, &m_atomicCounterBuffer);
567 	GLU_EXPECT_NO_ERROR(gl.getError(), "deleteBuffers() call failed.");
568 
569 	// delete atomic counter calls buffer
570 
571 	gl.deleteBuffers(1, &m_atomicCounterCallsBuffer);
572 	GLU_EXPECT_NO_ERROR(gl.getError(), "deleteBuffers() call failed.");
573 
574 	// delete operations
575 
576 	for (AtomicOperationIter iter = m_operations.begin(); iter != m_operations.end(); ++iter)
577 	{
578 		delete *iter;
579 	}
580 }
581 
iterate()582 tcu::TestNode::IterateResult ShaderAtomicCounterOpsTestBase::iterate()
583 {
584 	if (!m_contextSupportsGL46)
585 	{
586 		if (!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_atomic_counters") ||
587 			!m_context.getContextInfo().isExtensionSupported("GL_ARB_shader_atomic_counter_ops"))
588 		{
589 			m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not supported");
590 			return STOP;
591 		}
592 	}
593 
594 	for (ShaderPipelineIter iter = m_shaderPipelines.begin(); iter != m_shaderPipelines.end(); ++iter)
595 	{
596 		fillAtomicCounterBuffer(iter->getAtomicOperation());
597 		bindBuffers();
598 		iter->test(m_context);
599 
600 		bool		operationValueValid = checkAtomicCounterBuffer(iter->getAtomicOperation());
601 		std::string operationFailMsg	= "Result of atomic operation was different than expected (" +
602 									   iter->getAtomicOperation()->getFunction() + ").";
603 		TCU_CHECK_MSG(operationValueValid, operationFailMsg.c_str());
604 
605 		bool		returnValueValid = validateScreenPixels(tcu::Vec4(1.0f), tcu::Vec4(0.5f));
606 		std::string returnFailMsg	= "Result of atomic operation return value was different than expected (" +
607 									iter->getAtomicOperation()->getFunction() + ").";
608 		TCU_CHECK_MSG(returnValueValid, returnFailMsg.c_str());
609 	}
610 
611 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
612 	return STOP;
613 }
614 
615 /** Constructor.
616 *
617 *  @param context Rendering context
618 */
ShaderAtomicCounterOpsAdditionSubstractionTestCase(deqp::Context & context)619 ShaderAtomicCounterOpsAdditionSubstractionTestCase::ShaderAtomicCounterOpsAdditionSubstractionTestCase(
620 	deqp::Context& context)
621 	: ShaderAtomicCounterOpsTestBase(
622 		  context, "ShaderAtomicCounterOpsAdditionSubstractionTestCase",
623 		  "Implements verification of new built-in addition and substraction atomic counter operations")
624 {
625 }
626 
setOperations()627 void ShaderAtomicCounterOpsAdditionSubstractionTestCase::setOperations()
628 {
629 	glw::GLuint input = 12;
630 	glw::GLuint param = 4;
631 
632 	addOperation(new AtomicOperationAdd(input, param));
633 	addOperation(new AtomicOperationSubtract(input, param));
634 }
635 
636 /** Constructor.
637 *
638 *  @param context Rendering context
639 */
ShaderAtomicCounterOpsMinMaxTestCase(deqp::Context & context)640 ShaderAtomicCounterOpsMinMaxTestCase::ShaderAtomicCounterOpsMinMaxTestCase(deqp::Context& context)
641 	: ShaderAtomicCounterOpsTestBase(
642 		  context, "ShaderAtomicCounterOpsMinMaxTestCase",
643 		  "Implements verification of new built-in minimum and maximum atomic counter operations")
644 {
645 }
646 
setOperations()647 void ShaderAtomicCounterOpsMinMaxTestCase::setOperations()
648 {
649 	glw::GLuint input	= 12;
650 	glw::GLuint params[] = { 4, 16 };
651 
652 	addOperation(new AtomicOperationMin(input, params[0]));
653 	addOperation(new AtomicOperationMin(input, params[1]));
654 	addOperation(new AtomicOperationMax(input, params[0]));
655 	addOperation(new AtomicOperationMax(input, params[1]));
656 }
657 
658 /** Constructor.
659 *
660 *  @param context Rendering context
661 */
ShaderAtomicCounterOpsBitwiseTestCase(deqp::Context & context)662 ShaderAtomicCounterOpsBitwiseTestCase::ShaderAtomicCounterOpsBitwiseTestCase(deqp::Context& context)
663 	: ShaderAtomicCounterOpsTestBase(context, "ShaderAtomicCounterOpsBitwiseTestCase",
664 									 "Implements verification of new built-in bitwise atomic counter operations")
665 {
666 }
667 
setOperations()668 void ShaderAtomicCounterOpsBitwiseTestCase::setOperations()
669 {
670 	glw::GLuint input = 0x2ED; // 0b1011101101;
671 	glw::GLuint param = 0x3A9; // 0b1110101001;
672 
673 	addOperation(new AtomicOperationAnd(input, param));
674 	addOperation(new AtomicOperationOr(input, param));
675 	addOperation(new AtomicOperationXor(input, param));
676 }
677 
678 /** Constructor.
679 *
680 *  @param context Rendering context
681 */
ShaderAtomicCounterOpsExchangeTestCase(deqp::Context & context)682 ShaderAtomicCounterOpsExchangeTestCase::ShaderAtomicCounterOpsExchangeTestCase(deqp::Context& context)
683 	: ShaderAtomicCounterOpsTestBase(
684 		  context, "ShaderAtomicCounterOpsExchangeTestCase",
685 		  "Implements verification of new built-in exchange and swap atomic counter operations")
686 {
687 }
688 
setOperations()689 void ShaderAtomicCounterOpsExchangeTestCase::setOperations()
690 {
691 	glw::GLuint input	 = 5;
692 	glw::GLuint param	 = 10;
693 	glw::GLuint compare[] = { 5, 20 };
694 
695 	addOperation(new AtomicOperationExchange(input, param));
696 	addOperation(new AtomicOperationCompSwap(input, param, compare[0]));
697 	addOperation(new AtomicOperationCompSwap(input, param, compare[1]));
698 }
699 
700 /** Constructor.
701 *
702 *  @param context Rendering context.
703 */
ShaderAtomicCounterOps(deqp::Context & context)704 ShaderAtomicCounterOps::ShaderAtomicCounterOps(deqp::Context& context)
705 	: TestCaseGroup(context, "shader_atomic_counter_ops_tests",
706 					"Verify conformance of CTS_ARB_shader_atomic_counter_ops implementation")
707 {
708 }
709 
710 /** Initializes the test group contents. */
init()711 void ShaderAtomicCounterOps::init()
712 {
713 	addChild(new ShaderAtomicCounterOpsAdditionSubstractionTestCase(m_context));
714 	addChild(new ShaderAtomicCounterOpsMinMaxTestCase(m_context));
715 	addChild(new ShaderAtomicCounterOpsBitwiseTestCase(m_context));
716 	addChild(new ShaderAtomicCounterOpsExchangeTestCase(m_context));
717 }
718 } /* gl4cts namespace */
719