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