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