teglSwapBuffersTests.cpp revision 5f78b1323b6ef28d8b9cdce6fefcbbb61a0477a9
1/*-------------------------------------------------------------------------
2 * drawElements Quality Program EGL Module
3 * ---------------------------------------
4 *
5 * Copyright 2014 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 eglSwapBuffers() interaction with native window.
22 *//*--------------------------------------------------------------------*/
23
24#include "teglSwapBuffersTests.hpp"
25
26#include "teglSimpleConfigCase.hpp"
27
28#include "egluNativeWindow.hpp"
29#include "egluUtil.hpp"
30#include "egluUnique.hpp"
31#include "eglwLibrary.hpp"
32#include "eglwEnums.hpp"
33
34#include "gluDefs.hpp"
35#include "glwEnums.hpp"
36#include "glwFunctions.hpp"
37
38#include "tcuTestLog.hpp"
39#include "tcuSurface.hpp"
40#include "tcuTexture.hpp"
41#include "tcuTextureUtil.hpp"
42#include "tcuImageCompare.hpp"
43#include "tcuVector.hpp"
44#include "tcuVectorUtil.hpp"
45
46#include "deUniquePtr.hpp"
47#include "deThread.hpp"
48
49#include <string>
50#include <vector>
51#include <sstream>
52
53namespace deqp
54{
55namespace egl
56{
57
58using tcu::TestLog;
59using std::string;
60using std::vector;
61using namespace eglw;
62
63namespace
64{
65
66EGLContext createGLES2Context (const Library& egl, EGLDisplay display, EGLConfig config)
67{
68	EGLContext		context = EGL_NO_CONTEXT;
69	const EGLint	attribList[] =
70	{
71		EGL_CONTEXT_CLIENT_VERSION, 2,
72		EGL_NONE
73	};
74
75
76	EGLU_CHECK_CALL(egl, bindAPI(EGL_OPENGL_ES_API));
77
78	context = egl.createContext(display, config, EGL_NO_CONTEXT, attribList);
79	EGLU_CHECK_MSG(egl, "eglCreateContext() failed");
80	TCU_CHECK(context);
81
82	return context;
83}
84
85class SwapBuffersTest : public SimpleConfigCase
86{
87public:
88						SwapBuffersTest		(EglTestContext& eglTestCtx, const NamedFilterList& filters);
89						~SwapBuffersTest	(void);
90
91private:
92	void				executeForConfig	(EGLDisplay display, EGLConfig config);
93
94	// Not allowed
95						SwapBuffersTest		(const SwapBuffersTest&);
96	SwapBuffersTest&	operator=			(const SwapBuffersTest&);
97};
98
99
100SwapBuffersTest::SwapBuffersTest (EglTestContext& eglTestCtx, const NamedFilterList& filters)
101	: SimpleConfigCase(eglTestCtx, filters.getName(), filters.getDescription(), filters)
102{
103}
104
105SwapBuffersTest::~SwapBuffersTest (void)
106{
107}
108
109string getConfigIdString (const Library& egl, EGLDisplay display, EGLConfig config)
110{
111	std::ostringstream	stream;
112	EGLint				id;
113
114	EGLU_CHECK_CALL(egl, getConfigAttrib(display, config , EGL_CONFIG_ID, &id));
115
116	stream << id;
117
118	return stream.str();
119}
120
121deUint32 createGLES2Program (const glw::Functions& gl, TestLog& log)
122{
123	const char* const vertexShaderSource =
124	"attribute highp vec2 a_pos;\n"
125	"void main (void)\n"
126	"{\n"
127	"\tgl_Position = vec4(a_pos, 0.0, 1.0);\n"
128	"}";
129
130	const char* const fragmentShaderSource =
131	"void main (void)\n"
132	"{\n"
133	"\tgl_FragColor = vec4(0.9, 0.1, 0.4, 1.0);\n"
134	"}";
135
136	deUint32	program			= 0;
137	deUint32	vertexShader	= 0;
138	deUint32	fragmentShader	= 0;
139
140	deInt32		vertexCompileStatus;
141	string		vertexInfoLog;
142	deInt32		fragmentCompileStatus;
143	string		fragmentInfoLog;
144	deInt32		linkStatus;
145	string		programInfoLog;
146
147	try
148	{
149		program			= gl.createProgram();
150		vertexShader	= gl.createShader(GL_VERTEX_SHADER);
151		fragmentShader	= gl.createShader(GL_FRAGMENT_SHADER);
152
153		GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to create shaders and program");
154
155		gl.shaderSource(vertexShader, 1, &vertexShaderSource, DE_NULL);
156		gl.compileShader(vertexShader);
157		GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to setup vertex shader");
158
159		gl.shaderSource(fragmentShader, 1, &fragmentShaderSource, DE_NULL);
160		gl.compileShader(fragmentShader);
161		GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to setup fragment shader");
162
163		{
164			deInt32		infoLogLength = 0;
165
166			gl.getShaderiv(vertexShader, GL_COMPILE_STATUS, &vertexCompileStatus);
167			gl.getShaderiv(vertexShader, GL_INFO_LOG_LENGTH, &infoLogLength);
168
169			vertexInfoLog.resize(infoLogLength, '\0');
170
171			gl.getShaderInfoLog(vertexShader, (glw::GLsizei)vertexInfoLog.length(), &infoLogLength, &(vertexInfoLog[0]));
172			GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to get vertex shader compile info");
173
174			vertexInfoLog.resize(infoLogLength);
175		}
176
177		{
178			deInt32		infoLogLength = 0;
179
180			gl.getShaderiv(fragmentShader, GL_COMPILE_STATUS, &fragmentCompileStatus);
181			gl.getShaderiv(fragmentShader, GL_INFO_LOG_LENGTH, &infoLogLength);
182
183			fragmentInfoLog.resize(infoLogLength, '\0');
184
185			gl.getShaderInfoLog(fragmentShader, (glw::GLsizei)fragmentInfoLog.length(), &infoLogLength, &(fragmentInfoLog[0]));
186			GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to get fragment shader compile info");
187
188			fragmentInfoLog.resize(infoLogLength);
189		}
190
191		gl.attachShader(program, vertexShader);
192		gl.attachShader(program, fragmentShader);
193		gl.linkProgram(program);
194		GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to setup program");
195
196		{
197			deInt32		infoLogLength = 0;
198
199			gl.getProgramiv(program, GL_LINK_STATUS, &linkStatus);
200			gl.getProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogLength);
201
202			programInfoLog.resize(infoLogLength, '\0');
203
204			gl.getProgramInfoLog(program, (glw::GLsizei)programInfoLog.length(), &infoLogLength, &(programInfoLog[0]));
205			GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to get program link info");
206
207			programInfoLog.resize(infoLogLength);
208		}
209
210		if (linkStatus == 0 || vertexCompileStatus == 0 || fragmentCompileStatus == 0)
211		{
212
213			log.startShaderProgram(linkStatus != 0, programInfoLog.c_str());
214
215			log << TestLog::Shader(QP_SHADER_TYPE_VERTEX, vertexShaderSource, vertexCompileStatus != 0, vertexInfoLog);
216			log << TestLog::Shader(QP_SHADER_TYPE_FRAGMENT, fragmentShaderSource, fragmentCompileStatus != 0, fragmentInfoLog);
217
218			log.endShaderProgram();
219		}
220
221		gl.deleteShader(vertexShader);
222		gl.deleteShader(fragmentShader);
223		GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to delete shaders");
224
225		TCU_CHECK(linkStatus != 0 && vertexCompileStatus != 0 && fragmentCompileStatus != 0);
226	}
227	catch (...)
228	{
229		if (program)
230			gl.deleteProgram(program);
231
232		if (vertexShader)
233			gl.deleteShader(vertexShader);
234
235		if (fragmentShader)
236			gl.deleteShader(fragmentShader);
237
238		throw;
239	}
240
241	return program;
242}
243
244bool checkColor (tcu::TestLog& log, const tcu::TextureLevel& screen, const tcu::Vec4& color)
245{
246	const tcu::Vec4 threshold(0.01f, 0.01f, 0.01f, 1.00f);
247
248	for (int y = 0; y < screen.getHeight(); y++)
249	{
250		for (int x = 0; x < screen.getWidth(); x++)
251		{
252			const tcu::Vec4	pixel(screen.getAccess().getPixel(x, y));
253			const tcu::Vec4	diff(abs(pixel - color));
254
255			if (!boolAll(lessThanEqual(diff, threshold)))
256			{
257				log << TestLog::Message << "Unexpected color values read from screen expected: " << color << TestLog::EndMessage;
258				log << TestLog::Image("Screen", "Screen", screen.getAccess());
259				return false;
260			}
261		}
262	}
263
264	return true;
265}
266
267void SwapBuffersTest::executeForConfig (EGLDisplay display, EGLConfig config)
268{
269	const Library&						egl			= m_eglTestCtx.getLibrary();
270	const string						configIdStr	(getConfigIdString(egl, display, config));
271	tcu::ScopedLogSection				logSection	(m_testCtx.getLog(), ("Config ID " + configIdStr).c_str(), ("Config ID " + configIdStr).c_str());
272	const int							waitFrames	= 5;
273	const eglu::NativeWindowFactory*	factory		= eglu::selectNativeWindowFactory(m_eglTestCtx.getNativeDisplayFactory(), m_testCtx.getCommandLine());
274
275	if (!factory)
276		TCU_THROW(NotSupportedError, "Windows not supported");
277
278	if ((factory->getCapabilities() & eglu::NativeWindow::CAPABILITY_READ_SCREEN_PIXELS) == 0)
279		TCU_THROW(NotSupportedError, "eglu::NativeWindow doesn't support readScreenPixels()");
280
281	{
282		TestLog& log = m_testCtx.getLog();
283
284		log << TestLog::Message << "EGL_RED_SIZE: "		<< eglu::getConfigAttribInt(egl, display, config, EGL_RED_SIZE)		<< TestLog::EndMessage;
285		log << TestLog::Message << "EGL_GREEN_SIZE: "	<< eglu::getConfigAttribInt(egl, display, config, EGL_GREEN_SIZE)	<< TestLog::EndMessage;
286		log << TestLog::Message << "EGL_BLUE_SIZE: "	<< eglu::getConfigAttribInt(egl, display, config, EGL_BLUE_SIZE)	<< TestLog::EndMessage;
287		log << TestLog::Message << "EGL_ALPHA_SIZE: "	<< eglu::getConfigAttribInt(egl, display, config, EGL_ALPHA_SIZE)	<< TestLog::EndMessage;
288		log << TestLog::Message << "EGL_DEPTH_SIZE: "	<< eglu::getConfigAttribInt(egl, display, config, EGL_DEPTH_SIZE)	<< TestLog::EndMessage;
289		log << TestLog::Message << "EGL_STENCIL_SIZE: "	<< eglu::getConfigAttribInt(egl, display, config, EGL_STENCIL_SIZE)	<< TestLog::EndMessage;
290		log << TestLog::Message << "EGL_SAMPLES: "		<< eglu::getConfigAttribInt(egl, display, config, EGL_SAMPLES)		<< TestLog::EndMessage;
291
292		log << TestLog::Message << "Waiting " << waitFrames * 16 << "ms after eglSwapBuffers() and glFinish() for frame to become visible" << TestLog::EndMessage;
293	}
294
295	de::UniquePtr<eglu::NativeWindow>	window	(factory->createWindow(&m_eglTestCtx.getNativeDisplay(), display, config, DE_NULL, eglu::WindowParams(128, 128, eglu::WindowParams::VISIBILITY_VISIBLE)));
296
297	eglu::UniqueSurface					surface	(egl, display, eglu::createWindowSurface(m_eglTestCtx.getNativeDisplay(), *window, display, config, DE_NULL));
298	eglu::UniqueContext					context	(egl, display, createGLES2Context(egl, display, config));
299	glw::Functions						gl;
300	deUint32							program = 0;
301
302	tcu::TextureLevel					whiteFrame;
303	tcu::TextureLevel					blackFrame;
304	tcu::TextureLevel					frameBegin;
305	tcu::TextureLevel					frameEnd;
306
307	m_eglTestCtx.initGLFunctions(&gl, glu::ApiType::es(2,0));
308	EGLU_CHECK_CALL(egl, makeCurrent(display, *surface, *surface, *context));
309
310	try
311	{
312		const float positions1[] = {
313			 0.00f,  0.00f,
314			 0.75f,  0.00f,
315			 0.75f,  0.75f,
316
317			 0.75f,  0.75f,
318			 0.00f,  0.75f,
319			 0.00f,  0.00f
320		};
321
322		const float positions2[] = {
323			-0.75f, -0.75f,
324			 0.00f, -0.75f,
325			 0.00f,  0.00f,
326
327			 0.00f,  0.00f,
328			-0.75f,  0.00f,
329			-0.75f, -0.75f
330		};
331
332		deUint32 posLocation;
333
334		program	= createGLES2Program(gl, m_testCtx.getLog());
335
336		gl.useProgram(program);
337		posLocation	= gl.getAttribLocation(program, "a_pos");
338		gl.enableVertexAttribArray(posLocation);
339		GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to setup shader program for rendering");
340
341		// Clear screen to white and check that sceen is white
342		gl.clearColor(1.0f, 1.0f, 1.0f, 1.0f);
343		gl.clear(GL_COLOR_BUFFER_BIT);
344		GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to clear surface");
345
346		EGLU_CHECK_CALL(egl, swapBuffers(display, *surface));
347		gl.finish();
348		GLU_EXPECT_NO_ERROR(gl.getError(), "glFinish() failed");
349		deSleep(waitFrames * 16);
350		window->processEvents();
351		window->readScreenPixels(&whiteFrame);
352
353		if (!checkColor(m_testCtx.getLog(), whiteFrame, tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f)))
354		{
355			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Couldn't reliably read pixels from screen");
356			return;
357		}
358
359		// Clear screen to black and check that sceen is black
360		gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f);
361		gl.clear(GL_COLOR_BUFFER_BIT);
362		GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to clear surface");
363
364		EGLU_CHECK_CALL(egl, swapBuffers(display, *surface));
365		gl.finish();
366		GLU_EXPECT_NO_ERROR(gl.getError(), "glFinish() failed");
367		deSleep(waitFrames * 16);
368		window->processEvents();
369		window->readScreenPixels(&blackFrame);
370
371		if (!checkColor(m_testCtx.getLog(), blackFrame, tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f)))
372		{
373			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Couldn't reliably read pixels from screen");
374			return;
375		}
376
377		gl.clearColor(0.7f, 1.0f, 0.3f, 1.0f);
378		gl.clear(GL_COLOR_BUFFER_BIT);
379		GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to clear surface");
380
381		gl.vertexAttribPointer(posLocation, 2, GL_FLOAT, GL_FALSE, 0, positions1);
382		gl.drawArrays(GL_TRIANGLES, 0, 6);
383		GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to render");
384
385		EGLU_CHECK_CALL(egl, swapBuffers(display, *surface));
386		gl.finish();
387		GLU_EXPECT_NO_ERROR(gl.getError(), "glFinish() failed");
388		deSleep(waitFrames * 16);
389		window->processEvents();
390		window->readScreenPixels(&frameBegin);
391
392		gl.clearColor(0.7f, 0.7f, 1.0f, 1.0f);
393		gl.clear(GL_COLOR_BUFFER_BIT);
394		GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to clear surface");
395
396		gl.vertexAttribPointer(posLocation, 2, GL_FLOAT, GL_FALSE, 0, positions2);
397		gl.drawArrays(GL_TRIANGLES, 0, 6);
398		GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to render");
399
400		gl.finish();
401		GLU_EXPECT_NO_ERROR(gl.getError(), "glFinish() failed");
402		deSleep(waitFrames * 16);
403		window->readScreenPixels(&frameEnd);
404
405		EGLU_CHECK_CALL(egl, swapBuffers(display, *surface));
406		gl.finish();
407		GLU_EXPECT_NO_ERROR(gl.getError(), "glFinish() failed");
408		deSleep(waitFrames * 16);
409		window->processEvents();
410
411		gl.disableVertexAttribArray(posLocation);
412		gl.useProgram(0);
413		GLU_EXPECT_NO_ERROR(gl.getError(), "Failed to release program state");
414
415		gl.deleteProgram(program);
416		program = 0;
417		GLU_EXPECT_NO_ERROR(gl.getError(), "glDeleteProgram()");
418
419		if (!tcu::intThresholdCompare(m_testCtx.getLog(), "Compare end of frame against beginning of frame" , "Compare end of frame against beginning of frame", frameBegin.getAccess(), frameEnd.getAccess(), tcu::UVec4(0, 0, 0, 0), tcu::COMPARE_LOG_RESULT))
420			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Screen pixels changed during frame");
421	}
422	catch (...)
423	{
424		if (program != 0)
425			gl.deleteProgram(program);
426
427		EGLU_CHECK_CALL(egl, makeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
428		throw;
429	}
430
431	EGLU_CHECK_CALL(egl, makeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
432}
433
434} // anonymous
435
436SwapBuffersTests::SwapBuffersTests (EglTestContext& eglTestCtx)
437	: TestCaseGroup(eglTestCtx, "swap_buffers", "Swap buffers tests")
438{
439}
440
441static bool isWindow (const eglu::CandidateConfig& c) { return (c.surfaceType() & EGL_WINDOW_BIT) != 0; }
442
443void SwapBuffersTests::init (void)
444{
445	eglu::FilterList baseFilters;
446	baseFilters << isWindow;
447
448	vector<NamedFilterList> filterLists;
449	getDefaultFilterLists(filterLists, baseFilters);
450
451	for (vector<NamedFilterList>::iterator i = filterLists.begin(); i != filterLists.end(); i++)
452		addChild(new SwapBuffersTest(m_eglTestCtx, *i));
453}
454
455} // egl
456} // deqp
457