• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include "EglContext.h"
17 #include "EglDisplay.h"
18 #include "EglGlobalInfo.h"
19 #include "EglOsApi.h"
20 #include "EglPbufferSurface.h"
21 #include "ThreadInfo.h"
22 
23 #include <GLcommon/GLEScontext.h>
24 #include <memory>
25 
26 unsigned int EglContext::s_nextContextHndl = 0;
27 
28 extern EglGlobalInfo* g_eglInfo; // defined in EglImp.cpp
29 
usingSurface(SurfacePtr surface)30 bool EglContext::usingSurface(SurfacePtr surface) {
31   return surface.get() == m_read.get() || surface.get() == m_draw.get();
32 }
33 
EglContext(EglDisplay * dpy,uint64_t shareGroupId,EglConfig * config,GLEScontext * glesCtx,GLESVersion ver,EGLint profileMask,ObjectNameManager * mngr,android::base::Stream * stream)34 EglContext::EglContext(EglDisplay *dpy,
35                        uint64_t shareGroupId,
36                        EglConfig* config,
37                        GLEScontext* glesCtx,
38                        GLESVersion ver,
39                        EGLint profileMask,
40                        ObjectNameManager* mngr,
41                        android::base::Stream* stream) :
42         m_dpy(dpy),
43         m_config(config),
44         m_glesContext(glesCtx),
45         m_version(ver),
46         m_mngr(mngr),
47         // If we already have set core profile flag
48         // (through the first context creation in Framebuffer initialization
49         // or what have you),
50         // set all follow contexts to use core as well.
51         // Otherwise, we can end up testing unreliable driver paths where
52         // core and non-core contexts need to interact with each other.
53         m_profileMask(isCoreProfile() ?
54                       (profileMask | EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR) :
55                       profileMask)
56 {
57     // Set the GLES-side core profile flag,
58     // and the global EGL flag.
59     bool usingCoreProfile =
60         m_profileMask & EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR;
61     setCoreProfile(usingCoreProfile);
62     glesCtx->setCoreProfile(usingCoreProfile);
63 
64     if (stream) {
65         EGLint configId = EGLint(stream->getBe32());
66         m_config = dpy->getConfig(configId);
67         if (!m_config) {
68             m_config = dpy->getDefaultConfig();
69         }
70         assert(m_config);
71         shareGroupId = static_cast<uint64_t>(stream->getBe64());
72     }
73 
74     EglOS::Context* globalSharedContext = dpy->getGlobalSharedContext();
75     m_native =
76         dpy->nativeType()->createContext(
77             m_profileMask,
78             m_config->nativeFormat(),
79             globalSharedContext);
80 
81     if (m_native) {
82         // When loading from a snapshot, the first context within a share group
83         // will load share group data.
84         m_shareGroup = mngr->attachOrCreateShareGroup(
85                 m_native.get(), shareGroupId, stream,
86                 [glesCtx](NamedObjectType type,
87                           ObjectLocalName localName,
88                           android::base::Stream* stream) {
89                     return glesCtx->loadObject(type, localName, stream);
90                 });
91         if (stream) {
92             glesCtx->setShareGroup(m_shareGroup);
93             glesCtx->postLoad();
94         }
95         m_hndl = ++s_nextContextHndl;
96     } else {
97         m_hndl = 0;
98     }
99 }
100 
~EglContext()101 EglContext::~EglContext()
102 {
103     ThreadInfo* thread = getThreadInfo();
104     // get the current context
105     EglContext* rebindCtx = thread->eglContext.get();
106     SurfacePtr rebindRead = nullptr;
107     SurfacePtr rebindDraw = nullptr;
108     std::unique_ptr<EglPbufferSurface> pbSurface;
109     if (rebindCtx == this) {
110         // this context is current, no need to rebind.
111         rebindCtx = nullptr;
112     } else {
113         if (rebindCtx && !m_dpy->getContext((EGLContext)SafePointerFromUInt(
114                             rebindCtx->getHndl()))) {
115             rebindCtx = nullptr;
116         }
117         rebindRead = rebindCtx ? rebindCtx->read() : nullptr;
118         rebindDraw = rebindCtx ? rebindCtx->draw() : nullptr;
119         // we need to make the context current before releasing GL resources.
120         // create a dummy surface first
121         pbSurface.reset(new EglPbufferSurface(m_dpy, m_config));
122         pbSurface->setAttrib(EGL_WIDTH, 1);
123         pbSurface->setAttrib(EGL_HEIGHT, 1);
124         EglOS::PbufferInfo pbInfo;
125         pbSurface->getDim(&pbInfo.width, &pbInfo.height, &pbInfo.largest);
126         pbSurface->getTexInfo(&pbInfo.target, &pbInfo.format);
127         pbInfo.hasMipmap = false;
128         EglOS::Surface* pb = m_dpy->nativeType()->createPbufferSurface(
129                 m_config->nativeFormat(), &pbInfo);
130         assert(pb);
131         if (pb) {
132             const bool res = m_dpy->nativeType()->makeCurrent(pb, pb, m_native.get());
133             assert(res);
134             (void)res;
135             pbSurface->setNativePbuffer(pb);
136         }
137     }
138     //
139     // release GL resources. m_shareGroup, m_mngr and m_glesContext hold
140     // smart pointers to share groups. We must clean them up when the context
141     // is current.
142     //
143     g_eglInfo->getIface(version())->setShareGroup(m_glesContext, {});
144     if (m_mngr) {
145         m_mngr->deleteShareGroup(m_native.get());
146     }
147     m_shareGroup.reset();
148 
149     //
150     // call the client-api to remove the GLES context
151     //
152     g_eglInfo->getIface(version())->deleteGLESContext(m_glesContext);
153     //
154     // restore the previous context
155     //
156     if (rebindCtx) {
157         m_dpy->nativeType()->makeCurrent(rebindRead->native(),
158                                          rebindDraw->native(),
159                                          rebindCtx->nativeType());
160     } else {
161         m_dpy->nativeType()->makeCurrent(nullptr, nullptr, nullptr);
162     }
163 }
164 
setSurfaces(SurfacePtr read,SurfacePtr draw)165 void EglContext::setSurfaces(SurfacePtr read,SurfacePtr draw)
166 {
167     m_read = read;
168     m_draw = draw;
169 }
170 
getAttrib(EGLint attrib,EGLint * value)171 bool EglContext::getAttrib(EGLint attrib,EGLint* value) {
172     switch(attrib) {
173     case EGL_CONFIG_ID:
174         *value = m_config->id();
175         break;
176     default:
177         return false;
178     }
179     return true;
180 }
181 
onSave(android::base::Stream * stream)182 void EglContext::onSave(android::base::Stream* stream) {
183     // Save gles context first
184     assert(m_glesContext);
185     m_glesContext->onSave(stream);
186     // We save the information that
187     // is needed to restore the contexts.
188     // That means (1) context configurations (2) shared group IDs.
189 
190     // Save the config.
191     // The current implementation is pretty hacky. It stores the config id.
192     // It almost only works when snapshot saving and loading happens on the
193     // same system with the same GPU driver and hardware.
194     // TODO: make it more general
195     stream->putBe32(getConfig()->id());
196     // Save shared group ID
197     stream->putBe64(m_shareGroup->getId());
198     m_shareGroup->onSave(stream);
199 }
200 
postSave(android::base::Stream * stream)201 void EglContext::postSave(android::base::Stream* stream) {
202     m_glesContext->postSave(stream);
203     m_shareGroup->postSave(stream);
204 }
205