Skip to content

Commit

Permalink
attempt to repair PlatformEGLHeadLess
Browse files Browse the repository at this point in the history
It had been broken for a while. Here we attempt to repair it by moving
a lot of its functionality into PlatformEGL.
  • Loading branch information
pixelflinger committed Oct 23, 2023
1 parent f75f703 commit 892f94e
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 192 deletions.
8 changes: 6 additions & 2 deletions filament/backend/include/backend/platforms/PlatformEGL.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ class PlatformEGL : public OpenGLPlatform {
void createContext(bool shared) override;
void releaseContext() noexcept override;

// Return true if we're on an OpenGL platform (as opposed to OpenGL ES). false by default.
virtual bool isOpenGL() const noexcept;

protected:

// --------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -126,6 +129,7 @@ class PlatformEGL : public OpenGLPlatform {
EGLSurface mCurrentDrawSurface = EGL_NO_SURFACE;
EGLSurface mCurrentReadSurface = EGL_NO_SURFACE;
EGLSurface mEGLDummySurface = EGL_NO_SURFACE;
// mEGLConfig is valid only if ext.egl.KHR_no_config_context is false
EGLConfig mEGLConfig = EGL_NO_CONFIG_KHR;
Config mContextAttribs;
std::vector<EGLContext> mAdditionalContexts;
Expand All @@ -146,8 +150,8 @@ class PlatformEGL : public OpenGLPlatform {

void initializeGlExtensions() noexcept;

private:
EGLConfig findSwapChainConfig(uint64_t flags) const;
protected:
EGLConfig findSwapChainConfig(uint64_t flags, bool window, bool pbuffer) const;
};

} // namespace filament::backend
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ class PlatformEGLHeadless : public PlatformEGL {

Driver* createDriver(void* sharedContext,
const Platform::DriverConfig& driverConfig) noexcept override;

protected:
bool isOpenGL() const noexcept override;
};

} // namespace filament
Expand Down
77 changes: 58 additions & 19 deletions filament/backend/src/opengl/platforms/PlatformEGL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,13 +97,32 @@ int PlatformEGL::getOSVersion() const noexcept {
return 0;
}

bool PlatformEGL::isOpenGL() const noexcept {
return false;
}

Driver* PlatformEGL::createDriver(void* sharedContext, const Platform::DriverConfig& driverConfig) noexcept {
mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
assert_invariant(mEGLDisplay != EGL_NO_DISPLAY);

EGLint major, minor;
EGLBoolean const initialized = eglInitialize(mEGLDisplay, &major, &minor);
EGLBoolean initialized = eglInitialize(mEGLDisplay, &major, &minor);

if (!initialized) {
EGLDeviceEXT eglDevice;
EGLint numDevices;
PFNEGLQUERYDEVICESEXTPROC eglQueryDevicesEXT =
(PFNEGLQUERYDEVICESEXTPROC)eglGetProcAddress("eglQueryDevicesEXT");
if (eglQueryDevicesEXT != nullptr) {
eglQueryDevicesEXT(1, &eglDevice, &numDevices);
if(auto* getPlatformDisplay = reinterpret_cast<PFNEGLGETPLATFORMDISPLAYEXTPROC>(
eglGetProcAddress("eglGetPlatformDisplay"))) {
mEGLDisplay = getPlatformDisplay(EGL_PLATFORM_DEVICE_EXT, eglDevice, 0);
initialized = eglInitialize(mEGLDisplay, &major, &minor);
}
}
}

if (UTILS_UNLIKELY(!initialized)) {
slog.e << "eglInitialize failed" << io::endl;
return nullptr;
Expand Down Expand Up @@ -148,10 +167,16 @@ Driver* PlatformEGL::createDriver(void* sharedContext, const Platform::DriverCon
constexpr bool requestES2Context = false;
#endif

// Request a ES2 context, devices that support ES3 will return an ES3 context
Config contextAttribs = {
{ EGL_CONTEXT_CLIENT_VERSION, 2 },
};
Config contextAttribs;

if (isOpenGL()) {
// Request a OpenGL 4.1 context
contextAttribs[EGL_CONTEXT_MAJOR_VERSION] = 4;
contextAttribs[EGL_CONTEXT_MINOR_VERSION] = 1;
} else {
// Request a ES2 context, devices that support ES3 will return an ES3 context
contextAttribs[EGL_CONTEXT_CLIENT_VERSION] = 2;
}

// FOR TESTING ONLY, enforce the ES version we're asking for.
// FIXME: we should check EGL_ANGLE_create_context_backwards_compatible, however, at least
Expand All @@ -172,16 +197,17 @@ Driver* PlatformEGL::createDriver(void* sharedContext, const Platform::DriverCon
// config use for creating the context
EGLConfig eglConfig = EGL_NO_CONFIG_KHR;

// find a config we can use if we don't have "EGL_KHR_no_config_context" and that we can use
// for the dummy pbuffer surface.
mEGLConfig = findSwapChainConfig(
SWAP_CHAIN_CONFIG_TRANSPARENT |
SWAP_CHAIN_HAS_STENCIL_BUFFER );
if (UTILS_UNLIKELY(mEGLConfig == EGL_NO_CONFIG_KHR)) {
goto error; // error already logged
}

if (UTILS_UNLIKELY(!ext.egl.KHR_no_config_context)) {
// find a config we can use if we don't have "EGL_KHR_no_config_context" and that we can use
// for the dummy pbuffer surface.
mEGLConfig = findSwapChainConfig(
SWAP_CHAIN_CONFIG_TRANSPARENT |
SWAP_CHAIN_HAS_STENCIL_BUFFER,
true, true);
if (UTILS_UNLIKELY(mEGLConfig == EGL_NO_CONFIG_KHR)) {
goto error; // error already logged
}
// if we don't have the EGL_KHR_no_config_context the context must be created with
// the same config as the swapchain, so we have no choice but to create a
// transparent config.
Expand Down Expand Up @@ -335,12 +361,11 @@ void PlatformEGL::terminate() noexcept {
eglReleaseThread();
}

EGLConfig PlatformEGL::findSwapChainConfig(uint64_t flags) const {
EGLConfig PlatformEGL::findSwapChainConfig(uint64_t flags, bool window, bool pbuffer) const {
// Find config that support ES3.
EGLConfig config = EGL_NO_CONFIG_KHR;
EGLint configsCount;
Config configAttribs = {
{ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT },
{ EGL_RED_SIZE, 8 },
{ EGL_GREEN_SIZE, 8 },
{ EGL_BLUE_SIZE, 8 },
Expand All @@ -349,9 +374,23 @@ EGLConfig PlatformEGL::findSwapChainConfig(uint64_t flags) const {
{ EGL_STENCIL_SIZE, (flags & SWAP_CHAIN_HAS_STENCIL_BUFFER) ? 8 : 0 }
};

if (!ext.egl.KHR_no_config_context) {
if (isOpenGL()) {
configAttribs[EGL_RENDERABLE_TYPE] = EGL_OPENGL_BIT;
} else {
configAttribs[EGL_RENDERABLE_TYPE] = EGL_OPENGL_ES2_BIT;
if (ext.egl.KHR_create_context) {
configAttribs[EGL_RENDERABLE_TYPE] |= EGL_OPENGL_ES3_BIT_KHR;
}
}
}

if (ext.egl.KHR_create_context) {
configAttribs[EGL_RENDERABLE_TYPE] |= EGL_OPENGL_ES3_BIT_KHR;
if (window) {
configAttribs[EGL_SURFACE_TYPE] |= EGL_WINDOW_BIT;
}

if (pbuffer) {
configAttribs[EGL_SURFACE_TYPE] |= EGL_PBUFFER_BIT;
}

if (ext.egl.ANDROID_recordable) {
Expand Down Expand Up @@ -394,7 +433,7 @@ Platform::SwapChain* PlatformEGL::createSwapChain(

EGLConfig config = EGL_NO_CONFIG_KHR;
if (UTILS_LIKELY(ext.egl.KHR_no_config_context)) {
config = findSwapChainConfig(flags);
config = findSwapChainConfig(flags, true, false);
} else {
config = mEGLConfig;
}
Expand Down Expand Up @@ -430,7 +469,7 @@ Platform::SwapChain* PlatformEGL::createSwapChain(

EGLConfig config = EGL_NO_CONFIG_KHR;
if (UTILS_LIKELY(ext.egl.KHR_no_config_context)) {
config = findSwapChainConfig(flags);
config = findSwapChainConfig(flags, false, true);
} else {
config = mEGLConfig;
}
Expand Down
176 changes: 5 additions & 171 deletions filament/backend/src/opengl/platforms/PlatformEGLHeadless.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,14 @@ using namespace utils;
namespace filament {
using namespace backend;

namespace glext {
UTILS_PRIVATE PFNEGLCREATESYNCKHRPROC eglCreateSyncKHR = {};
UTILS_PRIVATE PFNEGLDESTROYSYNCKHRPROC eglDestroySyncKHR = {};
UTILS_PRIVATE PFNEGLCLIENTWAITSYNCKHRPROC eglClientWaitSyncKHR = {};
UTILS_PRIVATE PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR = {};
UTILS_PRIVATE PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR = {};
}
using namespace glext;

// ---------------------------------------------------------------------------------------------

PlatformEGLHeadless::PlatformEGLHeadless() noexcept
: PlatformEGL() {
}

bool PlatformEGLHeadless::isOpenGL() const noexcept {
return true;
}

backend::Driver* PlatformEGLHeadless::createDriver(void* sharedContext,
const Platform::DriverConfig& driverConfig) noexcept {
EGLBoolean bindAPI = eglBindAPI(EGL_OPENGL_API);
Expand All @@ -58,166 +51,7 @@ backend::Driver* PlatformEGLHeadless::createDriver(void* sharedContext,
return nullptr;
}

// Copied from the base class and modified slightly. Should be cleaned up/improved later.
mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
assert_invariant(mEGLDisplay != EGL_NO_DISPLAY);

EGLint major, minor;
EGLBoolean initialized = eglInitialize(mEGLDisplay, &major, &minor);

if (!initialized) {
EGLDeviceEXT eglDevice;
EGLint numDevices;

PFNEGLQUERYDEVICESEXTPROC eglQueryDevicesEXT =
(PFNEGLQUERYDEVICESEXTPROC)eglGetProcAddress("eglQueryDevicesEXT");
if (eglQueryDevicesEXT != NULL) {
eglQueryDevicesEXT(1, &eglDevice, &numDevices);
if(auto* getPlatformDisplay = reinterpret_cast<PFNEGLGETPLATFORMDISPLAYEXTPROC>(
eglGetProcAddress("eglGetPlatformDisplay"))) {
mEGLDisplay = getPlatformDisplay(EGL_PLATFORM_DEVICE_EXT, eglDevice, 0);
initialized = eglInitialize(mEGLDisplay, &major, &minor);
}
}
}

if (UTILS_UNLIKELY(!initialized)) {
slog.e << "eglInitialize failed" << io::endl;
return nullptr;
}

auto extensions = GLUtils::split(eglQueryString(mEGLDisplay, EGL_EXTENSIONS));

eglCreateSyncKHR = (PFNEGLCREATESYNCKHRPROC) eglGetProcAddress("eglCreateSyncKHR");
eglDestroySyncKHR = (PFNEGLDESTROYSYNCKHRPROC) eglGetProcAddress("eglDestroySyncKHR");
eglClientWaitSyncKHR = (PFNEGLCLIENTWAITSYNCKHRPROC) eglGetProcAddress("eglClientWaitSyncKHR");

eglCreateImageKHR = (PFNEGLCREATEIMAGEKHRPROC) eglGetProcAddress("eglCreateImageKHR");
eglDestroyImageKHR = (PFNEGLDESTROYIMAGEKHRPROC) eglGetProcAddress("eglDestroyImageKHR");

EGLint configsCount;

EGLint configAttribs[] = {
EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_ALPHA_SIZE, 0,
EGL_DEPTH_SIZE, 32,
EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
EGL_NONE
};

EGLint contextAttribs[] = {
EGL_CONTEXT_CLIENT_VERSION, 3,
EGL_NONE, EGL_NONE, // reserved for EGL_CONTEXT_OPENGL_NO_ERROR_KHR below
EGL_NONE
};

EGLint pbufferAttribs[] = {
EGL_WIDTH, 1,
EGL_HEIGHT, 1,
EGL_NONE
};

#ifdef NDEBUG
// When we don't have a shared context and we're in release mode, we always activate the
// EGL_KHR_create_context_no_error extension.
if (!sharedContext && extensions.has("EGL_KHR_create_context_no_error")) {
contextAttribs[2] = EGL_CONTEXT_OPENGL_NO_ERROR_KHR;
contextAttribs[3] = EGL_TRUE;
}
#endif

EGLConfig eglConfig = nullptr;

// find an opaque config
if (!eglChooseConfig(mEGLDisplay, configAttribs, &mEGLConfig, 1, &configsCount)) {
logEglError("eglChooseConfig");
goto error;
}

// fallback to a 24-bit depth buffer
if (configsCount == 0) {
configAttribs[10] = EGL_DEPTH_SIZE;
configAttribs[11] = 24;

if (!eglChooseConfig(mEGLDisplay, configAttribs, &mEGLConfig, 1, &configsCount)) {
logEglError("eglChooseConfig");
goto error;
}
}

// find a transparent config
configAttribs[8] = EGL_ALPHA_SIZE;
configAttribs[9] = 8;
if (!eglChooseConfig(mEGLDisplay, configAttribs, &mEGLTransparentConfig, 1, &configsCount) ||
(configAttribs[13] == EGL_DONT_CARE && configsCount == 0)) {
logEglError("eglChooseConfig");
goto error;
}

if (!extensions.has("EGL_KHR_no_config_context")) {
// if we have the EGL_KHR_no_config_context, we don't need to worry about the config
// when creating the context, otherwise, we must always pick a transparent config.
eglConfig = mEGLConfig = mEGLTransparentConfig;
}

// the pbuffer dummy surface is always created with a transparent surface because
// either we have EGL_KHR_no_config_context and it doesn't matter, or we don't and
// we must use a transparent surface
mEGLDummySurface = eglCreatePbufferSurface(mEGLDisplay, mEGLTransparentConfig, pbufferAttribs);
if (mEGLDummySurface == EGL_NO_SURFACE) {
logEglError("eglCreatePbufferSurface");
goto error;
}

mEGLContext = eglCreateContext(mEGLDisplay, eglConfig, (EGLContext)sharedContext, contextAttribs);
if (mEGLContext == EGL_NO_CONTEXT && sharedContext &&
extensions.has("EGL_KHR_create_context_no_error")) {
// context creation could fail because of EGL_CONTEXT_OPENGL_NO_ERROR_KHR
// not matching the sharedContext. Try with it.
contextAttribs[2] = EGL_CONTEXT_OPENGL_NO_ERROR_KHR;
contextAttribs[3] = EGL_TRUE;
mEGLContext = eglCreateContext(mEGLDisplay, eglConfig, (EGLContext)sharedContext, contextAttribs);
}
if (UTILS_UNLIKELY(mEGLContext == EGL_NO_CONTEXT)) {
// eglCreateContext failed
logEglError("eglCreateContext");
goto error;
}

if (!makeCurrent(mEGLDummySurface, mEGLDummySurface)) {
// eglMakeCurrent failed
logEglError("eglMakeCurrent");
goto error;
}

initializeGlExtensions();

clearGlError();

// success!!
return OpenGLPlatform::createDefaultDriver(this, sharedContext, driverConfig);

error:
// if we're here, we've failed
if (mEGLDummySurface) {
eglDestroySurface(mEGLDisplay, mEGLDummySurface);
}
if (mEGLContext) {
eglDestroyContext(mEGLDisplay, mEGLContext);
}

mEGLDummySurface = EGL_NO_SURFACE;
mEGLContext = EGL_NO_CONTEXT;

eglTerminate(mEGLDisplay);
eglReleaseThread();

return nullptr;
return PlatformEGL::createDriver(sharedContext, driverConfig);
}

} // namespace filament

// ---------------------------------------------------------------------------------------------

0 comments on commit 892f94e

Please sign in to comment.