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 "EmulatedEglWindowSurface.h"
17
18 #include <assert.h>
19 #include <ios>
20 #include <stdio.h>
21 #include <string.h>
22
23 #include <GLES/glext.h>
24
25 #include "OpenGLESDispatch/DispatchTables.h"
26 #include "OpenGLESDispatch/EGLDispatch.h"
27 #include "aemu/base/containers/Lookup.h"
28 #include "host-common/GfxstreamFatalError.h"
29 #include "host-common/logging.h"
30
31 using emugl::ABORT_REASON_OTHER;
32 using emugl::FatalError;
33
34 namespace gfxstream {
35 namespace gl {
36
EmulatedEglWindowSurface(EGLDisplay display,EGLConfig config,HandleType hndl)37 EmulatedEglWindowSurface::EmulatedEglWindowSurface(EGLDisplay display,
38 EGLConfig config,
39 HandleType hndl) :
40 mConfig(config),
41 mDisplay(display),
42 mHndl(hndl) {}
43
~EmulatedEglWindowSurface()44 EmulatedEglWindowSurface::~EmulatedEglWindowSurface() {
45 if (mSurface) {
46 s_egl.eglDestroySurface(mDisplay, mSurface);
47 }
48 }
49
create(EGLDisplay display,EGLConfig config,int p_width,int p_height,HandleType hndl)50 std::unique_ptr<EmulatedEglWindowSurface> EmulatedEglWindowSurface::create(
51 EGLDisplay display,
52 EGLConfig config,
53 int p_width,
54 int p_height,
55 HandleType hndl) {
56 std::unique_ptr<EmulatedEglWindowSurface> surface(
57 new EmulatedEglWindowSurface(display, config, hndl));
58
59 // Create a pbuffer to be used as the egl surface for that window.
60 if (!surface->resize(p_width, p_height)) {
61 return nullptr;
62 }
63
64 return surface;
65 }
66
setColorBuffer(ColorBufferPtr p_colorBuffer)67 void EmulatedEglWindowSurface::setColorBuffer(ColorBufferPtr p_colorBuffer) {
68 mAttachedColorBuffer = p_colorBuffer;
69 if (!p_colorBuffer) return;
70
71 // resize the window if the attached color buffer is of different
72 // size.
73 unsigned int cbWidth = mAttachedColorBuffer->getWidth();
74 unsigned int cbHeight = mAttachedColorBuffer->getHeight();
75
76 if (cbWidth != mWidth || cbHeight != mHeight) {
77 resize(cbWidth, cbHeight);
78 }
79 }
80
bind(EmulatedEglContextPtr p_ctx,BindType p_bindType)81 void EmulatedEglWindowSurface::bind(EmulatedEglContextPtr p_ctx, BindType p_bindType) {
82 if (p_bindType == BIND_READ) {
83 mReadContext = p_ctx;
84 } else if (p_bindType == BIND_DRAW) {
85 mDrawContext = p_ctx;
86 } else if (p_bindType == BIND_READDRAW) {
87 mReadContext = p_ctx;
88 mDrawContext = p_ctx;
89 }
90 }
91
getWidth() const92 GLuint EmulatedEglWindowSurface::getWidth() const { return mWidth; }
getHeight() const93 GLuint EmulatedEglWindowSurface::getHeight() const { return mHeight; }
94
flushColorBuffer()95 bool EmulatedEglWindowSurface::flushColorBuffer() {
96 if (!mAttachedColorBuffer.get()) {
97 return true;
98 }
99 if (!mWidth || !mHeight) {
100 return false;
101 }
102
103 if (mAttachedColorBuffer->getWidth() != mWidth ||
104 mAttachedColorBuffer->getHeight() != mHeight) {
105 // XXX: should never happen - how this needs to be handled?
106 ERR("Dimensions do not match");
107 return false;
108 }
109
110 if (!mDrawContext.get()) {
111 ERR("%p: Draw context is NULL", this);
112 return false;
113 }
114
115 GLenum resetStatus = s_gles2.glGetGraphicsResetStatusEXT();
116 if (resetStatus != GL_NO_ERROR) {
117 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) <<
118 "Stream server aborting due to graphics reset. ResetStatus: " <<
119 std::hex << resetStatus;
120 }
121
122 // Make the surface current
123 EGLContext prevContext = s_egl.eglGetCurrentContext();
124 EGLSurface prevReadSurf = s_egl.eglGetCurrentSurface(EGL_READ);
125 EGLSurface prevDrawSurf = s_egl.eglGetCurrentSurface(EGL_DRAW);
126
127 const bool needToSet = prevContext != mDrawContext->getEGLContext() ||
128 prevReadSurf != mSurface || prevDrawSurf != mSurface;
129 if (needToSet) {
130 if (!s_egl.eglMakeCurrent(mDisplay,
131 mSurface,
132 mSurface,
133 mDrawContext->getEGLContext())) {
134 ERR("Error making draw context current");
135 return false;
136 }
137 }
138
139 mAttachedColorBuffer->glOpBlitFromCurrentReadBuffer();
140
141 if (needToSet) {
142 // restore current context/surface
143 s_egl.eglMakeCurrent(mDisplay, prevDrawSurf, prevReadSurf, prevContext);
144 }
145
146 return true;
147 }
148
resize(unsigned int p_width,unsigned int p_height)149 bool EmulatedEglWindowSurface::resize(unsigned int p_width, unsigned int p_height)
150 {
151 if (mSurface && mWidth == p_width && mHeight == p_height) {
152 // no need to resize
153 return true;
154 }
155
156 EGLContext prevContext = s_egl.eglGetCurrentContext();
157 EGLSurface prevReadSurf = s_egl.eglGetCurrentSurface(EGL_READ);
158 EGLSurface prevDrawSurf = s_egl.eglGetCurrentSurface(EGL_DRAW);
159 EGLSurface prevPbuf = mSurface;
160 bool needRebindContext = mSurface &&
161 (prevReadSurf == mSurface ||
162 prevDrawSurf == mSurface);
163
164 if (needRebindContext) {
165 s_egl.eglMakeCurrent(
166 mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
167 }
168
169 //
170 // Destroy previous surface
171 //
172 if (mSurface) {
173 s_egl.eglDestroySurface(mDisplay, mSurface);
174 mSurface = NULL;
175 }
176
177 //
178 // Create pbuffer surface.
179 //
180 const EGLint pbufAttribs[5] = {
181 EGL_WIDTH, (EGLint) p_width, EGL_HEIGHT, (EGLint) p_height, EGL_NONE,
182 };
183
184 mSurface = s_egl.eglCreatePbufferSurface(mDisplay,
185 mConfig,
186 pbufAttribs);
187 if (mSurface == EGL_NO_SURFACE) {
188 ERR("Renderer error: failed to create/resize pbuffer!!");
189 return false;
190 }
191
192 mWidth = p_width;
193 mHeight = p_height;
194
195 if (needRebindContext) {
196 s_egl.eglMakeCurrent(
197 mDisplay,
198 (prevDrawSurf == prevPbuf) ? mSurface : prevDrawSurf,
199 (prevReadSurf == prevPbuf) ? mSurface : prevReadSurf,
200 prevContext);
201 }
202
203 return true;
204 }
205
getHndl() const206 HandleType EmulatedEglWindowSurface::getHndl() const {
207 return mHndl;
208 }
209
210 template <class obj_t>
saveHndlOrNull(obj_t obj,android::base::Stream * stream)211 static void saveHndlOrNull(obj_t obj, android::base::Stream* stream) {
212 if (obj) {
213 stream->putBe32(obj->getHndl());
214 } else {
215 stream->putBe32(0);
216 }
217 }
218
onSave(android::base::Stream * stream) const219 void EmulatedEglWindowSurface::onSave(android::base::Stream* stream) const {
220 stream->putBe32(getHndl());
221 saveHndlOrNull(mAttachedColorBuffer, stream);
222 saveHndlOrNull(mReadContext, stream);
223 saveHndlOrNull(mDrawContext, stream);
224 stream->putBe32(mWidth);
225 stream->putBe32(mHeight);
226 if (s_egl.eglSaveConfig) {
227 s_egl.eglSaveConfig(mDisplay, mConfig, stream);
228 }
229 }
230
onLoad(android::base::Stream * stream,EGLDisplay display,const ColorBufferMap & colorBuffers,const EmulatedEglContextMap & contexts)231 std::unique_ptr<EmulatedEglWindowSurface> EmulatedEglWindowSurface::onLoad(
232 android::base::Stream* stream,
233 EGLDisplay display,
234 const ColorBufferMap& colorBuffers,
235 const EmulatedEglContextMap& contexts) {
236 HandleType hndl = stream->getBe32();
237 HandleType colorBufferHndl = stream->getBe32();
238 HandleType readCtx = stream->getBe32();
239 HandleType drawCtx = stream->getBe32();
240
241 GLuint width = stream->getBe32();
242 GLuint height = stream->getBe32();
243 EGLConfig config = 0;
244 if (s_egl.eglLoadConfig) {
245 config = s_egl.eglLoadConfig(display, stream);
246 }
247
248 auto surface = create(display, config, width, height, hndl);
249 assert(surface);
250 // fb is already locked by its caller
251 if (colorBufferHndl) {
252 const auto* colorBufferRef = android::base::find(colorBuffers, colorBufferHndl);
253 assert(colorBufferRef);
254 surface->mAttachedColorBuffer = colorBufferRef->cb;
255 }
256 surface->mReadContext = android::base::findOrDefault(contexts, readCtx);
257 surface->mDrawContext = android::base::findOrDefault(contexts, drawCtx);
258 return surface;
259 }
260
261 } // namespace gl
262 } // namespace gfxstream
263