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 KHR_swap_buffer_with_damage
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "teglSwapBuffersWithDamageTests.hpp"
     25 
     26 #include "tcuImageCompare.hpp"
     27 #include "tcuSurface.hpp"
     28 #include "tcuTextureUtil.hpp"
     29 
     30 #include "egluNativeWindow.hpp"
     31 #include "egluUtil.hpp"
     32 #include "egluConfigFilter.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 #include "deString.h"
     47 
     48 #include <string>
     49 #include <vector>
     50 #include <sstream>
     51 
     52 using std::string;
     53 using std::vector;
     54 using glw::GLubyte;
     55 using tcu::IVec2;
     56 
     57 using namespace eglw;
     58 
     59 namespace deqp
     60 {
     61 namespace egl
     62 {
     63 namespace
     64 {
     65 
     66 typedef	tcu::Vector<GLubyte, 3> Color;
     67 
     68 enum DrawType
     69 {
     70     DRAWTYPE_GLES2_CLEAR,
     71     DRAWTYPE_GLES2_RENDER
     72 };
     73 
     74 enum ResizeType
     75 {
     76 	RESIZETYPE_NONE = 0,
     77 	RESIZETYPE_BEFORE_SWAP,
     78 	RESIZETYPE_AFTER_SWAP,
     79 
     80 	RESIZETYPE_LAST
     81 };
     82 
     83 struct ColoredRect
     84 {
     85 public:
     86 				ColoredRect (const IVec2& bottomLeft_, const IVec2& topRight_, const Color& color_);
     87 	IVec2		bottomLeft;
     88 	IVec2		topRight;
     89 	Color		color;
     90 };
     91 
     92 ColoredRect::ColoredRect (const IVec2& bottomLeft_, const IVec2& topRight_, const Color& color_)
     93 	: bottomLeft	(bottomLeft_)
     94 	, topRight		(topRight_)
     95 	, color			(color_)
     96 {
     97 }
     98 
     99 struct DrawCommand
    100 {
    101 				DrawCommand (DrawType drawType_, const ColoredRect& rect_);
    102     DrawType	drawType;
    103 	ColoredRect	rect;
    104 };
    105 
    106 DrawCommand::DrawCommand (DrawType drawType_, const ColoredRect& rect_)
    107 	: drawType	(drawType_)
    108 	, rect		(rect_)
    109 {
    110 }
    111 
    112 struct Frame
    113 {
    114 						Frame (int width_, int height_);
    115 	int					width;
    116 	int					height;
    117 	vector<DrawCommand> draws;
    118 };
    119 
    120 Frame::Frame (int width_, int height_)
    121 	: width (width_)
    122 	, height(height_)
    123 {
    124 }
    125 
    126 typedef vector<Frame> FrameSequence;
    127 
    128 //helper function declaration
    129 EGLConfig		getEGLConfig					(const Library& egl, EGLDisplay eglDisplay, bool preserveBuffer);
    130 void			clearColorScreen				(const glw::Functions& gl, const tcu::Vec4& clearColor);
    131 float			windowToDeviceCoordinates		(int x, int length);
    132 
    133 class GLES2Renderer
    134 {
    135 public:
    136 							GLES2Renderer		(const glw::Functions& gl);
    137 							~GLES2Renderer		(void);
    138 	void					render				(int width, int height, const Frame& frame) const;
    139 
    140 private:
    141 							GLES2Renderer		(const GLES2Renderer&);
    142 	GLES2Renderer&			operator=			(const GLES2Renderer&);
    143 
    144 	const glw::Functions&	m_gl;
    145 	glu::ShaderProgram		m_glProgram;
    146 	glw::GLuint				m_coordLoc;
    147 	glw::GLuint				m_colorLoc;
    148 };
    149 
    150 // generate sources for vertex and fragment buffer
    151 glu::ProgramSources getSources (void)
    152 {
    153 	const char* const vertexShaderSource =
    154 		"attribute mediump vec2 a_pos;\n"
    155 		"attribute mediump vec4 a_color;\n"
    156 		"varying mediump vec4 v_color;\n"
    157 		"void main(void)\n"
    158 		"{\n"
    159 		"\tv_color = a_color;\n"
    160 		"\tgl_Position = vec4(a_pos, 0.0, 1.0);\n"
    161 		"}";
    162 
    163 	const char* const fragmentShaderSource =
    164 		"varying mediump vec4 v_color;\n"
    165 		"void main(void)\n"
    166 		"{\n"
    167 		"\tgl_FragColor = v_color;\n"
    168 		"}";
    169 
    170 	return glu::makeVtxFragSources(vertexShaderSource, fragmentShaderSource);
    171 }
    172 
    173 GLES2Renderer::GLES2Renderer (const glw::Functions& gl)
    174 	: m_gl        (gl)
    175 	, m_glProgram (gl, getSources())
    176 	, m_coordLoc  ((glw::GLuint)-1)
    177 	, m_colorLoc  ((glw::GLuint)-1)
    178 {
    179 	m_colorLoc = m_gl.getAttribLocation(m_glProgram.getProgram(), "a_color");
    180 	m_coordLoc = m_gl.getAttribLocation(m_glProgram.getProgram(), "a_pos");
    181 	GLU_EXPECT_NO_ERROR(m_gl.getError(), "Failed to get attribute locations");
    182 }
    183 
    184 GLES2Renderer::~GLES2Renderer (void)
    185 {
    186 }
    187 
    188 void GLES2Renderer::render (int width, int height, const Frame& frame) const
    189 {
    190 	for (size_t drawNdx = 0; drawNdx < frame.draws.size(); drawNdx++)
    191 	{
    192 		const ColoredRect& coloredRect = frame.draws[drawNdx].rect;
    193 
    194 		if (frame.draws[drawNdx].drawType == DRAWTYPE_GLES2_RENDER)
    195 		{
    196 			const float x1 = windowToDeviceCoordinates(coloredRect.bottomLeft.x(), width);
    197 			const float y1 = windowToDeviceCoordinates(coloredRect.bottomLeft.y(), height);
    198 			const float x2 = windowToDeviceCoordinates(coloredRect.topRight.x(), width);
    199 			const float y2 = windowToDeviceCoordinates(coloredRect.topRight.y(), height);
    200 
    201 			const glw::GLfloat coords[] =
    202 			{
    203 				x1, y1,
    204 				x1, y2,
    205 				x2, y2,
    206 
    207 				x2, y2,
    208 				x2, y1,
    209 				x1, y1,
    210 			};
    211 
    212 			const glw::GLubyte colors[] =
    213 			{
    214 				coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255,
    215 				coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255,
    216 				coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255,
    217 
    218 				coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255,
    219 				coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255,
    220 				coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255,
    221 			};
    222 
    223 			m_gl.useProgram(m_glProgram.getProgram());
    224 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() failed");
    225 
    226 			m_gl.enableVertexAttribArray(m_coordLoc);
    227 			m_gl.enableVertexAttribArray(m_colorLoc);
    228 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "Failed to enable attributes");
    229 
    230 			m_gl.vertexAttribPointer(m_coordLoc, 2, GL_FLOAT, GL_FALSE, 0, coords);
    231 			m_gl.vertexAttribPointer(m_colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, colors);
    232 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "Failed to set attribute pointers");
    233 
    234 			m_gl.drawArrays(GL_TRIANGLES, 0, DE_LENGTH_OF_ARRAY(coords)/2);
    235 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArrays(), failed");
    236 
    237 			m_gl.disableVertexAttribArray(m_coordLoc);
    238 			m_gl.disableVertexAttribArray(m_colorLoc);
    239 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "Failed to disable attributes");
    240 
    241 			m_gl.useProgram(0);
    242 			GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() failed");
    243 		}
    244 		else if (frame.draws[drawNdx].drawType == DRAWTYPE_GLES2_CLEAR)
    245 		{
    246 			m_gl.enable(GL_SCISSOR_TEST);
    247 			m_gl.scissor(coloredRect.bottomLeft.x(), coloredRect.bottomLeft.y(),
    248 						 coloredRect.topRight.x()-coloredRect.bottomLeft.x(), coloredRect.topRight.y()-coloredRect.bottomLeft.y());
    249 			m_gl.clearColor(coloredRect.color.x()/255.0f, coloredRect.color.y()/255.0f, coloredRect.color.z()/255.0f, 1.0f);
    250 			m_gl.clear(GL_COLOR_BUFFER_BIT);
    251 			m_gl.disable(GL_SCISSOR_TEST);
    252 		}
    253 		else
    254 			DE_FATAL("Invalid drawtype");
    255 	}
    256 }
    257 
    258 class SwapBuffersWithDamageTest : public TestCase
    259 {
    260 public:
    261 								SwapBuffersWithDamageTest		(EglTestContext&			eglTestCtx,
    262 																 const vector<DrawType>&	frameDrawType,
    263 																 int						iterationTimes,
    264 																 ResizeType					resizeType,
    265 																 const char*				name,
    266 																 const char*				description);
    267 
    268 								~SwapBuffersWithDamageTest		(void);
    269 
    270 	virtual void				init							(void);
    271 	void						deinit							(void);
    272 	virtual IterateResult		iterate							(void);
    273 
    274 protected:
    275 	virtual EGLConfig			getConfig						(const Library& egl, EGLDisplay eglDisplay);
    276 	virtual void				checkExtension					(const Library& egl, EGLDisplay eglDisplay);
    277 	void						initEGLSurface					(EGLConfig config);
    278 	void						initEGLContext					(EGLConfig config);
    279 
    280 	eglu::NativeWindow*			m_window;
    281 	EGLConfig					m_eglConfig;
    282 	EGLContext					m_eglContext;
    283 	const int					m_seed;
    284 	const int					m_iterationTimes;
    285 	const vector<DrawType>		m_frameDrawType;
    286 	const ResizeType			m_resizeType;
    287 	EGLDisplay					m_eglDisplay;
    288 	EGLSurface					m_eglSurface;
    289 	glw::Functions				m_gl;
    290 	GLES2Renderer*				m_gles2Renderer;
    291 };
    292 
    293 SwapBuffersWithDamageTest::SwapBuffersWithDamageTest (EglTestContext& eglTestCtx, const vector<DrawType>& frameDrawType, int iterationTimes, ResizeType resizeType, const char* name, const char* description)
    294 	: TestCase			(eglTestCtx, name, description)
    295 	, m_window			(DE_NULL)
    296 	, m_eglContext		(EGL_NO_CONTEXT)
    297 	, m_seed			(deStringHash(name))
    298 	, m_iterationTimes	(iterationTimes)
    299 	, m_frameDrawType	(frameDrawType)
    300 	, m_resizeType		(resizeType)
    301 	, m_eglDisplay		(EGL_NO_DISPLAY)
    302 	, m_eglSurface		(EGL_NO_SURFACE)
    303 	, m_gles2Renderer	 (DE_NULL)
    304 {
    305 }
    306 
    307 SwapBuffersWithDamageTest::~SwapBuffersWithDamageTest (void)
    308 {
    309 	deinit();
    310 }
    311 
    312 EGLConfig SwapBuffersWithDamageTest::getConfig (const Library& egl, EGLDisplay eglDisplay)
    313 {
    314 	return getEGLConfig(egl, eglDisplay, false);
    315 }
    316 
    317 void SwapBuffersWithDamageTest::checkExtension (const Library& egl, EGLDisplay eglDisplay)
    318 {
    319 	if (!eglu::hasExtension(egl, eglDisplay, "EGL_KHR_swap_buffers_with_damage"))
    320 		TCU_THROW(NotSupportedError, "EGL_KHR_swap_buffers_with_damage is not supported");
    321 }
    322 
    323 void SwapBuffersWithDamageTest::init (void)
    324 {
    325 	const Library& egl = m_eglTestCtx.getLibrary();
    326 
    327 	m_eglDisplay = eglu::getAndInitDisplay(m_eglTestCtx.getNativeDisplay());
    328 	m_eglConfig  = getConfig(egl, m_eglDisplay);
    329 
    330 	checkExtension(egl, m_eglDisplay);
    331 
    332 	initEGLSurface(m_eglConfig);
    333 	initEGLContext(m_eglConfig);
    334 
    335 	m_eglTestCtx.initGLFunctions(&m_gl, glu::ApiType::es(2,0));
    336 	m_gles2Renderer = new GLES2Renderer(m_gl);
    337 }
    338 
    339 void SwapBuffersWithDamageTest::deinit (void)
    340 {
    341 	const Library& egl = m_eglTestCtx.getLibrary();
    342 
    343 	delete m_gles2Renderer;
    344 	m_gles2Renderer = DE_NULL;
    345 
    346 	if (m_eglContext != EGL_NO_CONTEXT)
    347 	{
    348 		egl.makeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    349 		egl.destroyContext(m_eglDisplay, m_eglContext);
    350 		m_eglContext = EGL_NO_CONTEXT;
    351 	}
    352 
    353 	if (m_eglSurface != EGL_NO_SURFACE)
    354 	{
    355 		egl.destroySurface(m_eglDisplay, m_eglSurface);
    356 		m_eglSurface = EGL_NO_SURFACE;
    357 	}
    358 
    359 	if (m_eglDisplay != EGL_NO_DISPLAY)
    360 	{
    361 		egl.terminate(m_eglDisplay);
    362 		m_eglDisplay = EGL_NO_DISPLAY;
    363 	}
    364 
    365 	delete m_window;
    366 	m_window = DE_NULL;
    367 }
    368 
    369 void SwapBuffersWithDamageTest::initEGLSurface (EGLConfig config)
    370 {
    371 	const eglu::NativeWindowFactory& factory = eglu::selectNativeWindowFactory(m_eglTestCtx.getNativeDisplayFactory(), m_testCtx.getCommandLine());
    372 	m_window = factory.createWindow(&m_eglTestCtx.getNativeDisplay(), m_eglDisplay, config, DE_NULL,
    373 									eglu::WindowParams(480, 480, eglu::parseWindowVisibility(m_testCtx.getCommandLine())));
    374 	m_eglSurface = eglu::createWindowSurface(m_eglTestCtx.getNativeDisplay(), *m_window, m_eglDisplay, config, DE_NULL);
    375 }
    376 
    377 void SwapBuffersWithDamageTest::initEGLContext (EGLConfig config)
    378 {
    379 	const Library&	egl			 = m_eglTestCtx.getLibrary();
    380 	const EGLint	attribList[] =
    381 	{
    382 		EGL_CONTEXT_CLIENT_VERSION, 2,
    383 		EGL_NONE
    384 	};
    385 
    386 	egl.bindAPI(EGL_OPENGL_ES_API);
    387 	m_eglContext = egl.createContext(m_eglDisplay, config, EGL_NO_CONTEXT, attribList);
    388 	EGLU_CHECK_MSG(egl, "eglCreateContext");
    389 	TCU_CHECK(m_eglSurface != EGL_NO_SURFACE);
    390 	egl.makeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext);
    391 	EGLU_CHECK_MSG(egl, "eglMakeCurrent");
    392 }
    393 
    394 FrameSequence	generateFrameSequence	(const vector<DrawType>& frameDrawType, de::Random& rnd, int numFrames, int width, int height);
    395 vector<EGLint>	getDamageRegion			(const Frame& frame);
    396 
    397 TestCase::IterateResult SwapBuffersWithDamageTest::iterate (void)
    398 {
    399 	de::Random			rnd				(m_seed);
    400 	const Library&		egl				= m_eglTestCtx.getLibrary();
    401 	const int			width			= eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_WIDTH);
    402 	const int			height			= eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_HEIGHT);
    403 	const float			clearRed		= rnd.getFloat();
    404 	const float			clearGreen		= rnd.getFloat();
    405 	const float			clearBlue		= rnd.getFloat();
    406 	const tcu::Vec4		clearColor		(clearRed, clearGreen, clearBlue, 1.0f);
    407 	const int			numFrames		= 24; // (width, height) = (480, 480) --> numFrame = 24, divisible
    408 	const FrameSequence frameSequence	= generateFrameSequence(m_frameDrawType, rnd, numFrames, width, height);
    409 
    410 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    411 	EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED));
    412 
    413 	for (int iterationNdx = 0; iterationNdx < m_iterationTimes; iterationNdx++)
    414 	{
    415 		for (int currentFrameNdx = 0; currentFrameNdx < numFrames; currentFrameNdx++)
    416 		{
    417 			vector<EGLint>	damageRegion = getDamageRegion(frameSequence[currentFrameNdx]);
    418 
    419 			clearColorScreen(m_gl, clearColor);
    420 			for (int ndx = 0; ndx <= currentFrameNdx; ndx++)
    421 				m_gles2Renderer->render(width, height, frameSequence[ndx]);
    422 
    423 			if (m_resizeType == RESIZETYPE_BEFORE_SWAP)
    424 			{
    425 				if (iterationNdx % 2 == 0)
    426 					m_window->setSurfaceSize(IVec2(width*2, height/2));
    427 				else
    428 					m_window->setSurfaceSize(IVec2(height/2, width*2));
    429 			}
    430 
    431 			EGLU_CHECK_CALL(egl, swapBuffersWithDamageKHR(m_eglDisplay, m_eglSurface, &damageRegion[0], (EGLint)damageRegion.size()/4));
    432 
    433 			if (m_resizeType == RESIZETYPE_AFTER_SWAP)
    434 			{
    435 				if (iterationNdx % 2 == 0)
    436 					m_window->setSurfaceSize(IVec2(width*2, height/2));
    437 				else
    438 					m_window->setSurfaceSize(IVec2(height/2, width*2));
    439 			}
    440 		}
    441 	}
    442 	return STOP;
    443 }
    444 
    445 class SwapBuffersWithDamageAndPreserveBufferTest : public SwapBuffersWithDamageTest
    446 {
    447 public:
    448 					SwapBuffersWithDamageAndPreserveBufferTest	(EglTestContext&			eglTestCtx,
    449 																 const vector<DrawType>&	frameDrawType,
    450 																 int						iterationTimes,
    451 																 ResizeType					resizeType,
    452 																 const char*				name,
    453 																 const char*				description);
    454 
    455 	IterateResult	iterate										(void);
    456 
    457 protected:
    458 	EGLConfig		getConfig									(const Library& egl, EGLDisplay eglDisplay);
    459 };
    460 
    461 SwapBuffersWithDamageAndPreserveBufferTest::SwapBuffersWithDamageAndPreserveBufferTest (EglTestContext&			eglTestCtx,
    462 																						const vector<DrawType>&	frameDrawType,
    463 																						int						iterationTimes,
    464 																						ResizeType				resizeType,
    465 																						const char*				name,
    466 																						const char*				description)
    467 	: SwapBuffersWithDamageTest (eglTestCtx, frameDrawType, iterationTimes, resizeType, name, description)
    468 {
    469 }
    470 
    471 EGLConfig SwapBuffersWithDamageAndPreserveBufferTest::getConfig (const Library& egl, EGLDisplay eglDisplay)
    472 {
    473 	return getEGLConfig(egl, eglDisplay, true);
    474 }
    475 
    476 TestCase::IterateResult SwapBuffersWithDamageAndPreserveBufferTest::iterate (void)
    477 {
    478 
    479 	de::Random			rnd				(m_seed);
    480 	const Library&		egl				= m_eglTestCtx.getLibrary();
    481 	const int			width			= eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_WIDTH);
    482 	const int			height			= eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_HEIGHT);
    483 	const float			clearRed		= rnd.getFloat();
    484 	const float			clearGreen		= rnd.getFloat();
    485 	const float			clearBlue		= rnd.getFloat();
    486 	const tcu::Vec4		clearColor		(clearRed, clearGreen, clearBlue, 1.0f);
    487 	const int			numFrames		= 24; // (width, height) = (480, 480) --> numFrame = 24, divisible
    488 	const FrameSequence frameSequence	= generateFrameSequence(m_frameDrawType, rnd, numFrames, width, height);
    489 
    490 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    491 	EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED));
    492 
    493 	for (int iterationNdx = 0; iterationNdx < m_iterationTimes; iterationNdx++)
    494 	{
    495 		clearColorScreen(m_gl, clearColor);
    496 		EGLU_CHECK_CALL(egl, swapBuffersWithDamageKHR(m_eglDisplay, m_eglSurface, DE_NULL, 0));
    497 
    498 		for (int frameNdx = 0; frameNdx < numFrames; frameNdx++)
    499 		{
    500 			const Frame&	currentFrame = frameSequence[frameNdx];
    501 			vector<EGLint>	damageRegion = getDamageRegion(currentFrame);
    502 
    503 			m_gles2Renderer->render(width, height, currentFrame);
    504 
    505 			if (m_resizeType == RESIZETYPE_BEFORE_SWAP)
    506 			{
    507 				if (iterationNdx % 2 == 0)
    508 					m_window->setSurfaceSize(IVec2(width*2, height/2));
    509 				else
    510 					m_window->setSurfaceSize(IVec2(height/2, width*2));
    511 			}
    512 
    513 			EGLU_CHECK_CALL(egl, swapBuffersWithDamageKHR(m_eglDisplay, m_eglSurface, &damageRegion[0], (EGLint)damageRegion.size()/4));
    514 
    515 			if (m_resizeType == RESIZETYPE_AFTER_SWAP)
    516 			{
    517 				if (iterationNdx % 2 == 0)
    518 					m_window->setSurfaceSize(IVec2(width*2, height/2));
    519 				else
    520 					m_window->setSurfaceSize(IVec2(height/2, width*2));
    521 			}
    522 		}
    523 	}
    524 
    525 	return STOP;
    526 }
    527 
    528 class SwapBuffersWithDamageAndBufferAgeTest : public SwapBuffersWithDamageTest
    529 {
    530 public:
    531 					SwapBuffersWithDamageAndBufferAgeTest	(EglTestContext&			eglTestCtx,
    532 															 const vector<DrawType>&	frameDrawType,
    533 															 int						iterationTimes,
    534 															 ResizeType					resizeType,
    535 															 const char*				name,
    536 															 const char*				description);
    537 
    538 	IterateResult	iterate									(void);
    539 
    540 protected:
    541 	void			checkExtension							(const Library& egl, EGLDisplay eglDisplay);
    542 };
    543 
    544 SwapBuffersWithDamageAndBufferAgeTest::SwapBuffersWithDamageAndBufferAgeTest (EglTestContext&			eglTestCtx,
    545 																			  const vector<DrawType>&	frameDrawType,
    546 																			  int						iterationTimes,
    547 																			  ResizeType				resizeType,
    548 																			  const char*				name,
    549 																			  const char*				description)
    550 	: SwapBuffersWithDamageTest (eglTestCtx, frameDrawType, iterationTimes, resizeType, name, description)
    551 {
    552 }
    553 
    554 
    555 void SwapBuffersWithDamageAndBufferAgeTest::checkExtension (const Library& egl, EGLDisplay eglDisplay)
    556 {
    557 	if (!eglu::hasExtension(egl, eglDisplay, "EGL_KHR_swap_buffers_with_damage"))
    558 		TCU_THROW(NotSupportedError, "EGL_KHR_swap_buffers_with_damage is not supported");
    559 
    560 	if (!eglu::hasExtension(egl, eglDisplay, "EGL_EXT_buffer_age"))
    561 		TCU_THROW(NotSupportedError, "EGL_EXT_buffer_age not supported");
    562 }
    563 
    564 TestCase::IterateResult SwapBuffersWithDamageAndBufferAgeTest::iterate (void)
    565 {
    566 
    567 	de::Random			rnd				(m_seed);
    568 	const Library&		egl				= m_eglTestCtx.getLibrary();
    569 	const int			width			= eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_WIDTH);
    570 	const int			height			= eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_HEIGHT);
    571 	const float			clearRed		= rnd.getFloat();
    572 	const float			clearGreen		= rnd.getFloat();
    573 	const float			clearBlue		= rnd.getFloat();
    574 	const tcu::Vec4		clearColor		(clearRed, clearGreen, clearBlue, 1.0f);
    575 	const int			numFrames		= 24; // (width, height) = (480, 480) --> numFrame = 24, divisible
    576 	const FrameSequence frameSequence	= generateFrameSequence(m_frameDrawType, rnd, numFrames, width, height);
    577 
    578 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    579 	EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED));
    580 
    581 	for (int iterationNdx = 0; iterationNdx < m_iterationTimes; iterationNdx++)
    582 	{
    583 		clearColorScreen(m_gl, clearColor);
    584 		EGLU_CHECK_CALL(egl, swapBuffersWithDamageKHR(m_eglDisplay, m_eglSurface, DE_NULL, 0));
    585 
    586 		for (int frameNdx = 0; frameNdx < numFrames; frameNdx++)
    587 		{
    588 			vector<EGLint>	damageRegion;
    589 			int				bufferAge		= -1;
    590 			int				startFrameNdx	= -1;
    591 			int				endFrameNdx		= frameNdx;
    592 
    593 			EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_BUFFER_AGE_EXT, &bufferAge));
    594 
    595 			if (bufferAge < 0) // invalid buffer age
    596 			{
    597 				std::ostringstream stream;
    598 				stream << "Fail, the age is invalid. Age: " << bufferAge << ", frameNdx: " << frameNdx;
    599 				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, stream.str().c_str());
    600 				return STOP;
    601 			}
    602 
    603 			if (bufferAge == 0 || bufferAge > frameNdx)
    604 			{
    605 				clearColorScreen(m_gl, clearColor);
    606 				startFrameNdx = 0;
    607 			}
    608 			else
    609 				startFrameNdx = frameNdx-bufferAge+1;
    610 
    611 			for (int ndx = startFrameNdx; ndx <= endFrameNdx; ndx++)
    612 			{
    613 				const vector<EGLint> partialDamageRegion = getDamageRegion(frameSequence[ndx]);
    614 
    615 				damageRegion.insert(damageRegion.end(), partialDamageRegion.begin(), partialDamageRegion.end());
    616 				m_gles2Renderer->render(width, height, frameSequence[ndx]);
    617 			}
    618 
    619 			if (m_resizeType == RESIZETYPE_BEFORE_SWAP)
    620 			{
    621 				if (iterationNdx % 2 == 0)
    622 					m_window->setSurfaceSize(IVec2(width*2, height/2));
    623 				else
    624 					m_window->setSurfaceSize(IVec2(height/2, width*2));
    625 			}
    626 
    627 			EGLU_CHECK_CALL(egl, swapBuffersWithDamageKHR(m_eglDisplay, m_eglSurface, &damageRegion[0], (EGLint)damageRegion.size()/4));
    628 
    629 			if (m_resizeType == RESIZETYPE_AFTER_SWAP)
    630 			{
    631 				if (iterationNdx % 2 == 0)
    632 					m_window->setSurfaceSize(IVec2(width*2, height/2));
    633 				else
    634 					m_window->setSurfaceSize(IVec2(height/2, width*2));
    635 			}
    636 		}
    637 	}
    638 	return STOP;
    639 }
    640 
    641 // generate a frame sequence with certain frame for visual verification
    642 FrameSequence generateFrameSequence (const vector<DrawType>& frameDrawType, de::Random& rnd, int numFrames, int width, int height)
    643 {
    644 	const int			frameDiff		= height / numFrames;
    645 	const GLubyte		r				= rnd.getUint8();
    646 	const GLubyte		g				= rnd.getUint8();
    647 	const GLubyte		b				= rnd.getUint8();
    648 	const Color			color			(r, g, b);
    649 	FrameSequence		frameSequence;
    650 
    651 	for (int frameNdx = 0; frameNdx < numFrames; frameNdx++)
    652 	{
    653 		Frame frame (width, height);
    654 
    655 		for (int rectNdx = 0; rectNdx < (int)frameDrawType.size(); rectNdx++)
    656 		{
    657 			const int			rectHeight		= frameDiff / (int)frameDrawType.size();
    658 			const ColoredRect	rect			(IVec2(0, frameNdx*frameDiff+rectNdx*rectHeight), IVec2(width, frameNdx*frameDiff+(rectNdx+1)*rectHeight), color);
    659 			const DrawCommand	drawCommand		(frameDrawType[rectNdx], rect);
    660 
    661 			frame.draws.push_back(drawCommand);
    662 		}
    663 		frameSequence.push_back(frame);
    664 	}
    665 	return frameSequence;
    666 }
    667 
    668 vector<EGLint> getDamageRegion (const Frame& frame)
    669 {
    670 	vector<EGLint> damageRegion;
    671 	for (size_t drawNdx = 0; drawNdx < frame.draws.size(); drawNdx++)
    672 	{
    673 		const ColoredRect& rect = frame.draws[drawNdx].rect;
    674 		damageRegion.push_back(rect.bottomLeft.x());
    675 		damageRegion.push_back(rect.bottomLeft.y());
    676 		damageRegion.push_back(rect.topRight.x() - rect.bottomLeft.x());
    677 		damageRegion.push_back(rect.topRight.y() - rect.bottomLeft.y());
    678 	}
    679 
    680 	DE_ASSERT(damageRegion.size() % 4 == 0);
    681 	return damageRegion;
    682 }
    683 
    684 string generateTestName (const vector<DrawType>& frameDrawType)
    685 {
    686 	std::ostringstream stream;
    687 
    688 	for (size_t ndx = 0; ndx < frameDrawType.size(); ndx++)
    689 	{
    690 		if (frameDrawType[ndx] == DRAWTYPE_GLES2_RENDER)
    691 			stream << "render";
    692 		else if (frameDrawType[ndx] == DRAWTYPE_GLES2_CLEAR)
    693 			stream << "clear";
    694 		else
    695 			DE_ASSERT(false);
    696 
    697 		if (ndx < frameDrawType.size()-1)
    698 			stream << "_";
    699 	}
    700 
    701 	return stream.str();
    702 }
    703 
    704 string generateResizeGroupName (ResizeType resizeType)
    705 {
    706 	switch (resizeType)
    707 	{
    708 		case RESIZETYPE_NONE:
    709 			return "no_resize";
    710 
    711 		case RESIZETYPE_AFTER_SWAP:
    712 			return "resize_after_swap";
    713 
    714 		case RESIZETYPE_BEFORE_SWAP:
    715 			return "resize_before_swap";
    716 
    717 		default:
    718 			DE_FATAL("Unknown resize type");
    719 			return "";
    720 	}
    721 }
    722 
    723 bool isWindow (const eglu::CandidateConfig& c)
    724 {
    725 	return (c.surfaceType() & EGL_WINDOW_BIT) == EGL_WINDOW_BIT;
    726 }
    727 
    728 bool isES2Renderable (const eglu::CandidateConfig& c)
    729 {
    730 	return (c.get(EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES2_BIT) == EGL_OPENGL_ES2_BIT;
    731 }
    732 
    733 bool hasPreserveSwap (const eglu::CandidateConfig& c)
    734 {
    735 	return (c.surfaceType() & EGL_SWAP_BEHAVIOR_PRESERVED_BIT) == EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
    736 }
    737 
    738 EGLConfig getEGLConfig (const Library& egl, EGLDisplay eglDisplay, bool preserveBuffer)
    739 {
    740 	eglu::FilterList filters;
    741 
    742 	filters << isWindow << isES2Renderable;
    743 	if (preserveBuffer)
    744 		filters << hasPreserveSwap;
    745 
    746 	return eglu::chooseSingleConfig(egl, eglDisplay, filters);
    747 }
    748 
    749 void clearColorScreen (const glw::Functions& gl, const tcu::Vec4& clearColor)
    750 {
    751 	gl.clearColor(clearColor.x(), clearColor.y(), clearColor.z(), clearColor.w());
    752 	gl.clear(GL_COLOR_BUFFER_BIT);
    753 }
    754 
    755 float windowToDeviceCoordinates (int x, int length)
    756 {
    757 	return (2.0f * float(x) / float(length)) - 1.0f;
    758 }
    759 
    760 } // anonymous
    761 
    762 SwapBuffersWithDamageTests::SwapBuffersWithDamageTests (EglTestContext& eglTestCtx)
    763 	: TestCaseGroup(eglTestCtx, "swap_buffers_with_damage", "Swap buffers with damages tests")
    764 {
    765 }
    766 
    767 void SwapBuffersWithDamageTests::init (void)
    768 {
    769 	const DrawType clearRender[2] =
    770 	{
    771 		DRAWTYPE_GLES2_CLEAR,
    772 		DRAWTYPE_GLES2_RENDER
    773 	};
    774 
    775 	const DrawType renderClear[2] =
    776 	{
    777 		DRAWTYPE_GLES2_RENDER,
    778 		DRAWTYPE_GLES2_CLEAR
    779 	};
    780 
    781 	const ResizeType resizeTypes[] =
    782 	{
    783 		RESIZETYPE_NONE,
    784 		RESIZETYPE_BEFORE_SWAP,
    785 		RESIZETYPE_AFTER_SWAP
    786 	};
    787 
    788 	vector< vector<DrawType> > frameDrawTypes;
    789 	frameDrawTypes.push_back(vector<DrawType> (1, DRAWTYPE_GLES2_CLEAR));
    790 	frameDrawTypes.push_back(vector<DrawType> (1, DRAWTYPE_GLES2_RENDER));
    791 	frameDrawTypes.push_back(vector<DrawType> (2, DRAWTYPE_GLES2_CLEAR));
    792 	frameDrawTypes.push_back(vector<DrawType> (2, DRAWTYPE_GLES2_RENDER));
    793 	frameDrawTypes.push_back(vector<DrawType> (DE_ARRAY_BEGIN(clearRender), DE_ARRAY_END(clearRender)));
    794 	frameDrawTypes.push_back(vector<DrawType> (DE_ARRAY_BEGIN(renderClear), DE_ARRAY_END(renderClear)));
    795 
    796 	for (size_t resizeTypeNdx = 0; resizeTypeNdx < DE_LENGTH_OF_ARRAY(resizeTypes); resizeTypeNdx++)
    797 	{
    798 		const ResizeType		resizeType	= resizeTypes[resizeTypeNdx];
    799 		TestCaseGroup* const	resizeGroup	= new TestCaseGroup(m_eglTestCtx, generateResizeGroupName(resizeType).c_str(), "");
    800 
    801 		for (size_t drawTypeNdx = 0; drawTypeNdx < frameDrawTypes.size(); drawTypeNdx++)
    802 		{
    803 			string name = generateTestName(frameDrawTypes[drawTypeNdx]);
    804 			resizeGroup->addChild(new SwapBuffersWithDamageTest(m_eglTestCtx, frameDrawTypes[drawTypeNdx], 4, resizeType, name.c_str(), ""));
    805 		}
    806 
    807 		for (size_t drawTypeNdx = 0; drawTypeNdx < frameDrawTypes.size(); drawTypeNdx++)
    808 		{
    809 			string name = "preserve_buffer_" + generateTestName(frameDrawTypes[drawTypeNdx]);
    810 			resizeGroup->addChild(new SwapBuffersWithDamageAndPreserveBufferTest(m_eglTestCtx, frameDrawTypes[drawTypeNdx], 4, resizeType, name.c_str(), ""));
    811 		}
    812 
    813 		for (size_t drawTypeNdx = 0; drawTypeNdx < frameDrawTypes.size(); drawTypeNdx++)
    814 		{
    815 			string name = "buffer_age_" + generateTestName(frameDrawTypes[drawTypeNdx]);
    816 			resizeGroup->addChild(new SwapBuffersWithDamageAndBufferAgeTest(m_eglTestCtx, frameDrawTypes[drawTypeNdx], 4, resizeType, name.c_str(),  ""));
    817 		}
    818 
    819 		addChild(resizeGroup);
    820 	}
    821 }
    822 
    823 } // egl
    824 } // deqp
    825