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