diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..9af3362 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,3 @@ +Coding conventions: +- Use `clang-format` on all C and C++ sources before committing. +- In `CMakeLists.txt`, indent with four spaces. Tabs may be used for C++ files as per .clang-format. diff --git a/CMakeLists.txt b/CMakeLists.txt index 607baf8..524bace 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,27 +28,28 @@ pkg_check_modules(X11 REQUIRED x11) pkg_check_modules(wayland REQUIRED wayland-server wayland-protocols) include_directories( - ${wayland_INCLUDE_DIRS} - ${X11_INCLUDE_DIRS} - ${GLM_INCLUDE_DIRS} - ${Wlroots_INCLUDE_DIRS} + ${wayland_INCLUDE_DIRS} + ${X11_INCLUDE_DIRS} + ${GLM_INCLUDE_DIRS} + ${Wlroots_INCLUDE_DIRS} ) set(SOURCES - src/wlr/backend.cpp - src/wlr/output.cpp + src/wlr/backend.cpp + src/wlr/output.cpp + src/wlr/openxr_gl.cpp - src/compositor.cpp - src/main.cpp + src/compositor.cpp + src/main.cpp ) add_executable(${PROJECT_NAME} ${SOURCES}) target_link_libraries(${PROJECT_NAME} - OpenGL::GL - openxr_loader - ${wayland_LIBRARIES} - ${X11_LIBRARIES} - ${GLM_LIBRARIES} - ${Wlroots_LIBRARIES} + OpenGL::GL + openxr_loader + ${wayland_LIBRARIES} + ${X11_LIBRARIES} + ${GLM_LIBRARIES} + ${Wlroots_LIBRARIES} ) diff --git a/src/wlr/backend.cpp b/src/wlr/backend.cpp index fecfa82..3d2d486 100644 --- a/src/wlr/backend.cpp +++ b/src/wlr/backend.cpp @@ -1,60 +1,20 @@ -#include +#include "openxr_gl.h" extern "C" { #include -#include -#include } -struct my_backend { - struct wlr_backend base; - // TODO: any backend‐specific fields -}; - extern "C" { -static bool backend_start(struct wlr_backend* backend) -{ - (void)backend; - // TODO: start event loops, create outputs, inputs, etc. - return true; -} - -static void backend_destroy(struct wlr_backend* backend) -{ - (void)backend; - // TODO: destroy outputs, free everything -} - -static int backend_get_drm_fd(struct wlr_backend* backend) -{ - (void)backend; - // TODO: return drm FD or -1 - return -1; -} - -static const struct wlr_backend_impl backend_impl = { - .start = backend_start, - .destroy = backend_destroy, - .get_drm_fd = backend_get_drm_fd, -}; - struct wlr_backend* wlr_my_backend_create( struct wl_event_loop* loop, char const* name) { - (void)loop; (void)name; - struct my_backend* b = (struct my_backend*)calloc(1, sizeof(*b)); - if (!b) { - return NULL; - } - wlr_backend_init(&b->base, &backend_impl); - // TODO: store loop/name, setup - return &b->base; + return wlr_openxr_backend_create(nullptr, loop); } bool wlr_backend_is_mybackend(struct wlr_backend* backend) { - return backend->impl == &backend_impl; + return wlr_backend_is_openxr(backend); } } diff --git a/src/wlr/openxr_gl.cpp b/src/wlr/openxr_gl.cpp new file mode 100644 index 0000000..f5c4b03 --- /dev/null +++ b/src/wlr/openxr_gl.cpp @@ -0,0 +1,208 @@ +#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; +} diff --git a/src/wlr/openxr_gl.h b/src/wlr/openxr_gl.h new file mode 100644 index 0000000..754386a --- /dev/null +++ b/src/wlr/openxr_gl.h @@ -0,0 +1,18 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +struct wlr_backend; +struct wl_display; +struct wl_event_loop; + +struct wlr_backend* wlr_openxr_backend_create( + struct wl_display* display, struct wl_event_loop* loop); + +bool wlr_backend_is_openxr(struct wlr_backend* backend); + +#ifdef __cplusplus +} +#endif