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