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 
53 using std::string;
54 using std::vector;
55 using glw::GLubyte;
56 using tcu::IVec2;
57 
58 using namespace eglw;
59 
60 namespace deqp
61 {
62 namespace egl
63 {
64 namespace
65 {
66 
67 typedef	tcu::Vector<GLubyte, 3> Color;
68 
69 class GLES2Renderer;
70 
71 class ReferenceRenderer;
72 
73 class PartialUpdateTest : public TestCase
74 {
75 public:
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 
93 private:
94 	eglu::NativeWindow*			m_window;
95 	EGLConfig					m_eglConfig;
96 	EGLContext					m_eglContext;
97 
98 protected:
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 
115 struct ColoredRect
116 {
117 public:
118 								ColoredRect (const IVec2& bottomLeft_, const IVec2& topRight_, const Color& color_);
119 	IVec2						bottomLeft;
120 	IVec2						topRight;
121 	Color						color;
122 };
123 
ColoredRect(const IVec2 & bottomLeft_,const IVec2 & topRight_,const Color & color_)124 ColoredRect::ColoredRect (const IVec2& bottomLeft_, const IVec2& topRight_, const Color& color_)
125 	: bottomLeft (bottomLeft_)
126 	, topRight	 (topRight_)
127 	, color		 (color_)
128 {
129 }
130 
131 struct DrawCommand
132 {
133 								DrawCommand (const PartialUpdateTest::DrawType drawType_, const ColoredRect& rect_);
134 	PartialUpdateTest::DrawType	drawType;
135 	ColoredRect					rect;
136 };
137 
DrawCommand(const PartialUpdateTest::DrawType drawType_,const ColoredRect & rect_)138 DrawCommand::DrawCommand (const PartialUpdateTest::DrawType drawType_, const ColoredRect& rect_)
139 	: drawType	(drawType_)
140 	, rect		(rect_)
141 {
142 }
143 
144 struct Frame
145 {
146 								Frame (int width_, int height_);
147 	int							width;
148 	int							height;
149 	vector<DrawCommand>			draws;
150 };
151 
Frame(int width_,int height_)152 Frame::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()
generateRandomFrame(Frame & dst,const vector<PartialUpdateTest::DrawType> & drawTypes,de::Random & rnd)162 void 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 
180 typedef vector<Frame> FrameSequence;
181 
182 //helper function declaration
183 EGLConfig		getEGLConfig					(const Library& egl, EGLDisplay eglDisplay);
184 void			clearColorScreen				(const glw::Functions& gl, const tcu::Vec4& clearColor);
185 void			clearColorReference				(tcu::Surface* ref, const tcu::Vec4& clearColor);
186 void			readPixels						(const glw::Functions& gl, tcu::Surface* screen);
187 float			windowToDeviceCoordinates		(int x, int length);
188 bool			compareToReference				(tcu::TestLog& log, const tcu::Surface& reference, const tcu::Surface& buffer, int frameNdx, int bufferNum);
189 vector<int>		getFramesOnBuffer				(const vector<int>& bufferAges, int frameNdx);
190 
191 class GLES2Renderer
192 {
193 public:
194 							GLES2Renderer		(const glw::Functions& gl);
195 							~GLES2Renderer		(void);
196 	void					render				(int width, int height, const Frame& frame) const;
197 
198 private:
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
getSources(void)209 glu::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 
GLES2Renderer(const glw::Functions & gl)231 GLES2Renderer::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 
~GLES2Renderer(void)242 GLES2Renderer::~GLES2Renderer (void)
243 {
244 }
245 
render(int width,int height,const Frame & frame) const246 void 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 
316 class ReferenceRenderer
317 {
318 public:
319 						ReferenceRenderer		(void);
320 	void				render					(tcu::Surface* target, const Frame& frame) const;
321 private:
322 						ReferenceRenderer		(const ReferenceRenderer&);
323 	ReferenceRenderer&	operator=				(const ReferenceRenderer&);
324 };
325 
ReferenceRenderer(void)326 ReferenceRenderer::ReferenceRenderer(void)
327 {
328 }
329 
render(tcu::Surface * target,const Frame & frame) const330 void 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 
PartialUpdateTest(EglTestContext & eglTestCtx,const vector<DrawType> & oddFrameDrawType,const vector<DrawType> & evenFrameDrawType,const char * name,const char * description)346 PartialUpdateTest::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 
~PartialUpdateTest(void)364 PartialUpdateTest::~PartialUpdateTest (void)
365 {
366 	deinit();
367 }
368 
init(void)369 void 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 
deinit(void)391 void 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 
initEGLSurface(EGLConfig config)424 void 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 
initEGLContext(EGLConfig config)432 void 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
getFramesOnBuffer(const vector<int> & bufferAges,int frameNdx)450 vector<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 
getDamageRegion(const Frame & frame,int marginLeft,int marginBottom,int marginRight,int marginTop)467 vector<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 
iterate(void)483 TestCase::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 
generateDrawTypeName(const vector<PartialUpdateTest::DrawType> & drawTypes)593 string 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 
generateTestName(const vector<PartialUpdateTest::DrawType> & oddFrameDrawType,const vector<PartialUpdateTest::DrawType> & evenFrameDrawType)611 string generateTestName (const vector<PartialUpdateTest::DrawType>& oddFrameDrawType, const vector<PartialUpdateTest::DrawType>& evenFrameDrawType)
612 {
613 	return "odd" + generateDrawTypeName(oddFrameDrawType) + "_even" + generateDrawTypeName(evenFrameDrawType);
614 }
615 
isWindow(const eglu::CandidateConfig & c)616 bool isWindow (const eglu::CandidateConfig& c)
617 {
618 	return (c.surfaceType() & EGL_WINDOW_BIT) == EGL_WINDOW_BIT;
619 }
620 
isES2Renderable(const eglu::CandidateConfig & c)621 bool isES2Renderable (const eglu::CandidateConfig& c)
622 {
623 	return (c.get(EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES2_BIT) == EGL_OPENGL_ES2_BIT;
624 }
625 
getEGLConfig(const Library & egl,EGLDisplay eglDisplay)626 EGLConfig getEGLConfig (const Library& egl, EGLDisplay eglDisplay)
627 {
628 	eglu::FilterList filters;
629 	filters << isWindow << isES2Renderable;
630 	return eglu::chooseSingleConfig(egl, eglDisplay, filters);
631 }
632 
clearColorScreen(const glw::Functions & gl,const tcu::Vec4 & clearColor)633 void 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 
clearColorReference(tcu::Surface * ref,const tcu::Vec4 & clearColor)639 void clearColorReference (tcu::Surface* ref, const tcu::Vec4& clearColor)
640 {
641 	tcu::clear(ref->getAccess(), clearColor);
642 }
643 
readPixels(const glw::Functions & gl,tcu::Surface * screen)644 void 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 
windowToDeviceCoordinates(int x,int length)649 float windowToDeviceCoordinates (int x, int length)
650 {
651 	return (2.0f * float(x) / float(length)) - 1.0f;
652 }
653 
compareToReference(tcu::TestLog & log,const tcu::Surface & reference,const tcu::Surface & buffer,int frameNdx,int bufferNum)654 bool 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 
662 class RenderOutsideDamageRegion : public PartialUpdateTest
663 {
664 public:
665 								RenderOutsideDamageRegion		(EglTestContext& eglTestCtx);
666 	TestCase::IterateResult		iterate							(void);
667 };
668 
RenderOutsideDamageRegion(EglTestContext & eglTestCtx)669 RenderOutsideDamageRegion::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 
iterate(void)674 TestCase::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 
724 class RenderBeforeSetDamageRegion : public PartialUpdateTest
725 {
726 public:
727 								RenderBeforeSetDamageRegion		(EglTestContext& eglTestCtx);
728 	TestCase::IterateResult		iterate							(void);
729 };
730 
RenderBeforeSetDamageRegion(EglTestContext & eglTestCtx)731 RenderBeforeSetDamageRegion::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 
iterate(void)736 TestCase::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 
PartialUpdateTests(EglTestContext & eglTestCtx)787 PartialUpdateTests::PartialUpdateTests (EglTestContext& eglTestCtx)
788 	: TestCaseGroup(eglTestCtx, "partial_update", "Partial update tests")
789 {
790 }
791 
init(void)792 void 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