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 
MultiContextTest(EglTestContext & eglTestCtx,Sharing sharing,Use use,const char * name,const char * description)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 
isES2Renderable(const eglu::CandidateConfig & c)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 
supportsPBuffer(const eglu::CandidateConfig & c)94 bool supportsPBuffer (const eglu::CandidateConfig& c)
95 {
96 	return (c.get(EGL_SURFACE_TYPE) & EGL_PBUFFER_BIT) == EGL_PBUFFER_BIT;
97 }
98 
getConfig(const eglw::Library & egl,eglw::EGLDisplay display)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 
iterate(void)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 
createMultiContextTests(EglTestContext & eglTestCtx)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