Home | History | Annotate | Download | only in egl
      1 /*-------------------------------------------------------------------------
      2  * drawElements Quality Program EGL Module
      3  * ---------------------------------------
      4  *
      5  * Copyright 2016 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 KHR_mutable_render_buffer
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "teglMutableRenderBufferTests.hpp"
     25 
     26 #include "egluUtil.hpp"
     27 
     28 #include "eglwLibrary.hpp"
     29 #include "eglwEnums.hpp"
     30 
     31 #include "gluDefs.hpp"
     32 #include "gluRenderContext.hpp"
     33 
     34 #include "glwFunctions.hpp"
     35 #include "glwEnums.hpp"
     36 
     37 using namespace eglw;
     38 
     39 using std::vector;
     40 
     41 namespace deqp
     42 {
     43 namespace egl
     44 {
     45 namespace
     46 {
     47 
     48 class MutableRenderBufferTest : public TestCase
     49 {
     50 public:
     51 						MutableRenderBufferTest		(EglTestContext&	eglTestCtx,
     52 													 const char*		name,
     53 													 const char*		description,
     54 													 bool				enableConfigBit);
     55 						~MutableRenderBufferTest	(void);
     56 	void				init						(void);
     57 	void				deinit						(void);
     58 	IterateResult		iterate						(void);
     59 
     60 protected:
     61 	deUint32			drawAndSwap					(const Library&		egl,
     62 													 deUint32			color,
     63 													 bool				flush);
     64 	bool				m_enableConfigBit;
     65 	EGLDisplay			m_eglDisplay;
     66 	EGLSurface			m_eglSurface;
     67 	EGLConfig			m_eglConfig;
     68 	eglu::NativeWindow*	m_window;
     69 	EGLContext			m_eglContext;
     70 	glw::Functions		m_gl;
     71 };
     72 
     73 MutableRenderBufferTest::MutableRenderBufferTest (EglTestContext& eglTestCtx,
     74 												  const char* name, const char* description,
     75 												  bool enableConfigBit)
     76 	: TestCase			(eglTestCtx, name, description)
     77 	, m_enableConfigBit	(enableConfigBit)
     78 	, m_eglDisplay		(EGL_NO_DISPLAY)
     79 	, m_eglSurface		(EGL_NO_SURFACE)
     80 	, m_eglConfig		(DE_NULL)
     81 	, m_window			(DE_NULL)
     82 	, m_eglContext		(EGL_NO_CONTEXT)
     83 {
     84 }
     85 
     86 MutableRenderBufferTest::~MutableRenderBufferTest (void)
     87 {
     88 	deinit();
     89 }
     90 
     91 void MutableRenderBufferTest::init (void)
     92 {
     93 	const Library&	egl	= m_eglTestCtx.getLibrary();
     94 
     95 	// create display
     96 	m_eglDisplay		= eglu::getAndInitDisplay(m_eglTestCtx.getNativeDisplay());
     97 
     98 	if (!eglu::hasExtension(egl, m_eglDisplay, "EGL_KHR_mutable_render_buffer"))
     99 	{
    100 		TCU_THROW(NotSupportedError, "EGL_KHR_mutable_render_buffer is not supported");
    101 	}
    102 
    103 	// get mutable render buffer config
    104 	const EGLint	attribs[]	=
    105 	{
    106         EGL_RED_SIZE,			8,
    107         EGL_GREEN_SIZE,			8,
    108         EGL_BLUE_SIZE,			8,
    109 		EGL_ALPHA_SIZE,			8,
    110 		EGL_SURFACE_TYPE,		EGL_WINDOW_BIT | EGL_MUTABLE_RENDER_BUFFER_BIT_KHR,
    111 		EGL_RENDERABLE_TYPE,	EGL_OPENGL_ES2_BIT,
    112 		EGL_NONE
    113 	};
    114 	const EGLint	attribsNoBit[]	=
    115 	{
    116         EGL_RED_SIZE,			8,
    117         EGL_GREEN_SIZE,			8,
    118         EGL_BLUE_SIZE,			8,
    119 		EGL_ALPHA_SIZE,			8,
    120 		EGL_SURFACE_TYPE,		EGL_WINDOW_BIT,
    121 		EGL_RENDERABLE_TYPE,	EGL_OPENGL_ES2_BIT,
    122 		EGL_NONE
    123 	};
    124 
    125 	if (m_enableConfigBit)
    126 	{
    127 		m_eglConfig = eglu::chooseSingleConfig(egl, m_eglDisplay, attribs);
    128 	}
    129 	else
    130 	{
    131 		const vector<EGLConfig> configs = eglu::chooseConfigs(egl, m_eglDisplay, attribsNoBit);
    132 
    133 		for (vector<EGLConfig>::const_iterator config = configs.begin(); config != configs.end(); ++config)
    134 		{
    135 			EGLint surfaceType = -1;
    136 			EGLU_CHECK_CALL(egl, getConfigAttrib(m_eglDisplay, *config, EGL_SURFACE_TYPE, &surfaceType));
    137 
    138 			if (!(surfaceType & EGL_MUTABLE_RENDER_BUFFER_BIT_KHR))
    139 			{
    140 				m_eglConfig = *config;
    141 				break;
    142 			}
    143 		}
    144 
    145 		if (m_eglConfig == DE_NULL)
    146 			TCU_THROW(NotSupportedError, "No config without support for mutable_render_buffer found");
    147 	}
    148 
    149 	// create surface
    150 	const eglu::NativeWindowFactory& factory = eglu::selectNativeWindowFactory(m_eglTestCtx.getNativeDisplayFactory(), m_testCtx.getCommandLine());
    151 	m_window = factory.createWindow(&m_eglTestCtx.getNativeDisplay(), m_eglDisplay, m_eglConfig, DE_NULL,
    152 									eglu::WindowParams(480, 480, eglu::parseWindowVisibility(m_testCtx.getCommandLine())));
    153 	m_eglSurface = eglu::createWindowSurface(m_eglTestCtx.getNativeDisplay(), *m_window, m_eglDisplay, m_eglConfig, DE_NULL);
    154 
    155 	// create context and make current
    156 	const EGLint	contextAttribList[]	=
    157 	{
    158 		EGL_CONTEXT_CLIENT_VERSION, 2,
    159 		EGL_NONE
    160 	};
    161 
    162 	egl.bindAPI(EGL_OPENGL_ES_API);
    163 	m_eglContext = egl.createContext(m_eglDisplay, m_eglConfig, EGL_NO_CONTEXT, contextAttribList);
    164 	EGLU_CHECK_MSG(egl, "eglCreateContext");
    165 	TCU_CHECK(m_eglSurface != EGL_NO_SURFACE);
    166 	egl.makeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext);
    167 	EGLU_CHECK_MSG(egl, "eglMakeCurrent");
    168 
    169 	m_eglTestCtx.initGLFunctions(&m_gl, glu::ApiType::es(2,0));
    170 }
    171 
    172 void MutableRenderBufferTest::deinit (void)
    173 {
    174 	const Library&	egl	= m_eglTestCtx.getLibrary();
    175 
    176 	if (m_eglContext != EGL_NO_CONTEXT)
    177 	{
    178 		egl.makeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    179 		egl.destroyContext(m_eglDisplay, m_eglContext);
    180 		m_eglContext = EGL_NO_CONTEXT;
    181 	}
    182 
    183 	if (m_eglSurface != EGL_NO_SURFACE)
    184 	{
    185 		egl.destroySurface(m_eglDisplay, m_eglSurface);
    186 		m_eglSurface = EGL_NO_SURFACE;
    187 	}
    188 
    189 	if (m_eglDisplay != EGL_NO_DISPLAY)
    190 	{
    191 		egl.terminate(m_eglDisplay);
    192 		m_eglDisplay = EGL_NO_DISPLAY;
    193 	}
    194 
    195 	if (m_window != DE_NULL)
    196 	{
    197 		delete m_window;
    198 		m_window = DE_NULL;
    199 	}
    200 }
    201 
    202 deUint32 MutableRenderBufferTest::drawAndSwap (const Library& egl, deUint32 color, bool flush)
    203 {
    204 	DE_ASSERT(color < 256);
    205 	m_gl.clearColor((float)color/255.f, (float)color/255.f, (float)color/255.f, (float)color/255.f);
    206 	m_gl.clear(GL_COLOR_BUFFER_BIT);
    207 	if (flush)
    208 	{
    209 		m_gl.flush();
    210 	}
    211 	else
    212 	{
    213 		EGLU_CHECK_CALL(egl, swapBuffers(m_eglDisplay, m_eglSurface));
    214 	}
    215 	return (color | color << 8 | color << 16 | color << 24);
    216 }
    217 
    218 TestCase::IterateResult MutableRenderBufferTest::iterate (void)
    219 {
    220 	const Library&	egl	= m_eglTestCtx.getLibrary();
    221 
    222 	int frameNumber = 1;
    223 
    224 	// run a few back-buffered frames even if we can't verify their contents
    225 	for (; frameNumber < 5; frameNumber++)
    226 	{
    227 		drawAndSwap(egl, frameNumber, false);
    228 	}
    229 
    230 	// switch to single-buffer rendering
    231 	EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER));
    232 
    233 	// Use eglSwapBuffers for the first frame
    234 	drawAndSwap(egl, frameNumber, false);
    235 	frameNumber++;
    236 
    237 	// test a few single-buffered frames
    238 	for (; frameNumber < 10; frameNumber++)
    239 	{
    240 		deUint32 backBufferPixel = 0xFFFFFFFF;
    241 		deUint32 frontBufferPixel = drawAndSwap(egl, frameNumber, true);
    242 		m_gl.readPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &backBufferPixel);
    243 
    244 		// when single buffered, front-buffer == back-buffer
    245 		if (backBufferPixel != frontBufferPixel)
    246 		{
    247 			m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Surface isn't single-buffered");
    248 			return STOP;
    249 		}
    250 	}
    251 
    252 	// switch back to back-buffer rendering
    253 	EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_RENDER_BUFFER, EGL_BACK_BUFFER));
    254 
    255 	// run a few back-buffered frames even if we can't verify their contents
    256 	for (; frameNumber < 14; frameNumber++)
    257 	{
    258 		drawAndSwap(egl, frameNumber, false);
    259 	}
    260 
    261 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    262 	return STOP;
    263 }
    264 
    265 class MutableRenderBufferQueryTest : public MutableRenderBufferTest
    266 {
    267 public:
    268 						MutableRenderBufferQueryTest	(EglTestContext&	eglTestCtx,
    269 														 const char*		name,
    270 														 const char*		description);
    271 						~MutableRenderBufferQueryTest	(void);
    272 	IterateResult		iterate							(void);
    273 };
    274 
    275 MutableRenderBufferQueryTest::MutableRenderBufferQueryTest (EglTestContext& eglTestCtx,
    276 															const char* name, const char* description)
    277 	: MutableRenderBufferTest	(eglTestCtx, name, description, true)
    278 {
    279 }
    280 
    281 MutableRenderBufferQueryTest::~MutableRenderBufferQueryTest (void)
    282 {
    283 	deinit();
    284 }
    285 
    286 TestCase::IterateResult MutableRenderBufferQueryTest::iterate (void)
    287 {
    288 	const Library&	egl	= m_eglTestCtx.getLibrary();
    289 
    290 	// check that by default the query returns back buffered
    291 	EGLint curRenderBuffer = -1;
    292 	EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_RENDER_BUFFER, &curRenderBuffer));
    293 	if (curRenderBuffer != EGL_BACK_BUFFER)
    294 	{
    295 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Surface didn't default to back-buffered rendering");
    296 		return STOP;
    297 	}
    298 
    299 	// switch to single-buffer rendering and check that the query output changed
    300 	EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER));
    301 	EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_RENDER_BUFFER, &curRenderBuffer));
    302 	if (curRenderBuffer != EGL_SINGLE_BUFFER)
    303 	{
    304 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Surface didn't switch to single-buffer rendering");
    305 		return STOP;
    306 	}
    307 
    308 	// switch back to back-buffer rendering and check the query again
    309 	EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_RENDER_BUFFER, EGL_BACK_BUFFER));
    310 	EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_RENDER_BUFFER, &curRenderBuffer));
    311 	if (curRenderBuffer != EGL_BACK_BUFFER)
    312 	{
    313 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Surface didn't switch back to back-buffer rendering");
    314 		return STOP;
    315 	}
    316 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    317 	return STOP;
    318 }
    319 
    320 class MutableRenderBufferQueryNegativeTest : public MutableRenderBufferTest
    321 {
    322 public:
    323 						MutableRenderBufferQueryNegativeTest	(EglTestContext&	eglTestCtx,
    324 																 const char*		name,
    325 																 const char*		description);
    326 						~MutableRenderBufferQueryNegativeTest	(void);
    327 	IterateResult		iterate									(void);
    328 };
    329 
    330 MutableRenderBufferQueryNegativeTest::MutableRenderBufferQueryNegativeTest (EglTestContext& eglTestCtx,
    331 															const char* name, const char* description)
    332 	: MutableRenderBufferTest	(eglTestCtx, name, description, false)
    333 {
    334 }
    335 
    336 MutableRenderBufferQueryNegativeTest::~MutableRenderBufferQueryNegativeTest (void)
    337 {
    338 	deinit();
    339 }
    340 
    341 TestCase::IterateResult MutableRenderBufferQueryNegativeTest::iterate (void)
    342 {
    343 	const Library&	egl	= m_eglTestCtx.getLibrary();
    344 
    345 	// check that by default the query returns back buffered
    346 	EGLint curRenderBuffer = -1;
    347 	EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_RENDER_BUFFER, &curRenderBuffer));
    348 	if (curRenderBuffer != EGL_BACK_BUFFER)
    349 	{
    350 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Surface didn't default to back-buffered rendering");
    351 		return STOP;
    352 	}
    353 
    354 	// check that trying to switch to single-buffer rendering fails when the config bit is not set
    355 	EGLBoolean ret = egl.surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER);
    356 	EGLint err = egl.getError();
    357 	if (ret != EGL_FALSE)
    358 	{
    359 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL,
    360 			"eglSurfaceAttrib didn't return false when trying to enable single-buffering on a context without the mutable render buffer bit set");
    361 		return STOP;
    362 	}
    363 	if (err != EGL_BAD_MATCH)
    364 	{
    365 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL,
    366 			"eglSurfaceAttrib didn't set the EGL_BAD_MATCH error when trying to enable single-buffering on a context without the mutable render buffer bit set");
    367 		return STOP;
    368 	}
    369 
    370     EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_RENDER_BUFFER, &curRenderBuffer));
    371     if (curRenderBuffer != EGL_BACK_BUFFER)
    372     {
    373         m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Surface didn't stay in back-buffered rendering after error");
    374         return STOP;
    375     }
    376 
    377 	m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
    378 	return STOP;
    379 }
    380 
    381 } // anonymous
    382 
    383 MutableRenderBufferTests::MutableRenderBufferTests (EglTestContext& eglTestCtx)
    384 	: TestCaseGroup(eglTestCtx, "mutable_render_buffer", "Mutable render buffer tests")
    385 {
    386 }
    387 
    388 void MutableRenderBufferTests::init (void)
    389 {
    390 	addChild(new MutableRenderBufferQueryTest(m_eglTestCtx, "querySurface",
    391 		"Tests if querySurface returns the correct value after surfaceAttrib is called"));
    392 	addChild(new MutableRenderBufferQueryNegativeTest(m_eglTestCtx, "negativeConfigBit",
    393 		"Tests trying to enable single-buffering on a context without the mutable render buffer bit set"));
    394 	addChild(new MutableRenderBufferTest(m_eglTestCtx, "basic",
    395 		"Tests enabling/disabling single-buffer rendering and checks the buffering behavior", true));
    396 }
    397 
    398 } // egl
    399 } // deqp
    400