xref: /aosp_15_r20/external/deqp/modules/egl/teglThreadCleanUpTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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