From 256699ee317fde9b1712c0ddf12a6903773aaff4 Mon Sep 17 00:00:00 2001 From: David Snopek Date: Thu, 3 Oct 2024 10:24:01 -0500 Subject: [PATCH] OpenXR: Add support for Wayland on Linux --- .github/workflows/linux_builds.yml | 2 +- doc/classes/DisplayServer.xml | 13 +++++++ drivers/egl/egl_manager.cpp | 24 ++++++++++++ drivers/egl/egl_manager.h | 2 + modules/openxr/SCsub | 2 +- .../platform/openxr_opengl_extension.cpp | 37 ++++++++++++++++--- .../platform/openxr_opengl_extension.h | 11 +++++- modules/openxr/openxr_platform_inc.h | 7 ++++ platform/android/display_server_android.cpp | 8 ++++ .../wayland/display_server_wayland.cpp | 12 ++++++ platform/linuxbsd/x11/display_server_x11.cpp | 12 ++++++ platform/macos/display_server_macos.mm | 12 ++++++ platform/windows/display_server_windows.cpp | 12 ++++++ servers/display_server.cpp | 2 + servers/display_server.h | 2 + 15 files changed, 149 insertions(+), 9 deletions(-) diff --git a/.github/workflows/linux_builds.yml b/.github/workflows/linux_builds.yml index dc3d9f37862..348e2bb317b 100644 --- a/.github/workflows/linux_builds.yml +++ b/.github/workflows/linux_builds.yml @@ -106,7 +106,7 @@ jobs: # TODO: Figure out somehow how to embed this one. - name: wayland-scanner dependency run: | - sudo apt-get install libwayland-bin + sudo apt-get install libwayland-bin libegl-dev - name: Free disk space on runner run: | diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml index 79064a88ba6..628f1dbf06a 100644 --- a/doc/classes/DisplayServer.xml +++ b/doc/classes/DisplayServer.xml @@ -2138,12 +2138,14 @@ Display handle: - Linux (X11): [code]X11::Display*[/code] for the display. + - Linux (Wayland): [code]wl_display[/code] for the display. - Android: [code]EGLDisplay[/code] for the display. Window handle: - Windows: [code]HWND[/code] for the window. - Linux (X11): [code]X11::Window*[/code] for the window. + - Linux (Wayland): [code]wl_surface[/code] for the window. - macOS: [code]NSWindow*[/code] for the window. - iOS: [code]UIViewController*[/code] for the view controller. - Android: [code]jObject[/code] for the activity. @@ -2158,9 +2160,20 @@ OpenGL context (only with the GL Compatibility renderer): - Windows: [code]HGLRC[/code] for the window (native GL), or [code]EGLContext[/code] for the window (ANGLE). - Linux (X11): [code]GLXContext*[/code] for the window. + - Linux (Wayland): [code]EGLContext[/code] for the window. - macOS: [code]NSOpenGLContext*[/code] for the window (native GL), or [code]EGLContext[/code] for the window (ANGLE). - Android: [code]EGLContext[/code] for the window. + + - Windows: [code]EGLDisplay[/code] for the window (ANGLE). + - macOS: [code]EGLDisplay[/code] for the window (ANGLE). + - Linux (Wayland): [code]EGLDisplay[/code] for the window. + + + - Windows: [code]EGLConfig[/code] for the window (ANGLE). + - macOS: [code]EGLConfig[/code] for the window (ANGLE). + - Linux (Wayland): [code]EGLConfig[/code] for the window. + Utterance has begun to be spoken. diff --git a/drivers/egl/egl_manager.cpp b/drivers/egl/egl_manager.cpp index 4477ba7752c..b25ae1d39f5 100644 --- a/drivers/egl/egl_manager.cpp +++ b/drivers/egl/egl_manager.cpp @@ -351,6 +351,30 @@ EGLContext EGLManager::get_context(DisplayServer::WindowID p_window_id) { return display.egl_context; } +EGLDisplay EGLManager::get_display(DisplayServer::WindowID p_window_id) { + GLWindow &glwindow = windows[p_window_id]; + + if (!glwindow.initialized) { + return EGL_NO_CONTEXT; + } + + GLDisplay &display = displays[glwindow.gldisplay_id]; + + return display.egl_display; +} + +EGLConfig EGLManager::get_config(DisplayServer::WindowID p_window_id) { + GLWindow &glwindow = windows[p_window_id]; + + if (!glwindow.initialized) { + return nullptr; + } + + GLDisplay &display = displays[glwindow.gldisplay_id]; + + return display.egl_config; +} + Error EGLManager::initialize(void *p_native_display) { #if defined(GLAD_ENABLED) && !defined(EGL_STATIC) // Loading EGL with a new display gets us just the bare minimum API. We'll then diff --git a/drivers/egl/egl_manager.h b/drivers/egl/egl_manager.h index a4502c06871..9fe9424ce0e 100644 --- a/drivers/egl/egl_manager.h +++ b/drivers/egl/egl_manager.h @@ -106,6 +106,8 @@ public: bool is_using_vsync() const; EGLContext get_context(DisplayServer::WindowID p_window_id); + EGLDisplay get_display(DisplayServer::WindowID p_window_id); + EGLConfig get_config(DisplayServer::WindowID p_window_id); Error initialize(void *p_native_display = nullptr); diff --git a/modules/openxr/SCsub b/modules/openxr/SCsub index dd6a9214402..48c87bcd59c 100644 --- a/modules/openxr/SCsub +++ b/modules/openxr/SCsub @@ -26,7 +26,7 @@ elif env["platform"] == "linuxbsd": env_openxr.AppendUnique(CPPDEFINES=["XR_USE_PLATFORM_XLIB"]) if env["wayland"]: - env_openxr.AppendUnique(CPPDEFINES=["XR_USE_PLATFORM_WAYLAND"]) + env_openxr.AppendUnique(CPPDEFINES=["XR_USE_PLATFORM_EGL"]) # FIXME: Review what needs to be set for Android and macOS. env_openxr.AppendUnique(CPPDEFINES=["HAVE_SECURE_GETENV"]) diff --git a/modules/openxr/extensions/platform/openxr_opengl_extension.cpp b/modules/openxr/extensions/platform/openxr_opengl_extension.cpp index caded14ca76..07e26298bfd 100644 --- a/modules/openxr/extensions/platform/openxr_opengl_extension.cpp +++ b/modules/openxr/extensions/platform/openxr_opengl_extension.cpp @@ -64,6 +64,9 @@ HashMap OpenXROpenGLExtension::get_requested_extensions() { #else request_extensions[XR_KHR_OPENGL_ENABLE_EXTENSION_NAME] = nullptr; #endif +#if defined(LINUXBSD_ENABLED) && defined(EGL_ENABLED) + request_extensions[XR_MNDX_EGL_ENABLE_EXTENSION_NAME] = &egl_extension_enabled; +#endif return request_extensions; } @@ -128,9 +131,14 @@ bool OpenXROpenGLExtension::check_graphics_api_support(XrVersion p_desired_versi XrGraphicsBindingOpenGLWin32KHR OpenXROpenGLExtension::graphics_binding_gl; #elif defined(ANDROID_ENABLED) XrGraphicsBindingOpenGLESAndroidKHR OpenXROpenGLExtension::graphics_binding_gl; -#elif defined(X11_ENABLED) +#elif defined(LINUXBSD_ENABLED) +#ifdef X11_ENABLED XrGraphicsBindingOpenGLXlibKHR OpenXROpenGLExtension::graphics_binding_gl; #endif +#ifdef EGL_ENABLED +XrGraphicsBindingEGLMNDX OpenXROpenGLExtension::graphics_binding_egl; +#endif +#endif void *OpenXROpenGLExtension::set_session_create_and_get_next_pointer(void *p_next_pointer) { XrVersion desired_version = XR_MAKE_VERSION(3, 3, 0); @@ -142,10 +150,6 @@ void *OpenXROpenGLExtension::set_session_create_and_get_next_pointer(void *p_nex DisplayServer *display_server = DisplayServer::get_singleton(); -#ifdef WAYLAND_ENABLED - ERR_FAIL_COND_V_MSG(display_server->get_name() == "Wayland", p_next_pointer, "OpenXR is not yet supported on OpenGL Wayland."); -#endif - #ifdef WIN32 graphics_binding_gl.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR, graphics_binding_gl.next = p_next_pointer; @@ -159,7 +163,23 @@ void *OpenXROpenGLExtension::set_session_create_and_get_next_pointer(void *p_nex graphics_binding_gl.display = (void *)display_server->window_get_native_handle(DisplayServer::DISPLAY_HANDLE); graphics_binding_gl.config = (EGLConfig)0; // https://github.com/KhronosGroup/OpenXR-SDK-Source/blob/master/src/tests/hello_xr/graphicsplugin_opengles.cpp#L122 graphics_binding_gl.context = (void *)display_server->window_get_native_handle(DisplayServer::OPENGL_CONTEXT); -#elif defined(X11_ENABLED) +#else +#if defined(EGL_ENABLED) && defined(WAYLAND_ENABLED) + if (display_server->get_name() == "Wayland") { + ERR_FAIL_COND_V_MSG(!egl_extension_enabled, p_next_pointer, "OpenXR cannot initialize on Wayland without the XR_MNDX_egl_enable extension."); + + graphics_binding_egl.type = XR_TYPE_GRAPHICS_BINDING_EGL_MNDX; + graphics_binding_egl.next = p_next_pointer; + + graphics_binding_egl.getProcAddress = eglGetProcAddress; + graphics_binding_egl.display = (void *)display_server->window_get_native_handle(DisplayServer::EGL_DISPLAY); + graphics_binding_egl.config = (void *)display_server->window_get_native_handle(DisplayServer::EGL_CONFIG); + graphics_binding_egl.context = (void *)display_server->window_get_native_handle(DisplayServer::OPENGL_CONTEXT); + + return &graphics_binding_egl; + } +#endif +#if defined(X11_ENABLED) graphics_binding_gl.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR; graphics_binding_gl.next = p_next_pointer; @@ -175,8 +195,13 @@ void *OpenXROpenGLExtension::set_session_create_and_get_next_pointer(void *p_nex graphics_binding_gl.visualid = 0; graphics_binding_gl.glxFBConfig = 0; #endif +#endif +#if defined(WIN32) || defined(ANDROID_ENABLED) || defined(X11_ENABLED) return &graphics_binding_gl; +#else + return p_next_pointer; +#endif } void OpenXROpenGLExtension::get_usable_swapchain_formats(Vector &p_usable_swap_chains) { diff --git a/modules/openxr/extensions/platform/openxr_opengl_extension.h b/modules/openxr/extensions/platform/openxr_opengl_extension.h index 8da3ca48f4f..beb68e47e38 100644 --- a/modules/openxr/extensions/platform/openxr_opengl_extension.h +++ b/modules/openxr/extensions/platform/openxr_opengl_extension.h @@ -64,8 +64,17 @@ private: static XrGraphicsBindingOpenGLWin32KHR graphics_binding_gl; #elif defined(ANDROID_ENABLED) static XrGraphicsBindingOpenGLESAndroidKHR graphics_binding_gl; -#else // Linux/X11 +#elif defined(LINUXBSD_ENABLED) +#ifdef X11_ENABLED static XrGraphicsBindingOpenGLXlibKHR graphics_binding_gl; +#endif +#ifdef EGL_ENABLED + static XrGraphicsBindingEGLMNDX graphics_binding_egl; + + bool egl_extension_enabled = false; +#endif +#else +#error "OpenXR with OpenGL isn't supported on this platform" #endif struct SwapchainGraphicsData { diff --git a/modules/openxr/openxr_platform_inc.h b/modules/openxr/openxr_platform_inc.h index 957a87cbb21..09bc0c89a28 100644 --- a/modules/openxr/openxr_platform_inc.h +++ b/modules/openxr/openxr_platform_inc.h @@ -49,6 +49,13 @@ #else #define XR_USE_GRAPHICS_API_OPENGL #endif // ANDROID_ENABLED +#if defined(LINUXBSD_ENABLED) && defined(EGL_ENABLED) +#ifdef GLAD_ENABLED +#include "thirdparty/glad/glad/egl.h" +#else +#include +#endif // GLAD_ENABLED +#endif // defined(LINUXBSD_ENABLED) && defined(EGL_ENABLED) #ifdef X11_ENABLED #define GL_GLEXT_PROTOTYPES 1 #define GL3_PROTOTYPES 1 diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp index c1053215c69..5922c70584e 100644 --- a/platform/android/display_server_android.cpp +++ b/platform/android/display_server_android.cpp @@ -382,6 +382,14 @@ int64_t DisplayServerAndroid::window_get_native_handle(HandleType p_handle_type, } return 0; } + case EGL_DISPLAY: { + // @todo Find a way to get this from the Java side. + return 0; + } + case EGL_CONFIG: { + // @todo Find a way to get this from the Java side. + return 0; + } #endif default: { return 0; diff --git a/platform/linuxbsd/wayland/display_server_wayland.cpp b/platform/linuxbsd/wayland/display_server_wayland.cpp index 3fbbc263a01..7a5ebb951e8 100644 --- a/platform/linuxbsd/wayland/display_server_wayland.cpp +++ b/platform/linuxbsd/wayland/display_server_wayland.cpp @@ -627,6 +627,18 @@ int64_t DisplayServerWayland::window_get_native_handle(HandleType p_handle_type, } return 0; } break; + case EGL_DISPLAY: { + if (egl_manager) { + return (int64_t)egl_manager->get_display(p_window); + } + return 0; + } + case EGL_CONFIG: { + if (egl_manager) { + return (int64_t)egl_manager->get_config(p_window); + } + return 0; + } #endif // GLES3_ENABLED default: { diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp index 97ea1147ec6..622a48e48ab 100644 --- a/platform/linuxbsd/x11/display_server_x11.cpp +++ b/platform/linuxbsd/x11/display_server_x11.cpp @@ -1861,6 +1861,18 @@ int64_t DisplayServerX11::window_get_native_handle(HandleType p_handle_type, Win } return 0; } + case EGL_DISPLAY: { + if (gl_manager_egl) { + return (int64_t)gl_manager_egl->get_display(p_window); + } + return 0; + } + case EGL_CONFIG: { + if (gl_manager_egl) { + return (int64_t)gl_manager_egl->get_config(p_window); + } + return 0; + } #endif default: { return 0; diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm index f6c1d11028d..4e590857983 100644 --- a/platform/macos/display_server_macos.mm +++ b/platform/macos/display_server_macos.mm @@ -2666,6 +2666,18 @@ int64_t DisplayServerMacOS::window_get_native_handle(HandleType p_handle_type, W } return 0; } + case EGL_DISPLAY: { + if (gl_manager_angle) { + return (int64_t)gl_manager_angle->get_display(p_window); + } + return 0; + } + case EGL_CONFIG: { + if (gl_manager_angle) { + return (int64_t)gl_manager_angle->get_config(p_window); + } + return 0; + } #endif default: { return 0; diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index 5b166d00752..3dbf81430b3 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -1649,6 +1649,18 @@ int64_t DisplayServerWindows::window_get_native_handle(HandleType p_handle_type, } return 0; } + case EGL_DISPLAY: { + if (gl_manager_angle) { + return (int64_t)gl_manager_angle->get_display(p_window); + } + return 0; + } + case EGL_CONFIG: { + if (gl_manager_angle) { + return (int64_t)gl_manager_angle->get_config(p_window); + } + return 0; + } #endif default: { return 0; diff --git a/servers/display_server.cpp b/servers/display_server.cpp index f092e23171a..1464dfa26b7 100644 --- a/servers/display_server.cpp +++ b/servers/display_server.cpp @@ -1142,6 +1142,8 @@ void DisplayServer::_bind_methods() { BIND_ENUM_CONSTANT(WINDOW_HANDLE); BIND_ENUM_CONSTANT(WINDOW_VIEW); BIND_ENUM_CONSTANT(OPENGL_CONTEXT); + BIND_ENUM_CONSTANT(EGL_DISPLAY); + BIND_ENUM_CONSTANT(EGL_CONFIG); BIND_ENUM_CONSTANT(TTS_UTTERANCE_STARTED); BIND_ENUM_CONSTANT(TTS_UTTERANCE_ENDED); diff --git a/servers/display_server.h b/servers/display_server.h index b518283331d..d9b9a11f244 100644 --- a/servers/display_server.h +++ b/servers/display_server.h @@ -82,6 +82,8 @@ public: WINDOW_HANDLE, WINDOW_VIEW, OPENGL_CONTEXT, + EGL_DISPLAY, + EGL_CONFIG, }; enum Context {