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 Base class for rendering tests.
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "teglRenderCase.hpp"
     25 
     26 #include "teglSimpleConfigCase.hpp"
     27 
     28 #include "egluNativeDisplay.hpp"
     29 #include "egluNativeWindow.hpp"
     30 #include "egluNativePixmap.hpp"
     31 #include "egluUtil.hpp"
     32 
     33 #include "tcuRenderTarget.hpp"
     34 #include "tcuTestLog.hpp"
     35 #include "tcuCommandLine.hpp"
     36 
     37 #include "deStringUtil.hpp"
     38 #include "deUniquePtr.hpp"
     39 
     40 #include <algorithm>
     41 #include <iterator>
     42 #include <memory>
     43 #include <set>
     44 
     45 #include <EGL/eglext.h>
     46 
     47 #if !defined(EGL_OPENGL_ES3_BIT_KHR)
     48 #	define EGL_OPENGL_ES3_BIT_KHR	0x0040
     49 #endif
     50 #if !defined(EGL_CONTEXT_MAJOR_VERSION_KHR)
     51 #	define EGL_CONTEXT_MAJOR_VERSION_KHR EGL_CONTEXT_CLIENT_VERSION
     52 #endif
     53 
     54 using std::string;
     55 using std::vector;
     56 using std::set;
     57 
     58 using tcu::TestLog;
     59 
     60 namespace deqp
     61 {
     62 namespace egl
     63 {
     64 
     65 // \todo [2013-04-24 pyry] Should we instead store surface bit somewhere?
     66 template<class Derived, class Base>
     67 inline bool instanceOf (Base& obj)
     68 {
     69 	return dynamic_cast<Derived*>(&obj) != DE_NULL;
     70 }
     71 
     72 static void postSurface (tcu::egl::Surface& surface)
     73 {
     74 	const bool	isWindow	= instanceOf<tcu::egl::WindowSurface>(surface);
     75 	const bool	isPixmap	= instanceOf<tcu::egl::PixmapSurface>(surface);
     76 	const bool	isPbuffer	= instanceOf<tcu::egl::PbufferSurface>(surface);
     77 
     78 	DE_ASSERT((isWindow?1:0) + (isPixmap?1:0) + (isPbuffer?1:0) == 1);
     79 
     80 	if (isWindow)
     81 	{
     82 		tcu::egl::WindowSurface& window = static_cast<tcu::egl::WindowSurface&>(surface);
     83 		window.swapBuffers();
     84 	}
     85 	else if (isPixmap)
     86 	{
     87 		TCU_CHECK_EGL_CALL(eglWaitClient());
     88 	}
     89 	else
     90 	{
     91 		DE_ASSERT(isPbuffer);
     92 		DE_UNREF(isPbuffer);
     93 		TCU_CHECK_EGL_CALL(eglWaitClient());
     94 	}
     95 }
     96 
     97 // RenderCase
     98 
     99 RenderCase::RenderCase (EglTestContext& eglTestCtx, const char* name, const char* description, EGLint apiMask, EGLint surfaceTypeMask, const vector<EGLint>& configIds)
    100 	: SimpleConfigCase	(eglTestCtx, name, description, configIds)
    101 	, m_apiMask			(apiMask)
    102 	, m_surfaceTypeMask	(surfaceTypeMask)
    103 {
    104 }
    105 
    106 RenderCase::~RenderCase (void)
    107 {
    108 }
    109 
    110 EGLint RenderCase::getSupportedApis (void)
    111 {
    112 	EGLint apiMask = 0;
    113 
    114 #if defined(DEQP_SUPPORT_GLES2)
    115 	apiMask |= EGL_OPENGL_ES2_BIT;
    116 #endif
    117 
    118 #if defined(DEQP_SUPPORT_GLES3)
    119 	apiMask |= EGL_OPENGL_ES3_BIT_KHR;
    120 #endif
    121 
    122 #if defined(DEQP_SUPPORT_GLES1)
    123 	apiMask |= EGL_OPENGL_ES_BIT;
    124 #endif
    125 
    126 #if defined(DEQP_SUPPORT_VG)
    127 	apiMask |= EGL_OPENVG_BIT;
    128 #endif
    129 
    130 	return apiMask;
    131 }
    132 
    133 void RenderCase::executeForConfig (tcu::egl::Display& defaultDisplay, EGLConfig config)
    134 {
    135 	tcu::TestLog&			log				= m_testCtx.getLog();
    136 	int						width			= 128;
    137 	int						height			= 128;
    138 	EGLint					configId		= defaultDisplay.getConfigAttrib(config, EGL_CONFIG_ID);
    139 	bool					isOk			= true;
    140 	string					failReason		= "";
    141 
    142 	if (m_surfaceTypeMask & EGL_WINDOW_BIT)
    143 	{
    144 		tcu::ScopedLogSection(log, (string("Config") + de::toString(configId) + "-Window").c_str(),
    145 										(string("Config ID ") + de::toString(configId) + ", window surface").c_str());
    146 
    147 		try
    148 		{
    149 			tcu::egl::Display&					display		= m_eglTestCtx.getDisplay();
    150 			de::UniquePtr<eglu::NativeWindow>	window		(m_eglTestCtx.createNativeWindow(display.getEGLDisplay(), config, DE_NULL, width, height, eglu::parseWindowVisibility(m_testCtx.getCommandLine())));
    151 			EGLSurface							eglSurface	= createWindowSurface(m_eglTestCtx.getNativeDisplay(), *window, display.getEGLDisplay(), config, DE_NULL);
    152 			tcu::egl::WindowSurface				surface		(display, eglSurface);
    153 
    154 			executeForSurface(display, surface, config);
    155 		}
    156 		catch (const tcu::TestError& e)
    157 		{
    158 			log << e;
    159 			isOk = false;
    160 			failReason = e.what();
    161 		}
    162 	}
    163 
    164 	if (m_surfaceTypeMask & EGL_PIXMAP_BIT)
    165 	{
    166 		tcu::ScopedLogSection(log, (string("Config") + de::toString(configId) + "-Pixmap").c_str(),
    167 										(string("Config ID ") + de::toString(configId) + ", pixmap surface").c_str());
    168 
    169 		try
    170 		{
    171 			tcu::egl::Display&					display		= m_eglTestCtx.getDisplay();
    172 			std::auto_ptr<eglu::NativePixmap>	pixmap		(m_eglTestCtx.createNativePixmap(display.getEGLDisplay(), config, DE_NULL, width, height));
    173 			EGLSurface							eglSurface	= createPixmapSurface(m_eglTestCtx.getNativeDisplay(), *pixmap, display.getEGLDisplay(), config, DE_NULL);
    174 			tcu::egl::PixmapSurface				surface		(display, eglSurface);
    175 
    176 			executeForSurface(display, surface, config);
    177 		}
    178 		catch (const tcu::TestError& e)
    179 		{
    180 			log << e;
    181 			isOk = false;
    182 			failReason = e.what();
    183 		}
    184 	}
    185 
    186 	if (m_surfaceTypeMask & EGL_PBUFFER_BIT)
    187 	{
    188 		tcu::ScopedLogSection(log, (string("Config") + de::toString(configId) + "-Pbuffer").c_str(),
    189 										(string("Config ID ") + de::toString(configId) + ", pbuffer surface").c_str());
    190 		try
    191 		{
    192 			EGLint surfaceAttribs[] =
    193 			{
    194 				EGL_WIDTH,	width,
    195 				EGL_HEIGHT,	height,
    196 				EGL_NONE
    197 			};
    198 
    199 			tcu::egl::PbufferSurface surface(defaultDisplay, config, surfaceAttribs);
    200 
    201 			executeForSurface(defaultDisplay, surface, config);
    202 		}
    203 		catch (const tcu::TestError& e)
    204 		{
    205 			log << e;
    206 			isOk = false;
    207 			failReason = e.what();
    208 		}
    209 	}
    210 
    211 	if (!isOk && m_testCtx.getTestResult() == QP_TEST_RESULT_PASS)
    212 		m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, failReason.c_str());
    213 }
    214 
    215 // SingleContextRenderCase
    216 
    217 SingleContextRenderCase::SingleContextRenderCase (EglTestContext& eglTestCtx, const char* name, const char* description, EGLint apiMask, EGLint surfaceTypeMask, const std::vector<EGLint>& configIds)
    218 	: RenderCase(eglTestCtx, name, description, apiMask, surfaceTypeMask, configIds)
    219 {
    220 }
    221 
    222 SingleContextRenderCase::~SingleContextRenderCase (void)
    223 {
    224 }
    225 
    226 void SingleContextRenderCase::executeForSurface (tcu::egl::Display& display, tcu::egl::Surface& surface, EGLConfig config)
    227 {
    228 	EGLint				supportedApis	= getSupportedApis();
    229 	const EGLint		apis[]			= { EGL_OPENGL_ES2_BIT, EGL_OPENGL_ES3_BIT_KHR, EGL_OPENGL_ES_BIT, EGL_OPENVG_BIT };
    230 	tcu::TestLog&		log				= m_testCtx.getLog();
    231 
    232 	// Check if case is supported
    233 	if ((m_apiMask & supportedApis) != m_apiMask)
    234 		throw tcu::NotSupportedError("Client APIs not supported", "", __FILE__, __LINE__);
    235 
    236 	for (int apiNdx = 0; apiNdx < DE_LENGTH_OF_ARRAY(apis); apiNdx++)
    237 	{
    238 		EGLint apiBit = apis[apiNdx];
    239 
    240 		if ((apiBit & m_apiMask) == 0)
    241 			continue; // Skip this api.
    242 
    243 		EGLint			api		= EGL_NONE;
    244 		const char*		apiName	= DE_NULL;
    245 		vector<EGLint>	contextAttribs;
    246 
    247 		// Select api enum and build context attributes.
    248 		switch (apiBit)
    249 		{
    250 			case EGL_OPENGL_ES2_BIT:
    251 				api		= EGL_OPENGL_ES_API;
    252 				apiName	= "OpenGL ES 2.x";
    253 				contextAttribs.push_back(EGL_CONTEXT_CLIENT_VERSION);
    254 				contextAttribs.push_back(2);
    255 				break;
    256 
    257 			case EGL_OPENGL_ES3_BIT_KHR:
    258 				api		= EGL_OPENGL_ES_API;
    259 				apiName	= "OpenGL ES 3.x";
    260 				contextAttribs.push_back(EGL_CONTEXT_MAJOR_VERSION_KHR);
    261 				contextAttribs.push_back(3);
    262 				break;
    263 
    264 			case EGL_OPENGL_ES_BIT:
    265 				api		= EGL_OPENGL_ES_API;
    266 				apiName	= "OpenGL ES 1.x";
    267 				contextAttribs.push_back(EGL_CONTEXT_CLIENT_VERSION);
    268 				contextAttribs.push_back(1);
    269 				break;
    270 
    271 			case EGL_OPENVG_BIT:
    272 				api		= EGL_OPENVG_API;
    273 				apiName	= "OpenVG";
    274 				break;
    275 
    276 			default:
    277 				DE_ASSERT(DE_FALSE);
    278 		}
    279 
    280 		contextAttribs.push_back(EGL_NONE);
    281 
    282 		log << TestLog::Message << apiName << TestLog::EndMessage;
    283 
    284 		tcu::egl::Context context(display, config, &contextAttribs[0], api);
    285 
    286 		context.makeCurrent(surface, surface);
    287 		executeForContext(display, context, surface, apiBit);
    288 
    289 		// Call SwapBuffers() / WaitClient() to finish rendering
    290 		postSurface(surface);
    291 	}
    292 }
    293 
    294 // MultiContextRenderCase
    295 
    296 MultiContextRenderCase::MultiContextRenderCase (EglTestContext& eglTestCtx, const char* name, const char* description, EGLint api, EGLint surfaceType, const vector<EGLint>& configIds, int numContextsPerApi)
    297 	: RenderCase			(eglTestCtx, name, description, api, surfaceType, configIds)
    298 	, m_numContextsPerApi	(numContextsPerApi)
    299 {
    300 }
    301 
    302 MultiContextRenderCase::~MultiContextRenderCase (void)
    303 {
    304 }
    305 
    306 void MultiContextRenderCase::executeForSurface (tcu::egl::Display& display, tcu::egl::Surface& surface, EGLConfig config)
    307 {
    308 	vector<std::pair<EGLint, tcu::egl::Context*> > contexts;
    309 	contexts.reserve(3*m_numContextsPerApi); // 3 types of contexts at maximum.
    310 
    311 	try
    312 	{
    313 		// Create contexts that will participate in rendering.
    314 		for (int ndx = 0; ndx < m_numContextsPerApi; ndx++)
    315 		{
    316 			if (m_apiMask & EGL_OPENGL_ES2_BIT)
    317 			{
    318 				static const EGLint attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
    319 				contexts.push_back(std::make_pair(EGL_OPENGL_ES2_BIT, new tcu::egl::Context(display, config, &attribs[0], EGL_OPENGL_ES_API)));
    320 			}
    321 
    322 			if (m_apiMask & EGL_OPENGL_ES3_BIT_KHR)
    323 			{
    324 				static const EGLint attribs[] = { EGL_CONTEXT_MAJOR_VERSION_KHR, 3, EGL_NONE };
    325 				contexts.push_back(std::make_pair(EGL_OPENGL_ES3_BIT_KHR, new tcu::egl::Context(display, config, &attribs[0], EGL_OPENGL_ES_API)));
    326 			}
    327 
    328 			if (m_apiMask & EGL_OPENGL_ES_BIT)
    329 			{
    330 				static const EGLint attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 1, EGL_NONE };
    331 				contexts.push_back(std::make_pair(EGL_OPENGL_ES_BIT, new tcu::egl::Context(display, config, &attribs[0], EGL_OPENGL_ES_API)));
    332 			}
    333 
    334 			if (m_apiMask & EGL_OPENVG_BIT)
    335 			{
    336 				static const EGLint attribs[] = { EGL_NONE };
    337 				contexts.push_back(std::make_pair(EGL_OPENVG_BIT, new tcu::egl::Context(display, config, &attribs[0], EGL_OPENVG_API)));
    338 			}
    339 		}
    340 
    341 		// Execute for contexts.
    342 		executeForContexts(display, surface, config, contexts);
    343 	}
    344 	catch (const std::exception&)
    345 	{
    346 		// Make sure all contexts have been destroyed.
    347 		for (vector<std::pair<EGLint, tcu::egl::Context*> >::iterator i = contexts.begin(); i != contexts.end(); i++)
    348 			delete i->second;
    349 		throw;
    350 	}
    351 
    352 	// Destroy contexts.
    353 	for (vector<std::pair<EGLint, tcu::egl::Context*> >::iterator i = contexts.begin(); i != contexts.end(); i++)
    354 		delete i->second;
    355 }
    356 
    357 // Utilities
    358 
    359 void addRenderConfigIdSet (
    360 	vector<RenderConfigIdSet>&			configSets,
    361 	const vector<eglu::ConfigInfo>&		configInfos,
    362 	const eglu::FilterList&				baseFilters,
    363 	const char*							name,
    364 	tcu::RGBA							colorBits,
    365 	EGLint								surfaceType)
    366 {
    367 	eglu::FilterList filters = baseFilters;
    368 	filters << (eglu::ConfigColorBits() == colorBits) << (eglu::ConfigSurfaceType() & surfaceType);
    369 
    370 	vector<EGLint> matchingConfigs;
    371 
    372 	for (vector<eglu::ConfigInfo>::const_iterator configIter = configInfos.begin(); configIter != configInfos.end(); configIter++)
    373 	{
    374 		if (!filters.match(*configIter))
    375 			continue;
    376 
    377 		matchingConfigs.push_back(configIter->configId);
    378 	}
    379 
    380 	configSets.push_back(RenderConfigIdSet(name, "", matchingConfigs, surfaceType));
    381 }
    382 
    383 void addRenderConfigIdSet (
    384 	vector<RenderConfigIdSet>&			configSets,
    385 	const vector<eglu::ConfigInfo>&		configInfos,
    386 	const eglu::FilterList&				baseFilters,
    387 	const char*							name,
    388 	tcu::RGBA							colorBits)
    389 {
    390 	addRenderConfigIdSet(configSets, configInfos, baseFilters, (string(name) + "_window").c_str(),	colorBits, EGL_WINDOW_BIT);
    391 	addRenderConfigIdSet(configSets, configInfos, baseFilters, (string(name) + "_pixmap").c_str(),	colorBits, EGL_PIXMAP_BIT);
    392 	addRenderConfigIdSet(configSets, configInfos, baseFilters, (string(name) + "_pbuffer").c_str(),	colorBits, EGL_PBUFFER_BIT);
    393 }
    394 
    395 void getDefaultRenderConfigIdSets (vector<RenderConfigIdSet>& configSets, const vector<eglu::ConfigInfo>& configInfos, const eglu::FilterList& baseFilters)
    396 {
    397 	using tcu::RGBA;
    398 
    399 	addRenderConfigIdSet(configSets, configInfos, baseFilters, "rgb565",	RGBA(5, 6, 5, 0));
    400 	addRenderConfigIdSet(configSets, configInfos, baseFilters, "rgb888",	RGBA(8, 8, 8, 0));
    401 	addRenderConfigIdSet(configSets, configInfos, baseFilters, "rgba4444",	RGBA(4, 4, 4, 4));
    402 	addRenderConfigIdSet(configSets, configInfos, baseFilters, "rgba5551",	RGBA(5, 5, 5, 1));
    403 	addRenderConfigIdSet(configSets, configInfos, baseFilters, "rgba8888",	RGBA(8, 8, 8, 8));
    404 
    405 	// Add other config ids to "other" set
    406 	{
    407 		set<EGLint>		usedConfigs;
    408 		vector<EGLint>	otherCfgSet;
    409 
    410 		for (vector<RenderConfigIdSet>::const_iterator setIter = configSets.begin(); setIter != configSets.end(); setIter++)
    411 		{
    412 			const vector<EGLint>& setCfgs = setIter->getConfigIds();
    413 			for (vector<EGLint>::const_iterator i = setCfgs.begin(); i != setCfgs.end(); i++)
    414 				usedConfigs.insert(*i);
    415 		}
    416 
    417 		for (vector<eglu::ConfigInfo>::const_iterator cfgIter = configInfos.begin(); cfgIter != configInfos.end(); cfgIter++)
    418 		{
    419 			if (!baseFilters.match(*cfgIter))
    420 				continue;
    421 
    422 			EGLint id = cfgIter->configId;
    423 
    424 			if (usedConfigs.find(id) == usedConfigs.end())
    425 				otherCfgSet.push_back(id);
    426 		}
    427 
    428 		configSets.push_back(RenderConfigIdSet("other", "", otherCfgSet, EGL_WINDOW_BIT|EGL_PIXMAP_BIT|EGL_PBUFFER_BIT));
    429 	}
    430 }
    431 
    432 } // egl
    433 } // deqp
    434