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