Home | History | Annotate | Download | only in glshared
      1 /*-------------------------------------------------------------------------
      2  * drawElements Quality Program OpenGL (ES) Module
      3  * -----------------------------------------------
      4  *
      5  * Copyright 2014 The Android Open Source Project
      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 Random shader test case.
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "glsRandomShaderCase.hpp"
     25 
     26 #include "gluShaderProgram.hpp"
     27 #include "gluPixelTransfer.hpp"
     28 #include "gluTextureUtil.hpp"
     29 
     30 #include "tcuImageCompare.hpp"
     31 #include "tcuTestLog.hpp"
     32 #include "deRandom.hpp"
     33 
     34 #include "rsgProgramGenerator.hpp"
     35 #include "rsgProgramExecutor.hpp"
     36 #include "rsgUtils.hpp"
     37 
     38 #include "tcuTextureUtil.hpp"
     39 #include "tcuRenderTarget.hpp"
     40 
     41 #include "glw.h"
     42 
     43 using std::vector;
     44 using std::string;
     45 using std::pair;
     46 using std::map;
     47 
     48 namespace deqp
     49 {
     50 namespace gls
     51 {
     52 
     53 enum
     54 {
     55 	VIEWPORT_WIDTH			= 64,
     56 	VIEWPORT_HEIGHT			= 64,
     57 
     58 	TEXTURE_2D_WIDTH		= 64,
     59 	TEXTURE_2D_HEIGHT		= 64,
     60 	TEXTURE_2D_FORMAT		= GL_RGBA,
     61 	TEXTURE_2D_DATA_TYPE	= GL_UNSIGNED_BYTE,
     62 
     63 	TEXTURE_CUBE_SIZE		= 16,
     64 	TEXTURE_CUBE_FORMAT		= GL_RGBA,
     65 	TEXTURE_CUBE_DATA_TYPE	= GL_UNSIGNED_BYTE,
     66 
     67 	TEXTURE_WRAP_S			= GL_CLAMP_TO_EDGE,
     68 	TEXTURE_WRAP_T			= GL_CLAMP_TO_EDGE,
     69 
     70 	TEXTURE_MIN_FILTER		= GL_LINEAR,
     71 	TEXTURE_MAG_FILTER		= GL_LINEAR
     72 };
     73 
     74 VertexArray::VertexArray (const rsg::ShaderInput* input, int numVertices)
     75 	: m_input			(input)
     76 	, m_vertices		(input->getVariable()->getType().getNumElements() * numVertices)
     77 {
     78 }
     79 
     80 TextureManager::TextureManager (void)
     81 {
     82 }
     83 
     84 TextureManager::~TextureManager (void)
     85 {
     86 }
     87 
     88 void TextureManager::bindTexture (int unit, const glu::Texture2D* tex2D)
     89 {
     90 	m_tex2D[unit] = tex2D;
     91 }
     92 
     93 void TextureManager::bindTexture (int unit, const glu::TextureCube* texCube)
     94 {
     95 	m_texCube[unit] = texCube;
     96 }
     97 
     98 inline vector<pair<int, const glu::Texture2D*> > TextureManager::getBindings2D (void) const
     99 {
    100 	vector<pair<int, const glu::Texture2D*> > bindings;
    101 	for (map<int, const glu::Texture2D*>::const_iterator i = m_tex2D.begin(); i != m_tex2D.end(); i++)
    102 		bindings.push_back(*i);
    103 	return bindings;
    104 }
    105 
    106 inline vector<pair<int, const glu::TextureCube*> > TextureManager::getBindingsCube (void) const
    107 {
    108 	vector<pair<int, const glu::TextureCube*> > bindings;
    109 	for (map<int, const glu::TextureCube*>::const_iterator i = m_texCube.begin(); i != m_texCube.end(); i++)
    110 		bindings.push_back(*i);
    111 	return bindings;
    112 }
    113 
    114 RandomShaderCase::RandomShaderCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const char* name, const char* description, const rsg::ProgramParameters& params)
    115 	: tcu::TestCase		(testCtx, name, description)
    116 	, m_renderCtx		(renderCtx)
    117 	, m_parameters		(params)
    118 	, m_gridWidth		(1)
    119 	, m_gridHeight		(1)
    120 	, m_vertexShader	(rsg::Shader::TYPE_VERTEX)
    121 	, m_fragmentShader	(rsg::Shader::TYPE_FRAGMENT)
    122 	, m_tex2D			(DE_NULL)
    123 	, m_texCube			(DE_NULL)
    124 {
    125 }
    126 
    127 RandomShaderCase::~RandomShaderCase (void)
    128 {
    129 	delete m_tex2D;
    130 	delete m_texCube;
    131 }
    132 
    133 void RandomShaderCase::init (void)
    134 {
    135 	// Generate shaders
    136 	rsg::ProgramGenerator programGenerator;
    137 	programGenerator.generate(m_parameters, m_vertexShader, m_fragmentShader);
    138 
    139 	// Compute uniform values
    140 	std::vector<const rsg::ShaderInput*>	unifiedUniforms;
    141 	de::Random								rnd(m_parameters.seed);
    142 	rsg::computeUnifiedUniforms(m_vertexShader, m_fragmentShader, unifiedUniforms);
    143 	rsg::computeUniformValues(rnd, m_uniforms, unifiedUniforms);
    144 
    145 	// Generate vertices
    146 	const vector<rsg::ShaderInput*>&	inputs		= m_vertexShader.getInputs();
    147 	int									numVertices	= (m_gridWidth+1)*(m_gridHeight+1);
    148 
    149 	for (vector<rsg::ShaderInput*>::const_iterator i = inputs.begin(); i != inputs.end(); i++)
    150 	{
    151 		const rsg::ShaderInput*			input			= *i;
    152 		rsg::ConstValueRangeAccess		valueRange		= input->getValueRange();
    153 		int								numComponents	= input->getVariable()->getType().getNumElements();
    154 		VertexArray						vtxArray(input, numVertices);
    155 		bool							isPosition		= string(input->getVariable()->getName()) == "dEQP_Position";
    156 
    157 		TCU_CHECK(input->getVariable()->getType().getBaseType() == rsg::VariableType::TYPE_FLOAT);
    158 
    159 		for (int vtxNdx = 0; vtxNdx < numVertices; vtxNdx++)
    160 		{
    161 			int		y	= vtxNdx / (m_gridWidth+1);
    162 			int		x	= vtxNdx - y*(m_gridWidth+1);
    163 			float	xf	= (float)x / (float)m_gridWidth;
    164 			float	yf	= (float)y / (float)m_gridHeight;
    165 			float*	dst	= &vtxArray.getVertices()[vtxNdx*numComponents];
    166 
    167 			if (isPosition)
    168 			{
    169 				// Position attribute gets special interpolation handling.
    170 				DE_ASSERT(numComponents == 4);
    171 				dst[0] = -1.0f + xf *  2.0f;
    172 				dst[1] =  1.0f + yf * -2.0f;
    173 				dst[2] = 0.0f;
    174 				dst[3] = 1.0f;
    175 			}
    176 			else
    177 			{
    178 				for (int compNdx = 0; compNdx < numComponents; compNdx++)
    179 				{
    180 					float	minVal	= valueRange.getMin().component(compNdx).asFloat();
    181 					float	maxVal	= valueRange.getMax().component(compNdx).asFloat();
    182 					float	xd, yd;
    183 
    184 					rsg::getVertexInterpolationCoords(xd, yd, xf, yf, compNdx);
    185 
    186 					float	f		= (xd+yd) / 2.0f;
    187 
    188 					dst[compNdx] = minVal + f * (maxVal-minVal);
    189 				}
    190 			}
    191 		}
    192 
    193 		m_vertexArrays.push_back(vtxArray);
    194 	}
    195 
    196 	// Generate indices
    197 	int numQuads	= m_gridWidth*m_gridHeight;
    198 	int numIndices	= numQuads*6;
    199 	m_indices.resize(numIndices);
    200 	for (int quadNdx = 0; quadNdx < numQuads; quadNdx++)
    201 	{
    202 		int	quadY	= quadNdx / (m_gridWidth);
    203 		int quadX	= quadNdx - quadY*m_gridWidth;
    204 
    205 		m_indices[quadNdx*6+0] = quadX + quadY*(m_gridWidth+1);
    206 		m_indices[quadNdx*6+1] = quadX + (quadY+1)*(m_gridWidth+1);
    207 		m_indices[quadNdx*6+2] = quadX + quadY*(m_gridWidth+1) + 1;
    208 		m_indices[quadNdx*6+3] = m_indices[quadNdx*6+2];
    209 		m_indices[quadNdx*6+4] = m_indices[quadNdx*6+1];
    210 		m_indices[quadNdx*6+5] = quadX + (quadY+1)*(m_gridWidth+1) + 1;
    211 	}
    212 
    213 	// Create textures.
    214 	for (vector<rsg::VariableValue>::const_iterator uniformIter = m_uniforms.begin(); uniformIter != m_uniforms.end(); uniformIter++)
    215 	{
    216 		const rsg::VariableType& type = uniformIter->getVariable()->getType();
    217 
    218 		if (!type.isSampler())
    219 			continue;
    220 
    221 		int unitNdx = uniformIter->getValue().asInt(0);
    222 
    223 		if (type == rsg::VariableType(rsg::VariableType::TYPE_SAMPLER_2D, 1))
    224 			m_texManager.bindTexture(unitNdx, getTex2D());
    225 		else if (type == rsg::VariableType(rsg::VariableType::TYPE_SAMPLER_CUBE, 1))
    226 			m_texManager.bindTexture(unitNdx, getTexCube());
    227 		else
    228 			DE_ASSERT(DE_FALSE);
    229 	}
    230 }
    231 
    232 const glu::Texture2D* RandomShaderCase::getTex2D (void)
    233 {
    234 	if (!m_tex2D)
    235 	{
    236 		m_tex2D = new glu::Texture2D(m_renderCtx, TEXTURE_2D_FORMAT, TEXTURE_2D_DATA_TYPE, TEXTURE_2D_WIDTH, TEXTURE_2D_HEIGHT);
    237 
    238 		m_tex2D->getRefTexture().allocLevel(0);
    239 		tcu::fillWithComponentGradients(m_tex2D->getRefTexture().getLevel(0), tcu::Vec4(-1.0f, -1.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f));
    240 		m_tex2D->upload();
    241 
    242 		// Setup parameters.
    243 		glBindTexture(GL_TEXTURE_2D, m_tex2D->getGLTexture());
    244 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,		TEXTURE_WRAP_S);
    245 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,		TEXTURE_WRAP_T);
    246 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,	TEXTURE_MIN_FILTER);
    247 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,	TEXTURE_MAG_FILTER);
    248 
    249 		GLU_CHECK();
    250 	}
    251 
    252 	return m_tex2D;
    253 }
    254 
    255 const glu::TextureCube* RandomShaderCase::getTexCube (void)
    256 {
    257 	if (!m_texCube)
    258 	{
    259 		m_texCube = new glu::TextureCube(m_renderCtx, TEXTURE_CUBE_FORMAT, TEXTURE_CUBE_DATA_TYPE, TEXTURE_CUBE_SIZE);
    260 
    261 		static const tcu::Vec4 gradients[tcu::CUBEFACE_LAST][2] =
    262 		{
    263 			{ tcu::Vec4(-1.0f, -1.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // negative x
    264 			{ tcu::Vec4( 0.0f, -1.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // positive x
    265 			{ tcu::Vec4(-1.0f,  0.0f, -1.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // negative y
    266 			{ tcu::Vec4(-1.0f, -1.0f,  0.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }, // positive y
    267 			{ tcu::Vec4(-1.0f, -1.0f, -1.0f, 0.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f) }, // negative z
    268 			{ tcu::Vec4( 0.0f,  0.0f,  0.0f, 2.0f), tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f) }  // positive z
    269 		};
    270 
    271 		// Fill level 0.
    272 		for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
    273 		{
    274 			m_texCube->getRefTexture().allocLevel((tcu::CubeFace)face, 0);
    275 			tcu::fillWithComponentGradients(m_texCube->getRefTexture().getLevelFace(0, (tcu::CubeFace)face), gradients[face][0], gradients[face][1]);
    276 		}
    277 
    278 		m_texCube->upload();
    279 
    280 		// Setup parameters.
    281 		glBindTexture(GL_TEXTURE_CUBE_MAP, m_texCube->getGLTexture());
    282 		glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S,		TEXTURE_WRAP_S);
    283 		glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T,		TEXTURE_WRAP_T);
    284 		glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER,	TEXTURE_MIN_FILTER);
    285 		glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER,	TEXTURE_MAG_FILTER);
    286 
    287 		GLU_CHECK();
    288 	}
    289 
    290 	return m_texCube;
    291 }
    292 
    293 void RandomShaderCase::deinit (void)
    294 {
    295 	delete m_tex2D;
    296 	delete m_texCube;
    297 
    298 	m_tex2D		= DE_NULL;
    299 	m_texCube	= DE_NULL;
    300 
    301 	// Free up memory
    302 	m_vertexArrays.clear();
    303 	m_indices.clear();
    304 }
    305 
    306 namespace
    307 {
    308 
    309 void setUniformValue (int location, rsg::ConstValueAccess value)
    310 {
    311 	DE_STATIC_ASSERT(sizeof(rsg::Scalar) == sizeof(float));
    312 	DE_STATIC_ASSERT(sizeof(rsg::Scalar) == sizeof(int));
    313 
    314 	switch (value.getType().getBaseType())
    315 	{
    316 		case rsg::VariableType::TYPE_FLOAT:
    317 			switch (value.getType().getNumElements())
    318 			{
    319 				case 1:		glUniform1fv(location, 1, (float*)value.value().getValuePtr());		break;
    320 				case 2:		glUniform2fv(location, 1, (float*)value.value().getValuePtr());		break;
    321 				case 3:		glUniform3fv(location, 1, (float*)value.value().getValuePtr());		break;
    322 				case 4:		glUniform4fv(location, 1, (float*)value.value().getValuePtr());		break;
    323 				default:	TCU_FAIL("Unsupported type");										break;
    324 			}
    325 			break;
    326 
    327 		case rsg::VariableType::TYPE_INT:
    328 		case rsg::VariableType::TYPE_BOOL:
    329 		case rsg::VariableType::TYPE_SAMPLER_2D:
    330 		case rsg::VariableType::TYPE_SAMPLER_CUBE:
    331 			switch (value.getType().getNumElements())
    332 			{
    333 				case 1:		glUniform1iv(location, 1, (int*)value.value().getValuePtr());		break;
    334 				case 2:		glUniform2iv(location, 1, (int*)value.value().getValuePtr());		break;
    335 				case 3:		glUniform3iv(location, 1, (int*)value.value().getValuePtr());		break;
    336 				case 4:		glUniform4iv(location, 1, (int*)value.value().getValuePtr());		break;
    337 				default:	TCU_FAIL("Unsupported type");										break;
    338 			}
    339 			break;
    340 
    341 		default:
    342 			TCU_FAIL("Unsupported type");
    343 	}
    344 }
    345 
    346 tcu::MessageBuilder& operator<< (tcu::MessageBuilder& message, rsg::ConstValueAccess value)
    347 {
    348 	const char*	scalarType	= DE_NULL;
    349 	const char* vecType		= DE_NULL;
    350 
    351 	switch (value.getType().getBaseType())
    352 	{
    353 		case rsg::VariableType::TYPE_FLOAT:			scalarType = "float";	vecType	= "vec";	break;
    354 		case rsg::VariableType::TYPE_INT:			scalarType = "int";		vecType = "ivec";	break;
    355 		case rsg::VariableType::TYPE_BOOL:			scalarType = "bool";	vecType = "bvec";	break;
    356 		case rsg::VariableType::TYPE_SAMPLER_2D:	scalarType = "sampler2D";					break;
    357 		case rsg::VariableType::TYPE_SAMPLER_CUBE:	scalarType = "samplerCube";					break;
    358 		default:
    359 			TCU_FAIL("Unsupported type.");
    360 	}
    361 
    362 	int numElements = value.getType().getNumElements();
    363 	if (numElements == 1)
    364 		message << scalarType << "(";
    365 	else
    366 		message << vecType << numElements << "(";
    367 
    368 	for (int elementNdx = 0; elementNdx < numElements; elementNdx++)
    369 	{
    370 		if (elementNdx > 0)
    371 			message << ", ";
    372 
    373 		switch (value.getType().getBaseType())
    374 		{
    375 			case rsg::VariableType::TYPE_FLOAT:			message << value.component(elementNdx).asFloat();						break;
    376 			case rsg::VariableType::TYPE_INT:			message << value.component(elementNdx).asInt();							break;
    377 			case rsg::VariableType::TYPE_BOOL:			message << (value.component(elementNdx).asBool() ? "true" : "false");	break;
    378 			case rsg::VariableType::TYPE_SAMPLER_2D:	message << value.component(elementNdx).asInt();							break;
    379 			case rsg::VariableType::TYPE_SAMPLER_CUBE:	message << value.component(elementNdx).asInt();							break;
    380 			default:
    381 				DE_ASSERT(DE_FALSE);
    382 		}
    383 	}
    384 
    385 	message << ")";
    386 
    387 	return message;
    388 }
    389 
    390 tcu::MessageBuilder& operator<< (tcu::MessageBuilder& message, rsg::ConstValueRangeAccess valueRange)
    391 {
    392 	return message << valueRange.getMin() << " -> " << valueRange.getMax();
    393 }
    394 
    395 } // anonymous
    396 
    397 RandomShaderCase::IterateResult RandomShaderCase::iterate (void)
    398 {
    399 	tcu::TestLog& log = m_testCtx.getLog();
    400 
    401 	// Compile program
    402 	glu::ShaderProgram program(m_renderCtx, glu::makeVtxFragSources(m_vertexShader.getSource(), m_fragmentShader.getSource()));
    403 	log << program;
    404 
    405 	if (!program.isOk())
    406 	{
    407 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Failed to compile shader");
    408 		return STOP;
    409 	}
    410 
    411 	// Compute random viewport
    412 	de::Random				rnd				(m_parameters.seed);
    413 	int						viewportWidth	= de::min<int>(VIEWPORT_WIDTH,	m_renderCtx.getRenderTarget().getWidth());
    414 	int						viewportHeight	= de::min<int>(VIEWPORT_HEIGHT,	m_renderCtx.getRenderTarget().getHeight());
    415 	int						viewportX		= rnd.getInt(0, m_renderCtx.getRenderTarget().getWidth()	- viewportWidth);
    416 	int						viewportY		= rnd.getInt(0, m_renderCtx.getRenderTarget().getHeight()	- viewportHeight);
    417 	bool					hasAlpha		= m_renderCtx.getRenderTarget().getPixelFormat().alphaBits > 0;
    418 	tcu::TextureLevel		rendered		(tcu::TextureFormat(hasAlpha ? tcu::TextureFormat::RGBA : tcu::TextureFormat::RGB, tcu::TextureFormat::UNORM_INT8), viewportWidth, viewportHeight);
    419 	tcu::TextureLevel		reference		(tcu::TextureFormat(hasAlpha ? tcu::TextureFormat::RGBA : tcu::TextureFormat::RGB, tcu::TextureFormat::UNORM_INT8), viewportWidth, viewportHeight);
    420 
    421 	// Reference program executor.
    422 	rsg::ProgramExecutor	executor		(reference.getAccess(), m_gridWidth, m_gridHeight);
    423 
    424 	GLU_CHECK_CALL(glUseProgram(program.getProgram()));
    425 
    426 	// Set up attributes
    427 	for (vector<VertexArray>::const_iterator attribIter = m_vertexArrays.begin(); attribIter != m_vertexArrays.end(); attribIter++)
    428 	{
    429 		GLint location = glGetAttribLocation(program.getProgram(), attribIter->getName());
    430 
    431 		// Print to log.
    432 		log << tcu::TestLog::Message << "attribute[" << location << "]: " << attribIter->getName() << " = " << attribIter->getValueRange() << tcu::TestLog::EndMessage;
    433 
    434 		if (location >= 0)
    435 		{
    436 			glVertexAttribPointer(location, attribIter->getNumComponents(), GL_FLOAT, GL_FALSE, 0, &attribIter->getVertices()[0]);
    437 			glEnableVertexAttribArray(location);
    438 		}
    439 	}
    440 	GLU_CHECK_MSG("After attribute setup");
    441 
    442 	// Uniforms
    443 	for (vector<rsg::VariableValue>::const_iterator uniformIter = m_uniforms.begin(); uniformIter != m_uniforms.end(); uniformIter++)
    444 	{
    445 		GLint location = glGetUniformLocation(program.getProgram(), uniformIter->getVariable()->getName());
    446 
    447 		log << tcu::TestLog::Message << "uniform[" << location << "]: " << uniformIter->getVariable()->getName() << " = " << uniformIter->getValue() << tcu::TestLog::EndMessage;
    448 
    449 		if (location >= 0)
    450 			setUniformValue(location, uniformIter->getValue());
    451 	}
    452 	GLU_CHECK_MSG("After uniform setup");
    453 
    454 	// Textures
    455 	vector<pair<int, const glu::Texture2D*> >	tex2DBindings		= m_texManager.getBindings2D();
    456 	vector<pair<int, const glu::TextureCube*> >	texCubeBindings		= m_texManager.getBindingsCube();
    457 
    458 	for (vector<pair<int, const glu::Texture2D*> >::const_iterator i = tex2DBindings.begin(); i != tex2DBindings.end(); i++)
    459 	{
    460 		int						unitNdx		= i->first;
    461 		const glu::Texture2D*	texture		= i->second;
    462 
    463 		glActiveTexture(GL_TEXTURE0 + unitNdx);
    464 		glBindTexture(GL_TEXTURE_2D, texture->getGLTexture());
    465 
    466 		executor.setTexture(unitNdx, &texture->getRefTexture(), glu::mapGLSampler(TEXTURE_WRAP_S, TEXTURE_WRAP_T, TEXTURE_MIN_FILTER, TEXTURE_MAG_FILTER));
    467 	}
    468 	GLU_CHECK_MSG("After 2D texture setup");
    469 
    470 	for (vector<pair<int, const glu::TextureCube*> >::const_iterator i = texCubeBindings.begin(); i != texCubeBindings.end(); i++)
    471 	{
    472 		int						unitNdx		= i->first;
    473 		const glu::TextureCube*	texture		= i->second;
    474 
    475 		glActiveTexture(GL_TEXTURE0 + unitNdx);
    476 		glBindTexture(GL_TEXTURE_CUBE_MAP, texture->getGLTexture());
    477 
    478 		executor.setTexture(unitNdx, &texture->getRefTexture(), glu::mapGLSampler(TEXTURE_WRAP_S, TEXTURE_WRAP_T, TEXTURE_MIN_FILTER, TEXTURE_MAG_FILTER));
    479 	}
    480 	GLU_CHECK_MSG("After cubemap setup");
    481 
    482 	// Draw and read
    483 	glViewport(viewportX, viewportY, viewportWidth, viewportHeight);
    484 	glDrawElements(GL_TRIANGLES, (GLsizei)m_indices.size(), GL_UNSIGNED_SHORT, &m_indices[0]);
    485 	glFlush();
    486 	GLU_CHECK_MSG("Draw");
    487 
    488 	// Render reference while GPU is doing work
    489 	executor.execute(m_vertexShader, m_fragmentShader, m_uniforms);
    490 
    491 	if (rendered.getFormat().order != tcu::TextureFormat::RGBA || rendered.getFormat().type != tcu::TextureFormat::UNORM_INT8)
    492 	{
    493 		// Read as GL_RGBA8
    494 		tcu::TextureLevel readBuf(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), rendered.getWidth(), rendered.getHeight());
    495 		glu::readPixels(m_renderCtx, viewportX, viewportY, readBuf.getAccess());
    496 		GLU_CHECK_MSG("Read pixels");
    497 		tcu::copy(rendered, readBuf);
    498 	}
    499 	else
    500 		glu::readPixels(m_renderCtx, viewportX, viewportY, rendered.getAccess());
    501 
    502 	// Compare
    503 	{
    504 		float	threshold	= 0.02f;
    505 		bool	imagesOk	= tcu::fuzzyCompare(log, "Result", "Result images", reference.getAccess(), rendered.getAccess(), threshold, tcu::COMPARE_LOG_RESULT);
    506 
    507 		if (imagesOk)
    508 			m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    509 		else
    510 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
    511 	}
    512 
    513 	return STOP;
    514 }
    515 
    516 } // gls
    517 } // deqp
    518