Home | History | Annotate | Download | only in egl
      1 /*-------------------------------------------------------------------------
      2  * drawElements Quality Program EGL Module
      3  * ---------------------------------------
      4  *
      5  * Copyright 2015 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 EXT_buffer_age
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "teglBufferAgeTests.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 #include "egluConfigFilter.hpp"
     34 
     35 #include "eglwLibrary.hpp"
     36 #include "eglwEnums.hpp"
     37 
     38 #include "gluDefs.hpp"
     39 #include "gluRenderContext.hpp"
     40 #include "gluShaderProgram.hpp"
     41 
     42 #include "glwDefs.hpp"
     43 #include "glwEnums.hpp"
     44 #include "glwFunctions.hpp"
     45 
     46 #include "deRandom.hpp"
     47 #include "deString.h"
     48 
     49 #include <string>
     50 #include <vector>
     51 #include <sstream>
     52 
     53 using std::string;
     54 using std::vector;
     55 using glw::GLubyte;
     56 using tcu::IVec2;
     57 
     58 using namespace eglw;
     59 
     60 namespace deqp
     61 {
     62 namespace egl
     63 {
     64 namespace
     65 {
     66 
     67 typedef	tcu::Vector<GLubyte, 3> Color;
     68 
     69 class GLES2Renderer;
     70 
     71 class ReferenceRenderer;
     72 
     73 class BufferAgeTest : public TestCase
     74 {
     75 public:
     76 	enum DrawType
     77 	{
     78 		DRAWTYPE_GLES2_CLEAR,
     79 		DRAWTYPE_GLES2_RENDER
     80 	};
     81 
     82 	enum ResizeType
     83 	{
     84 		RESIZETYPE_NONE = 0,
     85 		RESIZETYPE_BEFORE_SWAP,
     86 		RESIZETYPE_AFTER_SWAP,
     87 
     88 		RESIZETYPE_LAST
     89 	};
     90 
     91 								BufferAgeTest	(EglTestContext&			eglTestCtx,
     92 												 bool						preserveColorBuffer,
     93 												 const vector<DrawType>&	oddFrameDrawType,
     94 												 const vector<DrawType>&	evenFrameDrawType,
     95 												 ResizeType					resizeType,
     96 												 const char*				name,
     97 												 const char*				description);
     98 
     99 								~BufferAgeTest	(void);
    100 
    101 	void						init			(void);
    102 	void						deinit			(void);
    103 	IterateResult				iterate			(void);
    104 
    105 private:
    106 	void						initEGLSurface (EGLConfig config);
    107 	void						initEGLContext (EGLConfig config);
    108 
    109 	const int					m_seed;
    110 	const bool					m_preserveColorBuffer;
    111 	const vector<DrawType>		m_oddFrameDrawType;
    112 	const vector<DrawType>		m_evenFrameDrawType;
    113 	const ResizeType			m_resizeType;
    114 
    115 	EGLDisplay					m_eglDisplay;
    116 	eglu::NativeWindow*			m_window;
    117 	EGLSurface					m_eglSurface;
    118 	EGLConfig					m_eglConfig;
    119 	EGLContext					m_eglContext;
    120 	glw::Functions				m_gl;
    121 
    122 	GLES2Renderer*				m_gles2Renderer;
    123 	ReferenceRenderer*			m_refRenderer;
    124 
    125 };
    126 
    127 struct ColoredRect
    128 {
    129 public:
    130 							ColoredRect (const IVec2& bottomLeft_, const IVec2& topRight_, const Color& color_);
    131 	IVec2					bottomLeft;
    132 	IVec2					topRight;
    133 	Color					color;
    134 };
    135 
    136 ColoredRect::ColoredRect (const IVec2& bottomLeft_, const IVec2& topRight_, const Color& color_)
    137 	: bottomLeft(bottomLeft_)
    138 	, topRight	(topRight_)
    139 	, color		(color_)
    140 {
    141 }
    142 
    143 struct DrawCommand
    144 {
    145 							DrawCommand (const BufferAgeTest::DrawType drawType_, const ColoredRect& rect_);
    146 	BufferAgeTest::DrawType drawType;
    147 	ColoredRect				rect;
    148 };
    149 
    150 DrawCommand::DrawCommand (const BufferAgeTest::DrawType drawType_, const ColoredRect& rect_)
    151 	: drawType(drawType_)
    152 	, rect    (rect_)
    153 {
    154 }
    155 
    156 struct Frame
    157 {
    158 						Frame (int width_, int height_);
    159 	int					width;
    160 	int					height;
    161 	vector<DrawCommand> draws;
    162 };
    163 
    164 Frame::Frame (int width_, int height_)
    165 	: width(width_)
    166 	, height(height_)
    167 {
    168 }
    169 
    170 
    171 // (x1,y1) lie in the lower-left quadrant while (x2,y2) lie in the upper-right.
    172 // the coords are multiplied by 4 to amplify the minimial difference between coords to 4 (if not zero)
    173 // to avoid the situation where two edges are too close to each other which makes the rounding error
    174 // intoleratable by compareToReference()
    175 void generateRandomFrame (Frame* dst, const vector<BufferAgeTest::DrawType>& drawTypes, de::Random& rnd)
    176 {
    177 	for (size_t ndx = 0; ndx < drawTypes.size(); ndx++)
    178 	{
    179 		const int			x1			= rnd.getInt(0, (dst->width-1)/8) * 4;
    180 		const int			y1			= rnd.getInt(0, (dst->height-1)/8) * 4;
    181 		const int			x2			= rnd.getInt((dst->width-1)/8, (dst->width-1)/4) * 4;
    182 		const int			y2			= rnd.getInt((dst->height-1)/8, (dst->height-1)/4) * 4;
    183 		const GLubyte		r			= rnd.getUint8();
    184 		const GLubyte		g			= rnd.getUint8();
    185 		const GLubyte		b			= rnd.getUint8();
    186 		const ColoredRect	coloredRect	(IVec2(x1, y1), IVec2(x2, y2), Color(r, g, b));
    187 		const DrawCommand	drawCommand (drawTypes[ndx], coloredRect);
    188 		(*dst).draws.push_back(drawCommand);
    189 	}
    190 }
    191 
    192 typedef vector<Frame> FrameSequence;
    193 
    194 //helper function declaration
    195 EGLConfig		getEGLConfig					(const Library& egl, EGLDisplay eglDisplay, bool preserveColorBuffer);
    196 void			clearColorScreen				(const glw::Functions& gl, const tcu::Vec4& clearColor);
    197 void			clearColorReference				(tcu::Surface* ref, const tcu::Vec4& clearColor);
    198 void			readPixels						(const glw::Functions& gl, tcu::Surface* screen);
    199 float			windowToDeviceCoordinates		(int x, int length);
    200 bool			compareToReference				(tcu::TestLog& log, const tcu::Surface& reference, const tcu::Surface& buffer, int frameNdx, int bufferNum);
    201 vector<int>		getFramesOnBuffer				(const vector<int>& bufferAges, int frameNdx);
    202 
    203 class GLES2Renderer
    204 {
    205 public:
    206 							GLES2Renderer		(const glw::Functions& gl);
    207 							~GLES2Renderer		(void);
    208 	void					render				(int width, int height, const Frame& frame) const;
    209 
    210 private:
    211 							GLES2Renderer		(const GLES2Renderer&);
    212 	GLES2Renderer&			operator=			(const GLES2Renderer&);
    213 
    214 	const glw::Functions&	m_gl;
    215 	glu::ShaderProgram		m_glProgram;
    216 	glw::GLuint				m_coordLoc;
    217 	glw::GLuint				m_colorLoc;
    218 };
    219 
    220 // generate sources for vertex and fragment buffer
    221 glu::ProgramSources getSources (void)
    222 {
    223 	const char* const vertexShaderSource =
    224 		"attribute mediump vec4 a_pos;\n"
    225 		"attribute mediump vec4 a_color;\n"
    226 		"varying mediump vec4 v_color;\n"
    227 		"void main(void)\n"
    228 		"{\n"
    229 		"\tv_color = a_color;\n"
    230 		"\tgl_Position = a_pos;\n"
    231 		"}";
    232 
    233 	const char* const fragmentShaderSource =
    234 		"varying mediump vec4 v_color;\n"
    235 		"void main(void)\n"
    236 		"{\n"
    237 		"\tgl_FragColor = v_color;\n"
    238 		"}";
    239 
    240 	return glu::makeVtxFragSources(vertexShaderSource, fragmentShaderSource);
    241 }
    242 
    243 GLES2Renderer::GLES2Renderer (const glw::Functions& gl)
    244 	: m_gl		  (gl)
    245 	, m_glProgram (gl, getSources())
    246 	, m_coordLoc  ((glw::GLuint)-1)
    247 	, m_colorLoc  ((glw::GLuint)-1)
    248 {
    249 	m_colorLoc = m_gl.getAttribLocation(m_glProgram.getProgram(), "a_color");
    250 	m_coordLoc = m_gl.getAttribLocation(m_glProgram.getProgram(), "a_pos");
    251 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "Failed to get attribute locations");
    252 }
    253 
    254 GLES2Renderer::~GLES2Renderer (void)
    255 {
    256 }
    257 
    258 void GLES2Renderer::render (int width, int height, const Frame& frame) const
    259 {
    260 	for (size_t drawNdx = 0; drawNdx < frame.draws.size(); drawNdx++)
    261 	{
    262 		const ColoredRect& coloredRect = frame.draws[drawNdx].rect;
    263 		if (frame.draws[drawNdx].drawType == BufferAgeTest::DRAWTYPE_GLES2_RENDER)
    264 		{
    265 			float x1 = windowToDeviceCoordinates(coloredRect.bottomLeft.x(), width);
    266 			float y1 = windowToDeviceCoordinates(coloredRect.bottomLeft.y(), height);
    267 			float x2 = windowToDeviceCoordinates(coloredRect.topRight.x(), width);
    268 			float y2 = windowToDeviceCoordinates(coloredRect.topRight.y(), height);
    269 
    270 			const glw::GLfloat coords[] =
    271 			{
    272 				x1, y1, 0.0f, 1.0f,
    273 				x1, y2, 0.0f, 1.0f,
    274 				x2, y2, 0.0f, 1.0f,
    275 
    276 				x2, y2, 0.0f, 1.0f,
    277 				x2, y1, 0.0f, 1.0f,
    278 				x1, y1, 0.0f, 1.0f
    279 			};
    280 
    281 			const glw::GLubyte colors[] =
    282 			{
    283 				coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255,
    284 				coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255,
    285 				coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255,
    286 
    287 				coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255,
    288 				coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255,
    289 				coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255,
    290 			};
    291 
    292 			m_gl.useProgram(m_glProgram.getProgram());
    293 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() failed");
    294 
    295 			m_gl.enableVertexAttribArray(m_coordLoc);
    296 			m_gl.enableVertexAttribArray(m_colorLoc);
    297 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "Failed to enable attributes");
    298 
    299 			m_gl.vertexAttribPointer(m_coordLoc, 4, GL_FLOAT, GL_FALSE, 0, coords);
    300 			m_gl.vertexAttribPointer(m_colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, colors);
    301 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "Failed to set attribute pointers");
    302 
    303 			m_gl.drawArrays(GL_TRIANGLES, 0, DE_LENGTH_OF_ARRAY(coords)/4);
    304 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArrays(), failed");
    305 
    306 			m_gl.disableVertexAttribArray(m_coordLoc);
    307 			m_gl.disableVertexAttribArray(m_colorLoc);
    308 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "Failed to disable attributes");
    309 
    310 			m_gl.useProgram(0);
    311 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() failed");
    312 		}
    313 		else if (frame.draws[drawNdx].drawType == BufferAgeTest::DRAWTYPE_GLES2_CLEAR)
    314 		{
    315 			m_gl.enable(GL_SCISSOR_TEST);
    316 			m_gl.scissor(coloredRect.bottomLeft.x(), coloredRect.bottomLeft.y(),
    317 						 coloredRect.topRight.x()-coloredRect.bottomLeft.x(), coloredRect.topRight.y()-coloredRect.bottomLeft.y());
    318 			m_gl.clearColor(coloredRect.color.x()/255.0f, coloredRect.color.y()/255.0f, coloredRect.color.z()/255.0f, 1.0f);
    319 			m_gl.clear(GL_COLOR_BUFFER_BIT);
    320 			m_gl.disable(GL_SCISSOR_TEST);
    321 		}
    322 		else
    323 			DE_ASSERT(false);
    324 	}
    325 }
    326 
    327 class ReferenceRenderer
    328 {
    329 public:
    330 						ReferenceRenderer	(void);
    331 	void				render				(tcu::Surface* target, const Frame& frame) const;
    332 private:
    333 						ReferenceRenderer	(const ReferenceRenderer&);
    334 	ReferenceRenderer&	operator=			(const ReferenceRenderer&);
    335 };
    336 
    337 ReferenceRenderer::ReferenceRenderer(void)
    338 {
    339 }
    340 
    341 void ReferenceRenderer::render (tcu::Surface* target, const Frame& frame) const
    342 {
    343 	for (size_t drawNdx = 0; drawNdx < frame.draws.size(); drawNdx++)
    344 	{
    345 		const ColoredRect& coloredRect = frame.draws[drawNdx].rect;
    346 		if (frame.draws[drawNdx].drawType == BufferAgeTest::DRAWTYPE_GLES2_RENDER || frame.draws[drawNdx].drawType == BufferAgeTest::DRAWTYPE_GLES2_CLEAR)
    347 		{
    348 			// tcu does not support degenerate subregions. Since they correspond to no-op rendering, just skip them.
    349 			if (coloredRect.bottomLeft.x() == coloredRect.topRight.x() || coloredRect.bottomLeft.y() == coloredRect.topRight.y())
    350 				continue;
    351 
    352 			const tcu::UVec4 color(coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255);
    353 			tcu::clear(tcu::getSubregion(target->getAccess(), coloredRect.bottomLeft.x(), coloredRect.bottomLeft.y(),
    354 										 coloredRect.topRight.x()-coloredRect.bottomLeft.x(), coloredRect.topRight.y()-coloredRect.bottomLeft.y()), color);
    355 		}
    356 		else
    357 			DE_ASSERT(false);
    358 	}
    359 }
    360 
    361 BufferAgeTest::BufferAgeTest (EglTestContext&			eglTestCtx,
    362 							  bool						preserveColorBuffer,
    363 							  const vector<DrawType>&	oddFrameDrawType,
    364 							  const vector<DrawType>&	evenFrameDrawType,
    365 							  ResizeType				resizeType,
    366 							  const char*				name,
    367 							  const char*				description)
    368 	: TestCase				(eglTestCtx, name, description)
    369 	, m_seed				(deStringHash(name))
    370 	, m_preserveColorBuffer (preserveColorBuffer)
    371 	, m_oddFrameDrawType	(oddFrameDrawType)
    372 	, m_evenFrameDrawType	(evenFrameDrawType)
    373 	, m_resizeType			(resizeType)
    374 	, m_eglDisplay			(EGL_NO_DISPLAY)
    375 	, m_window				(DE_NULL)
    376 	, m_eglSurface			(EGL_NO_SURFACE)
    377 	, m_eglContext			(EGL_NO_CONTEXT)
    378 	, m_gles2Renderer		(DE_NULL)
    379 	, m_refRenderer			(DE_NULL)
    380 {
    381 }
    382 
    383 BufferAgeTest::~BufferAgeTest (void)
    384 {
    385 	deinit();
    386 }
    387 
    388 void BufferAgeTest::init (void)
    389 {
    390 	const Library&	egl	= m_eglTestCtx.getLibrary();
    391 
    392 	m_eglDisplay = eglu::getAndInitDisplay(m_eglTestCtx.getNativeDisplay());
    393 	m_eglConfig	 = getEGLConfig(m_eglTestCtx.getLibrary(), m_eglDisplay, m_preserveColorBuffer);
    394 
    395 	if (m_eglConfig == DE_NULL)
    396 		TCU_THROW(NotSupportedError, "No supported config found");
    397 
    398 	//create surface and context and make them current
    399 	initEGLSurface(m_eglConfig);
    400 	initEGLContext(m_eglConfig);
    401 
    402 	m_eglTestCtx.initGLFunctions(&m_gl, glu::ApiType::es(2,0));
    403 
    404 	if (eglu::hasExtension(egl, m_eglDisplay, "EGL_EXT_buffer_age") == false)
    405 		TCU_THROW(NotSupportedError, "EGL_EXT_buffer_age is not supported");
    406 
    407 	m_gles2Renderer = new GLES2Renderer(m_gl);
    408 	m_refRenderer   = new ReferenceRenderer();
    409 }
    410 
    411 void BufferAgeTest::deinit (void)
    412 {
    413 	const Library& egl = m_eglTestCtx.getLibrary();
    414 
    415 	delete m_refRenderer;
    416 	m_refRenderer = DE_NULL;
    417 
    418 	delete m_gles2Renderer;
    419 	m_gles2Renderer = DE_NULL;
    420 
    421 	if (m_eglContext != EGL_NO_CONTEXT)
    422 	{
    423 		egl.makeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    424 		egl.destroyContext(m_eglDisplay, m_eglContext);
    425 		m_eglContext = EGL_NO_CONTEXT;
    426 	}
    427 
    428 	if (m_eglSurface != EGL_NO_SURFACE)
    429 	{
    430 		egl.destroySurface(m_eglDisplay, m_eglSurface);
    431 		m_eglSurface = EGL_NO_SURFACE;
    432 	}
    433 
    434 	if (m_eglDisplay != EGL_NO_DISPLAY)
    435 	{
    436 		egl.terminate(m_eglDisplay);
    437 		m_eglDisplay = EGL_NO_DISPLAY;
    438 	}
    439 
    440 	delete m_window;
    441 	m_window = DE_NULL;
    442 }
    443 
    444 void BufferAgeTest::initEGLSurface (EGLConfig config)
    445 {
    446 	const eglu::NativeWindowFactory& factory = eglu::selectNativeWindowFactory(m_eglTestCtx.getNativeDisplayFactory(), m_testCtx.getCommandLine());
    447 	m_window = factory.createWindow(&m_eglTestCtx.getNativeDisplay(), m_eglDisplay, config, DE_NULL,
    448 									eglu::WindowParams(480, 480, eglu::parseWindowVisibility(m_testCtx.getCommandLine())));
    449 	m_eglSurface = eglu::createWindowSurface(m_eglTestCtx.getNativeDisplay(), *m_window, m_eglDisplay, config, DE_NULL);
    450 }
    451 
    452 void BufferAgeTest::initEGLContext (EGLConfig config)
    453 {
    454 	const Library&	egl			 = m_eglTestCtx.getLibrary();
    455 	const EGLint	attribList[] =
    456 	{
    457 		EGL_CONTEXT_CLIENT_VERSION, 2,
    458 		EGL_NONE
    459 	};
    460 
    461 	egl.bindAPI(EGL_OPENGL_ES_API);
    462 	m_eglContext = egl.createContext(m_eglDisplay, config, EGL_NO_CONTEXT, attribList);
    463 	EGLU_CHECK_MSG(egl, "eglCreateContext");
    464 	DE_ASSERT(m_eglSurface != EGL_NO_SURFACE);
    465 	egl.makeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext);
    466 	EGLU_CHECK_MSG(egl, "eglMakeCurrent");
    467 }
    468 
    469 // return indices of frames that have been written to the given buffer
    470 vector<int> getFramesOnBuffer (const vector<int>& bufferAges, int frameNdx)
    471 {
    472 	DE_ASSERT(frameNdx < (int)bufferAges.size());
    473 	vector<int> frameOnBuffer;
    474 	int			age = bufferAges[frameNdx];
    475 	while (age != 0)
    476 	{
    477 		frameNdx = frameNdx - age;
    478 		DE_ASSERT(frameNdx >= 0);
    479 		frameOnBuffer.push_back(frameNdx);
    480 		age = bufferAges[frameNdx];
    481 	}
    482 
    483 	reverse(frameOnBuffer.begin(), frameOnBuffer.end());
    484 	return frameOnBuffer;
    485 }
    486 
    487 TestCase::IterateResult BufferAgeTest::iterate (void)
    488 {
    489 	de::Random		rnd					(m_seed);
    490 	const Library&	egl					= m_eglTestCtx.getLibrary();
    491 	tcu::TestLog&	log					= m_testCtx.getLog();
    492 	const int		width				= eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_WIDTH);
    493 	const int		height				= eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_HEIGHT);
    494 	const float		clearRed			= rnd.getFloat();
    495 	const float		clearGreen			= rnd.getFloat();
    496 	const float		clearBlue			= rnd.getFloat();
    497 	const tcu::Vec4	clearColor			(clearRed, clearGreen, clearBlue, 1.0f);
    498 	const int		numFrames			= 20;
    499 	FrameSequence	frameSequence;
    500 	vector<int>		bufferAges;
    501 
    502 	if (m_preserveColorBuffer)
    503 		EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED));
    504 	else
    505 		EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED));
    506 
    507 	for (int frameNdx = 0; frameNdx < numFrames; frameNdx++)
    508 	{
    509 		tcu::Surface					currentBuffer			(width, height);
    510 		tcu::Surface					refBuffer				(width, height);
    511 		Frame							newFrame				(width, height);
    512 		EGLint							currentBufferAge		= -1;
    513 
    514 		if (frameNdx % 2 == 0)
    515 			generateRandomFrame(&newFrame, m_evenFrameDrawType, rnd);
    516 		else
    517 			generateRandomFrame(&newFrame, m_oddFrameDrawType, rnd);
    518 
    519 		frameSequence.push_back(newFrame);
    520 
    521 		EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_BUFFER_AGE_EXT, &currentBufferAge));
    522 
    523 		if (currentBufferAge > frameNdx || currentBufferAge < 0) // invalid buffer age
    524 		{
    525 			std::ostringstream stream;
    526 			stream << "Fail, the age is invalid. Age: " << currentBufferAge << ", frameNdx: " << frameNdx;
    527 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, stream.str().c_str());
    528 			return STOP;
    529 		}
    530 
    531 		if (frameNdx > 0 && m_preserveColorBuffer && currentBufferAge != 1)
    532 		{
    533 			std::ostringstream stream;
    534 			stream << "Fail, EGL_BUFFER_PRESERVED is set to true, but buffer age is: " << currentBufferAge << " (should be 1)";
    535 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, stream.str().c_str());
    536 			return STOP;
    537 		}
    538 
    539 		bufferAges.push_back(currentBufferAge);
    540 		DE_ASSERT((int)bufferAges.size() == frameNdx+1);
    541 
    542 		// during first half, just keep rendering without reading pixel back to mimic ordinary use case
    543 		if (frameNdx < numFrames/2)
    544 		{
    545 			if (currentBufferAge == 0)
    546 				clearColorScreen(m_gl, clearColor);
    547 
    548 			m_gles2Renderer->render(width, height, newFrame);
    549 
    550 			if (m_resizeType == RESIZETYPE_BEFORE_SWAP)
    551 			{
    552 				if (frameNdx % 2 == 0)
    553 					m_window->setSurfaceSize(IVec2(width*2, height/2));
    554 				else
    555 					m_window->setSurfaceSize(IVec2(height/2, width*2));
    556 			}
    557 
    558 			EGLU_CHECK_CALL(egl, swapBuffers(m_eglDisplay, m_eglSurface));
    559 
    560 			if (m_resizeType == RESIZETYPE_AFTER_SWAP)
    561 			{
    562 				if (frameNdx % 2 == 0)
    563 					m_window->setSurfaceSize(IVec2(width*2, height/2));
    564 				else
    565 					m_window->setSurfaceSize(IVec2(height/2, width*2));
    566 			}
    567 
    568 			continue;
    569 		}
    570 
    571 		// do verification in the second half
    572 		if (currentBufferAge > 0) //buffer contain previous content, need to verify
    573 		{
    574 			const vector<int> framesOnBuffer = getFramesOnBuffer(bufferAges, frameNdx);
    575 			readPixels(m_gl, &currentBuffer);
    576 			clearColorReference(&refBuffer, clearColor);
    577 
    578 			for (vector<int>::const_iterator it = framesOnBuffer.begin(); it != framesOnBuffer.end(); it++)
    579 				m_refRenderer->render(&refBuffer, frameSequence[*it]);
    580 
    581 			if (compareToReference(log, refBuffer, currentBuffer, frameNdx, frameNdx-currentBufferAge) == false)
    582 			{
    583 				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail, buffer content is not well preserved when age > 0");
    584 				return STOP;
    585 			}
    586 		}
    587 		else // currentBufferAge == 0, content is undefined, clear the buffer, currentBufferAge < 0 is ruled out at the beginning
    588 		{
    589 			clearColorScreen(m_gl, clearColor);
    590 			clearColorReference(&refBuffer, clearColor);
    591 		}
    592 
    593 		m_gles2Renderer->render(width, height, newFrame);
    594 		m_refRenderer->render(&refBuffer, newFrame);
    595 
    596 		readPixels(m_gl, &currentBuffer);
    597 
    598 		if (compareToReference(log, refBuffer, currentBuffer, frameNdx, frameNdx) == false)
    599 		{
    600 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail, render result is wrong");
    601 			return STOP;
    602 		}
    603 
    604 		if (m_resizeType == RESIZETYPE_BEFORE_SWAP)
    605 		{
    606 			if (frameNdx % 2 == 0)
    607 				m_window->setSurfaceSize(IVec2(width*2, height/2));
    608 			else
    609 				m_window->setSurfaceSize(IVec2(height/2, width*2));
    610 		}
    611 
    612 		EGLU_CHECK_CALL(egl, swapBuffers(m_eglDisplay, m_eglSurface));
    613 
    614 		if (m_resizeType == RESIZETYPE_AFTER_SWAP)
    615 		{
    616 			if (frameNdx % 2 == 0)
    617 				m_window->setSurfaceSize(IVec2(width*2, height/2));
    618 			else
    619 				m_window->setSurfaceSize(IVec2(height/2, width*2));
    620 		}
    621 	}
    622 
    623 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    624 	return STOP;
    625 }
    626 
    627 string generateDrawTypeName (const vector<BufferAgeTest::DrawType>& drawTypes)
    628 {
    629 	std::ostringstream stream;
    630 	if (drawTypes.size() == 0)
    631 		return string("_none");
    632 
    633 	for (size_t ndx = 0; ndx < drawTypes.size(); ndx++)
    634 	{
    635 		if (drawTypes[ndx] == BufferAgeTest::DRAWTYPE_GLES2_RENDER)
    636 			stream << "_render";
    637 		else if (drawTypes[ndx] == BufferAgeTest::DRAWTYPE_GLES2_CLEAR)
    638 			stream << "_clear";
    639 		else
    640 			DE_ASSERT(false);
    641 	}
    642 	return stream.str();
    643 }
    644 
    645 string generateTestName (const vector<BufferAgeTest::DrawType>& oddFrameDrawType, const vector<BufferAgeTest::DrawType>& evenFrameDrawType)
    646 {
    647 	return "odd" + generateDrawTypeName(oddFrameDrawType) + "_even" + generateDrawTypeName(evenFrameDrawType);
    648 }
    649 
    650 string generateResizeGroupName (BufferAgeTest::ResizeType resizeType)
    651 {
    652 	switch (resizeType)
    653 	{
    654 		case BufferAgeTest::RESIZETYPE_NONE:
    655 			return "no_resize";
    656 
    657 		case BufferAgeTest::RESIZETYPE_AFTER_SWAP:
    658 			return "resize_after_swap";
    659 
    660 		case BufferAgeTest::RESIZETYPE_BEFORE_SWAP:
    661 			return "resize_before_swap";
    662 
    663 		default:
    664 			DE_FATAL("Unknown resize type");
    665 			return "";
    666 	}
    667 }
    668 
    669 bool isWindow (const eglu::CandidateConfig& c)
    670 {
    671 	return (c.surfaceType() & EGL_WINDOW_BIT) == EGL_WINDOW_BIT;
    672 }
    673 
    674 bool isES2Renderable (const eglu::CandidateConfig& c)
    675 {
    676 	return (c.get(EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES2_BIT) == EGL_OPENGL_ES2_BIT;
    677 }
    678 
    679 bool hasPreserveSwap (const eglu::CandidateConfig& c)
    680 {
    681 	return (c.surfaceType() & EGL_SWAP_BEHAVIOR_PRESERVED_BIT) == EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
    682 }
    683 
    684 EGLConfig getEGLConfig (const Library& egl, EGLDisplay eglDisplay, bool preserveColorBuffer)
    685 {
    686 	eglu::FilterList filters;
    687 	filters << isWindow << isES2Renderable;
    688 	if (preserveColorBuffer)
    689 		filters << hasPreserveSwap;
    690 	return eglu::chooseSingleConfig(egl, eglDisplay, filters);
    691 }
    692 
    693 void clearColorScreen (const glw::Functions& gl, const tcu::Vec4& clearColor)
    694 {
    695 	gl.clearColor(clearColor.x(), clearColor.y(), clearColor.z(), clearColor.w());
    696 	gl.clear(GL_COLOR_BUFFER_BIT);
    697 }
    698 
    699 void clearColorReference (tcu::Surface* ref, const tcu::Vec4& clearColor)
    700 {
    701 	tcu::clear(ref->getAccess(), clearColor);
    702 }
    703 
    704 void readPixels (const glw::Functions& gl, tcu::Surface* screen)
    705 {
    706 	gl.readPixels(0, 0, screen->getWidth(), screen->getHeight(),  GL_RGBA, GL_UNSIGNED_BYTE, screen->getAccess().getDataPtr());
    707 }
    708 
    709 float windowToDeviceCoordinates (int x, int length)
    710 {
    711 	return (2.0f * float(x) / float(length)) - 1.0f;
    712 }
    713 
    714 bool compareToReference (tcu::TestLog& log,	 const tcu::Surface& reference, const tcu::Surface& buffer, int frameNdx, int bufferNum)
    715 {
    716 	std::ostringstream stream;
    717 	stream << "FrameNdx = " << frameNdx << ", compare current buffer (numbered: " << bufferNum << ") to reference";
    718 	return tcu::intThresholdPositionDeviationCompare(log, "buffer age test", stream.str().c_str(), reference.getAccess(), buffer.getAccess(),
    719 													 tcu::UVec4(8, 8, 8, 0), tcu::IVec3(2,2,0), true, tcu::COMPARE_LOG_RESULT);
    720 }
    721 
    722 } // anonymous
    723 
    724 BufferAgeTests::BufferAgeTests (EglTestContext& eglTestCtx)
    725 	: TestCaseGroup(eglTestCtx, "buffer_age", "Color buffer age tests")
    726 {
    727 }
    728 
    729 void BufferAgeTests::init (void)
    730 {
    731 	const BufferAgeTest::DrawType clearRender[] =
    732 	{
    733 		BufferAgeTest::DRAWTYPE_GLES2_CLEAR,
    734 		BufferAgeTest::DRAWTYPE_GLES2_RENDER
    735 	};
    736 
    737 	const BufferAgeTest::DrawType renderClear[] =
    738 	{
    739 		BufferAgeTest::DRAWTYPE_GLES2_RENDER,
    740 		BufferAgeTest::DRAWTYPE_GLES2_CLEAR
    741 	};
    742 
    743 	const BufferAgeTest::ResizeType resizeTypes[] =
    744 	{
    745 		BufferAgeTest::RESIZETYPE_NONE,
    746 		BufferAgeTest::RESIZETYPE_BEFORE_SWAP,
    747 		BufferAgeTest::RESIZETYPE_AFTER_SWAP
    748 	};
    749 
    750 	vector< vector<BufferAgeTest::DrawType> > frameDrawTypes;
    751 	frameDrawTypes.push_back(vector<BufferAgeTest::DrawType> ());
    752 	frameDrawTypes.push_back(vector<BufferAgeTest::DrawType> (1, BufferAgeTest::DRAWTYPE_GLES2_CLEAR));
    753 	frameDrawTypes.push_back(vector<BufferAgeTest::DrawType> (1, BufferAgeTest::DRAWTYPE_GLES2_RENDER));
    754 	frameDrawTypes.push_back(vector<BufferAgeTest::DrawType> (2, BufferAgeTest::DRAWTYPE_GLES2_CLEAR));
    755 	frameDrawTypes.push_back(vector<BufferAgeTest::DrawType> (2, BufferAgeTest::DRAWTYPE_GLES2_RENDER));
    756 	frameDrawTypes.push_back(vector<BufferAgeTest::DrawType> (DE_ARRAY_BEGIN(clearRender), DE_ARRAY_END(clearRender)));
    757 	frameDrawTypes.push_back(vector<BufferAgeTest::DrawType> (DE_ARRAY_BEGIN(renderClear), DE_ARRAY_END(renderClear)));
    758 
    759 	for (int preserveNdx = 0; preserveNdx < 2; preserveNdx++)
    760 	{
    761 		const bool				preserve		= (preserveNdx == 0);
    762 		TestCaseGroup* const	preserveGroup	= new TestCaseGroup(m_eglTestCtx, (preserve ? "preserve" : "no_preserve"), "");
    763 
    764 		for (size_t resizeTypeNdx = 0; resizeTypeNdx < DE_LENGTH_OF_ARRAY(resizeTypes); resizeTypeNdx++)
    765 		{
    766 			const BufferAgeTest::ResizeType	resizeType	= resizeTypes[resizeTypeNdx];
    767 			TestCaseGroup* const			resizeGroup	= new TestCaseGroup(m_eglTestCtx, generateResizeGroupName(resizeType).c_str(), "");
    768 
    769 			for (size_t evenNdx = 0; evenNdx < frameDrawTypes.size(); evenNdx++)
    770 			{
    771 				const vector<BufferAgeTest::DrawType>& evenFrameDrawType = frameDrawTypes[evenNdx];
    772 
    773 				for (size_t oddNdx = evenNdx; oddNdx < frameDrawTypes.size(); oddNdx++)
    774 				{
    775 					const vector<BufferAgeTest::DrawType>&	oddFrameDrawType	= frameDrawTypes[oddNdx];
    776 					const std::string						name				= generateTestName(oddFrameDrawType, evenFrameDrawType);
    777 					resizeGroup->addChild(new BufferAgeTest(m_eglTestCtx, preserve, oddFrameDrawType, evenFrameDrawType, BufferAgeTest::RESIZETYPE_NONE, name.c_str(), ""));
    778 				}
    779 			}
    780 
    781 			preserveGroup->addChild(resizeGroup);
    782 		}
    783 		addChild(preserveGroup);
    784 	}
    785 }
    786 
    787 } // egl
    788 } // deqp
    789