| // Copyright (C) 2022 The Android Open Source Project |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "DisplaySurfaceGl.h" |
| |
| #include "OpenGLESDispatch/DispatchTables.h" |
| #include "OpenGLESDispatch/EGLDispatch.h" |
| #include "host-common/GfxstreamFatalError.h" |
| #include "host-common/logging.h" |
| |
| namespace gfxstream { |
| namespace gl { |
| namespace { |
| |
| using emugl::ABORT_REASON_OTHER; |
| using emugl::FatalError; |
| |
| class DisplaySurfaceGlContextHelper : public ContextHelper { |
| public: |
| DisplaySurfaceGlContextHelper(EGLDisplay display, |
| EGLSurface surface, |
| EGLContext context) |
| : mDisplay(display), |
| mSurface(surface), |
| mContext(context) { |
| if (mDisplay == EGL_NO_DISPLAY) { |
| GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) |
| << "DisplaySurfaceGlContextHelper created with no display?"; |
| } |
| if (mSurface == EGL_NO_SURFACE) { |
| GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) |
| << "DisplaySurfaceGlContextHelper created with no surface?"; |
| } |
| if (mContext == EGL_NO_CONTEXT) { |
| GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) |
| << "DisplaySurfaceGlContextHelper created with no context?"; |
| } |
| } |
| |
| bool setupContext() override { |
| EGLContext currentContext = s_egl.eglGetCurrentContext(); |
| EGLSurface currentDrawSurface = s_egl.eglGetCurrentSurface(EGL_DRAW); |
| EGLSurface currentReadSurface = s_egl.eglGetCurrentSurface(EGL_READ); |
| |
| if (currentContext != mContext || |
| currentDrawSurface != mSurface || |
| currentReadSurface != mSurface) { |
| if (!s_egl.eglMakeCurrent(mDisplay, mSurface, mSurface, mContext)) { |
| // b/284523053 |
| // Legacy swiftshader logspam on exit with this line. |
| GL_LOG("Failed to make display surface context current: %d", s_egl.eglGetError()); |
| return false; |
| } |
| } |
| |
| mPreviousContext = currentContext; |
| mPreviousDrawSurface = currentDrawSurface; |
| mPreviousReadSurface = currentReadSurface; |
| |
| mIsBound = true; |
| |
| return mIsBound; |
| } |
| |
| void teardownContext() override { |
| EGLContext currentContext = s_egl.eglGetCurrentContext(); |
| EGLSurface currentDrawSurface = s_egl.eglGetCurrentSurface(EGL_DRAW); |
| EGLSurface currentReadSurface = s_egl.eglGetCurrentSurface(EGL_READ); |
| |
| if (currentContext != mPreviousContext || |
| currentDrawSurface != mPreviousDrawSurface || |
| currentReadSurface != mPreviousReadSurface) { |
| if (!s_egl.eglMakeCurrent(mDisplay, |
| mPreviousDrawSurface, |
| mPreviousReadSurface, |
| mPreviousContext)) { |
| ERR("Failed to make restore previous context: %d", s_egl.eglGetError()); |
| return; |
| } |
| } |
| |
| mPreviousContext = EGL_NO_CONTEXT; |
| mPreviousDrawSurface = EGL_NO_SURFACE; |
| mPreviousReadSurface = EGL_NO_SURFACE; |
| mIsBound = false; |
| } |
| |
| bool isBound() const override { return mIsBound; } |
| |
| private: |
| EGLDisplay mDisplay = EGL_NO_DISPLAY; |
| EGLSurface mSurface = EGL_NO_SURFACE; |
| EGLContext mContext = EGL_NO_CONTEXT; |
| |
| EGLContext mPreviousContext = EGL_NO_CONTEXT; |
| EGLSurface mPreviousReadSurface = EGL_NO_SURFACE; |
| EGLSurface mPreviousDrawSurface = EGL_NO_SURFACE; |
| |
| bool mIsBound = false; |
| }; |
| |
| } // namespace |
| |
| /*static*/ |
| std::unique_ptr<DisplaySurfaceGl> DisplaySurfaceGl::createPbufferSurface( |
| EGLDisplay display, |
| EGLConfig config, |
| EGLContext shareContext, |
| const EGLint* contextAttribs, |
| EGLint width, |
| EGLint height) { |
| EGLContext context = s_egl.eglCreateContext(display, config, shareContext, contextAttribs); |
| if (context == EGL_NO_CONTEXT) { |
| ERR("Failed to create context for DisplaySurfaceGl."); |
| return nullptr; |
| } |
| |
| const EGLint surfaceAttribs[] = { |
| EGL_WIDTH, width, // |
| EGL_HEIGHT, height, // |
| EGL_NONE, // |
| }; |
| EGLSurface surface = s_egl.eglCreatePbufferSurface(display, config, surfaceAttribs); |
| if (surface == EGL_NO_SURFACE) { |
| ERR("Failed to create pbuffer surface for DisplaySurfaceGl."); |
| return nullptr; |
| } |
| |
| return std::unique_ptr<DisplaySurfaceGl>(new DisplaySurfaceGl(display, surface, context)); |
| } |
| |
| /*static*/ |
| std::unique_ptr<DisplaySurfaceGl> DisplaySurfaceGl::createWindowSurface( |
| EGLDisplay display, |
| EGLConfig config, |
| EGLContext shareContext, |
| const GLint* contextAttribs, |
| FBNativeWindowType window) { |
| EGLContext context = s_egl.eglCreateContext(display, config, shareContext, contextAttribs); |
| if (context == EGL_NO_CONTEXT) { |
| ERR("Failed to create context for DisplaySurfaceGl."); |
| return nullptr; |
| } |
| |
| EGLSurface surface = s_egl.eglCreateWindowSurface(display, config, window, nullptr); |
| if (surface == EGL_NO_SURFACE) { |
| ERR("Failed to create window surface for DisplaySurfaceGl."); |
| return nullptr; |
| } |
| |
| return std::unique_ptr<DisplaySurfaceGl>(new DisplaySurfaceGl(display, surface, context)); |
| } |
| |
| bool DisplaySurfaceGl::bindContext() const { |
| if (!s_egl.eglMakeCurrent(mDisplay, mSurface, mSurface, mContext)) { |
| ERR("Failed to make display surface context current: %d", s_egl.eglGetError()); |
| return false; |
| } |
| return true; |
| } |
| |
| DisplaySurfaceGl::DisplaySurfaceGl(EGLDisplay display, |
| EGLSurface surface, |
| EGLContext context) |
| : mDisplay(display), |
| mSurface(surface), |
| mContext(context), |
| mContextHelper(new DisplaySurfaceGlContextHelper(display, surface, context)) {} |
| |
| DisplaySurfaceGl::~DisplaySurfaceGl() { |
| if (mDisplay != EGL_NO_DISPLAY) { |
| if (mSurface) { |
| s_egl.eglDestroySurface(mDisplay, mSurface); |
| } |
| if (mContext) { |
| s_egl.eglDestroyContext(mDisplay, mContext); |
| } |
| } |
| } |
| |
| } // namespace gl |
| } // namespace gfxstream |