xref: /aosp_15_r20/external/deqp/modules/egl/teglMultiContextTests.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 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,
83                                    const char *description)
84     : TestCase(eglTestCtx, name, description)
85     , m_sharing(sharing)
86     , m_use(use)
87 {
88 }
89 
isES2Renderable(const eglu::CandidateConfig & c)90 bool isES2Renderable(const eglu::CandidateConfig &c)
91 {
92     return (c.get(EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES2_BIT) == EGL_OPENGL_ES2_BIT;
93 }
94 
supportsPBuffer(const eglu::CandidateConfig & c)95 bool supportsPBuffer(const eglu::CandidateConfig &c)
96 {
97     return (c.get(EGL_SURFACE_TYPE) & EGL_PBUFFER_BIT) == EGL_PBUFFER_BIT;
98 }
99 
getConfig(const eglw::Library & egl,eglw::EGLDisplay display)100 eglw::EGLConfig getConfig(const eglw::Library &egl, eglw::EGLDisplay display)
101 {
102     eglu::FilterList filters;
103     filters << isES2Renderable;
104     filters << supportsPBuffer;
105     return eglu::chooseSingleConfig(egl, display, filters);
106 }
107 
iterate(void)108 tcu::TestCase::IterateResult MultiContextTest::iterate(void)
109 {
110     const uint32_t seed                    = m_sharing == SHARING_SHARED ? 2498541716u : 8825414;
111     const size_t maxContextCount           = 128;
112     const size_t minContextCount           = 32;
113     const eglw::EGLint attribList[]        = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
114     const eglw::EGLint pbufferAttribList[] = {EGL_WIDTH, 64, EGL_HEIGHT, 64, EGL_NONE};
115 
116     TestLog &log = m_testCtx.getLog();
117     tcu::ResultCollector resultCollector(log);
118     de::Random rng(seed);
119 
120     const eglw::Library &egl = m_eglTestCtx.getLibrary();
121     const eglu::UniqueDisplay display(egl, eglu::getAndInitDisplay(m_eglTestCtx.getNativeDisplay()));
122     const eglw::EGLConfig config = getConfig(egl, *display);
123 
124     const eglu::UniqueSurface surface(
125         egl, *display,
126         m_use != USE_NONE ? egl.createPbufferSurface(*display, config, pbufferAttribList) : EGL_NO_SURFACE);
127     EGLU_CHECK_MSG(egl, "Failed to create pbuffer.");
128 
129     std::vector<eglw::EGLContext> contexts;
130     glw::Functions gl;
131 
132     contexts.reserve(maxContextCount);
133 
134     log << TestLog::Message << "Trying to create " << maxContextCount
135         << (m_sharing == SHARING_SHARED ? " shared " : " ") << "contexts." << TestLog::EndMessage;
136     log << TestLog::Message << "Requiring that at least " << minContextCount << " contexts can be created."
137         << TestLog::EndMessage;
138 
139     if (m_use == USE_CLEAR)
140         m_eglTestCtx.initGLFunctions(&gl, glu::ApiType::es(2, 0));
141 
142     EGLU_CHECK_CALL(egl, bindAPI(EGL_OPENGL_ES_API));
143 
144     try
145     {
146         for (size_t contextCount = 0; contextCount < maxContextCount; contextCount++)
147         {
148             const eglw::EGLContext sharedContext =
149                 (m_sharing == SHARING_SHARED && contextCount > 0 ? contexts[rng.getUint32() % (uint32_t)contextCount] :
150                                                                    EGL_NO_CONTEXT);
151             const eglw::EGLContext context = egl.createContext(*display, config, sharedContext, attribList);
152             const eglw::EGLint error       = egl.getError();
153 
154             if (context == EGL_NO_CONTEXT || error != EGL_SUCCESS)
155             {
156                 log << TestLog::Message << "Got error after creating " << contextCount << " contexts."
157                     << TestLog::EndMessage;
158 
159                 if (error == EGL_BAD_ALLOC)
160                 {
161                     if (contextCount < minContextCount)
162                         resultCollector.fail("Couldn't create the minimum number of contexts required.");
163                     else
164                         log << TestLog::Message << "Got EGL_BAD_ALLOC." << TestLog::EndMessage;
165                 }
166                 else
167                     resultCollector.fail("eglCreateContext() produced error that is not EGL_BAD_ALLOC: " +
168                                          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)
187                             << "th context current: " << eglu::getErrorStr(makeCurrentError) << TestLog::EndMessage;
188                         resultCollector.fail("Failed to make context current");
189 
190                         break;
191                     }
192                     else if (m_use == USE_CLEAR)
193                     {
194                         gl.clearColor(0.25f, 0.75f, 0.50f, 1.00f);
195                         gl.clear(GL_COLOR_BUFFER_BIT);
196                         gl.finish();
197                         GLU_CHECK_GLW_MSG(gl, "Failed to clear color.");
198                     }
199                 }
200             }
201         }
202 
203         for (size_t contextNdx = 0; contextNdx < contexts.size(); contextNdx++)
204         {
205             EGLU_CHECK_CALL(egl, destroyContext(*display, contexts[contextNdx]));
206             contexts[contextNdx] = EGL_NO_CONTEXT;
207         }
208 
209         if (m_use == USE_MAKECURRENT || m_use == USE_CLEAR)
210             EGLU_CHECK_CALL(egl, makeCurrent(*display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
211     }
212     catch (...)
213     {
214         for (size_t contextNdx = 0; contextNdx < contexts.size(); contextNdx++)
215         {
216             if (contexts[contextNdx] != EGL_NO_CONTEXT)
217                 EGLU_CHECK_CALL(egl, destroyContext(*display, contexts[contextNdx]));
218         }
219 
220         if (m_use == USE_MAKECURRENT || m_use == USE_CLEAR)
221             EGLU_CHECK_CALL(egl, makeCurrent(*display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
222 
223         throw;
224     }
225 
226     resultCollector.setTestContextResult(m_testCtx);
227     return STOP;
228 }
229 
230 } // namespace
231 
createMultiContextTests(EglTestContext & eglTestCtx)232 TestCaseGroup *createMultiContextTests(EglTestContext &eglTestCtx)
233 {
234     de::MovePtr<TestCaseGroup> group(new TestCaseGroup(eglTestCtx, "multicontext", "EGL multi context tests."));
235 
236     group->addChild(new MultiContextTest(eglTestCtx, MultiContextTest::SHARING_NONE, MultiContextTest::USE_NONE,
237                                          "non_shared", "Create multiple non-shared contexts."));
238     group->addChild(new MultiContextTest(eglTestCtx, MultiContextTest::SHARING_SHARED, MultiContextTest::USE_NONE,
239                                          "shared", "Create multiple shared contexts."));
240 
241     group->addChild(new MultiContextTest(eglTestCtx, MultiContextTest::SHARING_NONE, MultiContextTest::USE_MAKECURRENT,
242                                          "non_shared_make_current", "Create multiple non-shared contexts."));
243     group->addChild(new MultiContextTest(eglTestCtx, MultiContextTest::SHARING_SHARED,
244                                          MultiContextTest::USE_MAKECURRENT, "shared_make_current",
245                                          "Create multiple shared contexts."));
246 
247     group->addChild(new MultiContextTest(eglTestCtx, MultiContextTest::SHARING_NONE, MultiContextTest::USE_CLEAR,
248                                          "non_shared_clear", "Create multiple non-shared contexts."));
249     group->addChild(new MultiContextTest(eglTestCtx, MultiContextTest::SHARING_SHARED, MultiContextTest::USE_CLEAR,
250                                          "shared_clear", "Create multiple shared contexts."));
251 
252     return group.release();
253 }
254 
255 } // namespace egl
256 } // namespace deqp
257