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