Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 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 | */ |
Jason Macnak | 5816f69 | 2022-09-28 15:40:01 -0700 | [diff] [blame] | 16 | #include "EmulatedEglWindowSurface.h" |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 17 | |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 18 | #include <assert.h> |
Jason Macnak | 8738ba1 | 2023-02-24 13:09:10 -0800 | [diff] [blame] | 19 | #include <ios> |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 20 | #include <stdio.h> |
| 21 | #include <string.h> |
| 22 | |
Jason Macnak | 491f758 | 2022-08-30 14:08:59 -0700 | [diff] [blame] | 23 | #include <GLES/glext.h> |
| 24 | |
Jason Macnak | 8738ba1 | 2023-02-24 13:09:10 -0800 | [diff] [blame] | 25 | #include "OpenGLESDispatch/DispatchTables.h" |
Jason Macnak | 491f758 | 2022-08-30 14:08:59 -0700 | [diff] [blame] | 26 | #include "OpenGLESDispatch/EGLDispatch.h" |
Jason Macnak | 5816f69 | 2022-09-28 15:40:01 -0700 | [diff] [blame] | 27 | #include "aemu/base/containers/Lookup.h" |
Jason Macnak | 8738ba1 | 2023-02-24 13:09:10 -0800 | [diff] [blame] | 28 | #include "host-common/GfxstreamFatalError.h" |
Jason Macnak | 491f758 | 2022-08-30 14:08:59 -0700 | [diff] [blame] | 29 | #include "host-common/logging.h" |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 30 | |
Jason Macnak | 8738ba1 | 2023-02-24 13:09:10 -0800 | [diff] [blame] | 31 | using emugl::ABORT_REASON_OTHER; |
| 32 | using emugl::FatalError; |
| 33 | |
Jason Macnak | bf06162 | 2022-11-03 09:46:56 -0700 | [diff] [blame] | 34 | namespace gfxstream { |
Jason Macnak | ed0c9e6 | 2023-03-30 15:58:24 -0700 | [diff] [blame] | 35 | namespace gl { |
Jason Macnak | bf06162 | 2022-11-03 09:46:56 -0700 | [diff] [blame] | 36 | |
Jason Macnak | 5816f69 | 2022-09-28 15:40:01 -0700 | [diff] [blame] | 37 | EmulatedEglWindowSurface::EmulatedEglWindowSurface(EGLDisplay display, |
| 38 | EGLConfig config, |
| 39 | HandleType hndl) : |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 40 | mConfig(config), |
| 41 | mDisplay(display), |
| 42 | mHndl(hndl) {} |
| 43 | |
Jason Macnak | 5816f69 | 2022-09-28 15:40:01 -0700 | [diff] [blame] | 44 | EmulatedEglWindowSurface::~EmulatedEglWindowSurface() { |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 45 | if (mSurface) { |
| 46 | s_egl.eglDestroySurface(mDisplay, mSurface); |
| 47 | } |
| 48 | } |
| 49 | |
Jason Macnak | 9bba8fa | 2022-11-04 11:03:02 -0700 | [diff] [blame] | 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; |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 62 | } |
| 63 | |
Jason Macnak | 9bba8fa | 2022-11-04 11:03:02 -0700 | [diff] [blame] | 64 | return surface; |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 65 | } |
| 66 | |
Jason Macnak | 5816f69 | 2022-09-28 15:40:01 -0700 | [diff] [blame] | 67 | void EmulatedEglWindowSurface::setColorBuffer(ColorBufferPtr p_colorBuffer) { |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 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 | |
Jason Macnak | 5816f69 | 2022-09-28 15:40:01 -0700 | [diff] [blame] | 81 | void EmulatedEglWindowSurface::bind(EmulatedEglContextPtr p_ctx, BindType p_bindType) { |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 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 | |
Jason Macnak | 5816f69 | 2022-09-28 15:40:01 -0700 | [diff] [blame] | 92 | GLuint EmulatedEglWindowSurface::getWidth() const { return mWidth; } |
| 93 | GLuint EmulatedEglWindowSurface::getHeight() const { return mHeight; } |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 94 | |
Jason Macnak | 5816f69 | 2022-09-28 15:40:01 -0700 | [diff] [blame] | 95 | bool EmulatedEglWindowSurface::flushColorBuffer() { |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 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? |
Jason Macnak | e43e3a0 | 2021-10-14 10:35:33 -0700 | [diff] [blame] | 106 | ERR("Dimensions do not match"); |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 107 | return false; |
| 108 | } |
| 109 | |
| 110 | if (!mDrawContext.get()) { |
Jason Macnak | e43e3a0 | 2021-10-14 10:35:33 -0700 | [diff] [blame] | 111 | ERR("%p: Draw context is NULL", this); |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 112 | return false; |
| 113 | } |
| 114 | |
Jason Macnak | 8738ba1 | 2023-02-24 13:09:10 -0800 | [diff] [blame] | 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 | |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 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())) { |
Jason Macnak | e43e3a0 | 2021-10-14 10:35:33 -0700 | [diff] [blame] | 134 | ERR("Error making draw context current"); |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 135 | return false; |
| 136 | } |
| 137 | } |
| 138 | |
Jason Macnak | b2a4a79 | 2023-02-23 00:40:01 +0000 | [diff] [blame] | 139 | mAttachedColorBuffer->glOpBlitFromCurrentReadBuffer(); |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 140 | |
| 141 | if (needToSet) { |
| 142 | // restore current context/surface |
| 143 | s_egl.eglMakeCurrent(mDisplay, prevDrawSurf, prevReadSurf, prevContext); |
| 144 | } |
| 145 | |
| 146 | return true; |
| 147 | } |
| 148 | |
Jason Macnak | 5816f69 | 2022-09-28 15:40:01 -0700 | [diff] [blame] | 149 | bool EmulatedEglWindowSurface::resize(unsigned int p_width, unsigned int p_height) |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 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) { |
Jason Macnak | e43e3a0 | 2021-10-14 10:35:33 -0700 | [diff] [blame] | 188 | ERR("Renderer error: failed to create/resize pbuffer!!"); |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 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 | |
Jason Macnak | 5816f69 | 2022-09-28 15:40:01 -0700 | [diff] [blame] | 206 | HandleType EmulatedEglWindowSurface::getHndl() const { |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 207 | return mHndl; |
| 208 | } |
| 209 | |
| 210 | template <class obj_t> |
| 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 | |
Jason Macnak | 5816f69 | 2022-09-28 15:40:01 -0700 | [diff] [blame] | 219 | void EmulatedEglWindowSurface::onSave(android::base::Stream* stream) const { |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 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 | |
Jason Macnak | 9bba8fa | 2022-11-04 11:03:02 -0700 | [diff] [blame] | 231 | std::unique_ptr<EmulatedEglWindowSurface> EmulatedEglWindowSurface::onLoad( |
| 232 | android::base::Stream* stream, |
| 233 | EGLDisplay display, |
| 234 | const ColorBufferMap& colorBuffers, |
| 235 | const EmulatedEglContextMap& contexts) { |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 236 | HandleType hndl = stream->getBe32(); |
Jason Macnak | 5816f69 | 2022-09-28 15:40:01 -0700 | [diff] [blame] | 237 | HandleType colorBufferHndl = stream->getBe32(); |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 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 | } |
Jason Macnak | 9bba8fa | 2022-11-04 11:03:02 -0700 | [diff] [blame] | 247 | |
| 248 | auto surface = create(display, config, width, height, hndl); |
| 249 | assert(surface); |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 250 | // fb is already locked by its caller |
Jason Macnak | 5816f69 | 2022-09-28 15:40:01 -0700 | [diff] [blame] | 251 | if (colorBufferHndl) { |
| 252 | const auto* colorBufferRef = android::base::find(colorBuffers, colorBufferHndl); |
| 253 | assert(colorBufferRef); |
Jason Macnak | 9bba8fa | 2022-11-04 11:03:02 -0700 | [diff] [blame] | 254 | surface->mAttachedColorBuffer = colorBufferRef->cb; |
Jason Macnak | 5816f69 | 2022-09-28 15:40:01 -0700 | [diff] [blame] | 255 | } |
Jason Macnak | 9bba8fa | 2022-11-04 11:03:02 -0700 | [diff] [blame] | 256 | surface->mReadContext = android::base::findOrDefault(contexts, readCtx); |
| 257 | surface->mDrawContext = android::base::findOrDefault(contexts, drawCtx); |
| 258 | return surface; |
Lingfeng Yang | ee4aea3 | 2020-10-29 08:52:13 -0700 | [diff] [blame] | 259 | } |
Jason Macnak | bf06162 | 2022-11-03 09:46:56 -0700 | [diff] [blame] | 260 | |
Jason Macnak | ed0c9e6 | 2023-03-30 15:58:24 -0700 | [diff] [blame] | 261 | } // namespace gl |
Jason Macnak | bf06162 | 2022-11-03 09:46:56 -0700 | [diff] [blame] | 262 | } // namespace gfxstream |