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