blob: 77b07da7b9b5591a53d3227d7896ea3e605c3d11 [file] [log] [blame]
// 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)) {
ERR("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