Home | History | Annotate | Download | only in egl
      1 /*-------------------------------------------------------------------------
      2  * drawElements Quality Program EGL 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 Rendering tests for different config and api combinations.
     22  * \todo [2013-03-19 pyry] GLES1 and VG support.
     23  *//*--------------------------------------------------------------------*/
     24 
     25 #include "teglRenderTests.hpp"
     26 #include "teglRenderCase.hpp"
     27 
     28 #include "tcuRenderTarget.hpp"
     29 #include "tcuTestLog.hpp"
     30 #include "tcuImageCompare.hpp"
     31 #include "tcuTextureUtil.hpp"
     32 #include "tcuSurface.hpp"
     33 
     34 #include "egluDefs.hpp"
     35 #include "egluUtil.hpp"
     36 
     37 #include "eglwLibrary.hpp"
     38 #include "eglwEnums.hpp"
     39 
     40 #include "gluShaderProgram.hpp"
     41 
     42 #include "glwFunctions.hpp"
     43 #include "glwEnums.hpp"
     44 
     45 #include "deRandom.hpp"
     46 #include "deSharedPtr.hpp"
     47 #include "deSemaphore.hpp"
     48 #include "deThread.hpp"
     49 #include "deString.h"
     50 
     51 #include "rrRenderer.hpp"
     52 #include "rrFragmentOperations.hpp"
     53 
     54 #include <algorithm>
     55 #include <iterator>
     56 #include <memory>
     57 #include <set>
     58 
     59 namespace deqp
     60 {
     61 namespace egl
     62 {
     63 
     64 using std::string;
     65 using std::vector;
     66 using std::set;
     67 
     68 using tcu::Vec4;
     69 
     70 using tcu::TestLog;
     71 
     72 using namespace glw;
     73 using namespace eglw;
     74 
     75 static const tcu::Vec4	CLEAR_COLOR		= tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f);
     76 static const float		CLEAR_DEPTH		= 1.0f;
     77 static const int		CLEAR_STENCIL	= 0;
     78 
     79 namespace
     80 {
     81 
     82 enum PrimitiveType
     83 {
     84 	PRIMITIVETYPE_TRIANGLE = 0,	//!< Triangles, requires 3 coordinates per primitive
     85 //	PRIMITIVETYPE_POINT,		//!< Points, requires 1 coordinate per primitive (w is used as size)
     86 //	PRIMITIVETYPE_LINE,			//!< Lines, requires 2 coordinates per primitive
     87 
     88 	PRIMITIVETYPE_LAST
     89 };
     90 
     91 enum BlendMode
     92 {
     93 	BLENDMODE_NONE = 0,			//!< No blending
     94 	BLENDMODE_ADDITIVE,			//!< Blending with ONE, ONE
     95 	BLENDMODE_SRC_OVER,			//!< Blending with SRC_ALPHA, ONE_MINUS_SRC_ALPHA
     96 
     97 	BLENDMODE_LAST
     98 };
     99 
    100 enum DepthMode
    101 {
    102 	DEPTHMODE_NONE = 0,			//!< No depth test or depth writes
    103 	DEPTHMODE_LESS,				//!< Depth test with less & depth write
    104 
    105 	DEPTHMODE_LAST
    106 };
    107 
    108 enum StencilMode
    109 {
    110 	STENCILMODE_NONE = 0,		//!< No stencil test or write
    111 	STENCILMODE_LEQUAL_INC,		//!< Stencil test with LEQUAL, increment on pass
    112 
    113 	STENCILMODE_LAST
    114 };
    115 
    116 struct DrawPrimitiveOp
    117 {
    118 	PrimitiveType	type;
    119 	int				count;
    120 	vector<Vec4>	positions;
    121 	vector<Vec4>	colors;
    122 	BlendMode		blend;
    123 	DepthMode		depth;
    124 	StencilMode		stencil;
    125 	int				stencilRef;
    126 };
    127 
    128 static bool isANarrowScreenSpaceTriangle (const tcu::Vec4& p0, const tcu::Vec4& p1, const tcu::Vec4& p2)
    129 {
    130 	// to clip space
    131 	const tcu::Vec2	csp0 				= p0.swizzle(0, 1) / p0.w();
    132 	const tcu::Vec2	csp1 				= p1.swizzle(0, 1) / p1.w();
    133 	const tcu::Vec2	csp2 				= p2.swizzle(0, 1) / p2.w();
    134 
    135 	const tcu::Vec2	e01					= (csp1 - csp0);
    136 	const tcu::Vec2	e02					= (csp2 - csp0);
    137 
    138 	const float		minimumVisibleArea	= 0.4f; // must cover at least 10% of the surface
    139 	const float		visibleArea			= de::abs(e01.x() * e02.y() - e02.x() * e01.y()) * 0.5f;
    140 
    141 	return visibleArea < minimumVisibleArea;
    142 }
    143 
    144 void randomizeDrawOp (de::Random& rnd, DrawPrimitiveOp& drawOp)
    145 {
    146 	const int	minStencilRef	= 0;
    147 	const int	maxStencilRef	= 8;
    148 	const int	minPrimitives	= 2;
    149 	const int	maxPrimitives	= 4;
    150 
    151 	const float	maxTriOffset	= 1.0f;
    152 	const float	minDepth		= -1.0f; // \todo [pyry] Reference doesn't support Z clipping yet
    153 	const float	maxDepth		= 1.0f;
    154 
    155 	const float	minRGB			= 0.2f;
    156 	const float	maxRGB			= 0.9f;
    157 	const float	minAlpha		= 0.3f;
    158 	const float	maxAlpha		= 1.0f;
    159 
    160 	drawOp.type			= (PrimitiveType)rnd.getInt(0, PRIMITIVETYPE_LAST-1);
    161 	drawOp.count		= rnd.getInt(minPrimitives, maxPrimitives);
    162 	drawOp.blend		= (BlendMode)rnd.getInt(0, BLENDMODE_LAST-1);
    163 	drawOp.depth		= (DepthMode)rnd.getInt(0, DEPTHMODE_LAST-1);
    164 	drawOp.stencil		= (StencilMode)rnd.getInt(0, STENCILMODE_LAST-1);
    165 	drawOp.stencilRef	= rnd.getInt(minStencilRef, maxStencilRef);
    166 
    167 	if (drawOp.type == PRIMITIVETYPE_TRIANGLE)
    168 	{
    169 		drawOp.positions.resize(drawOp.count*3);
    170 		drawOp.colors.resize(drawOp.count*3);
    171 
    172 		for (int triNdx = 0; triNdx < drawOp.count; triNdx++)
    173 		{
    174 			const float		cx		= rnd.getFloat(-1.0f, 1.0f);
    175 			const float		cy		= rnd.getFloat(-1.0f, 1.0f);
    176 
    177 			for (int coordNdx = 0; coordNdx < 3; coordNdx++)
    178 			{
    179 				tcu::Vec4&	position	= drawOp.positions[triNdx*3 + coordNdx];
    180 				tcu::Vec4&	color		= drawOp.colors[triNdx*3 + coordNdx];
    181 
    182 				position.x()	= cx + rnd.getFloat(-maxTriOffset, maxTriOffset);
    183 				position.y()	= cy + rnd.getFloat(-maxTriOffset, maxTriOffset);
    184 				position.z()	= rnd.getFloat(minDepth, maxDepth);
    185 				position.w()	= 1.0f;
    186 
    187 				color.x()		= rnd.getFloat(minRGB, maxRGB);
    188 				color.y()		= rnd.getFloat(minRGB, maxRGB);
    189 				color.z()		= rnd.getFloat(minRGB, maxRGB);
    190 				color.w()		= rnd.getFloat(minAlpha, maxAlpha);
    191 			}
    192 
    193 			// avoid generating narrow triangles
    194 			{
    195 				const int	maxAttempts	= 40;
    196 				int			numAttempts	= 0;
    197 				tcu::Vec4&	p0			= drawOp.positions[triNdx*3 + 0];
    198 				tcu::Vec4&	p1			= drawOp.positions[triNdx*3 + 1];
    199 				tcu::Vec4&	p2			= drawOp.positions[triNdx*3 + 2];
    200 
    201 				while (isANarrowScreenSpaceTriangle(p0, p1, p2))
    202 				{
    203 					p1.x()	= cx + rnd.getFloat(-maxTriOffset, maxTriOffset);
    204 					p1.y()	= cy + rnd.getFloat(-maxTriOffset, maxTriOffset);
    205 					p1.z()	= rnd.getFloat(minDepth, maxDepth);
    206 					p1.w()	= 1.0f;
    207 
    208 					p2.x()	= cx + rnd.getFloat(-maxTriOffset, maxTriOffset);
    209 					p2.y()	= cy + rnd.getFloat(-maxTriOffset, maxTriOffset);
    210 					p2.z()	= rnd.getFloat(minDepth, maxDepth);
    211 					p2.w()	= 1.0f;
    212 
    213 					if (++numAttempts > maxAttempts)
    214 					{
    215 						DE_ASSERT(false);
    216 						break;
    217 					}
    218 				}
    219 			}
    220 		}
    221 	}
    222 	else
    223 		DE_ASSERT(false);
    224 }
    225 
    226 // Reference rendering code
    227 
    228 class ReferenceShader : public rr::VertexShader, public rr::FragmentShader
    229 {
    230 public:
    231 	enum
    232 	{
    233 		VaryingLoc_Color = 0
    234 	};
    235 
    236 	ReferenceShader ()
    237 		: rr::VertexShader	(2, 1)		// color and pos in => color out
    238 		, rr::FragmentShader(1, 1)		// color in => color out
    239 	{
    240 		this->rr::VertexShader::m_inputs[0].type		= rr::GENERICVECTYPE_FLOAT;
    241 		this->rr::VertexShader::m_inputs[1].type		= rr::GENERICVECTYPE_FLOAT;
    242 
    243 		this->rr::VertexShader::m_outputs[0].type		= rr::GENERICVECTYPE_FLOAT;
    244 		this->rr::VertexShader::m_outputs[0].flatshade	= false;
    245 
    246 		this->rr::FragmentShader::m_inputs[0].type		= rr::GENERICVECTYPE_FLOAT;
    247 		this->rr::FragmentShader::m_inputs[0].flatshade	= false;
    248 
    249 		this->rr::FragmentShader::m_outputs[0].type		= rr::GENERICVECTYPE_FLOAT;
    250 	}
    251 
    252 	void shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const
    253 	{
    254 		for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
    255 		{
    256 			const int positionAttrLoc = 0;
    257 			const int colorAttrLoc = 1;
    258 
    259 			rr::VertexPacket& packet = *packets[packetNdx];
    260 
    261 			// Transform to position
    262 			packet.position = rr::readVertexAttribFloat(inputs[positionAttrLoc], packet.instanceNdx, packet.vertexNdx);
    263 
    264 			// Pass color to FS
    265 			packet.outputs[VaryingLoc_Color] = rr::readVertexAttribFloat(inputs[colorAttrLoc], packet.instanceNdx, packet.vertexNdx);
    266 		}
    267 	}
    268 
    269 	void shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const
    270 	{
    271 		for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx)
    272 		{
    273 			rr::FragmentPacket& packet = packets[packetNdx];
    274 
    275 			for (int fragNdx = 0; fragNdx < 4; ++fragNdx)
    276 				rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, rr::readVarying<float>(packet, context, VaryingLoc_Color, fragNdx));
    277 		}
    278 	}
    279 };
    280 
    281 void toReferenceRenderState (rr::RenderState& state, const DrawPrimitiveOp& drawOp)
    282 {
    283 	state.cullMode	= rr::CULLMODE_NONE;
    284 
    285 	if (drawOp.blend != BLENDMODE_NONE)
    286 	{
    287 		state.fragOps.blendMode = rr::BLENDMODE_STANDARD;
    288 
    289 		switch (drawOp.blend)
    290 		{
    291 			case BLENDMODE_ADDITIVE:
    292 				state.fragOps.blendRGBState.srcFunc		= rr::BLENDFUNC_ONE;
    293 				state.fragOps.blendRGBState.dstFunc		= rr::BLENDFUNC_ONE;
    294 				state.fragOps.blendRGBState.equation	= rr::BLENDEQUATION_ADD;
    295 				state.fragOps.blendAState				= state.fragOps.blendRGBState;
    296 				break;
    297 
    298 			case BLENDMODE_SRC_OVER:
    299 				state.fragOps.blendRGBState.srcFunc		= rr::BLENDFUNC_SRC_ALPHA;
    300 				state.fragOps.blendRGBState.dstFunc		= rr::BLENDFUNC_ONE_MINUS_SRC_ALPHA;
    301 				state.fragOps.blendRGBState.equation	= rr::BLENDEQUATION_ADD;
    302 				state.fragOps.blendAState				= state.fragOps.blendRGBState;
    303 				break;
    304 
    305 			default:
    306 				DE_ASSERT(false);
    307 		}
    308 	}
    309 
    310 	if (drawOp.depth != DEPTHMODE_NONE)
    311 	{
    312 		state.fragOps.depthTestEnabled = true;
    313 
    314 		DE_ASSERT(drawOp.depth == DEPTHMODE_LESS);
    315 		state.fragOps.depthFunc = rr::TESTFUNC_LESS;
    316 	}
    317 
    318 	if (drawOp.stencil != STENCILMODE_NONE)
    319 	{
    320 		state.fragOps.stencilTestEnabled = true;
    321 
    322 		DE_ASSERT(drawOp.stencil == STENCILMODE_LEQUAL_INC);
    323 		state.fragOps.stencilStates[0].func		= rr::TESTFUNC_LEQUAL;
    324 		state.fragOps.stencilStates[0].sFail	= rr::STENCILOP_KEEP;
    325 		state.fragOps.stencilStates[0].dpFail	= rr::STENCILOP_INCR;
    326 		state.fragOps.stencilStates[0].dpPass	= rr::STENCILOP_INCR;
    327 		state.fragOps.stencilStates[0].ref		= drawOp.stencilRef;
    328 		state.fragOps.stencilStates[1]			= state.fragOps.stencilStates[0];
    329 	}
    330 }
    331 
    332 tcu::TextureFormat getColorFormat (const tcu::PixelFormat& colorBits)
    333 {
    334 	using tcu::TextureFormat;
    335 
    336 	DE_ASSERT(de::inBounds(colorBits.redBits,	0, 0xff) &&
    337 			  de::inBounds(colorBits.greenBits,	0, 0xff) &&
    338 			  de::inBounds(colorBits.blueBits,	0, 0xff) &&
    339 			  de::inBounds(colorBits.alphaBits,	0, 0xff));
    340 
    341 #define PACK_FMT(R, G, B, A) (((R) << 24) | ((G) << 16) | ((B) << 8) | (A))
    342 
    343 	// \note [pyry] This may not hold true on some implementations - best effort guess only.
    344 	switch (PACK_FMT(colorBits.redBits, colorBits.greenBits, colorBits.blueBits, colorBits.alphaBits))
    345 	{
    346 		case PACK_FMT(8,8,8,8):		return TextureFormat(TextureFormat::RGBA,	TextureFormat::UNORM_INT8);
    347 		case PACK_FMT(8,8,8,0):		return TextureFormat(TextureFormat::RGB,	TextureFormat::UNORM_INT8);
    348 		case PACK_FMT(4,4,4,4):		return TextureFormat(TextureFormat::RGBA,	TextureFormat::UNORM_SHORT_4444);
    349 		case PACK_FMT(5,5,5,1):		return TextureFormat(TextureFormat::RGBA,	TextureFormat::UNORM_SHORT_5551);
    350 		case PACK_FMT(5,6,5,0):		return TextureFormat(TextureFormat::RGB,	TextureFormat::UNORM_SHORT_565);
    351 
    352 		// \note Defaults to RGBA8
    353 		default:					return TextureFormat(TextureFormat::RGBA,	TextureFormat::UNORM_INT8);
    354 	}
    355 
    356 #undef PACK_FMT
    357 }
    358 
    359 tcu::TextureFormat getDepthFormat (const int depthBits)
    360 {
    361 	switch (depthBits)
    362 	{
    363 		case 0:		return tcu::TextureFormat();
    364 		case 8:		return tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::UNORM_INT8);
    365 		case 16:	return tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::UNORM_INT16);
    366 		case 24:	return tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::UNORM_INT24);
    367 		case 32:
    368 		default:	return tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::FLOAT);
    369 	}
    370 }
    371 
    372 tcu::TextureFormat getStencilFormat (int stencilBits)
    373 {
    374 	switch (stencilBits)
    375 	{
    376 		case 0:		return tcu::TextureFormat();
    377 		case 8:
    378 		default:	return tcu::TextureFormat(tcu::TextureFormat::S, tcu::TextureFormat::UNSIGNED_INT8);
    379 	}
    380 }
    381 
    382 void renderReference (const tcu::PixelBufferAccess& dst, const vector<DrawPrimitiveOp>& drawOps, const tcu::PixelFormat& colorBits, const int depthBits, const int stencilBits, const int numSamples)
    383 {
    384 	const int						width			= dst.getWidth();
    385 	const int						height			= dst.getHeight();
    386 
    387 	tcu::TextureLevel				colorBuffer;
    388 	tcu::TextureLevel				depthBuffer;
    389 	tcu::TextureLevel				stencilBuffer;
    390 
    391 	rr::Renderer					referenceRenderer;
    392 	rr::VertexAttrib				attributes[2];
    393 	const ReferenceShader			shader;
    394 
    395 	attributes[0].type				= rr::VERTEXATTRIBTYPE_FLOAT;
    396 	attributes[0].size				= 4;
    397 	attributes[0].stride			= 0;
    398 	attributes[0].instanceDivisor	= 0;
    399 
    400 	attributes[1].type				= rr::VERTEXATTRIBTYPE_FLOAT;
    401 	attributes[1].size				= 4;
    402 	attributes[1].stride			= 0;
    403 	attributes[1].instanceDivisor	= 0;
    404 
    405 	// Initialize buffers.
    406 	colorBuffer.setStorage(getColorFormat(colorBits), numSamples, width, height);
    407 	rr::clearMultisampleColorBuffer(colorBuffer, CLEAR_COLOR, rr::WindowRectangle(0, 0, width, height));
    408 
    409 	if (depthBits > 0)
    410 	{
    411 		depthBuffer.setStorage(getDepthFormat(depthBits), numSamples, width, height);
    412 		rr::clearMultisampleDepthBuffer(depthBuffer, CLEAR_DEPTH, rr::WindowRectangle(0, 0, width, height));
    413 	}
    414 
    415 	if (stencilBits > 0)
    416 	{
    417 		stencilBuffer.setStorage(getStencilFormat(stencilBits), numSamples, width, height);
    418 		rr::clearMultisampleStencilBuffer(stencilBuffer, CLEAR_STENCIL, rr::WindowRectangle(0, 0, width, height));
    419 	}
    420 
    421 	const rr::RenderTarget renderTarget(rr::MultisamplePixelBufferAccess::fromMultisampleAccess(colorBuffer.getAccess()),
    422 										rr::MultisamplePixelBufferAccess::fromMultisampleAccess(depthBuffer.getAccess()),
    423 										rr::MultisamplePixelBufferAccess::fromMultisampleAccess(stencilBuffer.getAccess()));
    424 
    425 	for (vector<DrawPrimitiveOp>::const_iterator drawOp = drawOps.begin(); drawOp != drawOps.end(); drawOp++)
    426 	{
    427 		// Translate state
    428 		rr::RenderState renderState((rr::ViewportState)(rr::MultisamplePixelBufferAccess::fromMultisampleAccess(colorBuffer.getAccess())));
    429 		toReferenceRenderState(renderState, *drawOp);
    430 
    431 		DE_ASSERT(drawOp->type == PRIMITIVETYPE_TRIANGLE);
    432 
    433 		attributes[0].pointer = &drawOp->positions[0];
    434 		attributes[1].pointer = &drawOp->colors[0];
    435 
    436 		referenceRenderer.draw(
    437 			rr::DrawCommand(
    438 				renderState,
    439 				renderTarget,
    440 				rr::Program(static_cast<const rr::VertexShader*>(&shader), static_cast<const rr::FragmentShader*>(&shader)),
    441 				2,
    442 				attributes,
    443 				rr::PrimitiveList(rr::PRIMITIVETYPE_TRIANGLES, drawOp->count * 3, 0)));
    444 	}
    445 
    446 	rr::resolveMultisampleColorBuffer(dst, rr::MultisamplePixelBufferAccess::fromMultisampleAccess(colorBuffer.getAccess()));
    447 }
    448 
    449 // API rendering code
    450 
    451 class Program
    452 {
    453 public:
    454 					Program				(void) {}
    455 	virtual			~Program			(void) {}
    456 
    457 	virtual void	setup				(void) const = DE_NULL;
    458 };
    459 
    460 typedef de::SharedPtr<Program> ProgramSp;
    461 
    462 static glu::ProgramSources getProgramSourcesES2 (void)
    463 {
    464 	static const char* s_vertexSrc =
    465 		"attribute highp vec4 a_position;\n"
    466 		"attribute mediump vec4 a_color;\n"
    467 		"varying mediump vec4 v_color;\n"
    468 		"void main (void)\n"
    469 		"{\n"
    470 		"	gl_Position = a_position;\n"
    471 		"	v_color = a_color;\n"
    472 		"}\n";
    473 
    474 	static const char* s_fragmentSrc =
    475 		"varying mediump vec4 v_color;\n"
    476 		"void main (void)\n"
    477 		"{\n"
    478 		"	gl_FragColor = v_color;\n"
    479 		"}\n";
    480 
    481 	return glu::ProgramSources() << glu::VertexSource(s_vertexSrc) << glu::FragmentSource(s_fragmentSrc);
    482 }
    483 
    484 class GLES2Program : public Program
    485 {
    486 public:
    487 	GLES2Program (const glw::Functions& gl)
    488 		: m_gl				(gl)
    489 		, m_program			(gl, getProgramSourcesES2())
    490 		, m_positionLoc		(0)
    491 		, m_colorLoc		(0)
    492 	{
    493 
    494 		m_positionLoc	= m_gl.getAttribLocation(m_program.getProgram(), "a_position");
    495 		m_colorLoc		= m_gl.getAttribLocation(m_program.getProgram(), "a_color");
    496 	}
    497 
    498 	~GLES2Program (void)
    499 	{
    500 	}
    501 
    502 	void setup (void) const
    503 	{
    504 		m_gl.useProgram(m_program.getProgram());
    505 		m_gl.enableVertexAttribArray(m_positionLoc);
    506 		m_gl.enableVertexAttribArray(m_colorLoc);
    507 		GLU_CHECK_GLW_MSG(m_gl, "Program setup failed");
    508 	}
    509 
    510 	int						getPositionLoc		(void) const { return m_positionLoc;	}
    511 	int						getColorLoc			(void) const { return m_colorLoc;		}
    512 
    513 private:
    514 	const glw::Functions&	m_gl;
    515 	glu::ShaderProgram		m_program;
    516 	int						m_positionLoc;
    517 	int						m_colorLoc;
    518 };
    519 
    520 void clearGLES2 (const glw::Functions& gl, const tcu::Vec4& color, const float depth, const int stencil)
    521 {
    522 	gl.clearColor(color.x(), color.y(), color.z(), color.w());
    523 	gl.clearDepthf(depth);
    524 	gl.clearStencil(stencil);
    525 	gl.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
    526 }
    527 
    528 void drawGLES2 (const glw::Functions& gl, const Program& program, const DrawPrimitiveOp& drawOp)
    529 {
    530 	const GLES2Program& gles2Program = dynamic_cast<const GLES2Program&>(program);
    531 
    532 	switch (drawOp.blend)
    533 	{
    534 		case BLENDMODE_NONE:
    535 			gl.disable(GL_BLEND);
    536 			break;
    537 
    538 		case BLENDMODE_ADDITIVE:
    539 			gl.enable(GL_BLEND);
    540 			gl.blendFunc(GL_ONE, GL_ONE);
    541 			break;
    542 
    543 		case BLENDMODE_SRC_OVER:
    544 			gl.enable(GL_BLEND);
    545 			gl.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    546 			break;
    547 
    548 		default:
    549 			DE_ASSERT(false);
    550 	}
    551 
    552 	switch (drawOp.depth)
    553 	{
    554 		case DEPTHMODE_NONE:
    555 			gl.disable(GL_DEPTH_TEST);
    556 			break;
    557 
    558 		case DEPTHMODE_LESS:
    559 			gl.enable(GL_DEPTH_TEST);
    560 			break;
    561 
    562 		default:
    563 			DE_ASSERT(false);
    564 	}
    565 
    566 	switch (drawOp.stencil)
    567 	{
    568 		case STENCILMODE_NONE:
    569 			gl.disable(GL_STENCIL_TEST);
    570 			break;
    571 
    572 		case STENCILMODE_LEQUAL_INC:
    573 			gl.enable(GL_STENCIL_TEST);
    574 			gl.stencilFunc(GL_LEQUAL, drawOp.stencilRef, ~0u);
    575 			gl.stencilOp(GL_KEEP, GL_INCR, GL_INCR);
    576 			break;
    577 
    578 		default:
    579 			DE_ASSERT(false);
    580 	}
    581 
    582 	gl.disable(GL_DITHER);
    583 
    584 	gl.vertexAttribPointer(gles2Program.getPositionLoc(), 4, GL_FLOAT, GL_FALSE, 0, &drawOp.positions[0]);
    585 	gl.vertexAttribPointer(gles2Program.getColorLoc(), 4, GL_FLOAT, GL_FALSE, 0, &drawOp.colors[0]);
    586 
    587 	DE_ASSERT(drawOp.type == PRIMITIVETYPE_TRIANGLE);
    588 	gl.drawArrays(GL_TRIANGLES, 0, drawOp.count*3);
    589 }
    590 
    591 static void readPixelsGLES2 (const glw::Functions& gl, tcu::Surface& dst)
    592 {
    593 	gl.readPixels(0, 0, dst.getWidth(), dst.getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, dst.getAccess().getDataPtr());
    594 }
    595 
    596 Program* createProgram (const glw::Functions& gl, EGLint api)
    597 {
    598 	switch (api)
    599 	{
    600 		case EGL_OPENGL_ES2_BIT:		return new GLES2Program(gl);
    601 		case EGL_OPENGL_ES3_BIT_KHR:	return new GLES2Program(gl);
    602 		default:
    603 			throw tcu::NotSupportedError("Unsupported API");
    604 	}
    605 }
    606 
    607 void draw (const glw::Functions& gl, EGLint api, const Program& program, const DrawPrimitiveOp& drawOp)
    608 {
    609 	switch (api)
    610 	{
    611 		case EGL_OPENGL_ES2_BIT:		drawGLES2(gl, program, drawOp);		break;
    612 		case EGL_OPENGL_ES3_BIT_KHR:	drawGLES2(gl, program, drawOp);		break;
    613 		default:
    614 			throw tcu::NotSupportedError("Unsupported API");
    615 	}
    616 }
    617 
    618 void clear (const glw::Functions& gl, EGLint api, const tcu::Vec4& color, const float depth, const int stencil)
    619 {
    620 	switch (api)
    621 	{
    622 		case EGL_OPENGL_ES2_BIT:		clearGLES2(gl, color, depth, stencil);		break;
    623 		case EGL_OPENGL_ES3_BIT_KHR:	clearGLES2(gl, color, depth, stencil);		break;
    624 		default:
    625 			throw tcu::NotSupportedError("Unsupported API");
    626 	}
    627 }
    628 
    629 static void readPixels (const glw::Functions& gl, EGLint api, tcu::Surface& dst)
    630 {
    631 	switch (api)
    632 	{
    633 		case EGL_OPENGL_ES2_BIT:		readPixelsGLES2(gl, dst);		break;
    634 		case EGL_OPENGL_ES3_BIT_KHR:	readPixelsGLES2(gl, dst);		break;
    635 		default:
    636 			throw tcu::NotSupportedError("Unsupported API");
    637 	}
    638 }
    639 
    640 static void finish (const glw::Functions& gl, EGLint api)
    641 {
    642 	switch (api)
    643 	{
    644 		case EGL_OPENGL_ES2_BIT:
    645 		case EGL_OPENGL_ES3_BIT_KHR:
    646 			gl.finish();
    647 			break;
    648 
    649 		default:
    650 			throw tcu::NotSupportedError("Unsupported API");
    651 	}
    652 }
    653 
    654 tcu::PixelFormat getPixelFormat (const Library& egl, EGLDisplay display, EGLConfig config)
    655 {
    656 	tcu::PixelFormat fmt;
    657 	fmt.redBits		= eglu::getConfigAttribInt(egl, display, config, EGL_RED_SIZE);
    658 	fmt.greenBits	= eglu::getConfigAttribInt(egl, display, config, EGL_GREEN_SIZE);
    659 	fmt.blueBits	= eglu::getConfigAttribInt(egl, display, config, EGL_BLUE_SIZE);
    660 	fmt.alphaBits	= eglu::getConfigAttribInt(egl, display, config, EGL_ALPHA_SIZE);
    661 	return fmt;
    662 }
    663 
    664 } // anonymous
    665 
    666 // SingleThreadRenderCase
    667 
    668 class SingleThreadRenderCase : public MultiContextRenderCase
    669 {
    670 public:
    671 						SingleThreadRenderCase		(EglTestContext& eglTestCtx, const char* name, const char* description, EGLint api, EGLint surfaceType, const eglu::FilterList& filters, int numContextsPerApi);
    672 
    673 	void				init						(void);
    674 
    675 private:
    676 	virtual void		executeForContexts			(EGLDisplay display, EGLSurface surface, const Config& config, const std::vector<std::pair<EGLint, EGLContext> >& contexts);
    677 
    678 	glw::Functions		m_gl;
    679 };
    680 
    681 // SingleThreadColorClearCase
    682 
    683 SingleThreadRenderCase::SingleThreadRenderCase (EglTestContext& eglTestCtx, const char* name, const char* description, EGLint api, EGLint surfaceType, const eglu::FilterList& filters, int numContextsPerApi)
    684 	: MultiContextRenderCase(eglTestCtx, name, description, api, surfaceType, filters, numContextsPerApi)
    685 {
    686 }
    687 
    688 void SingleThreadRenderCase::init (void)
    689 {
    690 	MultiContextRenderCase::init();
    691 	m_eglTestCtx.initGLFunctions(&m_gl, glu::ApiType::es(2,0));
    692 }
    693 
    694 void SingleThreadRenderCase::executeForContexts (EGLDisplay display, EGLSurface surface, const Config& config, const std::vector<std::pair<EGLint, EGLContext> >& contexts)
    695 {
    696 	const Library&			egl			= m_eglTestCtx.getLibrary();
    697 	const int				width		= eglu::querySurfaceInt(egl, display, surface, EGL_WIDTH);
    698 	const int				height		= eglu::querySurfaceInt(egl, display, surface, EGL_HEIGHT);
    699 	const int				numContexts	= (int)contexts.size();
    700 	const int				drawsPerCtx	= 2;
    701 	const int				numIters	= 2;
    702 	const float				threshold	= 0.02f;
    703 
    704 	const tcu::PixelFormat	pixelFmt	= getPixelFormat(egl, display, config.config);
    705 	const int				depthBits	= eglu::getConfigAttribInt(egl, display, config.config, EGL_DEPTH_SIZE);
    706 	const int				stencilBits	= eglu::getConfigAttribInt(egl, display, config.config, EGL_STENCIL_SIZE);
    707 	const int				numSamples	= eglu::getConfigAttribInt(egl, display, config.config, EGL_SAMPLES);
    708 
    709 	TestLog&				log			= m_testCtx.getLog();
    710 
    711 	tcu::Surface			refFrame	(width, height);
    712 	tcu::Surface			frame		(width, height);
    713 
    714 	de::Random				rnd			(deStringHash(getName()) ^ deInt32Hash(numContexts));
    715 	vector<ProgramSp>		programs	(contexts.size());
    716 	vector<DrawPrimitiveOp>	drawOps;
    717 
    718 	// Log basic information about config.
    719 	log << TestLog::Message << "EGL_RED_SIZE = "		<< pixelFmt.redBits << TestLog::EndMessage;
    720 	log << TestLog::Message << "EGL_GREEN_SIZE = "		<< pixelFmt.greenBits << TestLog::EndMessage;
    721 	log << TestLog::Message << "EGL_BLUE_SIZE = "		<< pixelFmt.blueBits << TestLog::EndMessage;
    722 	log << TestLog::Message << "EGL_ALPHA_SIZE = "		<< pixelFmt.alphaBits << TestLog::EndMessage;
    723 	log << TestLog::Message << "EGL_DEPTH_SIZE = "		<< depthBits << TestLog::EndMessage;
    724 	log << TestLog::Message << "EGL_STENCIL_SIZE = "	<< stencilBits << TestLog::EndMessage;
    725 	log << TestLog::Message << "EGL_SAMPLES = "			<< numSamples << TestLog::EndMessage;
    726 
    727 	// Generate draw ops.
    728 	drawOps.resize(numContexts*drawsPerCtx*numIters);
    729 	for (vector<DrawPrimitiveOp>::iterator drawOp = drawOps.begin(); drawOp != drawOps.end(); ++drawOp)
    730 		randomizeDrawOp(rnd, *drawOp);
    731 
    732 	// Create and setup programs per context
    733 	for (int ctxNdx = 0; ctxNdx < numContexts; ctxNdx++)
    734 	{
    735 		EGLint		api			= contexts[ctxNdx].first;
    736 		EGLContext	context		= contexts[ctxNdx].second;
    737 
    738 		EGLU_CHECK_CALL(egl, makeCurrent(display, surface, surface, context));
    739 
    740 		programs[ctxNdx] = ProgramSp(createProgram(m_gl, api));
    741 		programs[ctxNdx]->setup();
    742 	}
    743 
    744 	// Clear to black using first context.
    745 	{
    746 		EGLint		api			= contexts[0].first;
    747 		EGLContext	context		= contexts[0].second;
    748 
    749 		EGLU_CHECK_CALL(egl, makeCurrent(display, surface, surface, context));
    750 
    751 		clear(m_gl, api, CLEAR_COLOR, CLEAR_DEPTH, CLEAR_STENCIL);
    752 		finish(m_gl, api);
    753 	}
    754 
    755 	// Render.
    756 	for (int iterNdx = 0; iterNdx < numIters; iterNdx++)
    757 	{
    758 		for (int ctxNdx = 0; ctxNdx < numContexts; ctxNdx++)
    759 		{
    760 			EGLint		api			= contexts[ctxNdx].first;
    761 			EGLContext	context		= contexts[ctxNdx].second;
    762 
    763 			EGLU_CHECK_CALL(egl, makeCurrent(display, surface, surface, context));
    764 
    765 			for (int drawNdx = 0; drawNdx < drawsPerCtx; drawNdx++)
    766 			{
    767 				const DrawPrimitiveOp& drawOp = drawOps[iterNdx*numContexts*drawsPerCtx + ctxNdx*drawsPerCtx + drawNdx];
    768 				draw(m_gl, api, *programs[ctxNdx], drawOp);
    769 			}
    770 
    771 			finish(m_gl, api);
    772 		}
    773 	}
    774 
    775 	// Read pixels using first context. \todo [pyry] Randomize?
    776 	{
    777 		EGLint		api		= contexts[0].first;
    778 		EGLContext	context	= contexts[0].second;
    779 
    780 		EGLU_CHECK_CALL(egl, makeCurrent(display, surface, surface, context));
    781 
    782 		readPixels(m_gl, api, frame);
    783 	}
    784 
    785 	EGLU_CHECK_CALL(egl, makeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
    786 
    787 	// Render reference.
    788 	// \note Reference image is always generated using single-sampling.
    789 	renderReference(refFrame.getAccess(), drawOps, pixelFmt, depthBits, stencilBits, 1);
    790 
    791 	// Compare images
    792 	{
    793 		bool imagesOk = tcu::fuzzyCompare(log, "ComparisonResult", "Image comparison result", refFrame, frame, threshold, tcu::COMPARE_LOG_RESULT);
    794 
    795 		if (!imagesOk)
    796 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
    797 	}
    798 }
    799 
    800 // MultiThreadRenderCase
    801 
    802 class MultiThreadRenderCase : public MultiContextRenderCase
    803 {
    804 public:
    805 						MultiThreadRenderCase		(EglTestContext& eglTestCtx, const char* name, const char* description, EGLint api, EGLint surfaceType, const eglu::FilterList& filters, int numContextsPerApi);
    806 
    807 	void				init						(void);
    808 
    809 private:
    810 	virtual void		executeForContexts			(EGLDisplay display, EGLSurface surface, const Config& config, const std::vector<std::pair<EGLint, EGLContext> >& contexts);
    811 
    812 	glw::Functions		m_gl;
    813 };
    814 
    815 class RenderTestThread;
    816 
    817 typedef de::SharedPtr<RenderTestThread>	RenderTestThreadSp;
    818 typedef de::SharedPtr<de::Semaphore>	SemaphoreSp;
    819 
    820 struct DrawOpPacket
    821 {
    822 	DrawOpPacket (void)
    823 		: drawOps	(DE_NULL)
    824 		, numOps	(0)
    825 	{
    826 	}
    827 
    828 	const DrawPrimitiveOp*	drawOps;
    829 	int						numOps;
    830 	SemaphoreSp				wait;
    831 	SemaphoreSp				signal;
    832 };
    833 
    834 class RenderTestThread : public de::Thread
    835 {
    836 public:
    837 	RenderTestThread (const Library& egl, EGLDisplay display, EGLSurface surface, EGLContext context, EGLint api, const glw::Functions& gl, const Program& program, const std::vector<DrawOpPacket>& packets)
    838 		: m_egl		(egl)
    839 		, m_display	(display)
    840 		, m_surface	(surface)
    841 		, m_context	(context)
    842 		, m_api		(api)
    843 		, m_gl		(gl)
    844 		, m_program	(program)
    845 		, m_packets	(packets)
    846 	{
    847 	}
    848 
    849 	void run (void)
    850 	{
    851 		for (std::vector<DrawOpPacket>::const_iterator packetIter = m_packets.begin(); packetIter != m_packets.end(); packetIter++)
    852 		{
    853 			// Wait until it is our turn.
    854 			packetIter->wait->decrement();
    855 
    856 			// Acquire context.
    857 			EGLU_CHECK_CALL(m_egl, makeCurrent(m_display, m_surface, m_surface, m_context));
    858 
    859 			// Execute rendering.
    860 			for (int ndx = 0; ndx < packetIter->numOps; ndx++)
    861 				draw(m_gl, m_api, m_program, packetIter->drawOps[ndx]);
    862 
    863 			finish(m_gl, m_api);
    864 
    865 			// Release context.
    866 			EGLU_CHECK_CALL(m_egl, makeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
    867 
    868 			// Signal completion.
    869 			packetIter->signal->increment();
    870 		}
    871 	}
    872 
    873 private:
    874 	const Library&						m_egl;
    875 	EGLDisplay							m_display;
    876 	EGLSurface							m_surface;
    877 	EGLContext							m_context;
    878 	EGLint								m_api;
    879 	const glw::Functions&				m_gl;
    880 	const Program&						m_program;
    881 	const std::vector<DrawOpPacket>&	m_packets;
    882 };
    883 
    884 MultiThreadRenderCase::MultiThreadRenderCase (EglTestContext& eglTestCtx, const char* name, const char* description, EGLint api, EGLint surfaceType, const eglu::FilterList& filters, int numContextsPerApi)
    885 	: MultiContextRenderCase(eglTestCtx, name, description, api, surfaceType, filters, numContextsPerApi)
    886 {
    887 }
    888 
    889 void MultiThreadRenderCase::init (void)
    890 {
    891 	MultiContextRenderCase::init();
    892 	m_eglTestCtx.initGLFunctions(&m_gl, glu::ApiType::es(2,0));
    893 }
    894 
    895 void MultiThreadRenderCase::executeForContexts (EGLDisplay display, EGLSurface surface, const Config& config, const std::vector<std::pair<EGLint, EGLContext> >& contexts)
    896 {
    897 	const Library&			egl					= m_eglTestCtx.getLibrary();
    898 	const int				width				= eglu::querySurfaceInt(egl, display, surface, EGL_WIDTH);
    899 	const int				height				= eglu::querySurfaceInt(egl, display, surface, EGL_HEIGHT);
    900 	const int				numContexts			= (int)contexts.size();
    901 	const int				opsPerPacket		= 2;
    902 	const int				packetsPerThread	= 2;
    903 	const int				numThreads			= numContexts;
    904 	const int				numPackets			= numThreads * packetsPerThread;
    905 	const float				threshold			= 0.02f;
    906 
    907 	const tcu::PixelFormat	pixelFmt			= getPixelFormat(egl, display, config.config);
    908 	const int				depthBits			= eglu::getConfigAttribInt(egl, display, config.config, EGL_DEPTH_SIZE);
    909 	const int				stencilBits			= eglu::getConfigAttribInt(egl, display, config.config, EGL_STENCIL_SIZE);
    910 	const int				numSamples			= eglu::getConfigAttribInt(egl, display, config.config, EGL_SAMPLES);
    911 
    912 	TestLog&				log					= m_testCtx.getLog();
    913 
    914 	tcu::Surface			refFrame			(width, height);
    915 	tcu::Surface			frame				(width, height);
    916 
    917 	de::Random				rnd					(deStringHash(getName()) ^ deInt32Hash(numContexts));
    918 
    919 	// Resources that need cleanup
    920 	vector<ProgramSp>				programs	(numContexts);
    921 	vector<SemaphoreSp>				semaphores	(numPackets+1);
    922 	vector<DrawPrimitiveOp>			drawOps		(numPackets*opsPerPacket);
    923 	vector<vector<DrawOpPacket> >	packets		(numThreads);
    924 	vector<RenderTestThreadSp>		threads		(numThreads);
    925 
    926 	// Log basic information about config.
    927 	log << TestLog::Message << "EGL_RED_SIZE = "		<< pixelFmt.redBits << TestLog::EndMessage;
    928 	log << TestLog::Message << "EGL_GREEN_SIZE = "		<< pixelFmt.greenBits << TestLog::EndMessage;
    929 	log << TestLog::Message << "EGL_BLUE_SIZE = "		<< pixelFmt.blueBits << TestLog::EndMessage;
    930 	log << TestLog::Message << "EGL_ALPHA_SIZE = "		<< pixelFmt.alphaBits << TestLog::EndMessage;
    931 	log << TestLog::Message << "EGL_DEPTH_SIZE = "		<< depthBits << TestLog::EndMessage;
    932 	log << TestLog::Message << "EGL_STENCIL_SIZE = "	<< stencilBits << TestLog::EndMessage;
    933 	log << TestLog::Message << "EGL_SAMPLES = "			<< numSamples << TestLog::EndMessage;
    934 
    935 	// Initialize semaphores.
    936 	for (vector<SemaphoreSp>::iterator sem = semaphores.begin(); sem != semaphores.end(); ++sem)
    937 		*sem = SemaphoreSp(new de::Semaphore(0));
    938 
    939 	// Create draw ops.
    940 	for (vector<DrawPrimitiveOp>::iterator drawOp = drawOps.begin(); drawOp != drawOps.end(); ++drawOp)
    941 		randomizeDrawOp(rnd, *drawOp);
    942 
    943 	// Create packets.
    944 	for (int threadNdx = 0; threadNdx < numThreads; threadNdx++)
    945 	{
    946 		packets[threadNdx].resize(packetsPerThread);
    947 
    948 		for (int packetNdx = 0; packetNdx < packetsPerThread; packetNdx++)
    949 		{
    950 			DrawOpPacket& packet = packets[threadNdx][packetNdx];
    951 
    952 			// Threads take turns with packets.
    953 			packet.wait		= semaphores[packetNdx*numThreads + threadNdx];
    954 			packet.signal	= semaphores[packetNdx*numThreads + threadNdx + 1];
    955 			packet.numOps	= opsPerPacket;
    956 			packet.drawOps	= &drawOps[(packetNdx*numThreads + threadNdx)*opsPerPacket];
    957 		}
    958 	}
    959 
    960 	// Create and setup programs per context
    961 	for (int ctxNdx = 0; ctxNdx < numContexts; ctxNdx++)
    962 	{
    963 		EGLint		api			= contexts[ctxNdx].first;
    964 		EGLContext	context		= contexts[ctxNdx].second;
    965 
    966 		EGLU_CHECK_CALL(egl, makeCurrent(display, surface, surface, context));
    967 
    968 		programs[ctxNdx] = ProgramSp(createProgram(m_gl, api));
    969 		programs[ctxNdx]->setup();
    970 
    971 		// Release context
    972 		EGLU_CHECK_CALL(egl, makeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
    973 	}
    974 
    975 	// Clear to black using first context.
    976 	{
    977 		EGLint		api			= contexts[0].first;
    978 		EGLContext	context		= contexts[0].second;
    979 
    980 		EGLU_CHECK_CALL(egl, makeCurrent(display, surface, surface, context));
    981 
    982 		clear(m_gl, api, CLEAR_COLOR, CLEAR_DEPTH, CLEAR_STENCIL);
    983 		finish(m_gl, api);
    984 
    985 		// Release context
    986 		EGLU_CHECK_CALL(egl, makeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
    987 	}
    988 
    989 	// Create and launch threads (actual rendering starts once first semaphore is signaled).
    990 	for (int threadNdx = 0; threadNdx < numThreads; threadNdx++)
    991 	{
    992 		threads[threadNdx] = RenderTestThreadSp(new RenderTestThread(egl, display, surface, contexts[threadNdx].second, contexts[threadNdx].first, m_gl, *programs[threadNdx], packets[threadNdx]));
    993 		threads[threadNdx]->start();
    994 	}
    995 
    996 	// Signal start and wait until complete.
    997 	semaphores.front()->increment();
    998 	semaphores.back()->decrement();
    999 
   1000 	// Read pixels using first context. \todo [pyry] Randomize?
   1001 	{
   1002 		EGLint		api		= contexts[0].first;
   1003 		EGLContext	context	= contexts[0].second;
   1004 
   1005 		EGLU_CHECK_CALL(egl, makeCurrent(display, surface, surface, context));
   1006 
   1007 		readPixels(m_gl, api, frame);
   1008 	}
   1009 
   1010 	EGLU_CHECK_CALL(egl, makeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
   1011 
   1012 	// Join threads.
   1013 	for (int threadNdx = 0; threadNdx < numThreads; threadNdx++)
   1014 		threads[threadNdx]->join();
   1015 
   1016 	// Render reference.
   1017 	renderReference(refFrame.getAccess(), drawOps, pixelFmt, depthBits, stencilBits, 1);
   1018 
   1019 	// Compare images
   1020 	{
   1021 		bool imagesOk = tcu::fuzzyCompare(log, "ComparisonResult", "Image comparison result", refFrame, frame, threshold, tcu::COMPARE_LOG_RESULT);
   1022 
   1023 		if (!imagesOk)
   1024 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed");
   1025 	}
   1026 }
   1027 
   1028 RenderTests::RenderTests (EglTestContext& eglTestCtx)
   1029 	: TestCaseGroup(eglTestCtx, "render", "Basic rendering with different client APIs")
   1030 {
   1031 }
   1032 
   1033 RenderTests::~RenderTests (void)
   1034 {
   1035 }
   1036 
   1037 struct RenderGroupSpec
   1038 {
   1039 	const char*			name;
   1040 	const char*			desc;
   1041 	EGLint				apiBits;
   1042 	eglu::ConfigFilter	baseFilter;
   1043 	int					numContextsPerApi;
   1044 };
   1045 
   1046 template <deUint32 Bits>
   1047 static bool renderable (const eglu::CandidateConfig& c)
   1048 {
   1049 	return (c.renderableType() & Bits) == Bits;
   1050 }
   1051 
   1052 template <class RenderClass>
   1053 static void createRenderGroups (EglTestContext& eglTestCtx, tcu::TestCaseGroup* group, const RenderGroupSpec* first, const RenderGroupSpec* last)
   1054 {
   1055 	for (const RenderGroupSpec* groupIter = first; groupIter != last; groupIter++)
   1056 	{
   1057 		tcu::TestCaseGroup* configGroup = new tcu::TestCaseGroup(eglTestCtx.getTestContext(), groupIter->name, groupIter->desc);
   1058 		group->addChild(configGroup);
   1059 
   1060 		vector<RenderFilterList>	filterLists;
   1061 		eglu::FilterList			baseFilters;
   1062 		baseFilters << groupIter->baseFilter;
   1063 		getDefaultRenderFilterLists(filterLists, baseFilters);
   1064 
   1065 		for (vector<RenderFilterList>::const_iterator listIter = filterLists.begin(); listIter != filterLists.end(); listIter++)
   1066 			configGroup->addChild(new RenderClass(eglTestCtx, listIter->getName(), "", groupIter->apiBits, listIter->getSurfaceTypeMask(), *listIter, groupIter->numContextsPerApi));
   1067 	}
   1068 }
   1069 
   1070 void RenderTests::init (void)
   1071 {
   1072 	static const RenderGroupSpec singleContextCases[] =
   1073 	{
   1074 		{
   1075 			"gles2",
   1076 			"Primitive rendering using GLES2",
   1077 			EGL_OPENGL_ES2_BIT,
   1078 			renderable<EGL_OPENGL_ES2_BIT>,
   1079 			1
   1080 		},
   1081 		{
   1082 			"gles3",
   1083 			"Primitive rendering using GLES3",
   1084 			EGL_OPENGL_ES3_BIT,
   1085 			renderable<EGL_OPENGL_ES3_BIT>,
   1086 			1
   1087 		},
   1088 	};
   1089 
   1090 	static const RenderGroupSpec multiContextCases[] =
   1091 	{
   1092 		{
   1093 			"gles2",
   1094 			"Primitive rendering using multiple GLES2 contexts to shared surface",
   1095 			EGL_OPENGL_ES2_BIT,
   1096 			renderable<EGL_OPENGL_ES2_BIT>,
   1097 			3
   1098 		},
   1099 		{
   1100 			"gles3",
   1101 			"Primitive rendering using multiple GLES3 contexts to shared surface",
   1102 			EGL_OPENGL_ES3_BIT,
   1103 			renderable<EGL_OPENGL_ES3_BIT>,
   1104 			3
   1105 		},
   1106 		{
   1107 			"gles2_gles3",
   1108 			"Primitive rendering using multiple APIs to shared surface",
   1109 			EGL_OPENGL_ES2_BIT|EGL_OPENGL_ES3_BIT,
   1110 			renderable<EGL_OPENGL_ES2_BIT|EGL_OPENGL_ES3_BIT>,
   1111 			1
   1112 		},
   1113 	};
   1114 
   1115 	tcu::TestCaseGroup* singleContextGroup = new tcu::TestCaseGroup(m_testCtx, "single_context", "Single-context rendering");
   1116 	addChild(singleContextGroup);
   1117 	createRenderGroups<SingleThreadRenderCase>(m_eglTestCtx, singleContextGroup, &singleContextCases[0], &singleContextCases[DE_LENGTH_OF_ARRAY(singleContextCases)]);
   1118 
   1119 	tcu::TestCaseGroup* multiContextGroup = new tcu::TestCaseGroup(m_testCtx, "multi_context", "Multi-context rendering with shared surface");
   1120 	addChild(multiContextGroup);
   1121 	createRenderGroups<SingleThreadRenderCase>(m_eglTestCtx, multiContextGroup, &multiContextCases[0], &multiContextCases[DE_LENGTH_OF_ARRAY(multiContextCases)]);
   1122 
   1123 	tcu::TestCaseGroup* multiThreadGroup = new tcu::TestCaseGroup(m_testCtx, "multi_thread", "Multi-thread rendering with shared surface");
   1124 	addChild(multiThreadGroup);
   1125 	createRenderGroups<MultiThreadRenderCase>(m_eglTestCtx, multiThreadGroup, &multiContextCases[0], &multiContextCases[DE_LENGTH_OF_ARRAY(multiContextCases)]);
   1126 }
   1127 
   1128 } // egl
   1129 } // deqp
   1130