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 thread clean up tests
22 *//*--------------------------------------------------------------------*/
23
24 #include "teglThreadCleanUpTests.hpp"
25
26 #include "egluUtil.hpp"
27 #include "egluUnique.hpp"
28 #include "egluConfigFilter.hpp"
29
30 #include "eglwLibrary.hpp"
31 #include "eglwEnums.hpp"
32
33 #include "tcuMaybe.hpp"
34 #include "tcuTestLog.hpp"
35
36 #include "deThread.hpp"
37
38 namespace deqp
39 {
40 namespace egl
41 {
42 namespace
43 {
44
45 using namespace eglw;
46 using tcu::TestLog;
47
isES2Renderable(const eglu::CandidateConfig & c)48 bool isES2Renderable(const eglu::CandidateConfig &c)
49 {
50 return (c.get(EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES2_BIT) == EGL_OPENGL_ES2_BIT;
51 }
52
isPBuffer(const eglu::CandidateConfig & c)53 bool isPBuffer(const eglu::CandidateConfig &c)
54 {
55 return (c.surfaceType() & EGL_PBUFFER_BIT) == EGL_PBUFFER_BIT;
56 }
57
58 class Thread : public de::Thread
59 {
60 public:
Thread(const Library & egl,EGLDisplay display,EGLSurface surface,EGLContext context,EGLConfig config,tcu::Maybe<eglu::Error> & error)61 Thread(const Library &egl, EGLDisplay display, EGLSurface surface, EGLContext context, EGLConfig config,
62 tcu::Maybe<eglu::Error> &error)
63 : m_egl(egl)
64 , m_display(display)
65 , m_surface(surface)
66 , m_context(context)
67 , m_config(config)
68 , m_error(error)
69 {
70 }
71
testContext(EGLContext context)72 void testContext(EGLContext context)
73 {
74 if (m_surface != EGL_NO_SURFACE)
75 {
76 EGLU_CHECK_MSG(m_egl, "eglCreateContext");
77 m_egl.makeCurrent(m_display, m_surface, m_surface, context);
78 EGLU_CHECK_MSG(m_egl, "eglMakeCurrent");
79 }
80 else
81 {
82 const EGLint attribs[] = {EGL_WIDTH, 32, EGL_HEIGHT, 32, EGL_NONE};
83 const eglu::UniqueSurface surface(m_egl, m_display,
84 m_egl.createPbufferSurface(m_display, m_config, attribs));
85
86 EGLU_CHECK_MSG(m_egl, "eglCreateContext");
87 m_egl.makeCurrent(m_display, *surface, *surface, context);
88 EGLU_CHECK_MSG(m_egl, "eglMakeCurrent");
89 }
90 }
91
run(void)92 void run(void)
93 {
94 try
95 {
96 const EGLint attribList[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
97
98 m_egl.bindAPI(EGL_OPENGL_ES_API);
99
100 if (m_context == EGL_NO_CONTEXT)
101 {
102 const eglu::UniqueContext context(m_egl, m_display,
103 m_egl.createContext(m_display, m_config, EGL_NO_CONTEXT, attribList));
104
105 testContext(*context);
106 }
107 else
108 {
109 testContext(m_context);
110 }
111 }
112 catch (const eglu::Error &error)
113 {
114 m_error = error;
115 }
116
117 m_egl.releaseThread();
118 }
119
120 private:
121 const Library &m_egl;
122 const EGLDisplay m_display;
123 const EGLSurface m_surface;
124 const EGLContext m_context;
125 const EGLConfig m_config;
126 tcu::Maybe<eglu::Error> &m_error;
127 };
128
129 class ThreadCleanUpTest : public TestCase
130 {
131 public:
132 enum ContextType
133 {
134 CONTEXTTYPE_SINGLE = 0,
135 CONTEXTTYPE_MULTI
136 };
137
138 enum SurfaceType
139 {
140 SURFACETYPE_SINGLE = 0,
141 SURFACETYPE_MULTI
142 };
143
testCaseName(ContextType contextType,SurfaceType surfaceType)144 static std::string testCaseName(ContextType contextType, SurfaceType surfaceType)
145 {
146 std::string name;
147
148 if (contextType == CONTEXTTYPE_SINGLE)
149 name += "single_context_";
150 else
151 name += "multi_context_";
152
153 if (surfaceType == SURFACETYPE_SINGLE)
154 name += "single_surface";
155 else
156 name += "multi_surface";
157
158 return name;
159 }
160
ThreadCleanUpTest(EglTestContext & eglTestCtx,ContextType contextType,SurfaceType surfaceType)161 ThreadCleanUpTest(EglTestContext &eglTestCtx, ContextType contextType, SurfaceType surfaceType)
162 : TestCase(eglTestCtx, testCaseName(contextType, surfaceType).c_str(), "Simple thread context clean up test")
163 , m_contextType(contextType)
164 , m_surfaceType(surfaceType)
165 , m_iterCount(250)
166 , m_iterNdx(0)
167 , m_display(EGL_NO_DISPLAY)
168 , m_config(0)
169 , m_surface(EGL_NO_SURFACE)
170 , m_context(EGL_NO_CONTEXT)
171 {
172 }
173
~ThreadCleanUpTest(void)174 ~ThreadCleanUpTest(void)
175 {
176 deinit();
177 }
178
init(void)179 void init(void)
180 {
181 const Library &egl = m_eglTestCtx.getLibrary();
182
183 m_display = eglu::getAndInitDisplay(m_eglTestCtx.getNativeDisplay());
184
185 {
186 eglu::FilterList filters;
187 filters << isES2Renderable << isPBuffer;
188 m_config = eglu::chooseSingleConfig(egl, m_display, filters);
189 }
190
191 if (m_contextType == CONTEXTTYPE_SINGLE)
192 {
193 const EGLint attribList[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
194
195 egl.bindAPI(EGL_OPENGL_ES_API);
196
197 m_context = egl.createContext(m_display, m_config, EGL_NO_CONTEXT, attribList);
198 EGLU_CHECK_MSG(egl, "Failed to create context");
199 }
200
201 if (m_surfaceType == SURFACETYPE_SINGLE)
202 {
203 const EGLint attribs[] = {EGL_WIDTH, 32, EGL_HEIGHT, 32, EGL_NONE};
204
205 m_surface = egl.createPbufferSurface(m_display, m_config, attribs);
206 EGLU_CHECK_MSG(egl, "Failed to create surface");
207 }
208 }
209
deinit(void)210 void deinit(void)
211 {
212 const Library &egl = m_eglTestCtx.getLibrary();
213
214 if (m_surface != EGL_NO_SURFACE)
215 {
216 egl.destroySurface(m_display, m_surface);
217 m_surface = EGL_NO_SURFACE;
218 }
219
220 if (m_context != EGL_NO_CONTEXT)
221 {
222 egl.destroyContext(m_display, m_context);
223 m_context = EGL_NO_CONTEXT;
224 }
225
226 if (m_display != EGL_NO_DISPLAY)
227 {
228 egl.terminate(m_display);
229 m_display = EGL_NO_DISPLAY;
230 }
231 }
232
iterate(void)233 IterateResult iterate(void)
234 {
235 if (m_iterNdx < m_iterCount)
236 {
237 tcu::Maybe<eglu::Error> error;
238
239 Thread thread(m_eglTestCtx.getLibrary(), m_display, m_surface, m_context, m_config, error);
240
241 thread.start();
242 thread.join();
243
244 if (error)
245 {
246 m_testCtx.getLog() << TestLog::Message << "Failed. Got error: " << error->getMessage()
247 << TestLog::EndMessage;
248 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, error->getMessage());
249 return STOP;
250 }
251
252 m_iterNdx++;
253 return CONTINUE;
254 }
255 else
256 {
257 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
258 return STOP;
259 }
260 }
261
262 private:
263 const ContextType m_contextType;
264 const SurfaceType m_surfaceType;
265 const size_t m_iterCount;
266 size_t m_iterNdx;
267 EGLDisplay m_display;
268 EGLConfig m_config;
269 EGLSurface m_surface;
270 EGLContext m_context;
271 };
272
273 } // namespace
274
createThreadCleanUpTest(EglTestContext & eglTestCtx)275 TestCaseGroup *createThreadCleanUpTest(EglTestContext &eglTestCtx)
276 {
277 de::MovePtr<TestCaseGroup> group(new TestCaseGroup(eglTestCtx, "thread_cleanup", "Thread cleanup tests"));
278
279 group->addChild(new ThreadCleanUpTest(eglTestCtx, ThreadCleanUpTest::CONTEXTTYPE_SINGLE,
280 ThreadCleanUpTest::SURFACETYPE_SINGLE));
281 group->addChild(
282 new ThreadCleanUpTest(eglTestCtx, ThreadCleanUpTest::CONTEXTTYPE_MULTI, ThreadCleanUpTest::SURFACETYPE_SINGLE));
283
284 group->addChild(
285 new ThreadCleanUpTest(eglTestCtx, ThreadCleanUpTest::CONTEXTTYPE_SINGLE, ThreadCleanUpTest::SURFACETYPE_MULTI));
286 group->addChild(
287 new ThreadCleanUpTest(eglTestCtx, ThreadCleanUpTest::CONTEXTTYPE_MULTI, ThreadCleanUpTest::SURFACETYPE_MULTI));
288
289 return group.release();
290 }
291
292 } // namespace egl
293 } // namespace deqp
294