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 EGL multi context tests
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "teglMultiContextTests.hpp"
     25 
     26 #include "egluUtil.hpp"
     27 #include "egluUnique.hpp"
     28 #include "egluStrUtil.hpp"
     29 #include "egluConfigFilter.hpp"
     30 
     31 #include "eglwLibrary.hpp"
     32 #include "eglwEnums.hpp"
     33 
     34 #include "gluDefs.hpp"
     35 
     36 #include "glwFunctions.hpp"
     37 #include "glwEnums.hpp"
     38 
     39 #include "tcuResultCollector.hpp"
     40 #include "tcuTestLog.hpp"
     41 
     42 #include "deRandom.hpp"
     43 
     44 #include <vector>
     45 
     46 namespace deqp
     47 {
     48 namespace egl
     49 {
     50 namespace
     51 {
     52 
     53 using tcu::TestLog;
     54 
     55 class MultiContextTest : public TestCase
     56 {
     57 public:
     58 	enum Use
     59 	{
     60 		USE_NONE = 0,
     61 		USE_MAKECURRENT,
     62 		USE_CLEAR,
     63 
     64 		USE_LAST
     65 	};
     66 
     67 	enum Sharing
     68 	{
     69 		SHARING_NONE = 0,
     70 		SHARING_SHARED,
     71 		SHARING_LAST
     72 	};
     73 					MultiContextTest	(EglTestContext& eglTestCtx, Sharing sharing, Use use, const char* name, const char* description);
     74 
     75 	IterateResult	iterate				(void);
     76 
     77 private:
     78 	const Sharing	m_sharing;
     79 	const Use		m_use;
     80 };
     81 
     82 MultiContextTest::MultiContextTest (EglTestContext& eglTestCtx, Sharing sharing, Use use, const char* name, const char* description)
     83 	: TestCase	(eglTestCtx, name, description)
     84 	, m_sharing	(sharing)
     85 	, m_use		(use)
     86 {
     87 }
     88 
     89 bool isES2Renderable (const eglu::CandidateConfig& c)
     90 {
     91 	return (c.get(EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES2_BIT) == EGL_OPENGL_ES2_BIT;
     92 }
     93 
     94 bool supportsPBuffer (const eglu::CandidateConfig& c)
     95 {
     96 	return (c.get(EGL_SURFACE_TYPE) & EGL_PBUFFER_BIT) == EGL_PBUFFER_BIT;
     97 }
     98 
     99 eglw::EGLConfig getConfig (const eglw::Library& egl, eglw::EGLDisplay display)
    100 {
    101 	eglu::FilterList filters;
    102 	filters << isES2Renderable;
    103 	filters << supportsPBuffer;
    104 	return eglu::chooseSingleConfig(egl, display, filters);
    105 }
    106 
    107 tcu::TestCase::IterateResult MultiContextTest::iterate (void)
    108 {
    109 	const deUint32					seed			= m_sharing == SHARING_SHARED ? 2498541716u : 8825414;
    110 	const size_t					maxContextCount	= 128;
    111 	const size_t					minContextCount	= 32;
    112 	const eglw::EGLint				attribList[]	=
    113 	{
    114 		EGL_CONTEXT_CLIENT_VERSION, 2,
    115 		EGL_NONE
    116 	};
    117 	const eglw::EGLint				pbufferAttribList[]	=
    118 	{
    119 		EGL_WIDTH,	64,
    120 		EGL_HEIGHT,	64,
    121 		EGL_NONE
    122 	};
    123 
    124 	TestLog&						log				= m_testCtx.getLog();
    125 	tcu::ResultCollector			resultCollector	(log);
    126 	de::Random						rng				(seed);
    127 
    128 	const eglw::Library&			egl				= m_eglTestCtx.getLibrary();
    129 	const eglu::UniqueDisplay		display			(egl, eglu::getAndInitDisplay(m_eglTestCtx.getNativeDisplay()));
    130 	const eglw::EGLConfig			config			= getConfig(egl, *display);
    131 
    132 	const eglu::UniqueSurface		surface			(egl, *display, m_use != USE_NONE ? egl.createPbufferSurface(*display, config, pbufferAttribList) : EGL_NO_SURFACE);
    133 	EGLU_CHECK_MSG(egl, "Failed to create pbuffer.");
    134 
    135 	std::vector<eglw::EGLContext>	contexts;
    136 	glw::Functions					gl;
    137 
    138 	contexts.reserve(maxContextCount);
    139 
    140 	log << TestLog::Message << "Trying to create " << maxContextCount << (m_sharing == SHARING_SHARED ? " shared " : " ") << "contexts." << TestLog::EndMessage;
    141 	log << TestLog::Message << "Requiring that at least " << minContextCount << " contexts can be created." << TestLog::EndMessage;
    142 
    143 	if (m_use == USE_CLEAR)
    144 		m_eglTestCtx.initGLFunctions(&gl, glu::ApiType::es(2,0));
    145 
    146 	EGLU_CHECK_CALL(egl, bindAPI(EGL_OPENGL_ES_API));
    147 
    148 	try
    149 	{
    150 		for (size_t contextCount = 0; contextCount < maxContextCount; contextCount++)
    151 		{
    152 			const eglw::EGLContext	sharedContext	= (m_sharing == SHARING_SHARED && contextCount > 0 ? contexts[rng.getUint32() % (deUint32)contextCount] : EGL_NO_CONTEXT);
    153 			const eglw::EGLContext	context			= egl.createContext(*display, config, sharedContext, attribList);
    154 			const eglw::EGLint		error			= egl.getError();
    155 
    156 			if (context == EGL_NO_CONTEXT || error != EGL_SUCCESS)
    157 			{
    158 				log << TestLog::Message << "Got error after creating " << contextCount << " contexts." << TestLog::EndMessage;
    159 
    160 				if (error == EGL_BAD_ALLOC)
    161 				{
    162 					if (contextCount < minContextCount)
    163 						resultCollector.fail("Couldn't create the minimum number of contexts required.");
    164 					else
    165 						log << TestLog::Message << "Got EGL_BAD_ALLOC." << TestLog::EndMessage;
    166 				}
    167 				else
    168 					resultCollector.fail("eglCreateContext() produced error that is not EGL_BAD_ALLOC: " + eglu::getErrorStr(error).toString());
    169 
    170 				if (context != EGL_NO_CONTEXT)
    171 					resultCollector.fail("eglCreateContext() produced error, but context is not EGL_NO_CONTEXT");
    172 
    173 				break;
    174 			}
    175 			else
    176 			{
    177 				contexts.push_back(context);
    178 
    179 				if (m_use == USE_MAKECURRENT || m_use == USE_CLEAR)
    180 				{
    181 					const eglw::EGLBoolean	result				= egl.makeCurrent(*display, *surface, *surface, context);
    182 					const eglw::EGLint		makeCurrentError	= egl.getError();
    183 
    184 					if (!result || makeCurrentError != EGL_SUCCESS)
    185 					{
    186 						log << TestLog::Message << "Failed to make " << (contextCount + 1) << "th context current: " << eglu::getErrorStr(makeCurrentError) << TestLog::EndMessage;
    187 						resultCollector.fail("Failed to make context current");
    188 
    189 						break;
    190 					}
    191 					else if (m_use == USE_CLEAR)
    192 					{
    193 						gl.clearColor(0.25f, 0.75f, 0.50f, 1.00f);
    194 						gl.clear(GL_COLOR_BUFFER_BIT);
    195 						gl.finish();
    196 						GLU_CHECK_GLW_MSG(gl, "Failed to clear color.");
    197 					}
    198 				}
    199 			}
    200 		}
    201 
    202 		for (size_t contextNdx = 0; contextNdx < contexts.size(); contextNdx++)
    203 		{
    204 			EGLU_CHECK_CALL(egl, destroyContext(*display, contexts[contextNdx]));
    205 			contexts[contextNdx] = EGL_NO_CONTEXT;
    206 		}
    207 
    208 		if (m_use == USE_MAKECURRENT || m_use == USE_CLEAR)
    209 			EGLU_CHECK_CALL(egl, makeCurrent(*display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
    210 	}
    211 	catch (...)
    212 	{
    213 		for (size_t contextNdx = 0; contextNdx < contexts.size(); contextNdx++)
    214 		{
    215 			if (contexts[contextNdx] != EGL_NO_CONTEXT)
    216 				EGLU_CHECK_CALL(egl, destroyContext(*display, contexts[contextNdx]));
    217 		}
    218 
    219 		if (m_use == USE_MAKECURRENT || m_use == USE_CLEAR)
    220 			EGLU_CHECK_CALL(egl, makeCurrent(*display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
    221 
    222 		throw;
    223 	}
    224 
    225 	resultCollector.setTestContextResult(m_testCtx);
    226 	return STOP;
    227 }
    228 
    229 } // anonymous
    230 
    231 TestCaseGroup* createMultiContextTests (EglTestContext& eglTestCtx)
    232 {
    233 	de::MovePtr<TestCaseGroup> group (new TestCaseGroup(eglTestCtx, "multicontext", "EGL multi context tests."));
    234 
    235 	group->addChild(new MultiContextTest(eglTestCtx, MultiContextTest::SHARING_NONE,	MultiContextTest::USE_NONE,			"non_shared",				"Create multiple non-shared contexts."));
    236 	group->addChild(new MultiContextTest(eglTestCtx, MultiContextTest::SHARING_SHARED,	MultiContextTest::USE_NONE,			"shared",					"Create multiple shared contexts."));
    237 
    238 	group->addChild(new MultiContextTest(eglTestCtx, MultiContextTest::SHARING_NONE,	MultiContextTest::USE_MAKECURRENT,	"non_shared_make_current",	"Create multiple non-shared contexts."));
    239 	group->addChild(new MultiContextTest(eglTestCtx, MultiContextTest::SHARING_SHARED,	MultiContextTest::USE_MAKECURRENT,	"shared_make_current",		"Create multiple shared contexts."));
    240 
    241 	group->addChild(new MultiContextTest(eglTestCtx, MultiContextTest::SHARING_NONE,	MultiContextTest::USE_CLEAR,		"non_shared_clear",			"Create multiple non-shared contexts."));
    242 	group->addChild(new MultiContextTest(eglTestCtx, MultiContextTest::SHARING_SHARED,	MultiContextTest::USE_CLEAR,		"shared_clear",				"Create multiple shared contexts."));
    243 
    244 	return group.release();
    245 }
    246 
    247 } // egl
    248 } // deqp
    249