Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OpenXR: Add support for Wayland on Linux #97771

Merged
merged 1 commit into from
Oct 25, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/linux_builds.yml
Original file line number Diff line number Diff line change
@@ -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: |
13 changes: 13 additions & 0 deletions doc/classes/DisplayServer.xml
Original file line number Diff line number Diff line change
@@ -2138,12 +2138,14 @@
<constant name="DISPLAY_HANDLE" value="0" enum="HandleType">
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.
</constant>
<constant name="WINDOW_HANDLE" value="1" enum="HandleType">
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.
</constant>
<constant name="EGL_DISPLAY" value="4" enum="HandleType">
- Windows: [code]EGLDisplay[/code] for the window (ANGLE).
- macOS: [code]EGLDisplay[/code] for the window (ANGLE).
- Linux (Wayland): [code]EGLDisplay[/code] for the window.
</constant>
<constant name="EGL_CONFIG" value="5" enum="HandleType">
- Windows: [code]EGLConfig[/code] for the window (ANGLE).
- macOS: [code]EGLConfig[/code] for the window (ANGLE).
- Linux (Wayland): [code]EGLConfig[/code] for the window.
</constant>
<constant name="TTS_UTTERANCE_STARTED" value="0" enum="TTSUtteranceEvent">
Utterance has begun to be spoken.
</constant>
24 changes: 24 additions & 0 deletions drivers/egl/egl_manager.cpp
Original file line number Diff line number Diff line change
@@ -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
2 changes: 2 additions & 0 deletions drivers/egl/egl_manager.h
Original file line number Diff line number Diff line change
@@ -106,6 +106,8 @@ class EGLManager {
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);

2 changes: 1 addition & 1 deletion modules/openxr/SCsub
Original file line number Diff line number Diff line change
@@ -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"])
37 changes: 31 additions & 6 deletions modules/openxr/extensions/platform/openxr_opengl_extension.cpp
Original file line number Diff line number Diff line change
@@ -64,6 +64,9 @@ HashMap<String, bool *> 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<int64_t> &p_usable_swap_chains) {
11 changes: 10 additions & 1 deletion modules/openxr/extensions/platform/openxr_opengl_extension.h
Original file line number Diff line number Diff line change
@@ -64,8 +64,17 @@ class OpenXROpenGLExtension : public OpenXRGraphicsExtensionWrapper {
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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understand correctly this include means that the XR_MNDX_egl_enable extension will be handled also on X11, although it will only be used with the Wayland backend, right?

Are there plans of using this extension also with X11 or other EGL-enabled gl managers, like the ANGLE ones?

Copy link
Contributor Author

@dsnopek dsnopek Oct 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understand correctly this include means that the XR_MNDX_egl_enable extension will be handled also on X11, although it will only be used with the Wayland backend, right?

Yes, on Linux we'll include the code for initializing OpenXR on both GLX and EGL, but only actually use the EGL version if we're on Wayland.

Are there plans of using this extension also with X11 or other EGL-enabled gl managers, like the ANGLE ones?

I haven't tested this (I should!) but I don't think OpenXR will be able to correctly initialize with ANGLE, because the OpenXR runtime will be using "real EGL", but we'll be passing it handles (EGLDisplay, EGLConfig, etc) from ANGLE, which I think it'll just see as invalid.

But I'll give it a test when I have a chance!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All right. This is absolutely not blocking. Just a curiosity :D

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 {
7 changes: 7 additions & 0 deletions modules/openxr/openxr_platform_inc.h
Original file line number Diff line number Diff line change
@@ -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 <EGL/egl.h>
#endif // GLAD_ENABLED
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we should one day put this block into some shared include, like we did with other GL-related stuff.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that'd be nice: this same "glad/egl.h" vs "EGL/egl.h" is done in a couple other places. It's always tricky with platform includes, though.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose we can do this in a separate PR sometime

#endif // defined(LINUXBSD_ENABLED) && defined(EGL_ENABLED)
#ifdef X11_ENABLED
#define GL_GLEXT_PROTOTYPES 1
#define GL3_PROTOTYPES 1
8 changes: 8 additions & 0 deletions platform/android/display_server_android.cpp
Original file line number Diff line number Diff line change
@@ -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;
12 changes: 12 additions & 0 deletions platform/linuxbsd/wayland/display_server_wayland.cpp
Original file line number Diff line number Diff line change
@@ -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: {
12 changes: 12 additions & 0 deletions platform/linuxbsd/x11/display_server_x11.cpp
Original file line number Diff line number Diff line change
@@ -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;
12 changes: 12 additions & 0 deletions platform/macos/display_server_macos.mm
Original file line number Diff line number Diff line change
@@ -2666,6 +2666,18 @@
}
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;
12 changes: 12 additions & 0 deletions platform/windows/display_server_windows.cpp
Original file line number Diff line number Diff line change
@@ -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;
2 changes: 2 additions & 0 deletions servers/display_server.cpp
Original file line number Diff line number Diff line change
@@ -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);
2 changes: 2 additions & 0 deletions servers/display_server.h
Original file line number Diff line number Diff line change
@@ -82,6 +82,8 @@ class DisplayServer : public Object {
WINDOW_HANDLE,
WINDOW_VIEW,
OPENGL_CONTEXT,
EGL_DISPLAY,
EGL_CONFIG,
};

enum Context {
Loading