Home | History | Annotate | Download | only in gl
      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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 */
    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 
    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 */
    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 
    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 */
    662 ShaderAtomicCounterOpsBitwiseTestCase::ShaderAtomicCounterOpsBitwiseTestCase(deqp::Context& context)
    663 	: ShaderAtomicCounterOpsTestBase(context, "ShaderAtomicCounterOpsBitwiseTestCase",
    664 									 "Implements verification of new built-in bitwise atomic counter operations")
    665 {
    666 }
    667 
    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 */
    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 
    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 */
    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. */
    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