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