• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 2022 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "DisplaySurfaceGl.h"
16 
17 #include <vector>
18 
19 #include <stdio.h>
20 
21 #include "OpenGLESDispatch/DispatchTables.h"
22 #include "OpenGLESDispatch/EGLDispatch.h"
23 #include "host-common/GfxstreamFatalError.h"
24 #include "host-common/logging.h"
25 
26 namespace gfxstream {
27 namespace gl {
28 namespace {
29 
30 using emugl::ABORT_REASON_OTHER;
31 using emugl::FatalError;
32 
33 struct PreviousContextInfo {
34     EGLContext context = EGL_NO_CONTEXT;
35     EGLSurface readSurface = EGL_NO_SURFACE;
36     EGLSurface drawSurface = EGL_NO_SURFACE;
37 };
38 
39 struct ThreadState {
40     std::vector<PreviousContextInfo> previousContexts;
41 };
42 
43 static thread_local ThreadState sThreadState;
44 
45 class DisplaySurfaceGlContextHelper : public ContextHelper {
46   public:
DisplaySurfaceGlContextHelper(EGLDisplay display,EGLSurface surface,EGLContext context)47     DisplaySurfaceGlContextHelper(EGLDisplay display,
48                                   EGLSurface surface,
49                                   EGLContext context)
50         : mDisplay(display),
51           mSurface(surface),
52           mContext(context) {
53         if (mDisplay == EGL_NO_DISPLAY) {
54             GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
55                 << "DisplaySurfaceGlContextHelper created with no display?";
56         }
57         if (mSurface == EGL_NO_SURFACE) {
58             GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
59                 << "DisplaySurfaceGlContextHelper created with no surface?";
60         }
61         if (mContext == EGL_NO_CONTEXT) {
62             GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
63                 << "DisplaySurfaceGlContextHelper created with no context?";
64         }
65     }
66 
setupContext()67     bool setupContext() override {
68         auto& previousContexts = sThreadState.previousContexts;
69 
70         EGLContext currentContext = s_egl.eglGetCurrentContext();
71         EGLSurface currentDrawSurface = s_egl.eglGetCurrentSurface(EGL_DRAW);
72         EGLSurface currentReadSurface = s_egl.eglGetCurrentSurface(EGL_READ);
73 
74         bool needsUpdate = (currentContext != mContext ||
75                             currentDrawSurface != mSurface ||
76                             currentReadSurface != mSurface);
77 
78         if (needsUpdate) {
79             if (!previousContexts.empty()) {
80                 ERR("DisplaySurfaceGlContextHelper context was preempted by others, "
81                     "current=%p, needed=%p, thread=%p", currentContext, mContext, &sThreadState);
82                 // Fall through to attempt to recover from error.
83             }
84 
85             if (!s_egl.eglMakeCurrent(mDisplay, mSurface, mSurface, mContext)) {
86                 // b/284523053
87                 // Legacy swiftshader logspam on exit with this line.
88                 GL_LOG("Failed to make display surface context current: %d", s_egl.eglGetError());
89                 // Fall through to allow adding previous context to stack.
90             }
91         }
92 
93         previousContexts.push_back(
94             {.context = currentContext,
95              .readSurface = currentReadSurface,
96              .drawSurface = currentDrawSurface});
97         return true;
98     }
99 
teardownContext()100     void teardownContext() override {
101         auto& previousContexts = sThreadState.previousContexts;
102 
103         EGLContext currentContext = s_egl.eglGetCurrentContext();
104         EGLSurface currentDrawSurface = s_egl.eglGetCurrentSurface(EGL_DRAW);
105         EGLSurface currentReadSurface = s_egl.eglGetCurrentSurface(EGL_READ);
106 
107         PreviousContextInfo newContext;
108         if (!previousContexts.empty()) {
109             newContext = previousContexts.back();
110             previousContexts.pop_back();
111         }
112 
113         bool needsUpdate = (currentContext != newContext.context ||
114                             currentDrawSurface != newContext.drawSurface ||
115                             currentReadSurface != newContext.readSurface);
116 
117         if (!needsUpdate) {
118             return;
119         }
120 
121         if (!s_egl.eglMakeCurrent(mDisplay,
122                                   newContext.drawSurface,
123                                   newContext.readSurface,
124                                   newContext.context)) {
125             ERR("Failed to restore previous context: %d", s_egl.eglGetError());
126         }
127     }
128 
isBound() const129     bool isBound() const override { return !sThreadState.previousContexts.empty(); }
130 
131   private:
132     EGLDisplay mDisplay = EGL_NO_DISPLAY;
133     EGLSurface mSurface = EGL_NO_SURFACE;
134     EGLContext mContext = EGL_NO_CONTEXT;
135 };
136 
137 }  // namespace
138 
139 /*static*/
createPbufferSurface(EGLDisplay display,EGLConfig config,EGLContext shareContext,const EGLint * contextAttribs,EGLint width,EGLint height)140 std::unique_ptr<DisplaySurfaceGl> DisplaySurfaceGl::createPbufferSurface(
141         EGLDisplay display,
142         EGLConfig config,
143         EGLContext shareContext,
144         const EGLint* contextAttribs,
145         EGLint width,
146         EGLint height) {
147     EGLContext context = s_egl.eglCreateContext(display, config, shareContext, contextAttribs);
148     if (context == EGL_NO_CONTEXT) {
149         ERR("Failed to create context for DisplaySurfaceGl.");
150         return nullptr;
151     }
152 
153     const EGLint surfaceAttribs[] = {
154         EGL_WIDTH, width,   //
155         EGL_HEIGHT, height, //
156         EGL_NONE,           //
157     };
158     EGLSurface surface = s_egl.eglCreatePbufferSurface(display, config, surfaceAttribs);
159     if (surface == EGL_NO_SURFACE) {
160         ERR("Failed to create pbuffer surface for DisplaySurfaceGl.");
161         return nullptr;
162     }
163 
164     return std::unique_ptr<DisplaySurfaceGl>(new DisplaySurfaceGl(display, surface, context));
165 }
166 
167 /*static*/
createWindowSurface(EGLDisplay display,EGLConfig config,EGLContext shareContext,const GLint * contextAttribs,FBNativeWindowType window)168 std::unique_ptr<DisplaySurfaceGl> DisplaySurfaceGl::createWindowSurface(
169         EGLDisplay display,
170         EGLConfig config,
171         EGLContext shareContext,
172         const GLint* contextAttribs,
173         FBNativeWindowType window) {
174     EGLContext context = s_egl.eglCreateContext(display, config, shareContext, contextAttribs);
175     if (context == EGL_NO_CONTEXT) {
176         ERR("Failed to create context for DisplaySurfaceGl.");
177         return nullptr;
178     }
179 
180     EGLSurface surface = s_egl.eglCreateWindowSurface(display, config, window, nullptr);
181     if (surface == EGL_NO_SURFACE) {
182         ERR("Failed to create window surface for DisplaySurfaceGl.");
183         return nullptr;
184     }
185 
186     return std::unique_ptr<DisplaySurfaceGl>(new DisplaySurfaceGl(display, surface, context));
187 }
188 
bindContext() const189 bool DisplaySurfaceGl::bindContext() const {
190     if (!s_egl.eglMakeCurrent(mDisplay, mSurface, mSurface, mContext)) {
191         ERR("Failed to make display surface context current: %d", s_egl.eglGetError());
192         return false;
193     }
194     return true;
195 }
196 
DisplaySurfaceGl(EGLDisplay display,EGLSurface surface,EGLContext context)197 DisplaySurfaceGl::DisplaySurfaceGl(EGLDisplay display,
198                                    EGLSurface surface,
199                                    EGLContext context)
200     : mDisplay(display),
201       mSurface(surface),
202       mContext(context),
203       mContextHelper(new DisplaySurfaceGlContextHelper(display, surface, context)) {}
204 
~DisplaySurfaceGl()205 DisplaySurfaceGl::~DisplaySurfaceGl() {
206     if (mDisplay != EGL_NO_DISPLAY) {
207         if (mSurface) {
208             s_egl.eglDestroySurface(mDisplay, mSurface);
209         }
210         if (mContext) {
211             s_egl.eglDestroyContext(mDisplay, mContext);
212         }
213     }
214 }
215 
216 }  // namespace gl
217 }  // namespace gfxstream