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