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 - render state interaction case.
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "glsFragOpInteractionCase.hpp"
     25 
     26 #include "glsRandomShaderProgram.hpp"
     27 #include "glsFragmentOpUtil.hpp"
     28 #include "glsInteractionTestUtil.hpp"
     29 
     30 #include "gluRenderContext.hpp"
     31 #include "gluContextInfo.hpp"
     32 
     33 #include "rsgShader.hpp"
     34 #include "rsgProgramGenerator.hpp"
     35 #include "rsgUtils.hpp"
     36 
     37 #include "sglrContext.hpp"
     38 #include "sglrReferenceContext.hpp"
     39 #include "sglrGLContext.hpp"
     40 #include "sglrContextUtil.hpp"
     41 
     42 #include "tcuRenderTarget.hpp"
     43 #include "tcuImageCompare.hpp"
     44 
     45 #include "deRandom.hpp"
     46 #include "deString.h"
     47 #include "deStringUtil.hpp"
     48 
     49 #include "glwEnums.hpp"
     50 
     51 #include "gluDrawUtil.hpp"
     52 
     53 namespace deqp
     54 {
     55 namespace gls
     56 {
     57 
     58 using std::vector;
     59 using std::string;
     60 using tcu::Vec2;
     61 using tcu::Vec4;
     62 using tcu::IVec2;
     63 using tcu::IVec4;
     64 
     65 using gls::InteractionTestUtil::RenderState;
     66 using gls::InteractionTestUtil::StencilState;
     67 
     68 enum
     69 {
     70 	NUM_ITERATIONS					= 5,
     71 	NUM_COMMANDS_PER_ITERATION		= 5,
     72 	VIEWPORT_WIDTH					= 64,
     73 	VIEWPORT_HEIGHT					= 64
     74 };
     75 
     76 namespace
     77 {
     78 
     79 static void computeVertexLayout (const vector<rsg::ShaderInput*>& attributes, int numVertices, vector<glu::VertexArrayBinding>* layout, int* stride)
     80 {
     81 	DE_ASSERT(layout->empty());
     82 
     83 	int curOffset = 0;
     84 
     85 	for (vector<rsg::ShaderInput*>::const_iterator iter = attributes.begin(); iter != attributes.end(); ++iter)
     86 	{
     87 		const rsg::ShaderInput*		attrib		= *iter;
     88 		const rsg::Variable*		var			= attrib->getVariable();
     89 		const rsg::VariableType&	type		= var->getType();
     90 		const int					numComps	= type.getNumElements();
     91 
     92 		TCU_CHECK_INTERNAL(type.getBaseType() == rsg::VariableType::TYPE_FLOAT && de::inRange(type.getNumElements(), 1, 4));
     93 
     94 		layout->push_back(glu::va::Float(var->getName(), numComps, numVertices, 0 /* computed later */, (const float*)(deUintptr)curOffset));
     95 
     96 		curOffset += numComps * (int)sizeof(float);
     97 	}
     98 
     99 	for (vector<glu::VertexArrayBinding>::iterator vaIter = layout->begin(); vaIter != layout->end(); ++vaIter)
    100 		vaIter->pointer.stride = curOffset;
    101 
    102 	*stride = curOffset;
    103 }
    104 
    105 class VertexDataStorage
    106 {
    107 public:
    108 												VertexDataStorage	(const vector<rsg::ShaderInput*>& attributes, int numVertices);
    109 
    110 	int											getDataSize			(void) const	{ return (int)m_data.size();					}
    111 	void*										getBasePtr			(void)			{ return m_data.empty() ? DE_NULL : &m_data[0]; }
    112 	const void*									getBasePtr			(void) const	{ return m_data.empty() ? DE_NULL : &m_data[0]; }
    113 
    114 	const std::vector<glu::VertexArrayBinding>&	getLayout			(void) const	{ return m_layout; }
    115 
    116 	int											getNumEntries		(void) const	{ return (int)m_layout.size();	}
    117 	const glu::VertexArrayBinding&				getLayoutEntry		(int ndx) const	{ return m_layout[ndx];			}
    118 
    119 private:
    120 	std::vector<deUint8>						m_data;
    121 	std::vector<glu::VertexArrayBinding>		m_layout;
    122 };
    123 
    124 VertexDataStorage::VertexDataStorage (const vector<rsg::ShaderInput*>& attributes, int numVertices)
    125 {
    126 	int stride = 0;
    127 	computeVertexLayout(attributes, numVertices, &m_layout, &stride);
    128 	m_data.resize(stride * numVertices);
    129 }
    130 
    131 static inline glu::VertexArrayBinding getEntryWithPointer (const VertexDataStorage& data, int ndx)
    132 {
    133 	const glu::VertexArrayBinding& entry = data.getLayoutEntry(ndx);
    134 	return glu::VertexArrayBinding(entry.binding, glu::VertexArrayPointer(entry.pointer.componentType,
    135 																		  entry.pointer.convert,
    136 																		  entry.pointer.numComponents,
    137 																		  entry.pointer.numElements,
    138 																		  entry.pointer.stride,
    139 																		  (const void*)((deUintptr)entry.pointer.data+(deUintptr)data.getBasePtr())));
    140 }
    141 
    142 template<int Size>
    143 static void setVertex (const glu::VertexArrayPointer& pointer, int vertexNdx, const tcu::Vector<float, Size>& value)
    144 {
    145 	// \todo [2013-12-14 pyry] Implement other modes.
    146 	DE_ASSERT(pointer.componentType == glu::VTX_COMP_FLOAT && pointer.convert == glu::VTX_COMP_CONVERT_NONE);
    147 	DE_ASSERT(pointer.numComponents == Size);
    148 	DE_ASSERT(de::inBounds(vertexNdx, 0, pointer.numElements));
    149 
    150 	float* dst = (float*)((deUint8*)pointer.data + pointer.stride*vertexNdx);
    151 
    152 	for (int ndx = 0; ndx < Size; ndx++)
    153 		dst[ndx] = value[ndx];
    154 }
    155 
    156 template<int Size>
    157 static tcu::Vector<float, Size> interpolateRange (const rsg::ConstValueRangeAccess& range, const tcu::Vector<float, Size>& t)
    158 {
    159 	tcu::Vector<float, Size> result;
    160 
    161 	for (int ndx = 0; ndx < Size; ndx++)
    162 		result[ndx] = range.getMin().component(ndx).asFloat()*(1.0f - t[ndx]) + range.getMax().component(ndx).asFloat()*t[ndx];
    163 
    164 	return result;
    165 }
    166 
    167 struct Quad
    168 {
    169 	tcu::IVec2	posA;
    170 	tcu::IVec2	posB;
    171 };
    172 
    173 struct RenderCommand
    174 {
    175 	Quad		quad;
    176 	float		depth;
    177 	RenderState	state;
    178 
    179 	RenderCommand (void) : depth(0.0f) {}
    180 };
    181 
    182 static Quad getRandomQuad (de::Random& rnd, int targetW, int targetH)
    183 {
    184 	// \note In viewport coordinates.
    185 	// \todo [2012-12-18 pyry] Out-of-bounds values.
    186 	const int		maxOutOfBounds	= 0;
    187 	const float		minSize			= 0.5f;
    188 
    189 	const int		minW			= deCeilFloatToInt32(minSize * (float)targetW);
    190 	const int		minH			= deCeilFloatToInt32(minSize * (float)targetH);
    191 	const int		maxW			= targetW + 2*maxOutOfBounds;
    192 	const int		maxH			= targetH + 2*maxOutOfBounds;
    193 
    194 	const int		width			= rnd.getInt(minW, maxW);
    195 	const int		height			= rnd.getInt(minH, maxH);
    196 	const int		x				= rnd.getInt(-maxOutOfBounds, targetW+maxOutOfBounds-width);
    197 	const int		y				= rnd.getInt(-maxOutOfBounds, targetH+maxOutOfBounds-height);
    198 
    199 	const bool		flipX			= rnd.getBool();
    200 	const bool		flipY			= rnd.getBool();
    201 
    202 	Quad			quad;
    203 
    204 	quad.posA	= tcu::IVec2(flipX ? (x+width-1) : x, flipY ? (y+height-1) : y);
    205 	quad.posB	= tcu::IVec2(flipX ? x : (x+width-1), flipY ? y : (y+height-1));
    206 
    207 	return quad;
    208 }
    209 
    210 static float getRandomDepth (de::Random& rnd)
    211 {
    212 	// \note Not using depth 1.0 since clearing with 1.0 and rendering with 1.0 may not be same value.
    213 	static const float depthValues[] = { 0.0f, 0.2f, 0.4f, 0.5f, 0.51f, 0.6f, 0.8f, 0.95f };
    214 	return rnd.choose<float>(DE_ARRAY_BEGIN(depthValues), DE_ARRAY_END(depthValues));
    215 }
    216 
    217 static void computeRandomRenderCommand (de::Random& rnd, RenderCommand& command, glu::ApiType apiType, int targetW, int targetH)
    218 {
    219 	command.quad	= getRandomQuad(rnd, targetW, targetH);
    220 	command.depth	= getRandomDepth(rnd);
    221 	gls::InteractionTestUtil::computeRandomRenderState(rnd, command.state, apiType, targetW, targetH);
    222 }
    223 
    224 static void setRenderState (sglr::Context& ctx, const RenderState& state)
    225 {
    226 	if (state.scissorTestEnabled)
    227 	{
    228 		ctx.enable(GL_SCISSOR_TEST);
    229 		ctx.scissor(state.scissorRectangle.left, state.scissorRectangle.bottom,
    230 					state.scissorRectangle.width, state.scissorRectangle.height);
    231 	}
    232 	else
    233 		ctx.disable(GL_SCISSOR_TEST);
    234 
    235 	if (state.stencilTestEnabled)
    236 	{
    237 		ctx.enable(GL_STENCIL_TEST);
    238 
    239 		for (int face = 0; face < rr::FACETYPE_LAST; face++)
    240 		{
    241 			deUint32				glFace	= face == rr::FACETYPE_BACK ? GL_BACK : GL_FRONT;
    242 			const StencilState&		sParams	= state.stencil[face];
    243 
    244 			ctx.stencilFuncSeparate(glFace, sParams.function, sParams.reference, sParams.compareMask);
    245 			ctx.stencilOpSeparate(glFace, sParams.stencilFailOp, sParams.depthFailOp, sParams.depthPassOp);
    246 			ctx.stencilMaskSeparate(glFace, sParams.writeMask);
    247 		}
    248 	}
    249 	else
    250 		ctx.disable(GL_STENCIL_TEST);
    251 
    252 	if (state.depthTestEnabled)
    253 	{
    254 		ctx.enable(GL_DEPTH_TEST);
    255 		ctx.depthFunc(state.depthFunc);
    256 		ctx.depthMask(state.depthWriteMask ? GL_TRUE : GL_FALSE);
    257 	}
    258 	else
    259 		ctx.disable(GL_DEPTH_TEST);
    260 
    261 	if (state.blendEnabled)
    262 	{
    263 		ctx.enable(GL_BLEND);
    264 		ctx.blendEquationSeparate(state.blendRGBState.equation, state.blendAState.equation);
    265 		ctx.blendFuncSeparate(state.blendRGBState.srcFunc, state.blendRGBState.dstFunc, state.blendAState.srcFunc, state.blendAState.dstFunc);
    266 		ctx.blendColor(state.blendColor.x(), state.blendColor.y(), state.blendColor.z(), state.blendColor.w());
    267 	}
    268 	else
    269 		ctx.disable(GL_BLEND);
    270 
    271 	if (state.ditherEnabled)
    272 		ctx.enable(GL_DITHER);
    273 	else
    274 		ctx.disable(GL_DITHER);
    275 
    276 	ctx.colorMask(state.colorMask[0] ? GL_TRUE : GL_FALSE,
    277 				  state.colorMask[1] ? GL_TRUE : GL_FALSE,
    278 				  state.colorMask[2] ? GL_TRUE : GL_FALSE,
    279 				  state.colorMask[3] ? GL_TRUE : GL_FALSE);
    280 }
    281 
    282 static void renderQuad (sglr::Context& ctx, const glu::VertexArrayPointer& posPtr, const Quad& quad, const float depth)
    283 {
    284 	const deUint16	indices[]	= { 0, 1, 2, 2, 1, 3 };
    285 
    286 	const bool		flipX		= quad.posB.x() < quad.posA.x();
    287 	const bool		flipY		= quad.posB.y() < quad.posA.y();
    288 	const int		viewportX	= de::min(quad.posA.x(), quad.posB.x());
    289 	const int		viewportY	= de::min(quad.posA.y(), quad.posB.y());
    290 	const int		viewportW	= de::abs(quad.posA.x()-quad.posB.x())+1;
    291 	const int		viewportH	= de::abs(quad.posA.y()-quad.posB.y())+1;
    292 
    293 	const Vec2		pA			(flipX ? 1.0f : -1.0f, flipY ? 1.0f : -1.0f);
    294 	const Vec2		pB			(flipX ? -1.0f : 1.0f, flipY ? -1.0f : 1.0f);
    295 
    296 	setVertex(posPtr, 0, Vec4(pA.x(), pA.y(), depth, 1.0f));
    297 	setVertex(posPtr, 1, Vec4(pB.x(), pA.y(), depth, 1.0f));
    298 	setVertex(posPtr, 2, Vec4(pA.x(), pB.y(), depth, 1.0f));
    299 	setVertex(posPtr, 3, Vec4(pB.x(), pB.y(), depth, 1.0f));
    300 
    301 	ctx.viewport(viewportX, viewportY, viewportW, viewportH);
    302 	ctx.drawElements(GL_TRIANGLES, DE_LENGTH_OF_ARRAY(indices), GL_UNSIGNED_SHORT, &indices[0]);
    303 }
    304 
    305 static void render (sglr::Context& ctx, const glu::VertexArrayPointer& posPtr, const RenderCommand& cmd)
    306 {
    307 	setRenderState(ctx, cmd.state);
    308 	renderQuad(ctx, posPtr, cmd.quad, cmd.depth);
    309 }
    310 
    311 static void setupAttributes (sglr::Context& ctx, const VertexDataStorage& vertexData, deUint32 program)
    312 {
    313 	for (int attribNdx = 0; attribNdx < vertexData.getNumEntries(); ++attribNdx)
    314 	{
    315 		const glu::VertexArrayBinding	bindingPtr	= getEntryWithPointer(vertexData, attribNdx);
    316 		const int						attribLoc	= bindingPtr.binding.type == glu::BindingPoint::TYPE_NAME ? ctx.getAttribLocation(program, bindingPtr.binding.name.c_str()) : bindingPtr.binding.location;
    317 
    318 		DE_ASSERT(bindingPtr.pointer.componentType == glu::VTX_COMP_FLOAT);
    319 
    320 		if (attribLoc >= 0)
    321 		{
    322 			ctx.enableVertexAttribArray(attribLoc);
    323 			ctx.vertexAttribPointer(attribLoc, bindingPtr.pointer.numComponents, GL_FLOAT, GL_FALSE, bindingPtr.pointer.stride, bindingPtr.pointer.data);
    324 		}
    325 	}
    326 }
    327 
    328 void setUniformValue (sglr::Context& ctx, int location, rsg::ConstValueAccess value)
    329 {
    330 	DE_STATIC_ASSERT(sizeof(rsg::Scalar) == sizeof(float));
    331 	DE_STATIC_ASSERT(sizeof(rsg::Scalar) == sizeof(int));
    332 
    333 	switch (value.getType().getBaseType())
    334 	{
    335 		case rsg::VariableType::TYPE_FLOAT:
    336 			switch (value.getType().getNumElements())
    337 			{
    338 				case 1:		ctx.uniform1fv(location, 1, (float*)value.value().getValuePtr());	break;
    339 				case 2:		ctx.uniform2fv(location, 1, (float*)value.value().getValuePtr());	break;
    340 				case 3:		ctx.uniform3fv(location, 1, (float*)value.value().getValuePtr());	break;
    341 				case 4:		ctx.uniform4fv(location, 1, (float*)value.value().getValuePtr());	break;
    342 				default:	TCU_FAIL("Unsupported type");										break;
    343 			}
    344 			break;
    345 
    346 		case rsg::VariableType::TYPE_INT:
    347 		case rsg::VariableType::TYPE_BOOL:
    348 		case rsg::VariableType::TYPE_SAMPLER_2D:
    349 		case rsg::VariableType::TYPE_SAMPLER_CUBE:
    350 			switch (value.getType().getNumElements())
    351 			{
    352 				case 1:		ctx.uniform1iv(location, 1, (int*)value.value().getValuePtr());		break;
    353 				case 2:		ctx.uniform2iv(location, 1, (int*)value.value().getValuePtr());		break;
    354 				case 3:		ctx.uniform3iv(location, 1, (int*)value.value().getValuePtr());		break;
    355 				case 4:		ctx.uniform4iv(location, 1, (int*)value.value().getValuePtr());		break;
    356 				default:	TCU_FAIL("Unsupported type");										break;
    357 			}
    358 			break;
    359 
    360 		default:
    361 			throw tcu::InternalError("Unsupported type", "", __FILE__, __LINE__);
    362 	}
    363 }
    364 
    365 static int findShaderInputIndex (const vector<rsg::ShaderInput*>& vars, const char* name)
    366 {
    367 	for (int ndx = 0; ndx < (int)vars.size(); ++ndx)
    368 	{
    369 		if (deStringEqual(vars[ndx]->getVariable()->getName(), name))
    370 			return ndx;
    371 	}
    372 
    373 	throw tcu::InternalError(string(name) + " not found in shader inputs");
    374 }
    375 
    376 static float getWellBehavingChannelColor (float v, int numBits)
    377 {
    378 	DE_ASSERT(de::inRange(numBits, 0, 32));
    379 
    380 	// clear color may not be accurately representable in the target format. If the clear color is
    381 	// on a representable value mapping range border, it could be rounded differently by the GL and in
    382 	// SGLR adding an unexpected error source. However, selecting an accurately representable background
    383 	// color would effectively disable dithering. To allow dithering and to prevent undefined rounding
    384 	// direction from affecting results, round accurate color to target color format with 8 sub-units
    385 	// (3 bits). If the selected sub-unit value is 3 or 4 (bordering 0.5), replace it with 2 and 5,
    386 	// respectively.
    387 
    388 	if (numBits == 0 || v <= 0.0f || v >= 1.0f)
    389 	{
    390 		// already accurately representable
    391 		return v;
    392 	}
    393 	else
    394 	{
    395 		const deUint64 numSubBits		= 3;
    396 		const deUint64 subUnitBorderLo	= (1u << (numSubBits - 1u)) - 1u;
    397 		const deUint64 subUnitBorderHi	= 1u << (numSubBits - 1u);
    398 		const deUint64 maxFixedValue	= (1u << (numBits + numSubBits)) - 1u;
    399 		const deUint64 fixedValue		= deRoundFloatToInt64(v * (float)maxFixedValue);
    400 
    401 		const deUint64 units			= fixedValue >> numSubBits;
    402 		const deUint64 subUnits			= fixedValue & ((1u << numSubBits) - 1u);
    403 
    404 		const deUint64 tweakedSubUnits	= (subUnits == subUnitBorderLo) ? (subUnitBorderLo - 1)
    405 										: (subUnits == subUnitBorderHi) ? (subUnitBorderHi + 1)
    406 										: (subUnits);
    407 		const deUint64 tweakedValue		= (units << numSubBits) | (tweakedSubUnits);
    408 
    409 		return float(tweakedValue) / float(maxFixedValue);
    410 	}
    411 }
    412 
    413 static tcu::Vec4 getWellBehavingColor (const tcu::Vec4& accurateColor, const tcu::PixelFormat& format)
    414 {
    415 	return tcu::Vec4(getWellBehavingChannelColor(accurateColor[0], format.redBits),
    416 					 getWellBehavingChannelColor(accurateColor[1], format.greenBits),
    417 					 getWellBehavingChannelColor(accurateColor[2], format.blueBits),
    418 					 getWellBehavingChannelColor(accurateColor[3], format.alphaBits));
    419 }
    420 
    421 } // anonymous
    422 
    423 struct FragOpInteractionCase::ReferenceContext
    424 {
    425 	const sglr::ReferenceContextLimits	limits;
    426 	sglr::ReferenceContextBuffers		buffers;
    427 	sglr::ReferenceContext				context;
    428 
    429 	ReferenceContext (glu::RenderContext& renderCtx, int width, int height)
    430 		: limits	(renderCtx)
    431 		, buffers	(renderCtx.getRenderTarget().getPixelFormat(), renderCtx.getRenderTarget().getDepthBits(), renderCtx.getRenderTarget().getStencilBits(), width, height)
    432 		, context	(limits, buffers.getColorbuffer(), buffers.getDepthbuffer(), buffers.getStencilbuffer())
    433 	{
    434 	}
    435 };
    436 
    437 FragOpInteractionCase::FragOpInteractionCase (tcu::TestContext& testCtx, glu::RenderContext& renderCtx, const glu::ContextInfo& ctxInfo, const char* name, const rsg::ProgramParameters& params)
    438 	: TestCase			(testCtx, name, "")
    439 	, m_renderCtx		(renderCtx)
    440 	, m_ctxInfo			(ctxInfo)
    441 	, m_params			(params)
    442 	, m_vertexShader	(rsg::Shader::TYPE_VERTEX)
    443 	, m_fragmentShader	(rsg::Shader::TYPE_FRAGMENT)
    444 	, m_program			(DE_NULL)
    445 	, m_glCtx			(DE_NULL)
    446 	, m_referenceCtx	(DE_NULL)
    447 	, m_glProgram		(0)
    448 	, m_refProgram		(0)
    449 	, m_iterNdx			(0)
    450 {
    451 }
    452 
    453 FragOpInteractionCase::~FragOpInteractionCase (void)
    454 {
    455 	FragOpInteractionCase::deinit();
    456 }
    457 
    458 void FragOpInteractionCase::init (void)
    459 {
    460 	de::Random				rnd				(m_params.seed ^ 0x232faac);
    461 	const int				viewportW		= de::min<int>(m_renderCtx.getRenderTarget().getWidth(),	VIEWPORT_WIDTH);
    462 	const int				viewportH		= de::min<int>(m_renderCtx.getRenderTarget().getHeight(),	VIEWPORT_HEIGHT);
    463 	const int				viewportX		= rnd.getInt(0, m_renderCtx.getRenderTarget().getWidth()	- viewportW);
    464 	const int				viewportY		= rnd.getInt(0, m_renderCtx.getRenderTarget().getHeight()	- viewportH);
    465 
    466 	rsg::ProgramGenerator	generator;
    467 
    468 	generator.generate(m_params, m_vertexShader, m_fragmentShader);
    469 	rsg::computeUnifiedUniforms(m_vertexShader, m_fragmentShader, m_unifiedUniforms);
    470 
    471 	try
    472 	{
    473 		DE_ASSERT(!m_program);
    474 		m_program = new gls::RandomShaderProgram(m_vertexShader, m_fragmentShader, (int)m_unifiedUniforms.size(), m_unifiedUniforms.empty() ? DE_NULL : &m_unifiedUniforms[0]);
    475 
    476 		DE_ASSERT(!m_referenceCtx);
    477 		m_referenceCtx = new ReferenceContext(m_renderCtx, viewportW, viewportH);
    478 
    479 		DE_ASSERT(!m_glCtx);
    480 		m_glCtx = new sglr::GLContext(m_renderCtx, m_testCtx.getLog(), sglr::GLCONTEXT_LOG_CALLS|sglr::GLCONTEXT_LOG_PROGRAMS, IVec4(viewportX, viewportY, viewportW, viewportH));
    481 
    482 		m_refProgram	= m_referenceCtx->context.createProgram(m_program);
    483 		m_glProgram		= m_glCtx->createProgram(m_program);
    484 
    485 		m_viewportSize	= tcu::IVec2(viewportW, viewportH);
    486 		m_iterNdx		= 0;
    487 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    488 	}
    489 	catch (...)
    490 	{
    491 		// Save some memory by cleaning up stuff.
    492 		FragOpInteractionCase::deinit();
    493 		throw;
    494 	}
    495 }
    496 
    497 void FragOpInteractionCase::deinit (void)
    498 {
    499 	delete m_referenceCtx;
    500 	m_referenceCtx = DE_NULL;
    501 
    502 	delete m_glCtx;
    503 	m_glCtx = DE_NULL;
    504 
    505 	delete m_program;
    506 	m_program = DE_NULL;
    507 }
    508 
    509 FragOpInteractionCase::IterateResult FragOpInteractionCase::iterate (void)
    510 {
    511 	de::Random							rnd					(m_params.seed ^ deInt32Hash(m_iterNdx));
    512 	const tcu::ScopedLogSection			section				(m_testCtx.getLog(), string("Iter") + de::toString(m_iterNdx), string("Iteration ") + de::toString(m_iterNdx));
    513 
    514 	const int							positionNdx			= findShaderInputIndex(m_vertexShader.getInputs(), "dEQP_Position");
    515 
    516 	const int							numVertices			= 4;
    517 	VertexDataStorage					vertexData			(m_vertexShader.getInputs(), numVertices);
    518 	std::vector<rsg::VariableValue>		uniformValues;
    519 	std::vector<RenderCommand>			renderCmds			(NUM_COMMANDS_PER_ITERATION);
    520 
    521 	tcu::Surface						rendered			(m_viewportSize.x(), m_viewportSize.y());
    522 	tcu::Surface						reference			(m_viewportSize.x(), m_viewportSize.y());
    523 
    524 	const tcu::Vec4						vtxInterpFactors[]	=
    525 	{
    526 		tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f),
    527 		tcu::Vec4(1.0f, 0.0f, 0.5f, 0.5f),
    528 		tcu::Vec4(0.0f, 1.0f, 0.5f, 0.5f),
    529 		tcu::Vec4(1.0f, 1.0f, 1.0f, 0.0f)
    530 	};
    531 
    532 	rsg::computeUniformValues(rnd, uniformValues, m_unifiedUniforms);
    533 
    534 	for (int attribNdx = 0; attribNdx < (int)m_vertexShader.getInputs().size(); ++attribNdx)
    535 	{
    536 		if (attribNdx == positionNdx)
    537 			continue;
    538 
    539 		const rsg::ShaderInput*				shaderIn		= m_vertexShader.getInputs()[attribNdx];
    540 		const rsg::VariableType&			varType			= shaderIn->getVariable()->getType();
    541 		const rsg::ConstValueRangeAccess	valueRange		= shaderIn->getValueRange();
    542 		const int							numComponents	= varType.getNumElements();
    543 		const glu::VertexArrayBinding		layoutEntry		= getEntryWithPointer(vertexData, attribNdx);
    544 
    545 		DE_ASSERT(varType.getBaseType() == rsg::VariableType::TYPE_FLOAT);
    546 
    547 		for (int vtxNdx = 0; vtxNdx < 4; vtxNdx++)
    548 		{
    549 			const int			fNdx	= (attribNdx+vtxNdx+m_iterNdx)%DE_LENGTH_OF_ARRAY(vtxInterpFactors);
    550 			const tcu::Vec4&	f		= vtxInterpFactors[fNdx];
    551 
    552 			switch (numComponents)
    553 			{
    554 				case 1:	setVertex(layoutEntry.pointer, vtxNdx, interpolateRange(valueRange, f.toWidth<1>()));	break;
    555 				case 2:	setVertex(layoutEntry.pointer, vtxNdx, interpolateRange(valueRange, f.toWidth<2>()));	break;
    556 				case 3:	setVertex(layoutEntry.pointer, vtxNdx, interpolateRange(valueRange, f.toWidth<3>()));	break;
    557 				case 4:	setVertex(layoutEntry.pointer, vtxNdx, interpolateRange(valueRange, f.toWidth<4>()));	break;
    558 				default:
    559 					DE_ASSERT(false);
    560 			}
    561 		}
    562 	}
    563 
    564 	for (vector<RenderCommand>::iterator cmdIter = renderCmds.begin(); cmdIter != renderCmds.end(); ++cmdIter)
    565 		computeRandomRenderCommand(rnd, *cmdIter, m_renderCtx.getType().getAPI(), m_viewportSize.x(), m_viewportSize.y());
    566 
    567 	// Workaround for inaccurate barycentric/depth computation in current reference renderer:
    568 	// Small bias is added to the draw call depths, in increasing order, to avoid accuracy issues in depth comparison.
    569 	for (int cmdNdx = 0; cmdNdx < (int)renderCmds.size(); cmdNdx++)
    570 		renderCmds[cmdNdx].depth += 0.0231725f * float(cmdNdx);
    571 
    572 	{
    573 		const glu::VertexArrayPointer		posPtr				= getEntryWithPointer(vertexData, positionNdx).pointer;
    574 
    575 		sglr::Context* const				contexts[]			= { m_glCtx, &m_referenceCtx->context };
    576 		const deUint32						programs[]			= { m_glProgram, m_refProgram };
    577 		tcu::PixelBufferAccess				readDst[]			= { rendered.getAccess(), reference.getAccess() };
    578 
    579 		const tcu::Vec4						accurateClearColor	= tcu::Vec4(0.0f, 0.25f, 0.5f, 1.0f);
    580 		const tcu::Vec4						clearColor			= getWellBehavingColor(accurateClearColor, m_renderCtx.getRenderTarget().getPixelFormat());
    581 
    582 		for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(contexts); ndx++)
    583 		{
    584 			sglr::Context&	ctx			= *contexts[ndx];
    585 			const deUint32	program		= programs[ndx];
    586 
    587 			setupAttributes(ctx, vertexData, program);
    588 
    589 			ctx.disable		(GL_SCISSOR_TEST);
    590 			ctx.colorMask	(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
    591 			ctx.depthMask	(GL_TRUE);
    592 			ctx.stencilMask	(~0u);
    593 			ctx.clearColor	(clearColor.x(), clearColor.y(), clearColor.z(), clearColor.w());
    594 			ctx.clear		(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
    595 
    596 			ctx.useProgram	(program);
    597 
    598 			for (vector<rsg::VariableValue>::const_iterator uniformIter = uniformValues.begin(); uniformIter != uniformValues.end(); ++uniformIter)
    599 				setUniformValue(ctx, ctx.getUniformLocation(program, uniformIter->getVariable()->getName()), uniformIter->getValue());
    600 
    601 			for (vector<RenderCommand>::const_iterator cmdIter = renderCmds.begin(); cmdIter != renderCmds.end(); ++cmdIter)
    602 				render(ctx, posPtr, *cmdIter);
    603 
    604 			GLU_EXPECT_NO_ERROR(ctx.getError(), "Rendering failed");
    605 
    606 			ctx.readPixels(0, 0, m_viewportSize.x(), m_viewportSize.y(), GL_RGBA, GL_UNSIGNED_BYTE, readDst[ndx].getDataPtr());
    607 		}
    608 	}
    609 
    610 	{
    611 		const tcu::RGBA		threshold		= m_renderCtx.getRenderTarget().getPixelFormat().getColorThreshold()+tcu::RGBA(3,3,3,3);
    612 		const bool			compareOk		= tcu::bilinearCompare(m_testCtx.getLog(), "CompareResult", "Image comparison result", reference.getAccess(), rendered.getAccess(), threshold, tcu::COMPARE_LOG_RESULT);
    613 
    614 		if (!compareOk)
    615 		{
    616 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
    617 			return STOP;
    618 		}
    619 	}
    620 
    621 	m_iterNdx += 1;
    622 	return (m_iterNdx < NUM_ITERATIONS) ? CONTINUE : STOP;
    623 }
    624 
    625 } // gls
    626 } // deqp
    627