blob: 64d2c8e84a0d375e7edee2d42b224676fe94e3de [file] [log] [blame]
Lingfeng Yangee4aea32020-10-29 08:52:13 -07001/*
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*/
Jason Macnak5816f692022-09-28 15:40:01 -070016#include "EmulatedEglWindowSurface.h"
Lingfeng Yangee4aea32020-10-29 08:52:13 -070017
Lingfeng Yangee4aea32020-10-29 08:52:13 -070018#include <assert.h>
Jason Macnak8738ba12023-02-24 13:09:10 -080019#include <ios>
Lingfeng Yangee4aea32020-10-29 08:52:13 -070020#include <stdio.h>
21#include <string.h>
22
Jason Macnak491f7582022-08-30 14:08:59 -070023#include <GLES/glext.h>
24
Jason Macnak8738ba12023-02-24 13:09:10 -080025#include "OpenGLESDispatch/DispatchTables.h"
Jason Macnak491f7582022-08-30 14:08:59 -070026#include "OpenGLESDispatch/EGLDispatch.h"
Jason Macnak5816f692022-09-28 15:40:01 -070027#include "aemu/base/containers/Lookup.h"
Jason Macnak8738ba12023-02-24 13:09:10 -080028#include "host-common/GfxstreamFatalError.h"
Jason Macnak491f7582022-08-30 14:08:59 -070029#include "host-common/logging.h"
Lingfeng Yangee4aea32020-10-29 08:52:13 -070030
Jason Macnak8738ba12023-02-24 13:09:10 -080031using emugl::ABORT_REASON_OTHER;
32using emugl::FatalError;
33
Jason Macnakbf061622022-11-03 09:46:56 -070034namespace gfxstream {
Jason Macnaked0c9e62023-03-30 15:58:24 -070035namespace gl {
Jason Macnakbf061622022-11-03 09:46:56 -070036
Jason Macnak5816f692022-09-28 15:40:01 -070037EmulatedEglWindowSurface::EmulatedEglWindowSurface(EGLDisplay display,
38 EGLConfig config,
39 HandleType hndl) :
Lingfeng Yangee4aea32020-10-29 08:52:13 -070040 mConfig(config),
41 mDisplay(display),
42 mHndl(hndl) {}
43
Jason Macnak5816f692022-09-28 15:40:01 -070044EmulatedEglWindowSurface::~EmulatedEglWindowSurface() {
Lingfeng Yangee4aea32020-10-29 08:52:13 -070045 if (mSurface) {
46 s_egl.eglDestroySurface(mDisplay, mSurface);
47 }
48}
49
Jason Macnak9bba8fa2022-11-04 11:03:02 -070050std::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;
Lingfeng Yangee4aea32020-10-29 08:52:13 -070062 }
63
Jason Macnak9bba8fa2022-11-04 11:03:02 -070064 return surface;
Lingfeng Yangee4aea32020-10-29 08:52:13 -070065}
66
Jason Macnak5816f692022-09-28 15:40:01 -070067void EmulatedEglWindowSurface::setColorBuffer(ColorBufferPtr p_colorBuffer) {
Lingfeng Yangee4aea32020-10-29 08:52:13 -070068 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
Jason Macnak5816f692022-09-28 15:40:01 -070081void EmulatedEglWindowSurface::bind(EmulatedEglContextPtr p_ctx, BindType p_bindType) {
Lingfeng Yangee4aea32020-10-29 08:52:13 -070082 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
Jason Macnak5816f692022-09-28 15:40:01 -070092GLuint EmulatedEglWindowSurface::getWidth() const { return mWidth; }
93GLuint EmulatedEglWindowSurface::getHeight() const { return mHeight; }
Lingfeng Yangee4aea32020-10-29 08:52:13 -070094
Jason Macnak5816f692022-09-28 15:40:01 -070095bool EmulatedEglWindowSurface::flushColorBuffer() {
Lingfeng Yangee4aea32020-10-29 08:52:13 -070096 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?
Jason Macnake43e3a02021-10-14 10:35:33 -0700106 ERR("Dimensions do not match");
Lingfeng Yangee4aea32020-10-29 08:52:13 -0700107 return false;
108 }
109
110 if (!mDrawContext.get()) {
Jason Macnake43e3a02021-10-14 10:35:33 -0700111 ERR("%p: Draw context is NULL", this);
Lingfeng Yangee4aea32020-10-29 08:52:13 -0700112 return false;
113 }
114
Jason Macnak8738ba12023-02-24 13:09:10 -0800115 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
Lingfeng Yangee4aea32020-10-29 08:52:13 -0700122 // 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())) {
Jason Macnake43e3a02021-10-14 10:35:33 -0700134 ERR("Error making draw context current");
Lingfeng Yangee4aea32020-10-29 08:52:13 -0700135 return false;
136 }
137 }
138
Jason Macnakb2a4a792023-02-23 00:40:01 +0000139 mAttachedColorBuffer->glOpBlitFromCurrentReadBuffer();
Lingfeng Yangee4aea32020-10-29 08:52:13 -0700140
141 if (needToSet) {
142 // restore current context/surface
143 s_egl.eglMakeCurrent(mDisplay, prevDrawSurf, prevReadSurf, prevContext);
144 }
145
146 return true;
147}
148
Jason Macnak5816f692022-09-28 15:40:01 -0700149bool EmulatedEglWindowSurface::resize(unsigned int p_width, unsigned int p_height)
Lingfeng Yangee4aea32020-10-29 08:52:13 -0700150{
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) {
Jason Macnake43e3a02021-10-14 10:35:33 -0700188 ERR("Renderer error: failed to create/resize pbuffer!!");
Lingfeng Yangee4aea32020-10-29 08:52:13 -0700189 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
Jason Macnak5816f692022-09-28 15:40:01 -0700206HandleType EmulatedEglWindowSurface::getHndl() const {
Lingfeng Yangee4aea32020-10-29 08:52:13 -0700207 return mHndl;
208}
209
210template <class obj_t>
211static 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
Jason Macnak5816f692022-09-28 15:40:01 -0700219void EmulatedEglWindowSurface::onSave(android::base::Stream* stream) const {
Lingfeng Yangee4aea32020-10-29 08:52:13 -0700220 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
Jason Macnak9bba8fa2022-11-04 11:03:02 -0700231std::unique_ptr<EmulatedEglWindowSurface> EmulatedEglWindowSurface::onLoad(
232 android::base::Stream* stream,
233 EGLDisplay display,
234 const ColorBufferMap& colorBuffers,
235 const EmulatedEglContextMap& contexts) {
Lingfeng Yangee4aea32020-10-29 08:52:13 -0700236 HandleType hndl = stream->getBe32();
Jason Macnak5816f692022-09-28 15:40:01 -0700237 HandleType colorBufferHndl = stream->getBe32();
Lingfeng Yangee4aea32020-10-29 08:52:13 -0700238 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 }
Jason Macnak9bba8fa2022-11-04 11:03:02 -0700247
248 auto surface = create(display, config, width, height, hndl);
249 assert(surface);
Lingfeng Yangee4aea32020-10-29 08:52:13 -0700250 // fb is already locked by its caller
Jason Macnak5816f692022-09-28 15:40:01 -0700251 if (colorBufferHndl) {
252 const auto* colorBufferRef = android::base::find(colorBuffers, colorBufferHndl);
253 assert(colorBufferRef);
Jason Macnak9bba8fa2022-11-04 11:03:02 -0700254 surface->mAttachedColorBuffer = colorBufferRef->cb;
Jason Macnak5816f692022-09-28 15:40:01 -0700255 }
Jason Macnak9bba8fa2022-11-04 11:03:02 -0700256 surface->mReadContext = android::base::findOrDefault(contexts, readCtx);
257 surface->mDrawContext = android::base::findOrDefault(contexts, drawCtx);
258 return surface;
Lingfeng Yangee4aea32020-10-29 08:52:13 -0700259}
Jason Macnakbf061622022-11-03 09:46:56 -0700260
Jason Macnaked0c9e62023-03-30 15:58:24 -0700261} // namespace gl
Jason Macnakbf061622022-11-03 09:46:56 -0700262} // namespace gfxstream