• 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 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 			// tcu does not support degenerate subregions. Since they correspond to no-op rendering, just skip them.
349 			if (coloredRect.bottomLeft.x() == coloredRect.topRight.x() || coloredRect.bottomLeft.y() == coloredRect.topRight.y())
350 				continue;
351 
352 			const tcu::UVec4 color(coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255);
353 			tcu::clear(tcu::getSubregion(target->getAccess(), coloredRect.bottomLeft.x(), coloredRect.bottomLeft.y(),
354 										 coloredRect.topRight.x()-coloredRect.bottomLeft.x(), coloredRect.topRight.y()-coloredRect.bottomLeft.y()), color);
355 		}
356 		else
357 			DE_ASSERT(false);
358 	}
359 }
360 
BufferAgeTest(EglTestContext & eglTestCtx,bool preserveColorBuffer,const vector<DrawType> & oddFrameDrawType,const vector<DrawType> & evenFrameDrawType,ResizeType resizeType,const char * name,const char * description)361 BufferAgeTest::BufferAgeTest (EglTestContext&			eglTestCtx,
362 							  bool						preserveColorBuffer,
363 							  const vector<DrawType>&	oddFrameDrawType,
364 							  const vector<DrawType>&	evenFrameDrawType,
365 							  ResizeType				resizeType,
366 							  const char*				name,
367 							  const char*				description)
368 	: TestCase				(eglTestCtx, name, description)
369 	, m_seed				(deStringHash(name))
370 	, m_preserveColorBuffer (preserveColorBuffer)
371 	, m_oddFrameDrawType	(oddFrameDrawType)
372 	, m_evenFrameDrawType	(evenFrameDrawType)
373 	, m_resizeType			(resizeType)
374 	, m_eglDisplay			(EGL_NO_DISPLAY)
375 	, m_window				(DE_NULL)
376 	, m_eglSurface			(EGL_NO_SURFACE)
377 	, m_eglContext			(EGL_NO_CONTEXT)
378 	, m_gles2Renderer		(DE_NULL)
379 	, m_refRenderer			(DE_NULL)
380 {
381 }
382 
~BufferAgeTest(void)383 BufferAgeTest::~BufferAgeTest (void)
384 {
385 	deinit();
386 }
387 
init(void)388 void BufferAgeTest::init (void)
389 {
390 	const Library&	egl	= m_eglTestCtx.getLibrary();
391 
392 	m_eglDisplay = eglu::getAndInitDisplay(m_eglTestCtx.getNativeDisplay());
393 	m_eglConfig	 = getEGLConfig(m_eglTestCtx.getLibrary(), m_eglDisplay, m_preserveColorBuffer);
394 
395 	if (m_eglConfig == DE_NULL)
396 		TCU_THROW(NotSupportedError, "No supported config found");
397 
398 	//create surface and context and make them current
399 	initEGLSurface(m_eglConfig);
400 	initEGLContext(m_eglConfig);
401 
402 	m_eglTestCtx.initGLFunctions(&m_gl, glu::ApiType::es(2,0));
403 
404 	if (eglu::hasExtension(egl, m_eglDisplay, "EGL_EXT_buffer_age") == false)
405 		TCU_THROW(NotSupportedError, "EGL_EXT_buffer_age is not supported");
406 
407 	m_gles2Renderer = new GLES2Renderer(m_gl);
408 	m_refRenderer   = new ReferenceRenderer();
409 }
410 
deinit(void)411 void BufferAgeTest::deinit (void)
412 {
413 	const Library& egl = m_eglTestCtx.getLibrary();
414 
415 	delete m_refRenderer;
416 	m_refRenderer = DE_NULL;
417 
418 	delete m_gles2Renderer;
419 	m_gles2Renderer = DE_NULL;
420 
421 	if (m_eglContext != EGL_NO_CONTEXT)
422 	{
423 		egl.makeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
424 		egl.destroyContext(m_eglDisplay, m_eglContext);
425 		m_eglContext = EGL_NO_CONTEXT;
426 	}
427 
428 	if (m_eglSurface != EGL_NO_SURFACE)
429 	{
430 		egl.destroySurface(m_eglDisplay, m_eglSurface);
431 		m_eglSurface = EGL_NO_SURFACE;
432 	}
433 
434 	if (m_eglDisplay != EGL_NO_DISPLAY)
435 	{
436 		egl.terminate(m_eglDisplay);
437 		m_eglDisplay = EGL_NO_DISPLAY;
438 	}
439 
440 	delete m_window;
441 	m_window = DE_NULL;
442 }
443 
initEGLSurface(EGLConfig config)444 void BufferAgeTest::initEGLSurface (EGLConfig config)
445 {
446 	const eglu::NativeWindowFactory& factory = eglu::selectNativeWindowFactory(m_eglTestCtx.getNativeDisplayFactory(), m_testCtx.getCommandLine());
447 	m_window = factory.createWindow(&m_eglTestCtx.getNativeDisplay(), m_eglDisplay, config, DE_NULL,
448 									eglu::WindowParams(480, 480, eglu::parseWindowVisibility(m_testCtx.getCommandLine())));
449 	m_eglSurface = eglu::createWindowSurface(m_eglTestCtx.getNativeDisplay(), *m_window, m_eglDisplay, config, DE_NULL);
450 }
451 
initEGLContext(EGLConfig config)452 void BufferAgeTest::initEGLContext (EGLConfig config)
453 {
454 	const Library&	egl			 = m_eglTestCtx.getLibrary();
455 	const EGLint	attribList[] =
456 	{
457 		EGL_CONTEXT_CLIENT_VERSION, 2,
458 		EGL_NONE
459 	};
460 
461 	egl.bindAPI(EGL_OPENGL_ES_API);
462 	m_eglContext = egl.createContext(m_eglDisplay, config, EGL_NO_CONTEXT, attribList);
463 	EGLU_CHECK_MSG(egl, "eglCreateContext");
464 	DE_ASSERT(m_eglSurface != EGL_NO_SURFACE);
465 	egl.makeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext);
466 	EGLU_CHECK_MSG(egl, "eglMakeCurrent");
467 }
468 
469 // return indices of frames that have been written to the given buffer
getFramesOnBuffer(const vector<int> & bufferAges,int frameNdx)470 vector<int> getFramesOnBuffer (const vector<int>& bufferAges, int frameNdx)
471 {
472 	DE_ASSERT(frameNdx < (int)bufferAges.size());
473 	vector<int> frameOnBuffer;
474 	int			age = bufferAges[frameNdx];
475 	while (age != 0)
476 	{
477 		frameNdx = frameNdx - age;
478 		DE_ASSERT(frameNdx >= 0);
479 		frameOnBuffer.push_back(frameNdx);
480 		age = bufferAges[frameNdx];
481 	}
482 
483 	reverse(frameOnBuffer.begin(), frameOnBuffer.end());
484 	return frameOnBuffer;
485 }
486 
iterate(void)487 TestCase::IterateResult BufferAgeTest::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 
502 	if (m_preserveColorBuffer)
503 		EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED));
504 	else
505 		EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED));
506 
507 	for (int frameNdx = 0; frameNdx < numFrames; frameNdx++)
508 	{
509 		tcu::Surface					currentBuffer			(width, height);
510 		tcu::Surface					refBuffer				(width, height);
511 		Frame							newFrame				(width, height);
512 		EGLint							currentBufferAge		= -1;
513 
514 		if (frameNdx % 2 == 0)
515 			generateRandomFrame(&newFrame, m_evenFrameDrawType, rnd);
516 		else
517 			generateRandomFrame(&newFrame, m_oddFrameDrawType, rnd);
518 
519 		frameSequence.push_back(newFrame);
520 
521 		EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_BUFFER_AGE_EXT, &currentBufferAge));
522 
523 		if (currentBufferAge > frameNdx || currentBufferAge < 0) // invalid buffer age
524 		{
525 			std::ostringstream stream;
526 			stream << "Fail, the age is invalid. Age: " << currentBufferAge << ", frameNdx: " << frameNdx;
527 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, stream.str().c_str());
528 			return STOP;
529 		}
530 
531 		if (frameNdx > 0 && m_preserveColorBuffer && currentBufferAge != 1)
532 		{
533 			std::ostringstream stream;
534 			stream << "Fail, EGL_BUFFER_PRESERVED is set to true, but buffer age is: " << currentBufferAge << " (should be 1)";
535 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, stream.str().c_str());
536 			return STOP;
537 		}
538 
539 		bufferAges.push_back(currentBufferAge);
540 		DE_ASSERT((int)bufferAges.size() == frameNdx+1);
541 
542 		// during first half, just keep rendering without reading pixel back to mimic ordinary use case
543 		if (frameNdx < numFrames/2)
544 		{
545 			if (currentBufferAge == 0)
546 				clearColorScreen(m_gl, clearColor);
547 
548 			m_gles2Renderer->render(width, height, newFrame);
549 
550 			if (m_resizeType == RESIZETYPE_BEFORE_SWAP)
551 			{
552 				if (frameNdx % 2 == 0)
553 					m_window->setSurfaceSize(IVec2(width*2, height/2));
554 				else
555 					m_window->setSurfaceSize(IVec2(height/2, width*2));
556 			}
557 
558 			EGLU_CHECK_CALL(egl, swapBuffers(m_eglDisplay, m_eglSurface));
559 
560 			if (m_resizeType == RESIZETYPE_AFTER_SWAP)
561 			{
562 				if (frameNdx % 2 == 0)
563 					m_window->setSurfaceSize(IVec2(width*2, height/2));
564 				else
565 					m_window->setSurfaceSize(IVec2(height/2, width*2));
566 			}
567 
568 			continue;
569 		}
570 
571 		// do verification in the second half
572 		if (currentBufferAge > 0) //buffer contain previous content, need to verify
573 		{
574 			const vector<int> framesOnBuffer = getFramesOnBuffer(bufferAges, frameNdx);
575 			readPixels(m_gl, &currentBuffer);
576 			clearColorReference(&refBuffer, clearColor);
577 
578 			for (vector<int>::const_iterator it = framesOnBuffer.begin(); it != framesOnBuffer.end(); it++)
579 				m_refRenderer->render(&refBuffer, frameSequence[*it]);
580 
581 			if (compareToReference(log, refBuffer, currentBuffer, frameNdx, frameNdx-currentBufferAge) == false)
582 			{
583 				m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail, buffer content is not well preserved when age > 0");
584 				return STOP;
585 			}
586 		}
587 		else // currentBufferAge == 0, content is undefined, clear the buffer, currentBufferAge < 0 is ruled out at the beginning
588 		{
589 			clearColorScreen(m_gl, clearColor);
590 			clearColorReference(&refBuffer, clearColor);
591 		}
592 
593 		m_gles2Renderer->render(width, height, newFrame);
594 		m_refRenderer->render(&refBuffer, newFrame);
595 
596 		readPixels(m_gl, &currentBuffer);
597 
598 		if (compareToReference(log, refBuffer, currentBuffer, frameNdx, frameNdx) == false)
599 		{
600 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail, render result is wrong");
601 			return STOP;
602 		}
603 
604 		if (m_resizeType == RESIZETYPE_BEFORE_SWAP)
605 		{
606 			if (frameNdx % 2 == 0)
607 				m_window->setSurfaceSize(IVec2(width*2, height/2));
608 			else
609 				m_window->setSurfaceSize(IVec2(height/2, width*2));
610 		}
611 
612 		EGLU_CHECK_CALL(egl, swapBuffers(m_eglDisplay, m_eglSurface));
613 
614 		if (m_resizeType == RESIZETYPE_AFTER_SWAP)
615 		{
616 			if (frameNdx % 2 == 0)
617 				m_window->setSurfaceSize(IVec2(width*2, height/2));
618 			else
619 				m_window->setSurfaceSize(IVec2(height/2, width*2));
620 		}
621 	}
622 
623 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
624 	return STOP;
625 }
626 
generateDrawTypeName(const vector<BufferAgeTest::DrawType> & drawTypes)627 string generateDrawTypeName (const vector<BufferAgeTest::DrawType>& drawTypes)
628 {
629 	std::ostringstream stream;
630 	if (drawTypes.size() == 0)
631 		return string("_none");
632 
633 	for (size_t ndx = 0; ndx < drawTypes.size(); ndx++)
634 	{
635 		if (drawTypes[ndx] == BufferAgeTest::DRAWTYPE_GLES2_RENDER)
636 			stream << "_render";
637 		else if (drawTypes[ndx] == BufferAgeTest::DRAWTYPE_GLES2_CLEAR)
638 			stream << "_clear";
639 		else
640 			DE_ASSERT(false);
641 	}
642 	return stream.str();
643 }
644 
generateTestName(const vector<BufferAgeTest::DrawType> & oddFrameDrawType,const vector<BufferAgeTest::DrawType> & evenFrameDrawType)645 string generateTestName (const vector<BufferAgeTest::DrawType>& oddFrameDrawType, const vector<BufferAgeTest::DrawType>& evenFrameDrawType)
646 {
647 	return "odd" + generateDrawTypeName(oddFrameDrawType) + "_even" + generateDrawTypeName(evenFrameDrawType);
648 }
649 
generateResizeGroupName(BufferAgeTest::ResizeType resizeType)650 string generateResizeGroupName (BufferAgeTest::ResizeType resizeType)
651 {
652 	switch (resizeType)
653 	{
654 		case BufferAgeTest::RESIZETYPE_NONE:
655 			return "no_resize";
656 
657 		case BufferAgeTest::RESIZETYPE_AFTER_SWAP:
658 			return "resize_after_swap";
659 
660 		case BufferAgeTest::RESIZETYPE_BEFORE_SWAP:
661 			return "resize_before_swap";
662 
663 		default:
664 			DE_FATAL("Unknown resize type");
665 			return "";
666 	}
667 }
668 
isWindow(const eglu::CandidateConfig & c)669 bool isWindow (const eglu::CandidateConfig& c)
670 {
671 	return (c.surfaceType() & EGL_WINDOW_BIT) == EGL_WINDOW_BIT;
672 }
673 
isES2Renderable(const eglu::CandidateConfig & c)674 bool isES2Renderable (const eglu::CandidateConfig& c)
675 {
676 	return (c.get(EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES2_BIT) == EGL_OPENGL_ES2_BIT;
677 }
678 
hasPreserveSwap(const eglu::CandidateConfig & c)679 bool hasPreserveSwap (const eglu::CandidateConfig& c)
680 {
681 	return (c.surfaceType() & EGL_SWAP_BEHAVIOR_PRESERVED_BIT) == EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
682 }
683 
getEGLConfig(const Library & egl,EGLDisplay eglDisplay,bool preserveColorBuffer)684 EGLConfig getEGLConfig (const Library& egl, EGLDisplay eglDisplay, bool preserveColorBuffer)
685 {
686 	eglu::FilterList filters;
687 	filters << isWindow << isES2Renderable;
688 	if (preserveColorBuffer)
689 		filters << hasPreserveSwap;
690 	return eglu::chooseSingleConfig(egl, eglDisplay, filters);
691 }
692 
clearColorScreen(const glw::Functions & gl,const tcu::Vec4 & clearColor)693 void clearColorScreen (const glw::Functions& gl, const tcu::Vec4& clearColor)
694 {
695 	gl.clearColor(clearColor.x(), clearColor.y(), clearColor.z(), clearColor.w());
696 	gl.clear(GL_COLOR_BUFFER_BIT);
697 }
698 
clearColorReference(tcu::Surface * ref,const tcu::Vec4 & clearColor)699 void clearColorReference (tcu::Surface* ref, const tcu::Vec4& clearColor)
700 {
701 	tcu::clear(ref->getAccess(), clearColor);
702 }
703 
readPixels(const glw::Functions & gl,tcu::Surface * screen)704 void readPixels (const glw::Functions& gl, tcu::Surface* screen)
705 {
706 	gl.readPixels(0, 0, screen->getWidth(), screen->getHeight(),  GL_RGBA, GL_UNSIGNED_BYTE, screen->getAccess().getDataPtr());
707 }
708 
windowToDeviceCoordinates(int x,int length)709 float windowToDeviceCoordinates (int x, int length)
710 {
711 	return (2.0f * float(x) / float(length)) - 1.0f;
712 }
713 
compareToReference(tcu::TestLog & log,const tcu::Surface & reference,const tcu::Surface & buffer,int frameNdx,int bufferNum)714 bool compareToReference (tcu::TestLog& log,	 const tcu::Surface& reference, const tcu::Surface& buffer, int frameNdx, int bufferNum)
715 {
716 	std::ostringstream stream;
717 	stream << "FrameNdx = " << frameNdx << ", compare current buffer (numbered: " << bufferNum << ") to reference";
718 	return tcu::intThresholdPositionDeviationCompare(log, "buffer age test", stream.str().c_str(), reference.getAccess(), buffer.getAccess(),
719 													 tcu::UVec4(8, 8, 8, 0), tcu::IVec3(2,2,0), true, tcu::COMPARE_LOG_RESULT);
720 }
721 
722 } // anonymous
723 
BufferAgeTests(EglTestContext & eglTestCtx)724 BufferAgeTests::BufferAgeTests (EglTestContext& eglTestCtx)
725 	: TestCaseGroup(eglTestCtx, "buffer_age", "Color buffer age tests")
726 {
727 }
728 
init(void)729 void BufferAgeTests::init (void)
730 {
731 	const BufferAgeTest::DrawType clearRender[] =
732 	{
733 		BufferAgeTest::DRAWTYPE_GLES2_CLEAR,
734 		BufferAgeTest::DRAWTYPE_GLES2_RENDER
735 	};
736 
737 	const BufferAgeTest::DrawType renderClear[] =
738 	{
739 		BufferAgeTest::DRAWTYPE_GLES2_RENDER,
740 		BufferAgeTest::DRAWTYPE_GLES2_CLEAR
741 	};
742 
743 	const BufferAgeTest::ResizeType resizeTypes[] =
744 	{
745 		BufferAgeTest::RESIZETYPE_NONE,
746 		BufferAgeTest::RESIZETYPE_BEFORE_SWAP,
747 		BufferAgeTest::RESIZETYPE_AFTER_SWAP
748 	};
749 
750 	vector< vector<BufferAgeTest::DrawType> > frameDrawTypes;
751 	frameDrawTypes.push_back(vector<BufferAgeTest::DrawType> ());
752 	frameDrawTypes.push_back(vector<BufferAgeTest::DrawType> (1, BufferAgeTest::DRAWTYPE_GLES2_CLEAR));
753 	frameDrawTypes.push_back(vector<BufferAgeTest::DrawType> (1, BufferAgeTest::DRAWTYPE_GLES2_RENDER));
754 	frameDrawTypes.push_back(vector<BufferAgeTest::DrawType> (2, BufferAgeTest::DRAWTYPE_GLES2_CLEAR));
755 	frameDrawTypes.push_back(vector<BufferAgeTest::DrawType> (2, BufferAgeTest::DRAWTYPE_GLES2_RENDER));
756 	frameDrawTypes.push_back(vector<BufferAgeTest::DrawType> (DE_ARRAY_BEGIN(clearRender), DE_ARRAY_END(clearRender)));
757 	frameDrawTypes.push_back(vector<BufferAgeTest::DrawType> (DE_ARRAY_BEGIN(renderClear), DE_ARRAY_END(renderClear)));
758 
759 	for (int preserveNdx = 0; preserveNdx < 2; preserveNdx++)
760 	{
761 		const bool				preserve		= (preserveNdx == 0);
762 		TestCaseGroup* const	preserveGroup	= new TestCaseGroup(m_eglTestCtx, (preserve ? "preserve" : "no_preserve"), "");
763 
764 		for (size_t resizeTypeNdx = 0; resizeTypeNdx < DE_LENGTH_OF_ARRAY(resizeTypes); resizeTypeNdx++)
765 		{
766 			const BufferAgeTest::ResizeType	resizeType	= resizeTypes[resizeTypeNdx];
767 			TestCaseGroup* const			resizeGroup	= new TestCaseGroup(m_eglTestCtx, generateResizeGroupName(resizeType).c_str(), "");
768 
769 			for (size_t evenNdx = 0; evenNdx < frameDrawTypes.size(); evenNdx++)
770 			{
771 				const vector<BufferAgeTest::DrawType>& evenFrameDrawType = frameDrawTypes[evenNdx];
772 
773 				for (size_t oddNdx = evenNdx; oddNdx < frameDrawTypes.size(); oddNdx++)
774 				{
775 					const vector<BufferAgeTest::DrawType>&	oddFrameDrawType	= frameDrawTypes[oddNdx];
776 					const std::string						name				= generateTestName(oddFrameDrawType, evenFrameDrawType);
777 					resizeGroup->addChild(new BufferAgeTest(m_eglTestCtx, preserve, oddFrameDrawType, evenFrameDrawType, BufferAgeTest::RESIZETYPE_NONE, name.c_str(), ""));
778 				}
779 			}
780 
781 			preserveGroup->addChild(resizeGroup);
782 		}
783 		addChild(preserveGroup);
784 	}
785 }
786 
787 } // egl
788 } // deqp
789