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 "OpenGLESDispatch/DispatchTables.h"
18 #include "OpenGLESDispatch/EGLDispatch.h"
19 #include "host-common/GfxstreamFatalError.h"
20 #include "host-common/logging.h"
21
22 namespace gfxstream {
23 namespace gl {
24 namespace {
25
26 using emugl::ABORT_REASON_OTHER;
27 using emugl::FatalError;
28
29 class DisplaySurfaceGlContextHelper : public ContextHelper {
30 public:
DisplaySurfaceGlContextHelper(EGLDisplay display,EGLSurface surface,EGLContext context)31 DisplaySurfaceGlContextHelper(EGLDisplay display,
32 EGLSurface surface,
33 EGLContext context)
34 : mDisplay(display),
35 mSurface(surface),
36 mContext(context) {
37 if (mDisplay == EGL_NO_DISPLAY) {
38 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
39 << "DisplaySurfaceGlContextHelper created with no display?";
40 }
41 if (mSurface == EGL_NO_SURFACE) {
42 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
43 << "DisplaySurfaceGlContextHelper created with no surface?";
44 }
45 if (mContext == EGL_NO_CONTEXT) {
46 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
47 << "DisplaySurfaceGlContextHelper created with no context?";
48 }
49 }
50
setupContext()51 bool setupContext() override {
52 EGLContext currentContext = s_egl.eglGetCurrentContext();
53 EGLSurface currentDrawSurface = s_egl.eglGetCurrentSurface(EGL_DRAW);
54 EGLSurface currentReadSurface = s_egl.eglGetCurrentSurface(EGL_READ);
55
56 if (currentContext != mContext ||
57 currentDrawSurface != mSurface ||
58 currentReadSurface != mSurface) {
59 if (!s_egl.eglMakeCurrent(mDisplay, mSurface, mSurface, mContext)) {
60 ERR("Failed to make display surface context current: %d", s_egl.eglGetError());
61 return false;
62 }
63 }
64
65 mPreviousContext = currentContext;
66 mPreviousDrawSurface = currentDrawSurface;
67 mPreviousReadSurface = currentReadSurface;
68
69 mIsBound = true;
70
71 return mIsBound;
72 }
73
teardownContext()74 void teardownContext() override {
75 EGLContext currentContext = s_egl.eglGetCurrentContext();
76 EGLSurface currentDrawSurface = s_egl.eglGetCurrentSurface(EGL_DRAW);
77 EGLSurface currentReadSurface = s_egl.eglGetCurrentSurface(EGL_READ);
78
79 if (currentContext != mPreviousContext ||
80 currentDrawSurface != mPreviousDrawSurface ||
81 currentReadSurface != mPreviousReadSurface) {
82 if (!s_egl.eglMakeCurrent(mDisplay,
83 mPreviousDrawSurface,
84 mPreviousReadSurface,
85 mPreviousContext)) {
86 ERR("Failed to make restore previous context: %d", s_egl.eglGetError());
87 return;
88 }
89 }
90
91 mPreviousContext = EGL_NO_CONTEXT;
92 mPreviousDrawSurface = EGL_NO_SURFACE;
93 mPreviousReadSurface = EGL_NO_SURFACE;
94 mIsBound = false;
95 }
96
isBound() const97 bool isBound() const override { return mIsBound; }
98
99 private:
100 EGLDisplay mDisplay = EGL_NO_DISPLAY;
101 EGLSurface mSurface = EGL_NO_SURFACE;
102 EGLContext mContext = EGL_NO_CONTEXT;
103
104 EGLContext mPreviousContext = EGL_NO_CONTEXT;
105 EGLSurface mPreviousReadSurface = EGL_NO_SURFACE;
106 EGLSurface mPreviousDrawSurface = EGL_NO_SURFACE;
107
108 bool mIsBound = false;
109 };
110
111 } // namespace
112
113 /*static*/
createPbufferSurface(EGLDisplay display,EGLConfig config,EGLContext shareContext,const EGLint * contextAttribs,EGLint width,EGLint height)114 std::unique_ptr<DisplaySurfaceGl> DisplaySurfaceGl::createPbufferSurface(
115 EGLDisplay display,
116 EGLConfig config,
117 EGLContext shareContext,
118 const EGLint* contextAttribs,
119 EGLint width,
120 EGLint height) {
121 EGLContext context = s_egl.eglCreateContext(display, config, shareContext, contextAttribs);
122 if (context == EGL_NO_CONTEXT) {
123 ERR("Failed to create context for DisplaySurfaceGl.");
124 return nullptr;
125 }
126
127 const EGLint surfaceAttribs[] = {
128 EGL_WIDTH, width, //
129 EGL_HEIGHT, height, //
130 EGL_NONE, //
131 };
132 EGLSurface surface = s_egl.eglCreatePbufferSurface(display, config, surfaceAttribs);
133 if (surface == EGL_NO_SURFACE) {
134 ERR("Failed to create pbuffer surface for DisplaySurfaceGl.");
135 return nullptr;
136 }
137
138 return std::unique_ptr<DisplaySurfaceGl>(new DisplaySurfaceGl(display, surface, context));
139 }
140
141 /*static*/
createWindowSurface(EGLDisplay display,EGLConfig config,EGLContext shareContext,const GLint * contextAttribs,FBNativeWindowType window)142 std::unique_ptr<DisplaySurfaceGl> DisplaySurfaceGl::createWindowSurface(
143 EGLDisplay display,
144 EGLConfig config,
145 EGLContext shareContext,
146 const GLint* contextAttribs,
147 FBNativeWindowType window) {
148 EGLContext context = s_egl.eglCreateContext(display, config, shareContext, contextAttribs);
149 if (context == EGL_NO_CONTEXT) {
150 ERR("Failed to create context for DisplaySurfaceGl.");
151 return nullptr;
152 }
153
154 EGLSurface surface = s_egl.eglCreateWindowSurface(display, config, window, nullptr);
155 if (surface == EGL_NO_SURFACE) {
156 ERR("Failed to create window surface for DisplaySurfaceGl.");
157 return nullptr;
158 }
159
160 return std::unique_ptr<DisplaySurfaceGl>(new DisplaySurfaceGl(display, surface, context));
161 }
162
DisplaySurfaceGl(EGLDisplay display,EGLSurface surface,EGLContext context)163 DisplaySurfaceGl::DisplaySurfaceGl(EGLDisplay display,
164 EGLSurface surface,
165 EGLContext context)
166 : mDisplay(display),
167 mSurface(surface),
168 mContext(context),
169 mContextHelper(new DisplaySurfaceGlContextHelper(display, surface, context)) {}
170
~DisplaySurfaceGl()171 DisplaySurfaceGl::~DisplaySurfaceGl() {
172 if (mDisplay != EGL_NO_DISPLAY) {
173 if (mSurface) {
174 s_egl.eglDestroySurface(mDisplay, mSurface);
175 }
176 if (mContext) {
177 s_egl.eglDestroyContext(mDisplay, mContext);
178 }
179 }
180 }
181
182 } // namespace gl
183 } // namespace gfxstream