#include "openxr_gl.h" extern "C" { #include #include #include #include } #include #include #include #include #include #include static void output_destroy(struct wlr_output* wlr_output) { (void)wlr_output; } static bool output_test( struct wlr_output* wlr_output, const struct wlr_output_state* state) { (void)wlr_output; (void)state; return true; } static bool output_commit( struct wlr_output* wlr_output, const struct wlr_output_state* state) { (void)wlr_output; (void)state; return true; } static const struct wlr_drm_format_set* output_get_primary_formats( struct wlr_output* wlr_output, uint32_t buffer_caps) { (void)wlr_output; (void)buffer_caps; return NULL; } static const struct wlr_output_impl output_impl = { .destroy = output_destroy, .test = output_test, .commit = output_commit, .get_primary_formats = output_get_primary_formats, }; #include #include #include #include #include #include struct openxr_backend { wlr_backend base; wl_display* display; XrInstance instance {}; XrSession session {}; bool started = false; struct wlr_output* output = nullptr; }; static bool backend_start(wlr_backend* backend) { auto* xr = reinterpret_cast(backend); if (xr->started) return true; XrApplicationInfo ai {}; std::strncpy( ai.applicationName, "LunarWM", XR_MAX_APPLICATION_NAME_SIZE - 1); ai.applicationVersion = 1; std::strncpy(ai.engineName, "LunarWM", XR_MAX_ENGINE_NAME_SIZE - 1); ai.engineVersion = 1; ai.apiVersion = XR_CURRENT_API_VERSION; char const* exts[] = { XR_EXT_DEBUG_UTILS_EXTENSION_NAME, XR_KHR_OPENGL_ENABLE_EXTENSION_NAME, }; XrInstanceCreateInfo ic { XR_TYPE_INSTANCE_CREATE_INFO }; ic.applicationInfo = ai; ic.enabledExtensionCount = sizeof(exts) / sizeof(exts[0]); ic.enabledExtensionNames = exts; if (xrCreateInstance(&ic, &xr->instance) != XR_SUCCESS) { wlr_log(WLR_ERROR, "Failed to create OpenXR instance"); return false; } XrSystemGetInfo sgi { XR_TYPE_SYSTEM_GET_INFO }; sgi.formFactor = XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY; XrSystemId system_id; if (xrGetSystem(xr->instance, &sgi, &system_id) != XR_SUCCESS) { wlr_log(WLR_ERROR, "xrGetSystem failed"); return false; } PFN_xrGetOpenGLGraphicsRequirementsKHR get_reqs; xrGetInstanceProcAddr(xr->instance, "xrGetOpenGLGraphicsRequirementsKHR", reinterpret_cast(&get_reqs)); XrGraphicsRequirementsOpenGLKHR gl_reqs { XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_KHR }; get_reqs(xr->instance, system_id, &gl_reqs); Display* dpy = XOpenDisplay(nullptr); if (!dpy) { wlr_log(WLR_ERROR, "Failed to open X display"); return false; } int screen = DefaultScreen(dpy); static int vis_attrs[] = { GLX_X_RENDERABLE, True, GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, GLX_RENDER_TYPE, GLX_RGBA_BIT, GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR, GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, True, None }; int fbcount; GLXFBConfig* fbcs = glXChooseFBConfig(dpy, screen, vis_attrs, &fbcount); if (!fbcs || !fbcount) { wlr_log(WLR_ERROR, "No GLXFBConfig found"); return false; } GLXFBConfig fbc = fbcs[0]; XFree(fbcs); XVisualInfo* vi = glXGetVisualFromFBConfig(dpy, fbc); Window root = RootWindow(dpy, screen); XSetWindowAttributes swa; swa.colormap = XCreateColormap(dpy, root, vi->visual, AllocNone); swa.event_mask = ExposureMask; Window win = XCreateWindow(dpy, root, 0, 0, 16, 16, 0, vi->depth, InputOutput, vi->visual, CWColormap | CWEventMask, &swa); GLXContext ctx = glXCreateNewContext(dpy, fbc, GLX_RGBA_TYPE, nullptr, True); glXMakeContextCurrent(dpy, win, win, ctx); XrGraphicsBindingOpenGLXlibKHR bind { XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR }; bind.xDisplay = dpy; bind.visualid = vi->visualid; bind.glxFBConfig = fbc; bind.glxDrawable = win; bind.glxContext = ctx; XrSessionCreateInfo sci { XR_TYPE_SESSION_CREATE_INFO }; sci.next = &bind; sci.systemId = system_id; if (xrCreateSession(xr->instance, &sci, &xr->session) != XR_SUCCESS) { wlr_log(WLR_ERROR, "xrCreateSession failed"); return false; } xr->output = static_cast(calloc(1, sizeof(wlr_output))); if (xr->output) { wlr_output_init(xr->output, &xr->base, &output_impl, "OpenXR"); wlr_output_create_global(xr->output); } xr->started = true; wlr_log(WLR_INFO, "OpenXR backend started"); return true; } static void backend_destroy(wlr_backend* backend) { auto* xr = reinterpret_cast(backend); if (xr->session) { xrDestroySession(xr->session); } if (xr->instance) { xrDestroyInstance(xr->instance); } free(xr); } static int backend_get_drm_fd(wlr_backend* backend) { (void)backend; return -1; } static wlr_backend_impl const backend_impl = { .start = backend_start, .destroy = backend_destroy, .get_drm_fd = backend_get_drm_fd, }; wlr_backend* wlr_openxr_backend_create(wl_display* display, wl_event_loop* loop) { (void)loop; auto* b = static_cast(calloc(1, sizeof(*b))); if (!b) return nullptr; b->display = display; wlr_backend_init(&b->base, &backend_impl); return &b->base; } bool wlr_backend_is_openxr(wlr_backend* backend) { return backend->impl == &backend_impl; }