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
25 unsigned int EglContext::s_nextContextHndl = 0;
26
27 extern EglGlobalInfo* g_eglInfo; // defined in EglImp.cpp
28
usingSurface(SurfacePtr surface)29 bool EglContext::usingSurface(SurfacePtr surface) {
30 return surface.get() == m_read.get() || surface.get() == m_draw.get();
31 }
32
EglContext(EglDisplay * dpy,uint64_t shareGroupId,EglConfig * config,GLEScontext * glesCtx,GLESVersion ver,EGLint profileMask,ObjectNameManager * mngr,android::base::Stream * stream)33 EglContext::EglContext(EglDisplay *dpy,
34 uint64_t shareGroupId,
35 EglConfig* config,
36 GLEScontext* glesCtx,
37 GLESVersion ver,
38 EGLint profileMask,
39 ObjectNameManager* mngr,
40 android::base::Stream* stream) :
41 m_dpy(dpy),
42 m_config(config),
43 m_glesContext(glesCtx),
44 m_version(ver),
45 m_mngr(mngr),
46 // If we already have set core profile flag
47 // (through the first context creation in Framebuffer initialization
48 // or what have you),
49 // set all follow contexts to use core as well.
50 // Otherwise, we can end up testing unreliable driver paths where
51 // core and non-core contexts need to interact with each other.
52 m_profileMask(isCoreProfile() ?
53 (profileMask | EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR) :
54 profileMask)
55 {
56 // Set the GLES-side core profile flag,
57 // and the global EGL flag.
58 bool usingCoreProfile =
59 m_profileMask & EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR;
60 setCoreProfile(usingCoreProfile);
61 glesCtx->setCoreProfile(usingCoreProfile);
62
63 if (stream) {
64 EGLint configId = EGLint(stream->getBe32());
65 m_config = dpy->getConfig(configId);
66 if (!m_config) {
67 m_config = dpy->getDefaultConfig();
68 }
69 assert(m_config);
70 shareGroupId = static_cast<uint64_t>(stream->getBe64());
71 }
72
73 EglOS::Context* globalSharedContext = dpy->getGlobalSharedContext();
74 m_native =
75 dpy->nativeType()->createContext(
76 m_profileMask,
77 m_config->nativeFormat(),
78 globalSharedContext);
79
80 if (m_native) {
81 // When loading from a snapshot, the first context within a share group
82 // will load share group data.
83 m_shareGroup = mngr->attachOrCreateShareGroup(
84 m_native.get(), shareGroupId, stream,
85 [glesCtx](NamedObjectType type,
86 ObjectLocalName localName,
87 android::base::Stream* stream) {
88 return glesCtx->loadObject(type, localName, stream);
89 });
90 if (stream) {
91 glesCtx->setShareGroup(m_shareGroup);
92 glesCtx->postLoad();
93 }
94 m_hndl = ++s_nextContextHndl;
95 } else {
96 m_hndl = 0;
97 }
98 }
99
~EglContext()100 EglContext::~EglContext()
101 {
102 ThreadInfo* thread = getThreadInfo();
103 // get the current context
104 ContextPtr currentCtx = thread->eglContext;
105 if (currentCtx && !m_dpy->getContext((EGLContext)SafePointerFromUInt(
106 currentCtx->getHndl()))) {
107 currentCtx.reset();
108 }
109 SurfacePtr currentRead = currentCtx ? currentCtx->read() : nullptr;
110 SurfacePtr currentDraw = currentCtx ? currentCtx->draw() : nullptr;
111 // we need to make the context current before releasing GL resources.
112 // create a dummy surface first
113 EglPbufferSurface pbSurface(m_dpy, m_config);
114 pbSurface.setAttrib(EGL_WIDTH, 1);
115 pbSurface.setAttrib(EGL_HEIGHT, 1);
116 EglOS::PbufferInfo pbInfo;
117 pbSurface.getDim(&pbInfo.width, &pbInfo.height, &pbInfo.largest);
118 pbSurface.getTexInfo(&pbInfo.target, &pbInfo.format);
119 pbInfo.hasMipmap = false;
120 EglOS::Surface* pb = m_dpy->nativeType()->createPbufferSurface(
121 m_config->nativeFormat(), &pbInfo);
122 assert(pb);
123 if (pb) {
124 const bool res = m_dpy->nativeType()->makeCurrent(pb, pb, m_native.get());
125 assert(res);
126 (void)res;
127 pbSurface.setNativePbuffer(pb);
128 }
129 //
130 // release GL resources. m_shareGroup, m_mngr and m_glesContext hold
131 // smart pointers to share groups. We must clean them up when the context
132 // is current.
133 //
134 g_eglInfo->getIface(version())->setShareGroup(m_glesContext, {});
135 if (m_mngr) {
136 m_mngr->deleteShareGroup(m_native.get());
137 }
138 m_shareGroup.reset();
139
140 //
141 // call the client-api to remove the GLES context
142 //
143 g_eglInfo->getIface(version())->deleteGLESContext(m_glesContext);
144 //
145 // restore the current context
146 //
147 if (currentCtx) {
148 m_dpy->nativeType()->makeCurrent(currentRead->native(),
149 currentDraw->native(),
150 currentCtx->nativeType());
151 } else {
152 m_dpy->nativeType()->makeCurrent(nullptr, nullptr, nullptr);
153 }
154 }
155
setSurfaces(SurfacePtr read,SurfacePtr draw)156 void EglContext::setSurfaces(SurfacePtr read,SurfacePtr draw)
157 {
158 m_read = read;
159 m_draw = draw;
160 }
161
getAttrib(EGLint attrib,EGLint * value)162 bool EglContext::getAttrib(EGLint attrib,EGLint* value) {
163 switch(attrib) {
164 case EGL_CONFIG_ID:
165 *value = m_config->id();
166 break;
167 default:
168 return false;
169 }
170 return true;
171 }
172
onSave(android::base::Stream * stream)173 void EglContext::onSave(android::base::Stream* stream) {
174 // Save gles context first
175 assert(m_glesContext);
176 m_glesContext->onSave(stream);
177 // We save the information that
178 // is needed to restore the contexts.
179 // That means (1) context configurations (2) shared group IDs.
180
181 // Save the config.
182 // The current implementation is pretty hacky. It stores the config id.
183 // It almost only works when snapshot saving and loading happens on the
184 // same system with the same GPU driver and hardware.
185 // TODO: make it more general
186 stream->putBe32(getConfig()->id());
187 // Save shared group ID
188 stream->putBe64(m_shareGroup->getId());
189 m_shareGroup->onSave(stream);
190 }
191
postSave(android::base::Stream * stream)192 void EglContext::postSave(android::base::Stream* stream) {
193 m_glesContext->postSave(stream);
194 m_shareGroup->postSave(stream);
195 }
196