void ShaderAtomicCounterOpsTestBase::ShaderPipeline::create(deqp::Context& context)
{
	glu::ProgramSources sources;
	for (unsigned int i = 0; i < glu::SHADERTYPE_COMPUTE; ++i)
	{
		if (!m_shaders[i].empty())
		{
			sources.sources[i].push_back(m_shaders[i]);
		}
	}
	m_program = new glu::ShaderProgram(context.getRenderContext(), sources);

	if (!m_program->isOk())
	{
		TCU_FAIL("Shader compilation failed");
	}

	glu::ProgramSources sourcesCompute;
	sourcesCompute.sources[glu::SHADERTYPE_COMPUTE].push_back(m_shaders[glu::SHADERTYPE_COMPUTE]);
	m_programCompute = new glu::ShaderProgram(context.getRenderContext(), sourcesCompute);

	if (!m_programCompute->isOk())
	{
		TCU_FAIL("Shader compilation failed");
	}
}
bool ShaderBallotBaseTestCase::validateScreenPixels(deqp::Context& context, tcu::Vec4 desiredColor,
													tcu::Vec4 ignoredColor)
{
	const glw::Functions&   gl			 = context.getRenderContext().getFunctions();
	const tcu::RenderTarget renderTarget = context.getRenderContext().getRenderTarget();
	tcu::IVec2				size(renderTarget.getWidth(), renderTarget.getHeight());

	glw::GLfloat* pixels = new glw::GLfloat[size.x() * size.y() * 4];

	// clear buffer
	for (int x = 0; x < size.x(); ++x)
	{
		for (int y = 0; y < size.y(); ++y)
		{
			int mappedPixelPosition = y * size.x() + x;

			pixels[mappedPixelPosition * 4 + 0] = -1.0f;
			pixels[mappedPixelPosition * 4 + 1] = -1.0f;
			pixels[mappedPixelPosition * 4 + 2] = -1.0f;
			pixels[mappedPixelPosition * 4 + 3] = -1.0f;
		}
	}

	// read pixels
	gl.readPixels(0, 0, size.x(), size.y(), GL_RGBA, GL_FLOAT, pixels);

	// validate pixels
	bool rendered = false;
	for (int x = 0; x < size.x(); ++x)
	{
		for (int y = 0; y < size.y(); ++y)
		{
			int mappedPixelPosition = y * size.x() + x;

			tcu::Vec4 color(pixels[mappedPixelPosition * 4 + 0], pixels[mappedPixelPosition * 4 + 1],
							pixels[mappedPixelPosition * 4 + 2], pixels[mappedPixelPosition * 4 + 3]);

			if (!ShaderBallotBaseTestCase::validateColor(color, ignoredColor))
			{
				rendered = true;
				if (!ShaderBallotBaseTestCase::validateColor(color, desiredColor))
				{
					return false;
				}
			}
		}
	}

	delete[] pixels;

	return rendered;
}
void ShaderBallotBaseTestCase::ShaderPipeline::renderQuad(deqp::Context& context)
{
	const glw::Functions& gl = context.getRenderContext().getFunctions();

	deUint16 const quadIndices[] = { 0, 1, 2, 2, 1, 3 };

	float const position[] = { -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f };

	glu::VertexArrayBinding vertexArrays[] = { glu::va::Float("inPosition", 2, 4, 0, position) };

	this->use(context);

	glu::PrimitiveList primitiveList = glu::pr::Patches(DE_LENGTH_OF_ARRAY(quadIndices), quadIndices);

	glu::draw(context.getRenderContext(), m_programRender->getProgram(), DE_LENGTH_OF_ARRAY(vertexArrays), vertexArrays,
			  primitiveList);

	GLU_EXPECT_NO_ERROR(gl.getError(), "glu::draw error");
}
bool ShaderBallotBaseTestCase::validateScreenPixelsSameColor(deqp::Context& context, tcu::Vec4 ignoredColor)
{
	const glw::Functions&   gl			 = context.getRenderContext().getFunctions();
	const tcu::RenderTarget renderTarget = context.getRenderContext().getRenderTarget();
	tcu::IVec2				size(renderTarget.getWidth(), renderTarget.getHeight());

	glw::GLfloat* centerPixel = new glw::GLfloat[4];
	centerPixel[0]			  = -1.0f;
	centerPixel[1]			  = -1.0f;
	centerPixel[2]			  = -1.0f;
	centerPixel[3]			  = -1.0f;

	// read pixel
	gl.readPixels(size.x() / 2, size.y() / 2, 1, 1, GL_RGBA, GL_FLOAT, centerPixel);

	tcu::Vec4 desiredColor(centerPixel[0], centerPixel[1], centerPixel[2], centerPixel[3]);

	delete[] centerPixel;

	// validation
	return ShaderBallotBaseTestCase::validateScreenPixels(context, desiredColor, ignoredColor);
}
void ShaderAtomicCounterOpsTestBase::ShaderPipeline::renderQuad(deqp::Context& context)
{
	const glw::Functions& gl = context.getRenderContext().getFunctions();

	deUint16 const quadIndices[] = { 0, 1, 2, 2, 1, 3 };

	float const position[] = { -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f };

	glu::VertexArrayBinding vertexArrays[] = { glu::va::Float("inPosition", 2, 4, 0, position) };

	this->use(context);

	glu::PrimitiveList primitiveList = glu::pr::Patches(DE_LENGTH_OF_ARRAY(quadIndices), quadIndices);

	glu::draw(context.getRenderContext(), this->getShaderProgram()->getProgram(), DE_LENGTH_OF_ARRAY(vertexArrays),
			  vertexArrays, primitiveList);

	GLU_EXPECT_NO_ERROR(gl.getError(), "glu::draw error");

	gl.memoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
	GLU_EXPECT_NO_ERROR(gl.getError(), "glMemoryBarrier() error");
}
void ShaderAtomicCounterOpsTestBase::ShaderPipeline::test(deqp::Context& context)
{
	const glw::Functions& gl = context.getRenderContext().getFunctions();

	gl.clearColor(0.5f, 0.5f, 0.5f, 1.0f);
	gl.clear(GL_COLOR_BUFFER_BIT);

	if (m_testedShader == glu::SHADERTYPE_COMPUTE)
	{
		executeComputeShader(context);
	}
	else
	{
		renderQuad(context);
	}

	gl.flush();
}
void ShaderBallotBaseTestCase::ShaderPipeline::use(deqp::Context& context)
{
	const glw::Functions& gl = context.getRenderContext().getFunctions();
	gl.useProgram(m_programRender->getProgram());
	GLU_EXPECT_NO_ERROR(gl.getError(), "glUseProgram failed");
}
void ShaderBallotBaseTestCase::ShaderPipeline::executeComputeShader(deqp::Context& context)
{
	const glw::Functions& gl = context.getRenderContext().getFunctions();

	const glu::Texture outputTexture(context.getRenderContext());

	gl.useProgram(m_programCompute->getProgram());

	// output image
	gl.bindTexture(GL_TEXTURE_2D, *outputTexture);
	gl.texStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32UI, 16, 16);
	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	GLU_EXPECT_NO_ERROR(gl.getError(), "Uploading image data failed");

	// bind image
	gl.bindImageTexture(1, *outputTexture, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32UI);
	GLU_EXPECT_NO_ERROR(gl.getError(), "Image setup failed");

	// dispatch compute
	gl.dispatchCompute(1, 1, 1);
	GLU_EXPECT_NO_ERROR(gl.getError(), "glDispatchCompute()");

	gl.memoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT);
	GLU_EXPECT_NO_ERROR(gl.getError(), "glMemoryBarrier()");

	// render output texture

	std::string vs = "#version 450 core\n"
					 "in highp vec2 position;\n"
					 "in vec2 inTexcoord;\n"
					 "out vec2 texcoord;\n"
					 "void main()\n"
					 "{\n"
					 "	texcoord = inTexcoord;\n"
					 "	gl_Position = vec4(position, 0.0, 1.0);\n"
					 "}\n";

	std::string fs = "#version 450 core\n"
					 "uniform sampler2D sampler;\n"
					 "in vec2 texcoord;\n"
					 "out vec4 color;\n"
					 "void main()\n"
					 "{\n"
					 "	color = texture(sampler, texcoord);\n"
					 "}\n";

	glu::ProgramSources sources;
	sources.sources[glu::SHADERTYPE_VERTEX].push_back(vs);
	sources.sources[glu::SHADERTYPE_FRAGMENT].push_back(fs);
	glu::ShaderProgram renderShader(context.getRenderContext(), sources);

	if (!m_programRender->isOk())
	{
		TCU_FAIL("Shader compilation failed");
	}

	gl.bindTexture(GL_TEXTURE_2D, *outputTexture);
	GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTexture() call failed.");

	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	gl.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

	gl.useProgram(renderShader.getProgram());

	gl.uniform1i(gl.getUniformLocation(renderShader.getProgram(), "sampler"), 0);
	GLU_EXPECT_NO_ERROR(gl.getError(), "glUniform1i failed");

	deUint16 const quadIndices[] = { 0, 1, 2, 2, 1, 3 };

	float const position[] = { -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f };

	float const texCoord[] = { 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f };

	glu::VertexArrayBinding vertexArrays[] = { glu::va::Float("position", 2, 4, 0, position),
											   glu::va::Float("inTexcoord", 2, 4, 0, texCoord) };

	glu::draw(context.getRenderContext(), renderShader.getProgram(), DE_LENGTH_OF_ARRAY(vertexArrays), vertexArrays,
			  glu::pr::TriangleStrip(DE_LENGTH_OF_ARRAY(quadIndices), quadIndices));

	GLU_EXPECT_NO_ERROR(gl.getError(), "glu::draw error");
}