• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 			// tcu does not support degenerate subregions. Since they correspond to no-op rendering, just skip them.
338 			if (coloredRect.bottomLeft.x() == coloredRect.topRight.x() || coloredRect.bottomLeft.y() == coloredRect.topRight.y())
339 				continue;
340 
341 			const tcu::UVec4 color(coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255);
342 			tcu::clear(tcu::getSubregion(target->getAccess(), coloredRect.bottomLeft.x(), coloredRect.bottomLeft.y(),
343 										 coloredRect.topRight.x()-coloredRect.bottomLeft.x(), coloredRect.topRight.y()-coloredRect.bottomLeft.y()), color);
344 		}
345 		else
346 			DE_FATAL("Invalid drawtype");
347 	}
348 }
349 
PartialUpdateTest(EglTestContext & eglTestCtx,const vector<DrawType> & oddFrameDrawType,const vector<DrawType> & evenFrameDrawType,const char * name,const char * description)350 PartialUpdateTest::PartialUpdateTest (EglTestContext& eglTestCtx,
351 									  const vector<DrawType>& oddFrameDrawType,
352 									  const vector<DrawType>& evenFrameDrawType,
353 									  const char* name, const char* description)
354 	: TestCase				(eglTestCtx, name, description)
355 	, m_window				(DE_NULL)
356 	, m_eglContext			(EGL_NO_CONTEXT)
357 	, m_seed				(deStringHash(name))
358 	, m_oddFrameDrawType	(oddFrameDrawType)
359 	, m_evenFrameDrawType	(evenFrameDrawType)
360 	, m_supportBufferAge	(false)
361 	, m_eglDisplay			(EGL_NO_DISPLAY)
362 	, m_eglSurface			(EGL_NO_SURFACE)
363 	, m_gles2Renderer		(DE_NULL)
364 	, m_refRenderer			(DE_NULL)
365 {
366 }
367 
~PartialUpdateTest(void)368 PartialUpdateTest::~PartialUpdateTest (void)
369 {
370 	deinit();
371 }
372 
init(void)373 void PartialUpdateTest::init (void)
374 {
375 	const Library&	egl	= m_eglTestCtx.getLibrary();
376 
377 	m_eglDisplay		= eglu::getAndInitDisplay(m_eglTestCtx.getNativeDisplay());
378 
379 	if (!eglu::hasExtension(egl, m_eglDisplay, "EGL_KHR_partial_update"))
380 	{
381 		egl.terminate(m_eglDisplay);
382 		m_eglDisplay = EGL_NO_DISPLAY;
383 		TCU_THROW(NotSupportedError, "EGL_KHR_partial_update is not supported");
384 	}
385 
386 	m_eglConfig			= getEGLConfig(m_eglTestCtx.getLibrary(), m_eglDisplay);
387 
388 	//create surface and context and make them current
389 	initEGLSurface(m_eglConfig);
390 	initEGLContext(m_eglConfig);
391 
392 	m_eglTestCtx.initGLFunctions(&m_gl, glu::ApiType::es(2,0));
393 
394 	m_supportBufferAge = eglu::hasExtension(egl, m_eglDisplay, "EGL_EXT_buffer_age");
395 
396 	m_gles2Renderer = new GLES2Renderer(m_gl);
397 	m_refRenderer   = new ReferenceRenderer();
398 }
399 
deinit(void)400 void PartialUpdateTest::deinit (void)
401 {
402 	const Library& egl = m_eglTestCtx.getLibrary();
403 
404 	delete m_refRenderer;
405 	m_refRenderer = DE_NULL;
406 
407 	delete m_gles2Renderer;
408 	m_gles2Renderer = DE_NULL;
409 
410 	if (m_eglContext != EGL_NO_CONTEXT)
411 	{
412 		egl.makeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
413 		egl.destroyContext(m_eglDisplay, m_eglContext);
414 		m_eglContext = EGL_NO_CONTEXT;
415 	}
416 
417 	if (m_eglSurface != EGL_NO_SURFACE)
418 	{
419 		egl.destroySurface(m_eglDisplay, m_eglSurface);
420 		m_eglSurface = EGL_NO_SURFACE;
421 	}
422 
423 	if (m_eglDisplay != EGL_NO_DISPLAY)
424 	{
425 		egl.terminate(m_eglDisplay);
426 		m_eglDisplay = EGL_NO_DISPLAY;
427 	}
428 
429 	delete m_window;
430 	m_window = DE_NULL;
431 }
432 
initEGLSurface(EGLConfig config)433 void PartialUpdateTest::initEGLSurface (EGLConfig config)
434 {
435 	const eglu::NativeWindowFactory& factory = eglu::selectNativeWindowFactory(m_eglTestCtx.getNativeDisplayFactory(), m_testCtx.getCommandLine());
436 	m_window = factory.createWindow(&m_eglTestCtx.getNativeDisplay(), m_eglDisplay, config, DE_NULL,
437 									eglu::WindowParams(480, 480, eglu::parseWindowVisibility(m_testCtx.getCommandLine())));
438 	m_eglSurface = eglu::createWindowSurface(m_eglTestCtx.getNativeDisplay(), *m_window, m_eglDisplay, config, DE_NULL);
439 }
440 
initEGLContext(EGLConfig config)441 void PartialUpdateTest::initEGLContext (EGLConfig config)
442 {
443 	const Library&	egl			 = m_eglTestCtx.getLibrary();
444 	const EGLint	attribList[] =
445 	{
446 		EGL_CONTEXT_CLIENT_VERSION, 2,
447 		EGL_NONE
448 	};
449 
450 	egl.bindAPI(EGL_OPENGL_ES_API);
451 	m_eglContext = egl.createContext(m_eglDisplay, config, EGL_NO_CONTEXT, attribList);
452 	EGLU_CHECK_MSG(egl, "eglCreateContext");
453 	TCU_CHECK(m_eglSurface != EGL_NO_SURFACE);
454 	egl.makeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext);
455 	EGLU_CHECK_MSG(egl, "eglMakeCurrent");
456 }
457 
458 // return indices of frames that have been written to the given buffer
getFramesOnBuffer(const vector<int> & bufferAges,int frameNdx)459 vector<int> getFramesOnBuffer (const vector<int>& bufferAges, int frameNdx)
460 {
461 	DE_ASSERT(frameNdx < (int)bufferAges.size());
462 	vector<int> frameOnBuffer;
463 	int			age = bufferAges[frameNdx];
464 	while (age != 0)
465 	{
466 		frameNdx = frameNdx - age;
467 		DE_ASSERT(frameNdx >= 0);
468 		frameOnBuffer.push_back(frameNdx);
469 		age = bufferAges[frameNdx];
470 	}
471 
472 	reverse(frameOnBuffer.begin(), frameOnBuffer.end());
473 	return frameOnBuffer;
474 }
475 
getDamageRegion(const Frame & frame,int marginLeft,int marginBottom,int marginRight,int marginTop)476 vector<EGLint> getDamageRegion (const Frame& frame, int marginLeft, int marginBottom, int marginRight, int marginTop)
477 {
478 	vector<EGLint> damageRegion;
479 	for (size_t drawNdx = 0; drawNdx < frame.draws.size(); drawNdx++)
480 	{
481 		const ColoredRect& rect = frame.draws[drawNdx].rect;
482 		damageRegion.push_back(rect.bottomLeft.x() - marginLeft);
483 		damageRegion.push_back(rect.bottomLeft.y() - marginBottom);
484 		damageRegion.push_back(rect.topRight.x() - rect.bottomLeft.x() + marginLeft + marginRight);
485 		damageRegion.push_back(rect.topRight.y() - rect.bottomLeft.y() + marginBottom + marginTop);
486 	}
487 
488 	DE_ASSERT(damageRegion.size() % 4 == 0);
489 	return damageRegion;
490 }
491 
iterate(void)492 TestCase::IterateResult PartialUpdateTest::iterate (void)
493 {
494 	de::Random		rnd				(m_seed);
495 	const Library&	egl				= m_eglTestCtx.getLibrary();
496 	tcu::TestLog&	log				= m_testCtx.getLog();
497 	const int		width			= eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_WIDTH);
498 	const int		height			= eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_HEIGHT);
499 	const float		clearRed		= rnd.getFloat();
500 	const float		clearGreen		= rnd.getFloat();
501 	const float		clearBlue		= rnd.getFloat();
502 	const tcu::Vec4	clearColor		(clearRed, clearGreen, clearBlue, 1.0f);
503 	const int		numFrames		= 20;
504 	FrameSequence	frameSequence;
505 	vector<int>		bufferAges;
506 	bool			hasPositiveAge  = false;
507 
508 	EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED));
509 
510 	for (int frameNdx = 0; frameNdx < numFrames; frameNdx++)
511 	{
512 		tcu::Surface	currentBuffer	 (width, height);
513 		tcu::Surface	refBuffer		 (width, height);
514 		Frame			newFrame		 (width, height);
515 		EGLint			currentBufferAge = -1;
516 
517 		if (frameNdx % 2 == 0)
518 			generateRandomFrame(newFrame, m_evenFrameDrawType, rnd);
519 		else
520 			generateRandomFrame(newFrame, m_oddFrameDrawType, rnd);
521 
522 		frameSequence.push_back(newFrame);
523 
524 		EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_BUFFER_AGE_KHR, &currentBufferAge));
525 
526 		if (currentBufferAge > frameNdx || currentBufferAge < 0) // invalid buffer age
527 		{
528 			std::ostringstream stream;
529 			stream << "Fail, the age is invalid. Age: " << currentBufferAge << ", frameNdx: " << frameNdx;
530 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, stream.str().c_str());
531 			return STOP;
532 		}
533 
534 		bufferAges.push_back(currentBufferAge);
535 		DE_ASSERT((int)bufferAges.size() == frameNdx+1);
536 
537 		if (currentBufferAge > 0)
538 		{
539 			vector<EGLint>	damageRegion;
540 
541 			hasPositiveAge = true;
542 
543 			if (m_supportBufferAge)
544 			{
545 				damageRegion = getDamageRegion(newFrame, 10, 10, 10, 10);
546 			}
547 			else
548 			{
549 				damageRegion = getDamageRegion(newFrame, 0, 0, 0, 0);
550 			}
551 
552 			// Set empty damage region to avoid invalidating the framebuffer. The damage area is invalidated
553 			// if the buffer age extension is not supported.
554 			if (damageRegion.size() == 0)
555 				damageRegion = vector<EGLint>(4, 0);
556 
557 			EGLU_CHECK_CALL(egl, setDamageRegionKHR(m_eglDisplay, m_eglSurface, &damageRegion[0], (EGLint)damageRegion.size()/4));
558 		}
559 		else
560 		{
561 			EGLU_CHECK_CALL(egl, setDamageRegionKHR(m_eglDisplay, m_eglSurface, NULL, 0));
562 			clearColorScreen(m_gl, clearColor);
563 		}
564 
565 		// during first half, just keep rendering without reading pixel back to mimic ordinary use case
566 		if (frameNdx < numFrames/2)
567 			m_gles2Renderer->render(width, height, newFrame);
568 		else // do verification in the second half
569 		{
570 			const vector<int> framesOnBuffer = getFramesOnBuffer(bufferAges, frameNdx);
571 
572 			clearColorReference(&refBuffer, clearColor);
573 
574 			for (vector<int>::const_iterator it = framesOnBuffer.begin(); it != framesOnBuffer.end(); it++)
575 				m_refRenderer->render(&refBuffer, frameSequence[*it]);
576 
577 			m_gles2Renderer->render(width, height, newFrame);
578 			m_refRenderer->render(&refBuffer, newFrame);
579 
580 			readPixels(m_gl, &currentBuffer);
581 
582 			if (!compareToReference(log, refBuffer, currentBuffer, frameNdx, frameNdx))
583 			{
584 				string errorMessage("Fail, render result is wrong. Buffer age is ");
585 				errorMessage += (m_supportBufferAge ? "supported" : "not supported");
586 				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, errorMessage.c_str());
587 				return STOP;
588 			}
589 		}
590 		EGLU_CHECK_CALL(egl, swapBuffers(m_eglDisplay, m_eglSurface));
591 	}
592 
593 	if (!hasPositiveAge) // fraud behavior, pretend to support partial_update
594 	{
595 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail, claim to support partial_update but buffer age is always 0");
596 		return STOP;
597 	}
598 
599 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
600 	return STOP;
601 }
602 
generateDrawTypeName(const vector<PartialUpdateTest::DrawType> & drawTypes)603 string generateDrawTypeName (const vector<PartialUpdateTest::DrawType>& drawTypes)
604 {
605 	std::ostringstream stream;
606 	if (drawTypes.size() == 0)
607 		return string("_none");
608 
609 	for (size_t ndx = 0; ndx < drawTypes.size(); ndx++)
610 	{
611 		if (drawTypes[ndx] == PartialUpdateTest::DRAWTYPE_GLES2_RENDER)
612 			stream << "_render";
613 		else if (drawTypes[ndx] == PartialUpdateTest::DRAWTYPE_GLES2_CLEAR)
614 			stream << "_clear";
615 		else
616 			DE_ASSERT(false);
617 	}
618 	return stream.str();
619 }
620 
generateTestName(const vector<PartialUpdateTest::DrawType> & oddFrameDrawType,const vector<PartialUpdateTest::DrawType> & evenFrameDrawType)621 string generateTestName (const vector<PartialUpdateTest::DrawType>& oddFrameDrawType, const vector<PartialUpdateTest::DrawType>& evenFrameDrawType)
622 {
623 	return "odd" + generateDrawTypeName(oddFrameDrawType) + "_even" + generateDrawTypeName(evenFrameDrawType);
624 }
625 
isWindow(const eglu::CandidateConfig & c)626 bool isWindow (const eglu::CandidateConfig& c)
627 {
628 	return (c.surfaceType() & EGL_WINDOW_BIT) == EGL_WINDOW_BIT;
629 }
630 
isES2Renderable(const eglu::CandidateConfig & c)631 bool isES2Renderable (const eglu::CandidateConfig& c)
632 {
633 	return (c.get(EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES2_BIT) == EGL_OPENGL_ES2_BIT;
634 }
635 
getEGLConfig(const Library & egl,EGLDisplay eglDisplay)636 EGLConfig getEGLConfig (const Library& egl, EGLDisplay eglDisplay)
637 {
638 	eglu::FilterList filters;
639 	filters << isWindow << isES2Renderable;
640 	return eglu::chooseSingleConfig(egl, eglDisplay, filters);
641 }
642 
clearColorScreen(const glw::Functions & gl,const tcu::Vec4 & clearColor)643 void clearColorScreen (const glw::Functions& gl, const tcu::Vec4& clearColor)
644 {
645 	gl.clearColor(clearColor.x(), clearColor.y(), clearColor.z(), clearColor.w());
646 	gl.clear(GL_COLOR_BUFFER_BIT);
647 }
648 
clearColorReference(tcu::Surface * ref,const tcu::Vec4 & clearColor)649 void clearColorReference (tcu::Surface* ref, const tcu::Vec4& clearColor)
650 {
651 	tcu::clear(ref->getAccess(), clearColor);
652 }
653 
readPixels(const glw::Functions & gl,tcu::Surface * screen)654 void readPixels (const glw::Functions& gl, tcu::Surface* screen)
655 {
656 	gl.readPixels(0, 0, screen->getWidth(), screen->getHeight(),  GL_RGBA, GL_UNSIGNED_BYTE, screen->getAccess().getDataPtr());
657 }
658 
windowToDeviceCoordinates(int x,int length)659 float windowToDeviceCoordinates (int x, int length)
660 {
661 	return (2.0f * float(x) / float(length)) - 1.0f;
662 }
663 
compareToReference(tcu::TestLog & log,const tcu::Surface & reference,const tcu::Surface & buffer,int frameNdx,int bufferNum)664 bool compareToReference (tcu::TestLog& log,	 const tcu::Surface& reference, const tcu::Surface& buffer, int frameNdx, int bufferNum)
665 {
666 	std::ostringstream stream;
667 	stream << "FrameNdx = " << frameNdx << ", compare current buffer (numbered: " << bufferNum << ") to reference";
668 	return tcu::intThresholdPositionDeviationCompare(log, "partial update test", stream.str().c_str(), reference.getAccess(), buffer.getAccess(),
669 													 tcu::UVec4(8, 8, 8, 0), tcu::IVec3(2,2,0), true, tcu::COMPARE_LOG_RESULT);
670 }
671 
672 class RenderOutsideDamageRegion : public PartialUpdateTest
673 {
674 public:
675 								RenderOutsideDamageRegion		(EglTestContext& eglTestCtx);
676 	TestCase::IterateResult		iterate							(void);
677 };
678 
RenderOutsideDamageRegion(EglTestContext & eglTestCtx)679 RenderOutsideDamageRegion::RenderOutsideDamageRegion (EglTestContext& eglTestCtx)
680 	: PartialUpdateTest (eglTestCtx, vector<DrawType>(1, DRAWTYPE_GLES2_RENDER), vector<DrawType>(1, DRAWTYPE_GLES2_RENDER), "render_outside_damage_region", "")
681 {
682 }
683 
iterate(void)684 TestCase::IterateResult RenderOutsideDamageRegion::iterate (void)
685 {
686 	de::Random			rnd				(m_seed);
687 	const Library&		egl				= m_eglTestCtx.getLibrary();
688 	tcu::TestLog&		log				= m_testCtx.getLog();
689 	const int			width			= eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_WIDTH);
690 	const int			height			= eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_HEIGHT);
691 	const float			clearRed		= rnd.getFloat();
692 	const float			clearGreen		= rnd.getFloat();
693 	const float			clearBlue		= rnd.getFloat();
694 	const tcu::Vec4		clearColor		(clearRed, clearGreen, clearBlue, 1.0f);
695 	tcu::Surface		currentBuffer	(width, height);
696 	tcu::Surface		refBuffer		(width, height);
697 	Frame				frame			(width, height);
698 
699 	EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED));
700 
701 	generateRandomFrame(frame, m_evenFrameDrawType, rnd);
702 
703 	{
704 		// render outside the region
705 		EGLint		   bufferAge	= -1;
706 		vector<EGLint> damageRegion = getDamageRegion(frame, 0, 0, 0, 0);
707 
708 		EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_BUFFER_AGE_KHR, &bufferAge));
709 		EGLU_CHECK_CALL(egl, setDamageRegionKHR(m_eglDisplay, m_eglSurface, &damageRegion[0], (EGLint)damageRegion.size()/4));
710 		clearColorScreen(m_gl, clearColor);
711 		m_gles2Renderer->render(width, height, frame);
712 
713 		// next line will make the bug on Nexus 6 disappear
714 		// readPixels(m_gl, &currentBuffer);
715 	}
716 
717 	EGLU_CHECK_CALL(egl, swapBuffers(m_eglDisplay, m_eglSurface));
718 
719 	// render a new frame
720 	clearColorScreen(m_gl, clearColor);
721 	m_gles2Renderer->render(width, height, frame);
722 	clearColorReference(&refBuffer, clearColor);
723 	m_refRenderer->render(&refBuffer, frame);
724 	readPixels(m_gl, &currentBuffer);
725 
726 	if (!compareToReference(log, refBuffer, currentBuffer, 0, 0))
727 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail, fail to recover after rendering outside damageRegion");
728 	else
729 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
730 
731 	return STOP;
732 }
733 
734 class RenderBeforeSetDamageRegion : public PartialUpdateTest
735 {
736 public:
737 								RenderBeforeSetDamageRegion		(EglTestContext& eglTestCtx);
738 	TestCase::IterateResult		iterate							(void);
739 };
740 
RenderBeforeSetDamageRegion(EglTestContext & eglTestCtx)741 RenderBeforeSetDamageRegion::RenderBeforeSetDamageRegion (EglTestContext& eglTestCtx)
742 	: PartialUpdateTest (eglTestCtx, vector<DrawType>(1, DRAWTYPE_GLES2_RENDER), vector<DrawType>(1, DRAWTYPE_GLES2_RENDER), "render_before_set_damage_region", "")
743 {
744 }
745 
iterate(void)746 TestCase::IterateResult RenderBeforeSetDamageRegion::iterate (void)
747 {
748 	de::Random			rnd				(m_seed);
749 	const Library&		egl				= m_eglTestCtx.getLibrary();
750 	tcu::TestLog&		log				= m_testCtx.getLog();
751 	const int			width			= eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_WIDTH);
752 	const int			height			= eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_HEIGHT);
753 	const float			clearRed		= rnd.getFloat();
754 	const float			clearGreen		= rnd.getFloat();
755 	const float			clearBlue		= rnd.getFloat();
756 	const tcu::Vec4		clearColor		(clearRed, clearGreen, clearBlue, 1.0f);
757 	tcu::Surface		currentBuffer	(width, height);
758 	tcu::Surface		refBuffer		(width, height);
759 	Frame				frame			(width, height);
760 
761 	EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED));
762 
763 	generateRandomFrame(frame, m_evenFrameDrawType, rnd);
764 
765 	{
766 		// render before setDamageRegion
767 		EGLint		   bufferAge	= -1;
768 		vector<EGLint> damageRegion = getDamageRegion(frame, 0, 0, 0, 0);
769 
770 		m_gles2Renderer->render(width, height, frame);
771 		EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_BUFFER_AGE_KHR, &bufferAge));
772 		EGLU_CHECK_CALL(egl, setDamageRegionKHR(m_eglDisplay, m_eglSurface, &damageRegion[0], (EGLint)damageRegion.size()/4));
773 
774 		// next line will make the bug on Nexus 6 disappear
775 		// readPixels(m_gl, &currentBuffer);
776 	}
777 
778 	EGLU_CHECK_CALL(egl, swapBuffers(m_eglDisplay, m_eglSurface));
779 
780 	// render a new frame
781 	clearColorScreen(m_gl, clearColor);
782 	m_gles2Renderer->render(width, height, frame);
783 	clearColorReference(&refBuffer, clearColor);
784 	m_refRenderer->render(&refBuffer, frame);
785 	readPixels(m_gl, &currentBuffer);
786 
787 	if (!compareToReference(log, refBuffer, currentBuffer, 0, 0))
788 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
789 	else
790 		m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
791 
792 	return STOP;
793 }
794 
795 } // anonymous
796 
PartialUpdateTests(EglTestContext & eglTestCtx)797 PartialUpdateTests::PartialUpdateTests (EglTestContext& eglTestCtx)
798 	: TestCaseGroup(eglTestCtx, "partial_update", "Partial update tests")
799 {
800 }
801 
init(void)802 void PartialUpdateTests::init (void)
803 {
804 	const PartialUpdateTest::DrawType clearRender[2] =
805 	{
806 		PartialUpdateTest::DRAWTYPE_GLES2_CLEAR,
807 		PartialUpdateTest::DRAWTYPE_GLES2_RENDER
808 	};
809 
810 	const PartialUpdateTest::DrawType renderClear[2] =
811 	{
812 		PartialUpdateTest::DRAWTYPE_GLES2_RENDER,
813 		PartialUpdateTest::DRAWTYPE_GLES2_CLEAR
814 	};
815 
816 	vector< vector<PartialUpdateTest::DrawType> > frameDrawTypes;
817 	frameDrawTypes.push_back(vector<PartialUpdateTest::DrawType> ());
818 	frameDrawTypes.push_back(vector<PartialUpdateTest::DrawType> (1, PartialUpdateTest::DRAWTYPE_GLES2_CLEAR));
819 	frameDrawTypes.push_back(vector<PartialUpdateTest::DrawType> (1, PartialUpdateTest::DRAWTYPE_GLES2_RENDER));
820 	frameDrawTypes.push_back(vector<PartialUpdateTest::DrawType> (2, PartialUpdateTest::DRAWTYPE_GLES2_CLEAR));
821 	frameDrawTypes.push_back(vector<PartialUpdateTest::DrawType> (2, PartialUpdateTest::DRAWTYPE_GLES2_RENDER));
822 	frameDrawTypes.push_back(vector<PartialUpdateTest::DrawType> (DE_ARRAY_BEGIN(clearRender), DE_ARRAY_END(clearRender)));
823 	frameDrawTypes.push_back(vector<PartialUpdateTest::DrawType> (DE_ARRAY_BEGIN(renderClear), DE_ARRAY_END(renderClear)));
824 
825 	for (size_t evenNdx = 0; evenNdx < frameDrawTypes.size(); evenNdx++)
826 	{
827 		const vector<PartialUpdateTest::DrawType>& evenFrameDrawType = frameDrawTypes[evenNdx];
828 
829 		for (size_t oddNdx = evenNdx; oddNdx < frameDrawTypes.size(); oddNdx++)
830 		{
831 			const vector<PartialUpdateTest::DrawType>&	oddFrameDrawType = frameDrawTypes[oddNdx];
832 			const std::string							name			 = generateTestName(oddFrameDrawType, evenFrameDrawType);
833 			if (oddFrameDrawType.size() == 0 && evenFrameDrawType.size() == 0)
834 				continue;
835 
836 			addChild(new PartialUpdateTest(m_eglTestCtx, oddFrameDrawType, evenFrameDrawType, name.c_str(), ""));
837 		}
838 	}
839 	addChild(new RenderOutsideDamageRegion(m_eglTestCtx));
840 	addChild(new RenderBeforeSetDamageRegion(m_eglTestCtx));
841 }
842 
843 } // egl
844 } // deqp
845