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