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 Test EGL_SWAP_BEHAVIOR_PRESERVED_BIT.
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "teglPreservingSwapTests.hpp"
     25 
     26 #include "tcuImageCompare.hpp"
     27 #include "tcuTestLog.hpp"
     28 #include "tcuSurface.hpp"
     29 #include "tcuTextureUtil.hpp"
     30 
     31 #include "egluNativeWindow.hpp"
     32 #include "egluUtil.hpp"
     33 
     34 #include "eglwLibrary.hpp"
     35 #include "eglwEnums.hpp"
     36 
     37 #include "gluDefs.hpp"
     38 #include "gluRenderContext.hpp"
     39 #include "gluShaderProgram.hpp"
     40 
     41 #include "glwDefs.hpp"
     42 #include "glwEnums.hpp"
     43 #include "glwFunctions.hpp"
     44 
     45 #include "deRandom.hpp"
     46 
     47 #include "deString.h"
     48 
     49 #include <vector>
     50 #include <string>
     51 
     52 using std::vector;
     53 using std::string;
     54 
     55 using namespace eglw;
     56 
     57 namespace deqp
     58 {
     59 namespace egl
     60 {
     61 
     62 namespace
     63 {
     64 class GLES2Program;
     65 class ReferenceProgram;
     66 
     67 class PreservingSwapTest : public TestCase
     68 {
     69 public:
     70 	enum DrawType
     71 	{
     72 		DRAWTYPE_NONE = 0,
     73 		DRAWTYPE_GLES2_CLEAR,
     74 		DRAWTYPE_GLES2_RENDER
     75 	};
     76 
     77 					PreservingSwapTest	(EglTestContext& eglTestCtx, bool preserveColorbuffer, bool readPixelsBeforeSwap, DrawType preSwapDrawType, DrawType postSwapDrawType, const char* name, const char* description);
     78 					~PreservingSwapTest	(void);
     79 
     80 	void			init				(void);
     81 	void			deinit				(void);
     82 	IterateResult	iterate				(void);
     83 
     84 private:
     85 	const int					m_seed;
     86 	const bool					m_preserveColorbuffer;
     87 	const bool					m_readPixelsBeforeSwap;
     88 	const DrawType				m_preSwapDrawType;
     89 	const DrawType				m_postSwapDrawType;
     90 
     91 	EGLDisplay					m_eglDisplay;
     92 	eglu::NativeWindow*			m_window;
     93 	EGLSurface					m_eglSurface;
     94 	EGLConfig					m_eglConfig;
     95 	EGLContext					m_eglContext;
     96 	glw::Functions				m_gl;
     97 
     98 	GLES2Program*				m_gles2Program;
     99 	ReferenceProgram*			m_refProgram;
    100 
    101 	void initEGLSurface	(EGLConfig config);
    102 	void initEGLContext (EGLConfig config);
    103 };
    104 
    105 class GLES2Program
    106 {
    107 public:
    108 					GLES2Program	(const glw::Functions& gl);
    109 					~GLES2Program	(void);
    110 
    111 	void			render			(int width, int height, float x1, float y1, float x2, float y2, PreservingSwapTest::DrawType drawType);
    112 
    113 private:
    114 	const glw::Functions&	m_gl;
    115 	glu::ShaderProgram		m_glProgram;
    116 	glw::GLuint				m_coordLoc;
    117 	glw::GLuint				m_colorLoc;
    118 
    119 	GLES2Program&			operator=		(const GLES2Program&);
    120 							GLES2Program	(const GLES2Program&);
    121 };
    122 
    123 static glu::ProgramSources getSources (void)
    124 {
    125 	const char* const vertexShaderSource =
    126 		"attribute mediump vec4 a_pos;\n"
    127 		"attribute mediump vec4 a_color;\n"
    128 		"varying mediump vec4 v_color;\n"
    129 		"void main(void)\n"
    130 		"{\n"
    131 		"\tv_color = a_color;\n"
    132 		"\tgl_Position = a_pos;\n"
    133 		"}";
    134 
    135 	const char* const fragmentShaderSource =
    136 		"varying mediump vec4 v_color;\n"
    137 		"void main(void)\n"
    138 		"{\n"
    139 		"\tgl_FragColor = v_color;\n"
    140 		"}";
    141 
    142 	return glu::makeVtxFragSources(vertexShaderSource, fragmentShaderSource);
    143 }
    144 
    145 GLES2Program::GLES2Program (const glw::Functions& gl)
    146 	: m_gl			(gl)
    147 	, m_glProgram	(gl, getSources())
    148 	, m_coordLoc	((glw::GLuint)-1)
    149 	, m_colorLoc	((glw::GLuint)-1)
    150 {
    151 	m_colorLoc = m_gl.getAttribLocation(m_glProgram.getProgram(), "a_color");
    152 	m_coordLoc = m_gl.getAttribLocation(m_glProgram.getProgram(), "a_pos");
    153 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "Failed to get attribute locations");
    154 }
    155 
    156 GLES2Program::~GLES2Program (void)
    157 {
    158 }
    159 
    160 void GLES2Program::render (int width, int height, float x1, float y1, float x2, float y2, PreservingSwapTest::DrawType drawType)
    161 {
    162 	if (drawType == PreservingSwapTest::DRAWTYPE_GLES2_RENDER)
    163 	{
    164 		const glw::GLfloat coords[] =
    165 		{
    166 			x1, y1, 0.0f, 1.0f,
    167 			x1, y2, 0.0f, 1.0f,
    168 			x2, y2, 0.0f, 1.0f,
    169 
    170 			x2, y2, 0.0f, 1.0f,
    171 			x2, y1, 0.0f, 1.0f,
    172 			x1, y1, 0.0f, 1.0f
    173 		};
    174 
    175 		const glw::GLubyte colors[] =
    176 		{
    177 			127,	127,	127,	255,
    178 			127,	127,	127,	255,
    179 			127,	127,	127,	255,
    180 
    181 			127,	127,	127,	255,
    182 			127,	127,	127,	255,
    183 			127,	127,	127,	255
    184 		};
    185 
    186 		m_gl.useProgram(m_glProgram.getProgram());
    187 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() failed");
    188 
    189 		m_gl.enableVertexAttribArray(m_coordLoc);
    190 		m_gl.enableVertexAttribArray(m_colorLoc);
    191 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "Failed to enable attributes");
    192 
    193 		m_gl.vertexAttribPointer(m_coordLoc, 4, GL_FLOAT, GL_FALSE, 0, coords);
    194 		m_gl.vertexAttribPointer(m_colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, colors);
    195 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "Failed to set attribute pointers");
    196 
    197 		m_gl.drawArrays(GL_TRIANGLES, 0, 6);
    198 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArrays() failed");
    199 
    200 		m_gl.disableVertexAttribArray(m_coordLoc);
    201 		m_gl.disableVertexAttribArray(m_colorLoc);
    202 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "Failed to disable attributes");
    203 
    204 		m_gl.useProgram(0);
    205 		GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() failed");
    206 	}
    207 	else if (drawType == PreservingSwapTest::DRAWTYPE_GLES2_CLEAR)
    208 	{
    209 		const int ox	= width/2;
    210 		const int oy	= height/2;
    211 
    212 		const int px	= width;
    213 		const int py	= height;
    214 
    215 		const int x1i	= (int)(((float)px/2.0f) * x1 + (float)ox);
    216 		const int y1i	= (int)(((float)py/2.0f) * y1 + (float)oy);
    217 
    218 		const int x2i	= (int)(((float)px/2.0f) * x2 + (float)ox);
    219 		const int y2i	= (int)(((float)py/2.0f) * y2 + (float)oy);
    220 
    221 		m_gl.enable(GL_SCISSOR_TEST);
    222 		m_gl.scissor(x1i, y1i, x2i-x1i, y2i-y1i);
    223 		m_gl.clearColor(0.5f, 0.5f, 0.5f, 1.0f);
    224 		m_gl.clear(GL_COLOR_BUFFER_BIT);
    225 		m_gl.disable(GL_SCISSOR_TEST);
    226 	}
    227 	else
    228 		DE_ASSERT(false);
    229 }
    230 
    231 class ReferenceProgram
    232 {
    233 public:
    234 			ReferenceProgram	(void);
    235 			~ReferenceProgram	(void);
    236 
    237 	void	render				(tcu::Surface* target, float x1, float y1, float x2, float y2, PreservingSwapTest::DrawType drawType);
    238 
    239 private:
    240 						ReferenceProgram	(const ReferenceProgram&);
    241 	ReferenceProgram&	operator=			(const ReferenceProgram&);
    242 };
    243 
    244 ReferenceProgram::ReferenceProgram (void)
    245 {
    246 }
    247 
    248 ReferenceProgram::~ReferenceProgram (void)
    249 {
    250 }
    251 
    252 void ReferenceProgram::render (tcu::Surface* target, float x1, float y1, float x2, float y2, PreservingSwapTest::DrawType drawType)
    253 {
    254 	if (drawType == PreservingSwapTest::DRAWTYPE_GLES2_RENDER || drawType == PreservingSwapTest::DRAWTYPE_GLES2_CLEAR)
    255 	{
    256 		const int ox	= target->getWidth()/2;
    257 		const int oy	= target->getHeight()/2;
    258 
    259 		const int px	= target->getWidth();
    260 		const int py	= target->getHeight();
    261 
    262 		const int x1i	= (int)((px/2.0) * x1 + ox);
    263 		const int y1i	= (int)((py/2.0) * y1 + oy);
    264 
    265 		const int x2i	= (int)((px/2.0) * x2 + ox);
    266 		const int y2i	= (int)((py/2.0) * y2 + oy);
    267 
    268 		const tcu::RGBA	color(127, 127, 127, 255);
    269 
    270 		for (int y = y1i; y <= y2i; y++)
    271 		{
    272 			for (int x = x1i; x <= x2i; x++)
    273 				target->setPixel(x, y, color);
    274 		}
    275 	}
    276 	else
    277 		DE_ASSERT(false);
    278 }
    279 
    280 PreservingSwapTest::PreservingSwapTest (EglTestContext& eglTestCtx, bool preserveColorbuffer, bool readPixelsBeforeSwap, DrawType preSwapDrawType, DrawType postSwapDrawType, const char* name, const char* description)
    281 	: TestCase					(eglTestCtx, name, description)
    282 	, m_seed					(deStringHash(name))
    283 	, m_preserveColorbuffer		(preserveColorbuffer)
    284 	, m_readPixelsBeforeSwap	(readPixelsBeforeSwap)
    285 	, m_preSwapDrawType			(preSwapDrawType)
    286 	, m_postSwapDrawType		(postSwapDrawType)
    287 	, m_eglDisplay				(EGL_NO_DISPLAY)
    288 	, m_window					(DE_NULL)
    289 	, m_eglSurface				(EGL_NO_SURFACE)
    290 	, m_eglContext				(EGL_NO_CONTEXT)
    291 	, m_gles2Program			(DE_NULL)
    292 	, m_refProgram				(DE_NULL)
    293 {
    294 }
    295 
    296 PreservingSwapTest::~PreservingSwapTest (void)
    297 {
    298 	deinit();
    299 }
    300 
    301 EGLConfig getEGLConfig (const Library& egl, EGLDisplay eglDisplay, bool preserveColorbuffer)
    302 {
    303 	const EGLint attribList[] =
    304 	{
    305 		EGL_SURFACE_TYPE,		EGL_WINDOW_BIT | (preserveColorbuffer ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0),
    306 		EGL_RENDERABLE_TYPE,	EGL_OPENGL_ES2_BIT,
    307 		EGL_NONE
    308 	};
    309 
    310 	return eglu::chooseSingleConfig(egl, eglDisplay, &attribList[0]);
    311 }
    312 
    313 void clearColorScreen (const glw::Functions& gl, float red, float green, float blue, float alpha)
    314 {
    315 	gl.clearColor(red, green, blue, alpha);
    316 	gl.clear(GL_COLOR_BUFFER_BIT);
    317 }
    318 
    319 void clearColorReference (tcu::Surface* ref, float red, float green, float blue, float alpha)
    320 {
    321 	tcu::clear(ref->getAccess(), tcu::Vec4(red, green, blue, alpha));
    322 }
    323 
    324 void readPixels (const glw::Functions& gl, tcu::Surface* screen)
    325 {
    326 	gl.readPixels(0, 0, screen->getWidth(), screen->getHeight(),  GL_RGBA, GL_UNSIGNED_BYTE, screen->getAccess().getDataPtr());
    327 }
    328 
    329 void PreservingSwapTest::initEGLSurface (EGLConfig config)
    330 {
    331 	const eglu::NativeWindowFactory&	factory	= eglu::selectNativeWindowFactory(m_eglTestCtx.getNativeDisplayFactory(), m_testCtx.getCommandLine());
    332 
    333 	m_window		= factory.createWindow(&m_eglTestCtx.getNativeDisplay(), m_eglDisplay, config, DE_NULL, eglu::WindowParams(480, 480, eglu::parseWindowVisibility(m_testCtx.getCommandLine())));
    334 	m_eglSurface	= eglu::createWindowSurface(m_eglTestCtx.getNativeDisplay(), *m_window, m_eglDisplay, config, DE_NULL);
    335 }
    336 
    337 void PreservingSwapTest::initEGLContext (EGLConfig config)
    338 {
    339 	const Library&	egl				= m_eglTestCtx.getLibrary();
    340 	const EGLint	attribList[]	=
    341 	{
    342 		EGL_CONTEXT_CLIENT_VERSION, 2,
    343 		EGL_NONE
    344 	};
    345 
    346 	egl.bindAPI(EGL_OPENGL_ES_API);
    347 	m_eglContext = egl.createContext(m_eglDisplay, config, EGL_NO_CONTEXT, attribList);
    348 	EGLU_CHECK_MSG(egl, "eglCreateContext");
    349 
    350 	DE_ASSERT(m_eglSurface != EGL_NO_SURFACE);
    351 	egl.makeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext);
    352 	EGLU_CHECK_MSG(egl, "eglMakeCurrent");
    353 }
    354 
    355 void PreservingSwapTest::init (void)
    356 {
    357 	m_eglDisplay	= eglu::getAndInitDisplay(m_eglTestCtx.getNativeDisplay());
    358 	m_eglConfig		= getEGLConfig(m_eglTestCtx.getLibrary(), m_eglDisplay, m_preserveColorbuffer);
    359 
    360 	if (m_eglConfig == DE_NULL)
    361 		TCU_THROW(NotSupportedError, "No supported config found");
    362 
    363 	initEGLSurface(m_eglConfig);
    364 	initEGLContext(m_eglConfig);
    365 
    366 	m_eglTestCtx.initGLFunctions(&m_gl, glu::ApiType::es(2,0));
    367 
    368 	m_gles2Program	= new GLES2Program(m_gl);
    369 	m_refProgram	= new ReferenceProgram();
    370 }
    371 
    372 void PreservingSwapTest::deinit (void)
    373 {
    374 	const Library& egl = m_eglTestCtx.getLibrary();
    375 
    376 	delete m_refProgram;
    377 	m_refProgram = DE_NULL;
    378 
    379 	delete m_gles2Program;
    380 	m_gles2Program = DE_NULL;
    381 
    382 	if (m_eglContext != EGL_NO_CONTEXT)
    383 	{
    384 		egl.makeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    385 		egl.destroyContext(m_eglDisplay, m_eglContext);
    386 		m_eglContext = EGL_NO_CONTEXT;
    387 	}
    388 
    389 	if (m_eglSurface != EGL_NO_SURFACE)
    390 	{
    391 		egl.destroySurface(m_eglDisplay, m_eglSurface);
    392 		m_eglSurface = EGL_NO_SURFACE;
    393 	}
    394 
    395 	if (m_eglDisplay != EGL_NO_DISPLAY)
    396 	{
    397 		egl.terminate(m_eglDisplay);
    398 		m_eglDisplay = EGL_NO_DISPLAY;
    399 	}
    400 
    401 	delete m_window;
    402 	m_window = DE_NULL;
    403 }
    404 
    405 bool compareToReference (tcu::TestLog& log, const char* name, const char* description, const tcu::Surface& reference, const tcu::Surface& screen, int x, int y, int width, int height)
    406 {
    407 	return tcu::fuzzyCompare(log, name, description,
    408 							 getSubregion(reference.getAccess(), x, y, width, height),
    409 							 getSubregion(screen.getAccess(), x, y, width, height),
    410 							 0.05f, tcu::COMPARE_LOG_RESULT);
    411 }
    412 
    413 bool comparePreAndPostSwapFramebuffers (tcu::TestLog& log, const tcu::Surface& preSwap, const tcu::Surface& postSwap)
    414 {
    415 	return tcu::pixelThresholdCompare(log, "Pre- / Post framebuffer compare", "Compare pre- and post-swap framebuffers", preSwap, postSwap, tcu::RGBA(0, 0, 0, 0), tcu::COMPARE_LOG_RESULT);
    416 }
    417 
    418 TestCase::IterateResult PreservingSwapTest::iterate (void)
    419 {
    420 	const Library&	egl				= m_eglTestCtx.getLibrary();
    421 	tcu::TestLog&	log				= m_testCtx.getLog();
    422 	de::Random		rnd(m_seed);
    423 
    424 	const int		width			= eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_WIDTH);
    425 	const int		height			= eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_HEIGHT);
    426 
    427 	const float		clearRed		= rnd.getFloat();
    428 	const float		clearGreen		= rnd.getFloat();
    429 	const float		clearBlue		= rnd.getFloat();
    430 	const float		clearAlpha		= 1.0f;
    431 
    432 	const float		preSwapX1		= -0.9f * rnd.getFloat();
    433 	const float		preSwapY1		= -0.9f * rnd.getFloat();
    434 	const float		preSwapX2		= 0.9f * rnd.getFloat();
    435 	const float		preSwapY2		= 0.9f * rnd.getFloat();
    436 
    437 	const float		postSwapX1		= -0.9f * rnd.getFloat();
    438 	const float		postSwapY1		= -0.9f * rnd.getFloat();
    439 	const float		postSwapX2		= 0.9f * rnd.getFloat();
    440 	const float		postSwapY2		= 0.9f * rnd.getFloat();
    441 
    442 	tcu::Surface	postSwapFramebufferReference(width, height);
    443 	tcu::Surface	preSwapFramebufferReference(width, height);
    444 
    445 	tcu::Surface	postSwapFramebuffer(width, height);
    446 	tcu::Surface	preSwapFramebuffer(width, height);
    447 
    448 	if (m_preserveColorbuffer)
    449 		EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED));
    450 
    451 	EGLU_CHECK_CALL(egl, makeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext));
    452 
    453 	clearColorScreen(m_gl, clearRed, clearGreen, clearBlue, clearAlpha);
    454 
    455 	if (m_readPixelsBeforeSwap)
    456 		clearColorReference(&preSwapFramebufferReference, clearRed, clearGreen, clearBlue, clearAlpha);
    457 
    458 	clearColorReference(&postSwapFramebufferReference, clearRed, clearGreen, clearBlue, clearAlpha);
    459 
    460 	if (m_preSwapDrawType != DRAWTYPE_NONE)
    461 	{
    462 		m_gles2Program->render(width, height, preSwapX1, preSwapY1, preSwapX2, preSwapY2, m_preSwapDrawType);
    463 		m_refProgram->render(&postSwapFramebufferReference, preSwapX1, preSwapY1, preSwapX2, preSwapY2, m_preSwapDrawType);
    464 	}
    465 
    466 	if (m_readPixelsBeforeSwap)
    467 	{
    468 		if (m_preSwapDrawType != DRAWTYPE_NONE)
    469 			m_refProgram->render(&preSwapFramebufferReference, preSwapX1, preSwapY1, preSwapX2, preSwapY2, m_preSwapDrawType);
    470 
    471 		readPixels(m_gl, &preSwapFramebuffer);
    472 	}
    473 
    474 	EGLU_CHECK_CALL(egl, swapBuffers(m_eglDisplay, m_eglSurface));
    475 
    476 	if (m_postSwapDrawType != DRAWTYPE_NONE)
    477 	{
    478 		m_refProgram->render(&postSwapFramebufferReference, postSwapX1, postSwapY1, postSwapX2, postSwapY2, m_postSwapDrawType);
    479 		m_gles2Program->render(width, height, postSwapX1, postSwapY1, postSwapX2, postSwapY2, m_postSwapDrawType);
    480 	}
    481 
    482 	readPixels(m_gl, &postSwapFramebuffer);
    483 
    484 	bool isOk = true;
    485 
    486 	if (m_preserveColorbuffer)
    487 	{
    488 		if (m_readPixelsBeforeSwap)
    489 			isOk = isOk && compareToReference(log, "Compare pre-swap framebuffer to reference", "Compare pre-swap framebuffer to reference", preSwapFramebufferReference, preSwapFramebuffer, 0, 0, width, height);
    490 
    491 		isOk = isOk && compareToReference(log, "Compare post-swap framebuffer to reference", "Compare post-swap framebuffer to reference", postSwapFramebufferReference, postSwapFramebuffer, 0, 0, width, height);
    492 
    493 		if (m_readPixelsBeforeSwap && m_postSwapDrawType == PreservingSwapTest::DRAWTYPE_NONE)
    494 			isOk = isOk && comparePreAndPostSwapFramebuffers(log, preSwapFramebuffer, postSwapFramebuffer);
    495 	}
    496 	else
    497 	{
    498 		const int ox	= width/2;
    499 		const int oy	= height/2;
    500 
    501 		const int px	= width;
    502 		const int py	= height;
    503 
    504 		const int x1i	= (int)(((float)px/2.0f) * postSwapX1 + (float)ox);
    505 		const int y1i	= (int)(((float)py/2.0f) * postSwapY1 + (float)oy);
    506 
    507 		const int x2i	= (int)(((float)px/2.0f) * postSwapX2 + (float)ox);
    508 		const int y2i	= (int)(((float)py/2.0f) * postSwapY2 + (float)oy);
    509 
    510 		if (m_readPixelsBeforeSwap)
    511 			isOk = isOk && compareToReference(log, "Compare pre-swap framebuffer to reference", "Compare pre-swap framebuffer to reference", preSwapFramebufferReference, preSwapFramebuffer, 0, 0, width, height);
    512 
    513 		DE_ASSERT(m_postSwapDrawType != DRAWTYPE_NONE);
    514 		isOk = isOk && compareToReference(log, "Compare valid are of post-swap framebuffer to reference", "Compare valid area of post-swap framebuffer to reference", postSwapFramebufferReference, postSwapFramebuffer, x1i, y1i, x2i - x1i, y2i - y1i);
    515 	}
    516 
    517 	if (isOk)
    518 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    519 	else
    520 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
    521 
    522 	return STOP;
    523 }
    524 
    525 string generateTestName (PreservingSwapTest::DrawType preSwapDrawType, PreservingSwapTest::DrawType postSwapDrawType)
    526 {
    527 	std::ostringstream stream;
    528 
    529 	if (preSwapDrawType == PreservingSwapTest::DRAWTYPE_NONE && postSwapDrawType == PreservingSwapTest::DRAWTYPE_NONE)
    530 		stream << "no_draw";
    531 	else
    532 	{
    533 		switch (preSwapDrawType)
    534 		{
    535 			case PreservingSwapTest::DRAWTYPE_NONE:
    536 				// Do nothing
    537 				break;
    538 
    539 			case PreservingSwapTest::DRAWTYPE_GLES2_RENDER:
    540 				stream << "pre_render";
    541 				break;
    542 
    543 			case PreservingSwapTest::DRAWTYPE_GLES2_CLEAR:
    544 				stream << "pre_clear";
    545 				break;
    546 
    547 			default:
    548 				DE_ASSERT(false);
    549 		}
    550 
    551 		if (preSwapDrawType != PreservingSwapTest::DRAWTYPE_NONE && postSwapDrawType != PreservingSwapTest::DRAWTYPE_NONE)
    552 			stream << "_";
    553 
    554 		switch (postSwapDrawType)
    555 		{
    556 			case PreservingSwapTest::DRAWTYPE_NONE:
    557 				// Do nothing
    558 				break;
    559 
    560 			case PreservingSwapTest::DRAWTYPE_GLES2_RENDER:
    561 				stream << "post_render";
    562 				break;
    563 
    564 			case PreservingSwapTest::DRAWTYPE_GLES2_CLEAR:
    565 				stream << "post_clear";
    566 				break;
    567 
    568 			default:
    569 				DE_ASSERT(false);
    570 		}
    571 	}
    572 
    573 	return stream.str();
    574 }
    575 
    576 } // anonymous
    577 
    578 PreservingSwapTests::PreservingSwapTests (EglTestContext& eglTestCtx)
    579 	: TestCaseGroup(eglTestCtx, "preserve_swap", "Color buffer preserving swap tests")
    580 {
    581 }
    582 
    583 void PreservingSwapTests::init (void)
    584 {
    585 	const PreservingSwapTest::DrawType preSwapDrawTypes[] =
    586 	{
    587 		PreservingSwapTest::DRAWTYPE_NONE,
    588 		PreservingSwapTest::DRAWTYPE_GLES2_CLEAR,
    589 		PreservingSwapTest::DRAWTYPE_GLES2_RENDER
    590 	};
    591 
    592 	const PreservingSwapTest::DrawType postSwapDrawTypes[] =
    593 	{
    594 		PreservingSwapTest::DRAWTYPE_NONE,
    595 		PreservingSwapTest::DRAWTYPE_GLES2_CLEAR,
    596 		PreservingSwapTest::DRAWTYPE_GLES2_RENDER
    597 	};
    598 
    599 	for (int preserveNdx = 0; preserveNdx < 2; preserveNdx++)
    600 	{
    601 		const bool				preserve		= (preserveNdx == 0);
    602 		TestCaseGroup* const	preserveGroup	= new TestCaseGroup(m_eglTestCtx, (preserve ? "preserve" : "no_preserve"), "");
    603 
    604 		for (int readPixelsNdx = 0; readPixelsNdx < 2; readPixelsNdx++)
    605 		{
    606 			const bool				readPixelsBeforeSwap		= (readPixelsNdx == 1);
    607 			TestCaseGroup* const	readPixelsBeforeSwapGroup	= new TestCaseGroup(m_eglTestCtx, (readPixelsBeforeSwap ? "read_before_swap" : "no_read_before_swap"), "");
    608 
    609 			for (int preSwapDrawTypeNdx = 0; preSwapDrawTypeNdx < DE_LENGTH_OF_ARRAY(preSwapDrawTypes); preSwapDrawTypeNdx++)
    610 			{
    611 				const PreservingSwapTest::DrawType preSwapDrawType = preSwapDrawTypes[preSwapDrawTypeNdx];
    612 
    613 				for (int postSwapDrawTypeNdx = 0; postSwapDrawTypeNdx < DE_LENGTH_OF_ARRAY(postSwapDrawTypes); postSwapDrawTypeNdx++)
    614 				{
    615 					const PreservingSwapTest::DrawType postSwapDrawType = postSwapDrawTypes[postSwapDrawTypeNdx];
    616 
    617 					// If not preserving and rendering after swap, then there is nothing to verify
    618 					if (!preserve && postSwapDrawType == PreservingSwapTest::DRAWTYPE_NONE)
    619 						continue;
    620 
    621 					const std::string name = generateTestName(preSwapDrawType, postSwapDrawType);
    622 
    623 					readPixelsBeforeSwapGroup->addChild(new PreservingSwapTest(m_eglTestCtx, preserve, readPixelsBeforeSwap, preSwapDrawType, postSwapDrawType, name.c_str(), ""));
    624 				}
    625 			}
    626 
    627 			preserveGroup->addChild(readPixelsBeforeSwapGroup);
    628 		}
    629 
    630 		addChild(preserveGroup);
    631 	}
    632 }
    633 
    634 } // egl
    635 } // deqp
    636