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 
isANarrowScreenSpaceTriangle(const tcu::Vec4 & p0,const tcu::Vec4 & p1,const tcu::Vec4 & p2)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 
randomizeDrawOp(de::Random & rnd,DrawPrimitiveOp & drawOp)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 
ReferenceShader()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 
shadeVertices(const rr::VertexAttrib * inputs,rr::VertexPacket * const * packets,const int numPackets) const252 	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 
shadeFragments(rr::FragmentPacket * packets,const int numPackets,const rr::FragmentShadingContext & context) const269 	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 
toReferenceRenderState(rr::RenderState & state,const DrawPrimitiveOp & drawOp)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 
getColorFormat(const tcu::PixelFormat & colorBits)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 
getDepthFormat(const int depthBits)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 
getStencilFormat(int stencilBits)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 
renderReference(const tcu::PixelBufferAccess & dst,const vector<DrawPrimitiveOp> & drawOps,const tcu::PixelFormat & colorBits,const int depthBits,const int stencilBits,const int numSamples)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:
Program(void)454 					Program				(void) {}
~Program(void)455 	virtual			~Program			(void) {}
456 
457 	virtual void	setup				(void) const = DE_NULL;
458 };
459 
460 typedef de::SharedPtr<Program> ProgramSp;
461 
getProgramSourcesES2(void)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:
GLES2Program(const glw::Functions & gl)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 
~GLES2Program(void)498 	~GLES2Program (void)
499 	{
500 	}
501 
setup(void) const502 	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 
getPositionLoc(void) const510 	int						getPositionLoc		(void) const { return m_positionLoc;	}
getColorLoc(void) const511 	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 
clearGLES2(const glw::Functions & gl,const tcu::Vec4 & color,const float depth,const int stencil)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 
drawGLES2(const glw::Functions & gl,const Program & program,const DrawPrimitiveOp & drawOp)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 
readPixelsGLES2(const glw::Functions & gl,tcu::Surface & dst)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 
createProgram(const glw::Functions & gl,EGLint api)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 
draw(const glw::Functions & gl,EGLint api,const Program & program,const DrawPrimitiveOp & drawOp)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 
clear(const glw::Functions & gl,EGLint api,const tcu::Vec4 & color,const float depth,const int stencil)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 
readPixels(const glw::Functions & gl,EGLint api,tcu::Surface & dst)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 
finish(const glw::Functions & gl,EGLint api)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 
getPixelFormat(const Library & egl,EGLDisplay display,EGLConfig config)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 
SingleThreadRenderCase(EglTestContext & eglTestCtx,const char * name,const char * description,EGLint api,EGLint surfaceType,const eglu::FilterList & filters,int numContextsPerApi)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 
init(void)688 void SingleThreadRenderCase::init (void)
689 {
690 	MultiContextRenderCase::init();
691 	m_eglTestCtx.initGLFunctions(&m_gl, glu::ApiType::es(2,0));
692 }
693 
executeForContexts(EGLDisplay display,EGLSurface surface,const Config & config,const std::vector<std::pair<EGLint,EGLContext>> & contexts)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 {
DrawOpPacketdeqp::egl::DrawOpPacket822 	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:
RenderTestThread(const Library & egl,EGLDisplay display,EGLSurface surface,EGLContext context,EGLint api,const glw::Functions & gl,const Program & program,const std::vector<DrawOpPacket> & packets)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 
run(void)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 
MultiThreadRenderCase(EglTestContext & eglTestCtx,const char * name,const char * description,EGLint api,EGLint surfaceType,const eglu::FilterList & filters,int numContextsPerApi)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 
init(void)889 void MultiThreadRenderCase::init (void)
890 {
891 	MultiContextRenderCase::init();
892 	m_eglTestCtx.initGLFunctions(&m_gl, glu::ApiType::es(2,0));
893 }
894 
executeForContexts(EGLDisplay display,EGLSurface surface,const Config & config,const std::vector<std::pair<EGLint,EGLContext>> & contexts)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 
RenderTests(EglTestContext & eglTestCtx)1028 RenderTests::RenderTests (EglTestContext& eglTestCtx)
1029 	: TestCaseGroup(eglTestCtx, "render", "Basic rendering with different client APIs")
1030 {
1031 }
1032 
~RenderTests(void)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>
renderable(const eglu::CandidateConfig & c)1047 static bool renderable (const eglu::CandidateConfig& c)
1048 {
1049 	return (c.renderableType() & Bits) == Bits;
1050 }
1051 
1052 template <class RenderClass>
createRenderGroups(EglTestContext & eglTestCtx,tcu::TestCaseGroup * group,const RenderGroupSpec * first,const RenderGroupSpec * last)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 
init(void)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