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