teglPartialUpdateTests.cpp revision 82306462136d28069705c52d21534636b3f8f3d9
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	eglu::NativeWindow*			m_window;
95	EGLConfig					m_eglConfig;
96	EGLContext					m_eglContext;
97
98protected:
99	void						initEGLSurface			(EGLConfig config);
100	void						initEGLContext			(EGLConfig config);
101
102	const int					m_seed;
103	const vector<DrawType>	    m_oddFrameDrawType;
104	const vector<DrawType>		m_evenFrameDrawType;
105
106	bool 						m_supportBufferAge;
107	EGLDisplay					m_eglDisplay;
108	EGLSurface					m_eglSurface;
109	glw::Functions				m_gl;
110
111	GLES2Renderer*				m_gles2Renderer;
112	ReferenceRenderer*			m_refRenderer;
113};
114
115struct ColoredRect
116{
117public:
118								ColoredRect (const IVec2& bottomLeft_, const IVec2& topRight_, const Color& color_);
119	IVec2	 					bottomLeft;
120	IVec2	 					topRight;
121	Color 						color;
122};
123
124ColoredRect::ColoredRect (const IVec2& bottomLeft_, const IVec2& topRight_, const Color& color_)
125	: bottomLeft (bottomLeft_)
126	, topRight	 (topRight_)
127	, color		 (color_)
128{
129}
130
131struct DrawCommand
132{
133								DrawCommand (const PartialUpdateTest::DrawType drawType_, const ColoredRect& rect_);
134	PartialUpdateTest::DrawType	drawType;
135	ColoredRect					rect;
136};
137
138DrawCommand::DrawCommand (const PartialUpdateTest::DrawType drawType_, const ColoredRect& rect_)
139	: drawType	(drawType_)
140	, rect    	(rect_)
141{
142}
143
144struct Frame
145{
146								Frame (int width_, int height_);
147	int 						width;
148	int							height;
149	vector<DrawCommand> 		draws;
150};
151
152Frame::Frame (int width_, int height_)
153	: width (width_)
154	, height(height_)
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_window				(DE_NULL)
352	, m_eglContext			(EGL_NO_CONTEXT)
353	, m_seed				(deStringHash(name))
354	, m_oddFrameDrawType	(oddFrameDrawType)
355	, m_evenFrameDrawType	(evenFrameDrawType)
356	, m_supportBufferAge	(false)
357	, m_eglDisplay			(EGL_NO_DISPLAY)
358	, m_eglSurface			(EGL_NO_SURFACE)
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
479	DE_ASSERT(damageRegion.size() % 4 == 0);
480	return damageRegion;
481}
482
483TestCase::IterateResult PartialUpdateTest::iterate (void)
484{
485	de::Random 		rnd				(m_seed);
486	const Library&	egl				= m_eglTestCtx.getLibrary();
487	tcu::TestLog& 	log				= m_testCtx.getLog();
488	const int 		width			= eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_WIDTH);
489	const int 		height			= eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_HEIGHT);
490	const float 	clearRed		= rnd.getFloat();
491	const float 	clearGreen		= rnd.getFloat();
492	const float 	clearBlue		= rnd.getFloat();
493	const tcu::Vec4	clearColor		(clearRed, clearGreen, clearBlue, 1.0f);
494	const int 		numFrames		= 20;
495	FrameSequence 	frameSequence;
496	vector<int> 	bufferAges;
497	bool			hasPositiveAge  = false;
498
499	EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED));
500
501	for (int frameNdx = 0; frameNdx < numFrames; frameNdx++)
502	{
503		tcu::Surface	currentBuffer	 (width, height);
504		tcu::Surface	refBuffer		 (width, height);
505		Frame			newFrame		 (width, height);
506		EGLint			currentBufferAge = -1;
507
508		if (frameNdx % 2 == 0)
509			generateRandomFrame(newFrame, m_evenFrameDrawType, rnd);
510		else
511			generateRandomFrame(newFrame, m_oddFrameDrawType, rnd);
512
513		frameSequence.push_back(newFrame);
514
515		EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_BUFFER_AGE_KHR, &currentBufferAge));
516
517		if (currentBufferAge > frameNdx || currentBufferAge < 0) // invalid buffer age
518		{
519			std::ostringstream stream;
520			stream << "Fail, the age is invalid. Age: " << currentBufferAge << ", frameNdx: " << frameNdx;
521			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, stream.str().c_str());
522			return STOP;
523		}
524
525		bufferAges.push_back(currentBufferAge);
526		DE_ASSERT((int)bufferAges.size() == frameNdx+1);
527
528		if (currentBufferAge > 0)
529		{
530			vector<EGLint>	damageRegion;
531
532			hasPositiveAge = true;
533
534			if (m_supportBufferAge)
535			{
536				damageRegion = getDamageRegion(newFrame, 10, 10, 10, 10);
537			}
538			else
539			{
540				damageRegion = getDamageRegion(newFrame, 0, 0, 0, 0);
541				// Set empty damage region to avoid invalidating the framebuffer. The damage area is invalidated
542				// if the buffer age extension is not supported.
543				if (damageRegion.size() == 0)
544					damageRegion = vector<EGLint>(4, 0);
545			}
546
547			EGLU_CHECK_CALL(egl, setDamageRegionKHR(m_eglDisplay, m_eglSurface, &damageRegion[0], (EGLint)damageRegion.size()/4));
548		}
549		else
550		{
551			EGLU_CHECK_CALL(egl, setDamageRegionKHR(m_eglDisplay, m_eglSurface, NULL, 0));
552			clearColorScreen(m_gl, clearColor);
553		}
554
555		// during first half, just keep rendering without reading pixel back to mimic ordinary use case
556		if (frameNdx < numFrames/2)
557			m_gles2Renderer->render(width, height, newFrame);
558		else // do verification in the second half
559		{
560			const vector<int> framesOnBuffer = getFramesOnBuffer(bufferAges, frameNdx);
561
562			clearColorReference(&refBuffer, clearColor);
563
564			for (vector<int>::const_iterator it = framesOnBuffer.begin(); it != framesOnBuffer.end(); it++)
565				m_refRenderer->render(&refBuffer, frameSequence[*it]);
566
567			m_gles2Renderer->render(width, height, newFrame);
568			m_refRenderer->render(&refBuffer, newFrame);
569
570			readPixels(m_gl, &currentBuffer);
571
572			if (!compareToReference(log, refBuffer, currentBuffer, frameNdx, frameNdx))
573			{
574				string errorMessage("Fail, render result is wrong. Buffer age is ");
575				errorMessage += (m_supportBufferAge ? "supported" : "not supported");
576				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, errorMessage.c_str());
577				return STOP;
578			}
579		}
580		EGLU_CHECK_CALL(egl, swapBuffers(m_eglDisplay, m_eglSurface));
581	}
582
583	if (!hasPositiveAge) // fraud behavior, pretend to support partial_update
584	{
585		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail, claim to support partial_update but buffer age is always 0");
586		return STOP;
587	}
588
589	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
590	return STOP;
591}
592
593string generateDrawTypeName (const vector<PartialUpdateTest::DrawType>& drawTypes)
594{
595	std::ostringstream stream;
596	if (drawTypes.size() == 0)
597		return string("_none");
598
599	for (size_t ndx = 0; ndx < drawTypes.size(); ndx++)
600	{
601		if (drawTypes[ndx] == PartialUpdateTest::DRAWTYPE_GLES2_RENDER)
602			stream << "_render";
603		else if (drawTypes[ndx] == PartialUpdateTest::DRAWTYPE_GLES2_CLEAR)
604			stream << "_clear";
605		else
606			DE_ASSERT(false);
607	}
608	return stream.str();
609}
610
611string generateTestName (const vector<PartialUpdateTest::DrawType>& oddFrameDrawType, const vector<PartialUpdateTest::DrawType>& evenFrameDrawType)
612{
613	return "odd" + generateDrawTypeName(oddFrameDrawType) + "_even" + generateDrawTypeName(evenFrameDrawType);
614}
615
616bool isWindow (const eglu::CandidateConfig& c)
617{
618	return (c.surfaceType() & EGL_WINDOW_BIT) == EGL_WINDOW_BIT;
619}
620
621bool isES2Renderable (const eglu::CandidateConfig& c)
622{
623	return (c.get(EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES2_BIT) == EGL_OPENGL_ES2_BIT;
624}
625
626EGLConfig getEGLConfig (const Library& egl, EGLDisplay eglDisplay)
627{
628	eglu::FilterList filters;
629	filters << isWindow << isES2Renderable;
630	return eglu::chooseSingleConfig(egl, eglDisplay, filters);
631}
632
633void clearColorScreen (const glw::Functions& gl, const tcu::Vec4& clearColor)
634{
635	gl.clearColor(clearColor.x(), clearColor.y(), clearColor.z(), clearColor.w());
636	gl.clear(GL_COLOR_BUFFER_BIT);
637}
638
639void clearColorReference (tcu::Surface* ref, const tcu::Vec4& clearColor)
640{
641	tcu::clear(ref->getAccess(), clearColor);
642}
643
644void readPixels (const glw::Functions& gl, tcu::Surface* screen)
645{
646	gl.readPixels(0, 0, screen->getWidth(), screen->getHeight(),  GL_RGBA, GL_UNSIGNED_BYTE, screen->getAccess().getDataPtr());
647}
648
649float windowToDeviceCoordinates (int x, int length)
650{
651	return (2.0f * float(x) / float(length)) - 1.0f;
652}
653
654bool compareToReference (tcu::TestLog& log,	 const tcu::Surface& reference, const tcu::Surface& buffer, int frameNdx, int bufferNum)
655{
656	std::ostringstream stream;
657	stream << "FrameNdx = " << frameNdx << ", compare current buffer (numbered: " << bufferNum << ") to reference";
658	return tcu::intThresholdPositionDeviationCompare(log, "partial update test", stream.str().c_str(), reference.getAccess(), buffer.getAccess(),
659													 tcu::UVec4(8, 8, 8, 0), tcu::IVec3(2,2,0), true, tcu::COMPARE_LOG_RESULT);
660}
661
662class RenderOutsideDamageRegion : public PartialUpdateTest
663{
664public:
665								RenderOutsideDamageRegion		(EglTestContext& eglTestCtx);
666	TestCase::IterateResult		iterate							(void);
667};
668
669RenderOutsideDamageRegion::RenderOutsideDamageRegion (EglTestContext& eglTestCtx)
670	: PartialUpdateTest (eglTestCtx, vector<DrawType>(1, DRAWTYPE_GLES2_RENDER), vector<DrawType>(1, DRAWTYPE_GLES2_RENDER), "render_outside_damage_region", "")
671{
672}
673
674TestCase::IterateResult RenderOutsideDamageRegion::iterate (void)
675{
676	de::Random			rnd				(m_seed);
677	const Library&		egl				= m_eglTestCtx.getLibrary();
678	tcu::TestLog&		log				= m_testCtx.getLog();
679	const int			width			= eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_WIDTH);
680	const int			height			= eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_HEIGHT);
681	const float			clearRed		= rnd.getFloat();
682	const float			clearGreen		= rnd.getFloat();
683	const float			clearBlue		= rnd.getFloat();
684	const tcu::Vec4		clearColor		(clearRed, clearGreen, clearBlue, 1.0f);
685	tcu::Surface		currentBuffer	(width, height);
686	tcu::Surface		refBuffer		(width, height);
687	Frame				frame			(width, height);
688
689	EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED));
690
691	generateRandomFrame(frame, m_evenFrameDrawType, rnd);
692
693	{
694		// render outside the region
695		EGLint		   bufferAge	= -1;
696		vector<EGLint> damageRegion = getDamageRegion(frame, 0, 0, 0, 0);
697
698		EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_BUFFER_AGE_KHR, &bufferAge));
699		EGLU_CHECK_CALL(egl, setDamageRegionKHR(m_eglDisplay, m_eglSurface, &damageRegion[0], (EGLint)damageRegion.size()/4));
700		clearColorScreen(m_gl, clearColor);
701		m_gles2Renderer->render(width, height, frame);
702
703		// next line will make the bug on Nexus 6 disappear
704		// readPixels(m_gl, &currentBuffer);
705	}
706
707	EGLU_CHECK_CALL(egl, swapBuffers(m_eglDisplay, m_eglSurface));
708
709	// render a new frame
710	clearColorScreen(m_gl, clearColor);
711	m_gles2Renderer->render(width, height, frame);
712	clearColorReference(&refBuffer, clearColor);
713	m_refRenderer->render(&refBuffer, frame);
714	readPixels(m_gl, &currentBuffer);
715
716	if (!compareToReference(log, refBuffer, currentBuffer, 0, 0))
717		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail, fail to recover after rendering outside damageRegion");
718	else
719		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
720
721	return STOP;
722}
723
724class RenderBeforeSetDamageRegion : public PartialUpdateTest
725{
726public:
727								RenderBeforeSetDamageRegion		(EglTestContext& eglTestCtx);
728	TestCase::IterateResult		iterate							(void);
729};
730
731RenderBeforeSetDamageRegion::RenderBeforeSetDamageRegion (EglTestContext& eglTestCtx)
732	: PartialUpdateTest (eglTestCtx, vector<DrawType>(1, DRAWTYPE_GLES2_RENDER), vector<DrawType>(1, DRAWTYPE_GLES2_RENDER), "render_before_set_damage_region", "")
733{
734}
735
736TestCase::IterateResult RenderBeforeSetDamageRegion::iterate (void)
737{
738	de::Random			rnd				(m_seed);
739	const Library&		egl				= m_eglTestCtx.getLibrary();
740	tcu::TestLog&		log				= m_testCtx.getLog();
741	const int			width			= eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_WIDTH);
742	const int			height			= eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_HEIGHT);
743	const float			clearRed		= rnd.getFloat();
744	const float			clearGreen		= rnd.getFloat();
745	const float			clearBlue		= rnd.getFloat();
746	const tcu::Vec4		clearColor		(clearRed, clearGreen, clearBlue, 1.0f);
747	tcu::Surface		currentBuffer	(width, height);
748	tcu::Surface		refBuffer		(width, height);
749	Frame				frame			(width, height);
750
751	EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED));
752
753	generateRandomFrame(frame, m_evenFrameDrawType, rnd);
754
755	{
756		// render before setDamageRegion
757		EGLint		   bufferAge	= -1;
758		vector<EGLint> damageRegion = getDamageRegion(frame, 0, 0, 0, 0);
759
760		m_gles2Renderer->render(width, height, frame);
761		EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_BUFFER_AGE_KHR, &bufferAge));
762		EGLU_CHECK_CALL(egl, setDamageRegionKHR(m_eglDisplay, m_eglSurface, &damageRegion[0], (EGLint)damageRegion.size()/4));
763
764		// next line will make the bug on Nexus 6 disappear
765		// readPixels(m_gl, &currentBuffer);
766	}
767
768	EGLU_CHECK_CALL(egl, swapBuffers(m_eglDisplay, m_eglSurface));
769
770	// render a new frame
771	clearColorScreen(m_gl, clearColor);
772	m_gles2Renderer->render(width, height, frame);
773	clearColorReference(&refBuffer, clearColor);
774	m_refRenderer->render(&refBuffer, frame);
775	readPixels(m_gl, &currentBuffer);
776
777	if (!compareToReference(log, refBuffer, currentBuffer, 0, 0))
778		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
779	else
780		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
781
782	return STOP;
783}
784
785} // anonymous
786
787PartialUpdateTests::PartialUpdateTests (EglTestContext& eglTestCtx)
788	: TestCaseGroup(eglTestCtx, "partial_update", "Partial update tests")
789{
790}
791
792void PartialUpdateTests::init (void)
793{
794	const PartialUpdateTest::DrawType clearRender[2] =
795	{
796		PartialUpdateTest::DRAWTYPE_GLES2_CLEAR,
797		PartialUpdateTest::DRAWTYPE_GLES2_RENDER
798	};
799
800	const PartialUpdateTest::DrawType renderClear[2] =
801	{
802		PartialUpdateTest::DRAWTYPE_GLES2_RENDER,
803		PartialUpdateTest::DRAWTYPE_GLES2_CLEAR
804	};
805
806	vector< vector<PartialUpdateTest::DrawType> > frameDrawTypes;
807	frameDrawTypes.push_back(vector<PartialUpdateTest::DrawType> ());
808	frameDrawTypes.push_back(vector<PartialUpdateTest::DrawType> (1, PartialUpdateTest::DRAWTYPE_GLES2_CLEAR));
809	frameDrawTypes.push_back(vector<PartialUpdateTest::DrawType> (1, PartialUpdateTest::DRAWTYPE_GLES2_RENDER));
810	frameDrawTypes.push_back(vector<PartialUpdateTest::DrawType> (2, PartialUpdateTest::DRAWTYPE_GLES2_CLEAR));
811	frameDrawTypes.push_back(vector<PartialUpdateTest::DrawType> (2, PartialUpdateTest::DRAWTYPE_GLES2_RENDER));
812	frameDrawTypes.push_back(vector<PartialUpdateTest::DrawType> (DE_ARRAY_BEGIN(clearRender), DE_ARRAY_END(clearRender)));
813	frameDrawTypes.push_back(vector<PartialUpdateTest::DrawType> (DE_ARRAY_BEGIN(renderClear), DE_ARRAY_END(renderClear)));
814
815	for (size_t evenNdx = 0; evenNdx < frameDrawTypes.size(); evenNdx++)
816	{
817		const vector<PartialUpdateTest::DrawType>& evenFrameDrawType = frameDrawTypes[evenNdx];
818
819		for (size_t oddNdx = evenNdx; oddNdx < frameDrawTypes.size(); oddNdx++)
820		{
821			const vector<PartialUpdateTest::DrawType>& 	oddFrameDrawType = frameDrawTypes[oddNdx];
822			const std::string 							name 			 = generateTestName(oddFrameDrawType, evenFrameDrawType);
823			if (oddFrameDrawType.size() == 0 && evenFrameDrawType.size() == 0)
824				continue;
825
826			addChild(new PartialUpdateTest(m_eglTestCtx, oddFrameDrawType, evenFrameDrawType, name.c_str(), ""));
827		}
828	}
829	addChild(new RenderOutsideDamageRegion(m_eglTestCtx));
830	addChild(new RenderBeforeSetDamageRegion(m_eglTestCtx));
831}
832
833} // egl
834} // deqp
835