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 Shader execute test.
     22  *
     23  * \todo [petri] Multiple grid with differing constants/uniforms.
     24  * \todo [petri]
     25  *//*--------------------------------------------------------------------*/
     26 
     27 #include "glsShaderRenderCase.hpp"
     28 
     29 #include "tcuSurface.hpp"
     30 #include "tcuVector.hpp"
     31 #include "tcuImageCompare.hpp"
     32 #include "tcuTestLog.hpp"
     33 #include "tcuRenderTarget.hpp"
     34 
     35 #include "gluPixelTransfer.hpp"
     36 #include "gluTexture.hpp"
     37 #include "gluTextureUtil.hpp"
     38 #include "gluDrawUtil.hpp"
     39 
     40 #include "glwFunctions.hpp"
     41 #include "glwEnums.hpp"
     42 
     43 #include "deRandom.hpp"
     44 #include "deMemory.h"
     45 #include "deString.h"
     46 #include "deMath.h"
     47 #include "deStringUtil.hpp"
     48 
     49 #include <stdio.h>
     50 #include <vector>
     51 #include <string>
     52 
     53 namespace deqp
     54 {
     55 namespace gls
     56 {
     57 
     58 using namespace std;
     59 using namespace tcu;
     60 using namespace glu;
     61 
     62 static const int			GRID_SIZE				= 64;
     63 static const int			MAX_RENDER_WIDTH		= 128;
     64 static const int			MAX_RENDER_HEIGHT		= 112;
     65 static const tcu::Vec4		DEFAULT_CLEAR_COLOR		= tcu::Vec4(0.125f, 0.25f, 0.5f, 1.0f);
     66 
     67 // TextureBinding
     68 
     69 TextureBinding::TextureBinding (const glu::Texture2D* tex2D, const tcu::Sampler& sampler)
     70 	: m_type	(TYPE_2D)
     71 	, m_sampler	(sampler)
     72 {
     73 	m_binding.tex2D = tex2D;
     74 }
     75 
     76 TextureBinding::TextureBinding (const glu::TextureCube* texCube, const tcu::Sampler& sampler)
     77 	: m_type	(TYPE_CUBE_MAP)
     78 	, m_sampler	(sampler)
     79 {
     80 	m_binding.texCube = texCube;
     81 }
     82 
     83 TextureBinding::TextureBinding (const glu::Texture2DArray* tex2DArray, const tcu::Sampler& sampler)
     84 	: m_type	(TYPE_2D_ARRAY)
     85 	, m_sampler	(sampler)
     86 {
     87 	m_binding.tex2DArray = tex2DArray;
     88 }
     89 
     90 TextureBinding::TextureBinding (const glu::Texture3D* tex3D, const tcu::Sampler& sampler)
     91 	: m_type	(TYPE_3D)
     92 	, m_sampler	(sampler)
     93 {
     94 	m_binding.tex3D = tex3D;
     95 }
     96 
     97 TextureBinding::TextureBinding (void)
     98 	: m_type	(TYPE_NONE)
     99 {
    100 	m_binding.tex2D = DE_NULL;
    101 }
    102 
    103 void TextureBinding::setSampler (const tcu::Sampler& sampler)
    104 {
    105 	m_sampler = sampler;
    106 }
    107 
    108 void TextureBinding::setTexture (const glu::Texture2D* tex2D)
    109 {
    110 	m_type			= TYPE_2D;
    111 	m_binding.tex2D	= tex2D;
    112 }
    113 
    114 void TextureBinding::setTexture (const glu::TextureCube* texCube)
    115 {
    116 	m_type				= TYPE_CUBE_MAP;
    117 	m_binding.texCube	= texCube;
    118 }
    119 
    120 void TextureBinding::setTexture (const glu::Texture2DArray* tex2DArray)
    121 {
    122 	m_type					= TYPE_2D_ARRAY;
    123 	m_binding.tex2DArray	= tex2DArray;
    124 }
    125 
    126 void TextureBinding::setTexture (const glu::Texture3D* tex3D)
    127 {
    128 	m_type			= TYPE_3D;
    129 	m_binding.tex3D	= tex3D;
    130 }
    131 
    132 // QuadGrid.
    133 
    134 class QuadGrid
    135 {
    136 public:
    137 							QuadGrid				(int gridSize, int screenWidth, int screenHeight, const Vec4& constCoords, const vector<Mat4>& userAttribTransforms, const vector<TextureBinding>& textures);
    138 							~QuadGrid				(void);
    139 
    140 	int						getGridSize				(void) const { return m_gridSize; }
    141 	int						getNumVertices			(void) const { return m_numVertices; }
    142 	int						getNumTriangles			(void) const { return m_numTriangles; }
    143 	const Vec4&				getConstCoords			(void) const { return m_constCoords; }
    144 	const vector<Mat4>		getUserAttribTransforms	(void) const { return m_userAttribTransforms; }
    145 	const vector<TextureBinding>&	getTextures		(void) const { return m_textures; }
    146 
    147 	const Vec4*				getPositions			(void) const { return &m_positions[0]; }
    148 	const float*			getAttribOne			(void) const { return &m_attribOne[0]; }
    149 	const Vec4*				getCoords				(void) const { return &m_coords[0]; }
    150 	const Vec4*				getUnitCoords			(void) const { return &m_unitCoords[0]; }
    151 	const Vec4*				getUserAttrib			(int attribNdx) const { return &m_userAttribs[attribNdx][0]; }
    152 	const deUint16*			getIndices				(void) const { return &m_indices[0]; }
    153 
    154 	Vec4					getCoords				(float sx, float sy) const;
    155 	Vec4					getUnitCoords			(float sx, float sy) const;
    156 
    157 	int						getNumUserAttribs		(void) const { return (int)m_userAttribTransforms.size(); }
    158 	Vec4					getUserAttrib			(int attribNdx, float sx, float sy) const;
    159 
    160 private:
    161 	int						m_gridSize;
    162 	int						m_numVertices;
    163 	int						m_numTriangles;
    164 	Vec4					m_constCoords;
    165 	vector<Mat4>			m_userAttribTransforms;
    166 	vector<TextureBinding>	m_textures;
    167 
    168 	vector<Vec4>			m_screenPos;
    169 	vector<Vec4>			m_positions;
    170 	vector<Vec4>			m_coords;			//!< Near-unit coordinates, roughly [-2.0 .. 2.0].
    171 	vector<Vec4>			m_unitCoords;		//!< Positive-only coordinates [0.0 .. 1.5].
    172 	vector<float>			m_attribOne;
    173 	vector<Vec4>			m_userAttribs[ShaderEvalContext::MAX_TEXTURES];
    174 	vector<deUint16>		m_indices;
    175 };
    176 
    177 QuadGrid::QuadGrid (int gridSize, int width, int height, const Vec4& constCoords, const vector<Mat4>& userAttribTransforms, const vector<TextureBinding>& textures)
    178 	: m_gridSize				(gridSize)
    179 	, m_numVertices				((gridSize + 1) * (gridSize + 1))
    180 	, m_numTriangles			(gridSize * gridSize * 2)
    181 	, m_constCoords				(constCoords)
    182 	, m_userAttribTransforms	(userAttribTransforms)
    183 	, m_textures				(textures)
    184 {
    185 	Vec4 viewportScale = Vec4((float)width, (float)height, 0.0f, 0.0f);
    186 
    187 	// Compute vertices.
    188 	m_positions.resize(m_numVertices);
    189 	m_coords.resize(m_numVertices);
    190 	m_unitCoords.resize(m_numVertices);
    191 	m_attribOne.resize(m_numVertices);
    192 	m_screenPos.resize(m_numVertices);
    193 
    194 	// User attributes.
    195 	for (int i = 0; i < DE_LENGTH_OF_ARRAY(m_userAttribs); i++)
    196 		m_userAttribs[i].resize(m_numVertices);
    197 
    198 	for (int y = 0; y < gridSize+1; y++)
    199 	for (int x = 0; x < gridSize+1; x++)
    200 	{
    201 		float				sx			= (float)x / (float)gridSize;
    202 		float				sy			= (float)y / (float)gridSize;
    203 		float				fx			= 2.0f * sx - 1.0f;
    204 		float				fy			= 2.0f * sy - 1.0f;
    205 		int					vtxNdx		= ((y * (gridSize+1)) + x);
    206 
    207 		m_positions[vtxNdx]		= Vec4(fx, fy, 0.0f, 1.0f);
    208 		m_attribOne[vtxNdx]		= 1.0f;
    209 		m_screenPos[vtxNdx]		= Vec4(sx, sy, 0.0f, 1.0f) * viewportScale;
    210 		m_coords[vtxNdx]		= getCoords(sx, sy);
    211 		m_unitCoords[vtxNdx]	= getUnitCoords(sx, sy);
    212 
    213 		for (int attribNdx = 0; attribNdx < getNumUserAttribs(); attribNdx++)
    214 			m_userAttribs[attribNdx][vtxNdx] = getUserAttrib(attribNdx, sx, sy);
    215 	}
    216 
    217 	// Compute indices.
    218 	m_indices.resize(3 * m_numTriangles);
    219 	for (int y = 0; y < gridSize; y++)
    220 	for (int x = 0; x < gridSize; x++)
    221 	{
    222 		int stride = gridSize + 1;
    223 		int v00 = (y * stride) + x;
    224 		int v01 = (y * stride) + x + 1;
    225 		int v10 = ((y+1) * stride) + x;
    226 		int v11 = ((y+1) * stride) + x + 1;
    227 
    228 		int baseNdx = ((y * gridSize) + x) * 6;
    229 		m_indices[baseNdx + 0] = (deUint16)v10;
    230 		m_indices[baseNdx + 1] = (deUint16)v00;
    231 		m_indices[baseNdx + 2] = (deUint16)v01;
    232 
    233 		m_indices[baseNdx + 3] = (deUint16)v10;
    234 		m_indices[baseNdx + 4] = (deUint16)v01;
    235 		m_indices[baseNdx + 5] = (deUint16)v11;
    236 	}
    237 }
    238 
    239 QuadGrid::~QuadGrid (void)
    240 {
    241 }
    242 
    243 inline Vec4 QuadGrid::getCoords (float sx, float sy) const
    244 {
    245 	float fx = 2.0f * sx - 1.0f;
    246 	float fy = 2.0f * sy - 1.0f;
    247 	return Vec4(fx, fy, -fx + 0.33f*fy, -0.275f*fx - fy);
    248 }
    249 
    250 inline Vec4 QuadGrid::getUnitCoords (float sx, float sy) const
    251 {
    252 	return Vec4(sx, sy, 0.33f*sx + 0.5f*sy, 0.5f*sx + 0.25f*sy);
    253 }
    254 
    255 inline Vec4 QuadGrid::getUserAttrib (int attribNdx, float sx, float sy) const
    256 {
    257 	// homogeneous normalized screen-space coordinates
    258 	return m_userAttribTransforms[attribNdx] * Vec4(sx, sy, 0.0f, 1.0f);
    259 }
    260 
    261 // ShaderEvalContext.
    262 
    263 ShaderEvalContext::ShaderEvalContext (const QuadGrid& quadGrid_)
    264 	: constCoords	(quadGrid_.getConstCoords())
    265 	, isDiscarded	(false)
    266 	, quadGrid		(quadGrid_)
    267 {
    268 	const vector<TextureBinding>& bindings = quadGrid.getTextures();
    269 	DE_ASSERT((int)bindings.size() <= MAX_TEXTURES);
    270 
    271 	// Fill in texture array.
    272 	for (int ndx = 0; ndx < (int)bindings.size(); ndx++)
    273 	{
    274 		const TextureBinding& binding = bindings[ndx];
    275 
    276 		if (binding.getType() == TextureBinding::TYPE_NONE)
    277 			continue;
    278 
    279 		textures[ndx].sampler = binding.getSampler();
    280 
    281 		switch (binding.getType())
    282 		{
    283 			case TextureBinding::TYPE_2D:		textures[ndx].tex2D			= &binding.get2D()->getRefTexture();		break;
    284 			case TextureBinding::TYPE_CUBE_MAP:	textures[ndx].texCube		= &binding.getCube()->getRefTexture();		break;
    285 			case TextureBinding::TYPE_2D_ARRAY:	textures[ndx].tex2DArray	= &binding.get2DArray()->getRefTexture();	break;
    286 			case TextureBinding::TYPE_3D:		textures[ndx].tex3D			= &binding.get3D()->getRefTexture();		break;
    287 			default:
    288 				DE_ASSERT(DE_FALSE);
    289 		}
    290 	}
    291 }
    292 
    293 ShaderEvalContext::~ShaderEvalContext (void)
    294 {
    295 }
    296 
    297 void ShaderEvalContext::reset (float sx, float sy)
    298 {
    299 	// Clear old values
    300 	color		= Vec4(0.0f, 0.0f, 0.0f, 1.0f);
    301 	isDiscarded	= false;
    302 
    303 	// Compute coords
    304 	coords		= quadGrid.getCoords(sx, sy);
    305 	unitCoords	= quadGrid.getUnitCoords(sx, sy);
    306 
    307 	// Compute user attributes.
    308 	int numAttribs = quadGrid.getNumUserAttribs();
    309 	DE_ASSERT(numAttribs <= MAX_USER_ATTRIBS);
    310 	for (int attribNdx = 0; attribNdx < numAttribs; attribNdx++)
    311 		in[attribNdx] = quadGrid.getUserAttrib(attribNdx, sx, sy);
    312 }
    313 
    314 tcu::Vec4 ShaderEvalContext::texture2D (int unitNdx, const tcu::Vec2& texCoords)
    315 {
    316 	if (textures[unitNdx].tex2D)
    317 		return textures[unitNdx].tex2D->sample(textures[unitNdx].sampler, texCoords.x(), texCoords.y(), 0.0f);
    318 	else
    319 		return tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f);
    320 }
    321 
    322 // ShaderEvaluator
    323 
    324 ShaderEvaluator::ShaderEvaluator (void)
    325 	: m_evalFunc(DE_NULL)
    326 {
    327 }
    328 
    329 ShaderEvaluator::ShaderEvaluator (ShaderEvalFunc evalFunc)
    330 	: m_evalFunc(evalFunc)
    331 {
    332 }
    333 
    334 ShaderEvaluator::~ShaderEvaluator (void)
    335 {
    336 }
    337 
    338 void ShaderEvaluator::evaluate (ShaderEvalContext& ctx)
    339 {
    340 	DE_ASSERT(m_evalFunc);
    341 	m_evalFunc(ctx);
    342 }
    343 
    344 // ShaderRenderCase.
    345 
    346 ShaderRenderCase::ShaderRenderCase (TestContext& testCtx, RenderContext& renderCtx, const ContextInfo& ctxInfo, const char* name, const char* description, bool isVertexCase, ShaderEvalFunc evalFunc)
    347 	: TestCase				(testCtx, name, description)
    348 	, m_renderCtx			(renderCtx)
    349 	, m_ctxInfo				(ctxInfo)
    350 	, m_isVertexCase		(isVertexCase)
    351 	, m_defaultEvaluator	(evalFunc)
    352 	, m_evaluator			(m_defaultEvaluator)
    353 	, m_clearColor			(DEFAULT_CLEAR_COLOR)
    354 	, m_program				(DE_NULL)
    355 {
    356 }
    357 
    358 ShaderRenderCase::ShaderRenderCase (TestContext& testCtx, RenderContext& renderCtx, const ContextInfo& ctxInfo, const char* name, const char* description, bool isVertexCase, ShaderEvaluator& evaluator)
    359 	: TestCase				(testCtx, name, description)
    360 	, m_renderCtx			(renderCtx)
    361 	, m_ctxInfo				(ctxInfo)
    362 	, m_isVertexCase		(isVertexCase)
    363 	, m_defaultEvaluator	(DE_NULL)
    364 	, m_evaluator			(evaluator)
    365 	, m_clearColor			(DEFAULT_CLEAR_COLOR)
    366 	, m_program				(DE_NULL)
    367 {
    368 }
    369 
    370 ShaderRenderCase::~ShaderRenderCase (void)
    371 {
    372 	ShaderRenderCase::deinit();
    373 }
    374 
    375 void ShaderRenderCase::init (void)
    376 {
    377 	TestLog&				log		= m_testCtx.getLog();
    378 	const glw::Functions&	gl		= m_renderCtx.getFunctions();
    379 
    380 	GLU_EXPECT_NO_ERROR(gl.getError(), "ShaderRenderCase::init() begin");
    381 
    382 	if (m_vertShaderSource.empty() || m_fragShaderSource.empty())
    383 	{
    384 		DE_ASSERT(m_vertShaderSource.empty() && m_fragShaderSource.empty());
    385 		setupShaderData();
    386 	}
    387 
    388 	DE_ASSERT(!m_program);
    389 	m_program = new ShaderProgram(m_renderCtx, makeVtxFragSources(m_vertShaderSource, m_fragShaderSource));
    390 
    391 	try
    392 	{
    393 		log << *m_program; // Always log shader program.
    394 
    395 		if (!m_program->isOk())
    396 			throw CompileFailed(__FILE__, __LINE__);
    397 
    398 		GLU_EXPECT_NO_ERROR(gl.getError(), "ShaderRenderCase::init() end");
    399 	}
    400 	catch (const std::exception&)
    401 	{
    402 		// Clean up.
    403 		ShaderRenderCase::deinit();
    404 		throw;
    405 	}
    406 }
    407 
    408 void ShaderRenderCase::deinit (void)
    409 {
    410 	delete m_program;
    411 	m_program = DE_NULL;
    412 }
    413 
    414 tcu::IVec2 ShaderRenderCase::getViewportSize (void) const
    415 {
    416 	return tcu::IVec2(de::min(m_renderCtx.getRenderTarget().getWidth(), MAX_RENDER_WIDTH),
    417 					  de::min(m_renderCtx.getRenderTarget().getHeight(), MAX_RENDER_HEIGHT));
    418 }
    419 
    420 TestNode::IterateResult ShaderRenderCase::iterate (void)
    421 {
    422 	const glw::Functions& gl = m_renderCtx.getFunctions();
    423 
    424 	GLU_EXPECT_NO_ERROR(gl.getError(), "ShaderRenderCase::iterate() begin");
    425 
    426 	DE_ASSERT(m_program);
    427 	deUint32 programID = m_program->getProgram();
    428 	gl.useProgram(programID);
    429 
    430 	// Create quad grid.
    431 	IVec2	viewportSize	= getViewportSize();
    432 	int		width			= viewportSize.x();
    433 	int		height			= viewportSize.y();
    434 
    435 	// \todo [petri] Better handling of constCoords (render in multiple chunks, vary coords).
    436 	QuadGrid quadGrid(m_isVertexCase ? GRID_SIZE : 4, width, height, Vec4(0.125f, 0.25f, 0.5f, 1.0f), m_userAttribTransforms, m_textures);
    437 
    438 	// Render result.
    439 	Surface resImage(width, height);
    440 	render(resImage, programID, quadGrid);
    441 
    442 	// Compute reference.
    443 	Surface refImage (width, height);
    444 	if (m_isVertexCase)
    445 		computeVertexReference(refImage, quadGrid);
    446 	else
    447 		computeFragmentReference(refImage, quadGrid);
    448 
    449 	// Compare.
    450 	bool testOk = compareImages(resImage, refImage, 0.07f);
    451 
    452 	// De-initialize.
    453 	gl.useProgram(0);
    454 
    455 	m_testCtx.setTestResult(testOk ? QP_TEST_RESULT_PASS	: QP_TEST_RESULT_FAIL,
    456 							testOk ? "Pass"					: "Fail");
    457 	return TestNode::STOP;
    458 }
    459 
    460 void ShaderRenderCase::setupShaderData (void)
    461 {
    462 }
    463 
    464 void ShaderRenderCase::setup (int programID)
    465 {
    466 	DE_UNREF(programID);
    467 }
    468 
    469 void ShaderRenderCase::setupUniforms (int programID, const Vec4& constCoords)
    470 {
    471 	DE_UNREF(programID);
    472 	DE_UNREF(constCoords);
    473 }
    474 
    475 void ShaderRenderCase::setupDefaultInputs (int programID)
    476 {
    477 	const glw::Functions& gl = m_renderCtx.getFunctions();
    478 
    479 	// SETUP UNIFORMS.
    480 
    481 	setupDefaultUniforms(m_renderCtx, programID);
    482 
    483 	GLU_EXPECT_NO_ERROR(gl.getError(), "post uniform setup");
    484 
    485 	// SETUP TEXTURES.
    486 
    487 	for (int ndx = 0; ndx < (int)m_textures.size(); ndx++)
    488 	{
    489 		const TextureBinding&	tex			= m_textures[ndx];
    490 		const tcu::Sampler&		sampler		= tex.getSampler();
    491 		deUint32				texTarget	= GL_NONE;
    492 		deUint32				texObj		= 0;
    493 
    494 		if (tex.getType() == TextureBinding::TYPE_NONE)
    495 			continue;
    496 
    497 		// Feature check.
    498 		if (m_renderCtx.getType().getAPI() == glu::ApiType::es(2,0))
    499 		{
    500 			if (tex.getType() == TextureBinding::TYPE_2D_ARRAY)
    501 				throw tcu::NotSupportedError("2D array texture binding is not supported");
    502 
    503 			if (tex.getType() == TextureBinding::TYPE_3D)
    504 				throw tcu::NotSupportedError("3D texture binding is not supported");
    505 
    506 			if (sampler.compare != tcu::Sampler::COMPAREMODE_NONE)
    507 				throw tcu::NotSupportedError("Shadow lookups are not supported");
    508 		}
    509 
    510 		switch (tex.getType())
    511 		{
    512 			case TextureBinding::TYPE_2D:		texTarget = GL_TEXTURE_2D;			texObj = tex.get2D()->getGLTexture();		break;
    513 			case TextureBinding::TYPE_CUBE_MAP:	texTarget = GL_TEXTURE_CUBE_MAP;	texObj = tex.getCube()->getGLTexture();		break;
    514 			case TextureBinding::TYPE_2D_ARRAY:	texTarget = GL_TEXTURE_2D_ARRAY;	texObj = tex.get2DArray()->getGLTexture();	break;
    515 			case TextureBinding::TYPE_3D:		texTarget = GL_TEXTURE_3D;			texObj = tex.get3D()->getGLTexture();		break;
    516 			default:
    517 				DE_ASSERT(DE_FALSE);
    518 		}
    519 
    520 		gl.activeTexture(GL_TEXTURE0+ndx);
    521 		gl.bindTexture(texTarget, texObj);
    522 		gl.texParameteri(texTarget, GL_TEXTURE_WRAP_S,		glu::getGLWrapMode(sampler.wrapS));
    523 		gl.texParameteri(texTarget, GL_TEXTURE_WRAP_T,		glu::getGLWrapMode(sampler.wrapT));
    524 		gl.texParameteri(texTarget, GL_TEXTURE_MIN_FILTER,	glu::getGLFilterMode(sampler.minFilter));
    525 		gl.texParameteri(texTarget, GL_TEXTURE_MAG_FILTER,	glu::getGLFilterMode(sampler.magFilter));
    526 
    527 		if (texTarget == GL_TEXTURE_3D)
    528 			gl.texParameteri(texTarget, GL_TEXTURE_WRAP_R, glu::getGLWrapMode(sampler.wrapR));
    529 
    530 		if (sampler.compare != tcu::Sampler::COMPAREMODE_NONE)
    531 		{
    532 			gl.texParameteri(texTarget, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
    533 			gl.texParameteri(texTarget, GL_TEXTURE_COMPARE_FUNC, glu::getGLCompareFunc(sampler.compare));
    534 		}
    535 	}
    536 
    537 	GLU_EXPECT_NO_ERROR(gl.getError(), "texture sampler setup");
    538 }
    539 
    540 static void getDefaultVertexArrays (const glw::Functions& gl, const QuadGrid& quadGrid, deUint32 program, vector<VertexArrayBinding>& vertexArrays)
    541 {
    542 	const int numElements = quadGrid.getNumVertices();
    543 
    544 	vertexArrays.push_back(va::Float("a_position",		4, numElements, 0, (const float*)quadGrid.getPositions()));
    545 	vertexArrays.push_back(va::Float("a_coords",		4, numElements, 0, (const float*)quadGrid.getCoords()));
    546 	vertexArrays.push_back(va::Float("a_unitCoords",	4, numElements, 0, (const float*)quadGrid.getUnitCoords()));
    547 	vertexArrays.push_back(va::Float("a_one",			1, numElements, 0, quadGrid.getAttribOne()));
    548 
    549 	// a_inN.
    550 	for (int userNdx = 0; userNdx < quadGrid.getNumUserAttribs(); userNdx++)
    551 	{
    552 		string name = string("a_in") + de::toString(userNdx);
    553 		vertexArrays.push_back(va::Float(name, 4, numElements, 0, (const float*)quadGrid.getUserAttrib(userNdx)));
    554 	}
    555 
    556 	// Matrix attributes - these are set by location
    557 	static const struct
    558 	{
    559 		const char*	name;
    560 		int			numCols;
    561 		int			numRows;
    562 	} matrices[] =
    563 	{
    564 		{ "a_mat2",		2, 2 },
    565 		{ "a_mat2x3",	2, 3 },
    566 		{ "a_mat2x4",	2, 4 },
    567 		{ "a_mat3x2",	3, 2 },
    568 		{ "a_mat3",		3, 3 },
    569 		{ "a_mat3x4",	3, 4 },
    570 		{ "a_mat4x2",	4, 2 },
    571 		{ "a_mat4x3",	4, 3 },
    572 		{ "a_mat4",		4, 4 }
    573 	};
    574 
    575 	for (int matNdx = 0; matNdx < DE_LENGTH_OF_ARRAY(matrices); matNdx++)
    576 	{
    577 		int loc = gl.getAttribLocation(program, matrices[matNdx].name);
    578 
    579 		if (loc < 0)
    580 			continue; // Not used in shader.
    581 
    582 		int numRows	= matrices[matNdx].numRows;
    583 		int numCols	= matrices[matNdx].numCols;
    584 
    585 		for (int colNdx = 0; colNdx < numCols; colNdx++)
    586 			vertexArrays.push_back(va::Float(loc+colNdx, numRows, numElements, 4*(int)sizeof(float), (const float*)quadGrid.getUserAttrib(colNdx)));
    587 	}
    588 }
    589 
    590 void ShaderRenderCase::render (Surface& result, int programID, const QuadGrid& quadGrid)
    591 {
    592 	const glw::Functions& gl = m_renderCtx.getFunctions();
    593 
    594 	GLU_EXPECT_NO_ERROR(gl.getError(), "pre render");
    595 
    596 	// Buffer info.
    597 	int				width		= result.getWidth();
    598 	int				height		= result.getHeight();
    599 
    600 	int				xOffsetMax	= m_renderCtx.getRenderTarget().getWidth() - width;
    601 	int				yOffsetMax	= m_renderCtx.getRenderTarget().getHeight() - height;
    602 
    603 	deUint32		hash		= deStringHash(m_vertShaderSource.c_str()) + deStringHash(m_fragShaderSource.c_str());
    604 	de::Random		rnd			(hash);
    605 
    606 	int				xOffset		= rnd.getInt(0, xOffsetMax);
    607 	int				yOffset		= rnd.getInt(0, yOffsetMax);
    608 
    609 	gl.viewport(xOffset, yOffset, width, height);
    610 
    611 	// Setup program.
    612 	setupUniforms(programID, quadGrid.getConstCoords());
    613 	setupDefaultInputs(programID);
    614 
    615 	// Clear.
    616 	gl.clearColor(m_clearColor.x(), m_clearColor.y(), m_clearColor.z(), m_clearColor.w());
    617 	gl.clear(GL_COLOR_BUFFER_BIT);
    618 
    619 	// Draw.
    620 	{
    621 		std::vector<VertexArrayBinding>	vertexArrays;
    622 		const int						numElements		= quadGrid.getNumTriangles()*3;
    623 
    624 		getDefaultVertexArrays(gl, quadGrid, programID, vertexArrays);
    625 		draw(m_renderCtx, programID, (int)vertexArrays.size(), &vertexArrays[0], pr::Triangles(numElements, quadGrid.getIndices()));
    626 	}
    627 	GLU_EXPECT_NO_ERROR(gl.getError(), "draw");
    628 
    629 	// Read back results.
    630 	glu::readPixels(m_renderCtx, xOffset, yOffset, result.getAccess());
    631 
    632 	GLU_EXPECT_NO_ERROR(gl.getError(), "post render");
    633 }
    634 
    635 void ShaderRenderCase::computeVertexReference (Surface& result, const QuadGrid& quadGrid)
    636 {
    637 	// Buffer info.
    638 	int					width		= result.getWidth();
    639 	int					height		= result.getHeight();
    640 	int					gridSize	= quadGrid.getGridSize();
    641 	int					stride		= gridSize + 1;
    642 	bool				hasAlpha	= m_renderCtx.getRenderTarget().getPixelFormat().alphaBits > 0;
    643 	ShaderEvalContext	evalCtx		(quadGrid);
    644 
    645 	// Evaluate color for each vertex.
    646 	vector<Vec4> colors((gridSize+1)*(gridSize+1));
    647 	for (int y = 0; y < gridSize+1; y++)
    648 	for (int x = 0; x < gridSize+1; x++)
    649 	{
    650 		float				sx			= (float)x / (float)gridSize;
    651 		float				sy			= (float)y / (float)gridSize;
    652 		int					vtxNdx		= ((y * (gridSize+1)) + x);
    653 
    654 		evalCtx.reset(sx, sy);
    655 		m_evaluator.evaluate(evalCtx);
    656 		DE_ASSERT(!evalCtx.isDiscarded); // Discard is not available in vertex shader.
    657 		Vec4 color = evalCtx.color;
    658 
    659 		if (!hasAlpha)
    660 			color.w() = 1.0f;
    661 
    662 		colors[vtxNdx] = color;
    663 	}
    664 
    665 	// Render quads.
    666 	for (int y = 0; y < gridSize; y++)
    667 	for (int x = 0; x < gridSize; x++)
    668 	{
    669 		float x0 = (float)x       / (float)gridSize;
    670 		float x1 = (float)(x + 1) / (float)gridSize;
    671 		float y0 = (float)y       / (float)gridSize;
    672 		float y1 = (float)(y + 1) / (float)gridSize;
    673 
    674 		float sx0 = x0 * (float)width;
    675 		float sx1 = x1 * (float)width;
    676 		float sy0 = y0 * (float)height;
    677 		float sy1 = y1 * (float)height;
    678 		float oosx = 1.0f / (sx1 - sx0);
    679 		float oosy = 1.0f / (sy1 - sy0);
    680 
    681 		int ix0 = deCeilFloatToInt32(sx0 - 0.5f);
    682 		int ix1 = deCeilFloatToInt32(sx1 - 0.5f);
    683 		int iy0 = deCeilFloatToInt32(sy0 - 0.5f);
    684 		int iy1 = deCeilFloatToInt32(sy1 - 0.5f);
    685 
    686 		int		v00 = (y * stride) + x;
    687 		int		v01 = (y * stride) + x + 1;
    688 		int		v10 = ((y + 1) * stride) + x;
    689 		int		v11 = ((y + 1) * stride) + x + 1;
    690 		Vec4	c00 = colors[v00];
    691 		Vec4	c01 = colors[v01];
    692 		Vec4	c10 = colors[v10];
    693 		Vec4	c11 = colors[v11];
    694 
    695 		//printf("(%d,%d) -> (%f..%f, %f..%f) (%d..%d, %d..%d)\n", x, y, sx0, sx1, sy0, sy1, ix0, ix1, iy0, iy1);
    696 
    697 		for (int iy = iy0; iy < iy1; iy++)
    698 		for (int ix = ix0; ix < ix1; ix++)
    699 		{
    700 			DE_ASSERT(deInBounds32(ix, 0, width));
    701 			DE_ASSERT(deInBounds32(iy, 0, height));
    702 
    703 			float		sfx		= (float)ix + 0.5f;
    704 			float		sfy		= (float)iy + 0.5f;
    705 			float		fx1		= deFloatClamp((sfx - sx0) * oosx, 0.0f, 1.0f);
    706 			float		fy1		= deFloatClamp((sfy - sy0) * oosy, 0.0f, 1.0f);
    707 
    708 			// Triangle quad interpolation.
    709 			bool		tri		= fx1 + fy1 <= 1.0f;
    710 			float		tx		= tri ? fx1 : (1.0f-fx1);
    711 			float		ty		= tri ? fy1 : (1.0f-fy1);
    712 			const Vec4&	t0		= tri ? c00 : c11;
    713 			const Vec4&	t1		= tri ? c01 : c10;
    714 			const Vec4&	t2		= tri ? c10 : c01;
    715 			Vec4		color	= t0 + (t1-t0)*tx + (t2-t0)*ty;
    716 
    717 			result.setPixel(ix, iy, tcu::RGBA(color));
    718 		}
    719 	}
    720 }
    721 
    722 void ShaderRenderCase::computeFragmentReference (Surface& result, const QuadGrid& quadGrid)
    723 {
    724 	// Buffer info.
    725 	int					width		= result.getWidth();
    726 	int					height		= result.getHeight();
    727 	bool				hasAlpha	= m_renderCtx.getRenderTarget().getPixelFormat().alphaBits > 0;
    728 	ShaderEvalContext	evalCtx		(quadGrid);
    729 
    730 	// Render.
    731 	for (int y = 0; y < height; y++)
    732 	for (int x = 0; x < width; x++)
    733 	{
    734 		float sx = ((float)x + 0.5f) / (float)width;
    735 		float sy = ((float)y + 0.5f) / (float)height;
    736 
    737 		evalCtx.reset(sx, sy);
    738 		m_evaluator.evaluate(evalCtx);
    739 		// Select either clear color or computed color based on discarded bit.
    740 		Vec4 color = evalCtx.isDiscarded ? m_clearColor : evalCtx.color;
    741 
    742 		if (!hasAlpha)
    743 			color.w() = 1.0f;
    744 
    745 		result.setPixel(x, y, tcu::RGBA(color));
    746 	}
    747 }
    748 
    749 bool ShaderRenderCase::compareImages (const Surface& resImage, const Surface& refImage, float errorThreshold)
    750 {
    751 	return tcu::fuzzyCompare(m_testCtx.getLog(), "ComparisonResult", "Image comparison result", refImage, resImage, errorThreshold, tcu::COMPARE_LOG_RESULT);
    752 }
    753 
    754 // Uniform name helpers.
    755 
    756 const char* getIntUniformName (int number)
    757 {
    758 	switch (number)
    759 	{
    760 		case 0:		return "ui_zero";
    761 		case 1:		return "ui_one";
    762 		case 2:		return "ui_two";
    763 		case 3:		return "ui_three";
    764 		case 4:		return "ui_four";
    765 		case 5:		return "ui_five";
    766 		case 6:		return "ui_six";
    767 		case 7:		return "ui_seven";
    768 		case 8:		return "ui_eight";
    769 		case 101:	return "ui_oneHundredOne";
    770 		default:
    771 			DE_ASSERT(false);
    772 			return "";
    773 	}
    774 }
    775 
    776 const char* getFloatUniformName (int number)
    777 {
    778 	switch (number)
    779 	{
    780 		case 0:	return "uf_zero";
    781 		case 1: return "uf_one";
    782 		case 2: return "uf_two";
    783 		case 3: return "uf_three";
    784 		case 4: return "uf_four";
    785 		case 5: return "uf_five";
    786 		case 6: return "uf_six";
    787 		case 7: return "uf_seven";
    788 		case 8: return "uf_eight";
    789 		default:
    790 			DE_ASSERT(false);
    791 			return "";
    792 	}
    793 }
    794 
    795 const char* getFloatFractionUniformName (int number)
    796 {
    797 	switch (number)
    798 	{
    799 		case 1: return "uf_one";
    800 		case 2: return "uf_half";
    801 		case 3: return "uf_third";
    802 		case 4: return "uf_fourth";
    803 		case 5: return "uf_fifth";
    804 		case 6: return "uf_sixth";
    805 		case 7: return "uf_seventh";
    806 		case 8: return "uf_eighth";
    807 		default:
    808 			DE_ASSERT(false);
    809 			return "";
    810 	}
    811 }
    812 
    813 void setupDefaultUniforms (const glu::RenderContext& context, deUint32 programID)
    814 {
    815 	const glw::Functions& gl = context.getFunctions();
    816 
    817 	// Bool.
    818 	struct BoolUniform { const char* name; bool value; };
    819 	static const BoolUniform s_boolUniforms[] =
    820 	{
    821 		{ "ub_true",	true },
    822 		{ "ub_false",	false },
    823 	};
    824 
    825 	for (int i = 0; i < DE_LENGTH_OF_ARRAY(s_boolUniforms); i++)
    826 	{
    827 		int uniLoc = gl.getUniformLocation(programID, s_boolUniforms[i].name);
    828 		if (uniLoc != -1)
    829 			gl.uniform1i(uniLoc, s_boolUniforms[i].value);
    830 	}
    831 
    832 	// BVec4.
    833 	struct BVec4Uniform { const char* name; BVec4 value; };
    834 	static const BVec4Uniform s_bvec4Uniforms[] =
    835 	{
    836 		{ "ub4_true",	BVec4(true) },
    837 		{ "ub4_false",	BVec4(false) },
    838 	};
    839 
    840 	for (int i = 0; i < DE_LENGTH_OF_ARRAY(s_bvec4Uniforms); i++)
    841 	{
    842 		const BVec4Uniform& uni = s_bvec4Uniforms[i];
    843 		int arr[4];
    844 		arr[0] = (int)uni.value.x();
    845 		arr[1] = (int)uni.value.y();
    846 		arr[2] = (int)uni.value.z();
    847 		arr[3] = (int)uni.value.w();
    848 		int uniLoc = gl.getUniformLocation(programID, uni.name);
    849 		if (uniLoc != -1)
    850 			gl.uniform4iv(uniLoc, 1, &arr[0]);
    851 	}
    852 
    853 	// Int.
    854 	struct IntUniform { const char* name; int value; };
    855 	static const IntUniform s_intUniforms[] =
    856 	{
    857 		{ "ui_minusOne",		-1 },
    858 		{ "ui_zero",			0 },
    859 		{ "ui_one",				1 },
    860 		{ "ui_two",				2 },
    861 		{ "ui_three",			3 },
    862 		{ "ui_four",			4 },
    863 		{ "ui_five",			5 },
    864 		{ "ui_six",				6 },
    865 		{ "ui_seven",			7 },
    866 		{ "ui_eight",			8 },
    867 		{ "ui_oneHundredOne",	101 }
    868 	};
    869 
    870 	for (int i = 0; i < DE_LENGTH_OF_ARRAY(s_intUniforms); i++)
    871 	{
    872 		int uniLoc = gl.getUniformLocation(programID, s_intUniforms[i].name);
    873 		if (uniLoc != -1)
    874 			gl.uniform1i(uniLoc, s_intUniforms[i].value);
    875 	}
    876 
    877 	// IVec2.
    878 	struct IVec2Uniform { const char* name; IVec2 value; };
    879 	static const IVec2Uniform s_ivec2Uniforms[] =
    880 	{
    881 		{ "ui2_minusOne",	IVec2(-1) },
    882 		{ "ui2_zero",		IVec2(0) },
    883 		{ "ui2_one",		IVec2(1) },
    884 		{ "ui2_two",		IVec2(2) },
    885 		{ "ui2_four",		IVec2(4) },
    886 		{ "ui2_five",		IVec2(5) }
    887 	};
    888 
    889 	for (int i = 0; i < DE_LENGTH_OF_ARRAY(s_ivec2Uniforms); i++)
    890 	{
    891 		int uniLoc = gl.getUniformLocation(programID, s_ivec2Uniforms[i].name);
    892 		if (uniLoc != -1)
    893 			gl.uniform2iv(uniLoc, 1, s_ivec2Uniforms[i].value.getPtr());
    894 	}
    895 
    896 	// IVec3.
    897 	struct IVec3Uniform { const char* name; IVec3 value; };
    898 	static const IVec3Uniform s_ivec3Uniforms[] =
    899 	{
    900 		{ "ui3_minusOne",	IVec3(-1) },
    901 		{ "ui3_zero",		IVec3(0) },
    902 		{ "ui3_one",		IVec3(1) },
    903 		{ "ui3_two",		IVec3(2) },
    904 		{ "ui3_four",		IVec3(4) },
    905 		{ "ui3_five",		IVec3(5) }
    906 	};
    907 
    908 	for (int i = 0; i < DE_LENGTH_OF_ARRAY(s_ivec3Uniforms); i++)
    909 	{
    910 		int uniLoc = gl.getUniformLocation(programID, s_ivec3Uniforms[i].name);
    911 		if (uniLoc != -1)
    912 			gl.uniform3iv(uniLoc, 1, s_ivec3Uniforms[i].value.getPtr());
    913 	}
    914 
    915 	// IVec4.
    916 	struct IVec4Uniform { const char* name; IVec4 value; };
    917 	static const IVec4Uniform s_ivec4Uniforms[] =
    918 	{
    919 		{ "ui4_minusOne",	IVec4(-1) },
    920 		{ "ui4_zero",		IVec4(0) },
    921 		{ "ui4_one",		IVec4(1) },
    922 		{ "ui4_two",		IVec4(2) },
    923 		{ "ui4_four",		IVec4(4) },
    924 		{ "ui4_five",		IVec4(5) }
    925 	};
    926 
    927 	for (int i = 0; i < DE_LENGTH_OF_ARRAY(s_ivec4Uniforms); i++)
    928 	{
    929 		int uniLoc = gl.getUniformLocation(programID, s_ivec4Uniforms[i].name);
    930 		if (uniLoc != -1)
    931 			gl.uniform4iv(uniLoc, 1, s_ivec4Uniforms[i].value.getPtr());
    932 	}
    933 
    934 	// Float.
    935 	struct FloatUniform { const char* name; float value; };
    936 	static const FloatUniform s_floatUniforms[] =
    937 	{
    938 		{ "uf_zero",	0.0f },
    939 		{ "uf_one",		1.0f },
    940 		{ "uf_two",		2.0f },
    941 		{ "uf_three",	3.0f },
    942 		{ "uf_four",	4.0f },
    943 		{ "uf_five",	5.0f },
    944 		{ "uf_six",		6.0f },
    945 		{ "uf_seven",	7.0f },
    946 		{ "uf_eight",	8.0f },
    947 		{ "uf_half",	1.0f / 2.0f },
    948 		{ "uf_third",	1.0f / 3.0f },
    949 		{ "uf_fourth",	1.0f / 4.0f },
    950 		{ "uf_fifth",	1.0f / 5.0f },
    951 		{ "uf_sixth",	1.0f / 6.0f },
    952 		{ "uf_seventh",	1.0f / 7.0f },
    953 		{ "uf_eighth",	1.0f / 8.0f }
    954 	};
    955 
    956 	for (int i = 0; i < DE_LENGTH_OF_ARRAY(s_floatUniforms); i++)
    957 	{
    958 		int uniLoc = gl.getUniformLocation(programID, s_floatUniforms[i].name);
    959 		if (uniLoc != -1)
    960 			gl.uniform1f(uniLoc, s_floatUniforms[i].value);
    961 	}
    962 
    963 	// Vec2.
    964 	struct Vec2Uniform { const char* name; Vec2 value; };
    965 	static const Vec2Uniform s_vec2Uniforms[] =
    966 	{
    967 		{ "uv2_minusOne",	Vec2(-1.0f) },
    968 		{ "uv2_zero",		Vec2(0.0f) },
    969 		{ "uv2_half",		Vec2(0.5f) },
    970 		{ "uv2_one",		Vec2(1.0f) },
    971 		{ "uv2_two",		Vec2(2.0f) },
    972 	};
    973 
    974 	for (int i = 0; i < DE_LENGTH_OF_ARRAY(s_vec2Uniforms); i++)
    975 	{
    976 		int uniLoc = gl.getUniformLocation(programID, s_vec2Uniforms[i].name);
    977 		if (uniLoc != -1)
    978 			gl.uniform2fv(uniLoc, 1, s_vec2Uniforms[i].value.getPtr());
    979 	}
    980 
    981 	// Vec3.
    982 	struct Vec3Uniform { const char* name; Vec3 value; };
    983 	static const Vec3Uniform s_vec3Uniforms[] =
    984 	{
    985 		{ "uv3_minusOne",	Vec3(-1.0f) },
    986 		{ "uv3_zero",		Vec3(0.0f) },
    987 		{ "uv3_half",		Vec3(0.5f) },
    988 		{ "uv3_one",		Vec3(1.0f) },
    989 		{ "uv3_two",		Vec3(2.0f) },
    990 	};
    991 
    992 	for (int i = 0; i < DE_LENGTH_OF_ARRAY(s_vec3Uniforms); i++)
    993 	{
    994 		int uniLoc = gl.getUniformLocation(programID, s_vec3Uniforms[i].name);
    995 		if (uniLoc != -1)
    996 			gl.uniform3fv(uniLoc, 1, s_vec3Uniforms[i].value.getPtr());
    997 	}
    998 
    999 	// Vec4.
   1000 	struct Vec4Uniform { const char* name; Vec4 value; };
   1001 	static const Vec4Uniform s_vec4Uniforms[] =
   1002 	{
   1003 		{ "uv4_minusOne",	Vec4(-1.0f) },
   1004 		{ "uv4_zero",		Vec4(0.0f) },
   1005 		{ "uv4_half",		Vec4(0.5f) },
   1006 		{ "uv4_one",		Vec4(1.0f) },
   1007 		{ "uv4_two",		Vec4(2.0f) },
   1008 		{ "uv4_black",		Vec4(0.0f, 0.0f, 0.0f, 1.0f) },
   1009 		{ "uv4_gray",		Vec4(0.5f, 0.5f, 0.5f, 1.0f) },
   1010 		{ "uv4_white",		Vec4(1.0f, 1.0f, 1.0f, 1.0f) },
   1011 	};
   1012 
   1013 	for (int i = 0; i < DE_LENGTH_OF_ARRAY(s_vec4Uniforms); i++)
   1014 	{
   1015 		int uniLoc = gl.getUniformLocation(programID, s_vec4Uniforms[i].name);
   1016 		if (uniLoc != -1)
   1017 			gl.uniform4fv(uniLoc, 1, s_vec4Uniforms[i].value.getPtr());
   1018 	}
   1019 }
   1020 
   1021 } // gls
   1022 } // deqp
   1023