Get window up and running

Signed-off-by: Slendi <slendi@socopon.com>
This commit is contained in:
2025-09-30 15:26:30 +03:00
parent d193ef0295
commit ed429d6a30
6 changed files with 300 additions and 111 deletions

6
flake.lock generated
View File

@@ -97,11 +97,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1759180376, "lastModified": 1759215258,
"narHash": "sha256-DaQNW/lQH5HA78Cz/Daoi3G6TmMEbAc2DePkMR9VMFY=", "narHash": "sha256-Y7aXk0Zxu+X2BbO5MLkCvClrPsKfZ2sm34N2n7tXx4I=",
"owner": "slendidev", "owner": "slendidev",
"repo": "wlroots-lunar", "repo": "wlroots-lunar",
"rev": "d0716220ff8bb32889048a3df87b3faf6805aa81", "rev": "a9abd5a6e4fb4e5ac6c410e1fb1ad438d3b12001",
"type": "github" "type": "github"
}, },
"original": { "original": {

View File

@@ -8,7 +8,6 @@
#include "vec.h" #include "vec.h"
#include <assert.h> #include <assert.h>
#include <errno.h>
#include <math.h> #include <math.h>
#include <spawn.h> #include <spawn.h>
#include <stdlib.h> #include <stdlib.h>
@@ -199,10 +198,10 @@ bool LunarWM_init(LunarWM *wm)
config_manager_reload(wm->cman); config_manager_reload(wm->cman);
} }
if (getenv("DISPLAY") != NULL || getenv("WAYLAND_DISPLAY") != NULL) { // if (getenv("DISPLAY") != NULL || getenv("WAYLAND_DISPLAY") != NULL) {
wlr_log(WLR_ERROR, "This compositor can only be ran in DRM mode."); // wlr_log(WLR_ERROR, "This compositor can only be ran in DRM mode.");
return false; // return false;
} // }
if (!LunarWM_wayland_init(wm)) { if (!LunarWM_wayland_init(wm)) {
wlr_log(WLR_ERROR, "Failed to initialize wlroots"); wlr_log(WLR_ERROR, "Failed to initialize wlroots");
@@ -219,8 +218,11 @@ bool LunarWM_init(LunarWM *wm)
} }
if (!LunarWM_xr_init(wm)) { if (!LunarWM_xr_init(wm)) {
wlr_log(WLR_ERROR, "Failed to initialize OpenXR"); wlr_log(WLR_ERROR, "Failed to initialize OpenXR! Disabling XR...");
return false; wm->xr.available = false;
LunarWM_xr_cleanup(wm);
} else {
wm->xr.available = true;
} }
wlr_log(WLR_INFO, "OpenGL ES version: %s", glGetString(GL_VERSION)); wlr_log(WLR_INFO, "OpenGL ES version: %s", glGetString(GL_VERSION));
@@ -315,101 +317,110 @@ void LunarWM_run(LunarWM *wm)
WindowShouldClose(); WindowShouldClose();
BeginDrawing(); BeginDrawing();
LunarWM_xr_poll_events(wm); if (wm->xr.available) {
LunarWM_xr_poll_events(wm);
if (!wm->xr.session_running) {
EndDrawing();
continue;
}
XrFrameState frame_state = {
.type = XR_TYPE_FRAME_STATE,
};
XrFrameWaitInfo frame_wait_info = {
.type = XR_TYPE_FRAME_WAIT_INFO,
};
if (xrWaitFrame(wm->xr.session, &frame_wait_info, &frame_state)
!= XR_SUCCESS) {
wlr_log(WLR_ERROR, "Failed to wait for OpenXR frame");
return;
}
XrFrameBeginInfo frame_begin_info = {
.type = XR_TYPE_FRAME_BEGIN_INFO,
};
XrResult res = xrBeginFrame(wm->xr.session, &frame_begin_info);
if (res != XR_FRAME_DISCARDED && res != XR_SUCCESS) {
wlr_log(WLR_ERROR, "Failed to begin the OpenXR Frame: %d", res);
return;
}
if (wm->xr.hand_tracking_enabled) {
for (size_t i = 0; i < 2; i++) {
LunarWM_Hand *hand = &wm->xr.hands[i];
bool const unobstructed = true;
if (!wm->xr.LocateHandJointsEXT
|| hand->hand_tracker == XR_NULL_HANDLE) {
continue;
}
XrHandJointsMotionRangeInfoEXT mri = {
.type = XR_TYPE_HAND_JOINTS_MOTION_RANGE_INFO_EXT,
};
mri.handJointsMotionRange = unobstructed
? XR_HAND_JOINTS_MOTION_RANGE_UNOBSTRUCTED_EXT
: XR_HAND_JOINTS_MOTION_RANGE_CONFORMING_TO_CONTROLLER_EXT;
XrHandJointsLocateInfoEXT li = {
.type = XR_TYPE_HAND_JOINTS_LOCATE_INFO_EXT,
.next = &mri,
.baseSpace = wm->xr.local_space,
.time = frame_state.predictedDisplayTime,
};
XrHandJointLocationsEXT hji = {
.type = XR_TYPE_HAND_JOINT_LOCATIONS_EXT,
.jointCount = XR_HAND_JOINT_COUNT_EXT,
.jointLocations = hand->joint_locations,
};
if (wm->xr.LocateHandJointsEXT(
hand->hand_tracker, &li, &hji)
!= XR_SUCCESS) {
wlr_log(WLR_ERROR, "Failed to locate hand joints");
return;
}
}
}
LunarWM_RenderLayerInfo render_layer_info = {
.predicted_display_time = frame_state.predictedDisplayTime,
.layer_projection.type = XR_TYPE_COMPOSITION_LAYER_PROJECTION,
};
bool const session_active
= (wm->xr.session_state == XR_SESSION_STATE_SYNCHRONIZED)
|| (wm->xr.session_state == XR_SESSION_STATE_VISIBLE)
|| (wm->xr.session_state == XR_SESSION_STATE_FOCUSED);
if (session_active && (frame_state.shouldRender != 0u)) {
bool rendered
= LunarWM_render_layer(wm, &render_layer_info, dt);
if (rendered) {
render_layer_info.layers[render_layer_info.layers_count]
= (XrCompositionLayerBaseHeader *)&render_layer_info
.layer_projection;
}
}
XrFrameEndInfo frame_end_info = {
.type = XR_TYPE_FRAME_END_INFO,
.displayTime = frame_state.predictedDisplayTime,
.environmentBlendMode = wm->xr.environment_blend_mode,
.layerCount = render_layer_info.layers_count,
.layers = (XrCompositionLayerBaseHeader const **)
render_layer_info.layers,
};
if (xrEndFrame(wm->xr.session, &frame_end_info) != XR_SUCCESS) {
wlr_log(WLR_ERROR, "Failed to end OpenXR frame");
return;
}
EndDrawing();
} else {
ClearBackground(RED);
if (!wm->xr.session_running) {
EndDrawing(); EndDrawing();
continue;
} }
XrFrameState frame_state = {
.type = XR_TYPE_FRAME_STATE,
};
XrFrameWaitInfo frame_wait_info = {
.type = XR_TYPE_FRAME_WAIT_INFO,
};
if (xrWaitFrame(wm->xr.session, &frame_wait_info, &frame_state)
!= XR_SUCCESS) {
wlr_log(WLR_ERROR, "Failed to wait for OpenXR frame");
return;
}
XrFrameBeginInfo frame_begin_info = {
.type = XR_TYPE_FRAME_BEGIN_INFO,
};
XrResult res = xrBeginFrame(wm->xr.session, &frame_begin_info);
if (res != XR_FRAME_DISCARDED && res != XR_SUCCESS) {
wlr_log(WLR_ERROR, "Failed to begin the OpenXR Frame: %d", res);
return;
}
if (wm->xr.hand_tracking_enabled) {
for (size_t i = 0; i < 2; i++) {
LunarWM_Hand *hand = &wm->xr.hands[i];
bool const unobstructed = true;
if (!wm->xr.LocateHandJointsEXT
|| hand->hand_tracker == XR_NULL_HANDLE) {
continue;
}
XrHandJointsMotionRangeInfoEXT mri = {
.type = XR_TYPE_HAND_JOINTS_MOTION_RANGE_INFO_EXT,
};
mri.handJointsMotionRange = unobstructed
? XR_HAND_JOINTS_MOTION_RANGE_UNOBSTRUCTED_EXT
: XR_HAND_JOINTS_MOTION_RANGE_CONFORMING_TO_CONTROLLER_EXT;
XrHandJointsLocateInfoEXT li = {
.type = XR_TYPE_HAND_JOINTS_LOCATE_INFO_EXT,
.next = &mri,
.baseSpace = wm->xr.local_space,
.time = frame_state.predictedDisplayTime,
};
XrHandJointLocationsEXT hji = {
.type = XR_TYPE_HAND_JOINT_LOCATIONS_EXT,
.jointCount = XR_HAND_JOINT_COUNT_EXT,
.jointLocations = hand->joint_locations,
};
if (wm->xr.LocateHandJointsEXT(hand->hand_tracker, &li, &hji)
!= XR_SUCCESS) {
wlr_log(WLR_ERROR, "Failed to locate hand joints");
return;
}
}
}
LunarWM_RenderLayerInfo render_layer_info = {
.predicted_display_time = frame_state.predictedDisplayTime,
.layer_projection.type = XR_TYPE_COMPOSITION_LAYER_PROJECTION,
};
bool const session_active
= (wm->xr.session_state == XR_SESSION_STATE_SYNCHRONIZED)
|| (wm->xr.session_state == XR_SESSION_STATE_VISIBLE)
|| (wm->xr.session_state == XR_SESSION_STATE_FOCUSED);
if (session_active && (frame_state.shouldRender != 0u)) {
bool rendered = LunarWM_render_layer(wm, &render_layer_info, dt);
if (rendered) {
render_layer_info.layers[render_layer_info.layers_count]
= (XrCompositionLayerBaseHeader *)&render_layer_info
.layer_projection;
}
}
XrFrameEndInfo frame_end_info = {
.type = XR_TYPE_FRAME_END_INFO,
.displayTime = frame_state.predictedDisplayTime,
.environmentBlendMode = wm->xr.environment_blend_mode,
.layerCount = render_layer_info.layers_count,
.layers
= (XrCompositionLayerBaseHeader const **)render_layer_info.layers,
};
if (xrEndFrame(wm->xr.session, &frame_end_info) != XR_SUCCESS) {
wlr_log(WLR_ERROR, "Failed to end OpenXR frame");
return;
}
EndDrawing();
} }
} }

View File

@@ -23,6 +23,7 @@
#include <wlr/types/wlr_cursor.h> #include <wlr/types/wlr_cursor.h>
#include <wlr/types/wlr_data_device.h> #include <wlr/types/wlr_data_device.h>
#include <wlr/types/wlr_pointer.h> #include <wlr/types/wlr_pointer.h>
#include <wlr/types/wlr_output.h>
#include <wlr/types/wlr_subcompositor.h> #include <wlr/types/wlr_subcompositor.h>
#include <wlr/types/wlr_xdg_shell.h> #include <wlr/types/wlr_xdg_shell.h>
#include <wlr/util/box.h> #include <wlr/util/box.h>
@@ -103,6 +104,15 @@ typedef struct {
struct wl_listener destroy; struct wl_listener destroy;
} LunarWM_Pointer; } LunarWM_Pointer;
typedef struct {
struct LunarWM *wm;
struct wlr_output *wlr_output;
struct wl_listener frame;
struct wl_listener destroy;
} LunarWM_Output;
typedef struct { typedef struct {
uint32_t id; uint32_t id;
@@ -212,9 +222,15 @@ typedef struct LunarWM {
LunarWM_Toplevel **v_toplevels; LunarWM_Toplevel **v_toplevels;
int current_focus; int current_focus;
struct wl_listener new_output_listener;
LunarWM_Output **v_outputs;
} wayland; } wayland;
struct { struct {
bool available;
XrInstance instance; XrInstance instance;
XrSystemId system_id; XrSystemId system_id;
XrSession session; XrSession session;

View File

@@ -3,6 +3,9 @@
#include "common.h" #include "common.h"
#include "vec.h" #include "vec.h"
#include <wlr/render/pass.h>
#include <wlr/render/color.h>
#include <assert.h> #include <assert.h>
#include <math.h> #include <math.h>
#include <stdio.h> #include <stdio.h>
@@ -15,6 +18,10 @@
#include <xkbcommon/xkbcommon-keysyms.h> #include <xkbcommon/xkbcommon-keysyms.h>
#include <xkbcommon/xkbcommon.h> #include <xkbcommon/xkbcommon.h>
static void handle_new_output(struct wl_listener *listener, void *data);
static void handle_output_frame(struct wl_listener *listener, void *data);
static void handle_output_destroy(struct wl_listener *listener, void *data);
static inline SphericalCoord get_forward_spherical_with_nearest( static inline SphericalCoord get_forward_spherical_with_nearest(
Vector3 fwd, float r) Vector3 fwd, float r)
{ {
@@ -1481,12 +1488,151 @@ static void setup_xwayland(LunarWM *this)
wl_signal_add(&this->wayland.xwayland->events.new_surface, wl_signal_add(&this->wayland.xwayland->events.new_surface,
&this->wayland.xwayland_new_surface); &this->wayland.xwayland_new_surface);
} }
static void destroy_output(LunarWM_Output *output) {
if (!output) {
return;
}
if (output->frame.link.prev || output->frame.link.next) {
wl_list_remove(&output->frame.link);
}
if (output->destroy.link.prev || output->destroy.link.next) {
wl_list_remove(&output->destroy.link);
}
free(output);
}
static void handle_output_destroy(struct wl_listener *listener, void *data) {
(void)data;
LunarWM_Output *output = wl_container_of(listener, output, destroy);
LunarWM *wm = output->wm;
if (wm && wm->wayland.v_outputs) {
for (size_t i = 0; i < vector_size(wm->wayland.v_outputs); ++i) {
if (wm->wayland.v_outputs[i] == output) {
vector_remove(wm->wayland.v_outputs, i);
break;
}
}
}
destroy_output(output);
}
static void handle_output_frame(struct wl_listener *listener, void *data) {
(void)data;
LunarWM_Output *output = wl_container_of(listener, output, frame);
LunarWM *wm = output->wm;
struct wlr_output *wlr_output = output->wlr_output;
if (wm->xr.available) {
wlr_output_schedule_frame(wlr_output);
return;
}
struct wlr_output_state state;
wlr_output_state_init(&state);
struct wlr_render_pass *pass
= wlr_output_begin_render_pass(wlr_output, &state, NULL);
if (pass == NULL) {
wlr_output_state_finish(&state);
wlr_output_schedule_frame(wlr_output);
wlr_log(WLR_ERROR, "Failed to begin render pass for output %s",
wlr_output->name);
return;
}
struct wlr_box box = {
.x = 0,
.y = 0,
.width = wlr_output->width,
.height = wlr_output->height,
};
wlr_render_pass_add_rect(pass, &(struct wlr_render_rect_options){
.box = box,
.color = {
.r = 1.0f,
.g = 0.0f,
.b = 0.0f,
.a = 1.0f,
},
});
if (!wlr_render_pass_submit(pass)) {
wlr_output_state_finish(&state);
wlr_output_schedule_frame(wlr_output);
wlr_log(WLR_ERROR, "Failed to submit render pass for output %s",
wlr_output->name);
return;
}
if (!wlr_output_commit_state(wlr_output, &state)) {
wlr_log(WLR_ERROR, "Failed to commit state for output %s",
wlr_output->name);
wlr_output_state_finish(&state);
wlr_output_schedule_frame(wlr_output);
return;
}
wlr_output_state_finish(&state);
}
static void handle_new_output(struct wl_listener *listener, void *data) {
struct wlr_output *wlr_output = data;
LunarWM *wm = wl_container_of(listener, wm, wayland.new_output_listener);
if (!wlr_output_init_render(
wlr_output, wm->wayland.allocator, wm->wayland.renderer)) {
wlr_log(WLR_ERROR, "Failed to init render for output %s",
wlr_output->name);
return;
}
struct wlr_output_state state;
wlr_output_state_init(&state);
wlr_output_state_set_enabled(&state, true);
struct wlr_output_mode *mode = wlr_output_preferred_mode(wlr_output);
if (mode != NULL) {
wlr_output_state_set_mode(&state, mode);
}
bool committed = wlr_output_commit_state(wlr_output, &state);
wlr_output_state_finish(&state);
if (!committed) {
wlr_log(WLR_ERROR, "Failed to commit init state for output %s",
wlr_output->name);
return;
}
LunarWM_Output *output = calloc(1, sizeof(*output));
if (!output) {
wlr_log(WLR_ERROR, "Out of memory creating output state");
return;
}
output->wm = wm;
output->wlr_output = wlr_output;
output->frame.notify = handle_output_frame;
wl_signal_add(&wlr_output->events.frame, &output->frame);
output->destroy.notify = handle_output_destroy;
wl_signal_add(&wlr_output->events.destroy, &output->destroy);
vector_add(&wm->wayland.v_outputs, output);
wlr_output_schedule_frame(wlr_output);
}
bool LunarWM_wayland_init(LunarWM *this) bool LunarWM_wayland_init(LunarWM *this)
{ {
wlr_log_init(WLR_DEBUG, nullptr); wlr_log_init(WLR_DEBUG, nullptr);
this->wayland.v_toplevels = vector_create(); this->wayland.v_toplevels = vector_create();
this->wayland.v_outputs = vector_create();
this->wayland.display = wl_display_create(); this->wayland.display = wl_display_create();
if (this->wayland.display == nullptr) { if (this->wayland.display == nullptr) {
@@ -1587,6 +1733,10 @@ bool LunarWM_wayland_init(LunarWM *this)
wl_list_init(&this->wayland.keyboards); wl_list_init(&this->wayland.keyboards);
wl_list_init(&this->wayland.pointers); wl_list_init(&this->wayland.pointers);
this->wayland.new_output_listener.notify = handle_new_output;
wl_signal_add(&this->wayland.backend->events.new_output,
&this->wayland.new_output_listener);
this->wayland.new_input_listener.notify = new_input_listener_notify; this->wayland.new_input_listener.notify = new_input_listener_notify;
wl_signal_add(&this->wayland.backend->events.new_input, wl_signal_add(&this->wayland.backend->events.new_input,
&this->wayland.new_input_listener); &this->wayland.new_input_listener);
@@ -1616,6 +1766,20 @@ void LunarWM_wayland_cleanup(LunarWM *this)
this->wayland.custom_out_hud = NULL; this->wayland.custom_out_hud = NULL;
} }
if (this->wayland.new_output_listener.link.prev
|| this->wayland.new_output_listener.link.next) {
wl_list_remove(&this->wayland.new_output_listener.link);
this->wayland.new_output_listener.notify = NULL;
}
if (this->wayland.v_outputs) {
for (size_t i = 0; i < vector_size(this->wayland.v_outputs); ++i) {
destroy_output(this->wayland.v_outputs[i]);
}
vector_free(this->wayland.v_outputs);
this->wayland.v_outputs = NULL;
}
if (this->wayland.xwayland) { if (this->wayland.xwayland) {
if (this->wayland.xwayland_new_surface.link.prev if (this->wayland.xwayland_new_surface.link.prev
|| this->wayland.xwayland_new_surface.link.next) { || this->wayland.xwayland_new_surface.link.next) {

View File

@@ -389,13 +389,13 @@ bool LunarWM_xr_init(LunarWM *this)
} }
} }
auto const swapchain_format_depth = GL_DEPTH_COMPONENT16; auto const swapchain_format_depth = GL_DEPTH_COMPONENT24;
auto const swapchain_format_color = GL_SRGB8_ALPHA8; auto const swapchain_format_color = GL_RGBA8;
{ {
bool found = false; bool found = false;
for (size_t i = 0; i < a_swapchain_formats_count; i++) { for (size_t i = 0; i < a_swapchain_formats_count; i++) {
if (a_swapchain_formats[i] == GL_SRGB8_ALPHA8) { if (a_swapchain_formats[i] == swapchain_format_color) {
found = true; found = true;
break; break;
} }
@@ -434,8 +434,7 @@ bool LunarWM_xr_init(LunarWM *this)
.type = XR_TYPE_SWAPCHAIN_CREATE_INFO, .type = XR_TYPE_SWAPCHAIN_CREATE_INFO,
.next = nullptr, .next = nullptr,
.createFlags = 0, .createFlags = 0,
.usageFlags = XR_SWAPCHAIN_USAGE_SAMPLED_BIT .usageFlags = XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT,
| XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT,
.format = swapchain_format_color, .format = swapchain_format_color,
.sampleCount = vcv->recommendedSwapchainSampleCount, .sampleCount = vcv->recommendedSwapchainSampleCount,
.width = buf_w, .width = buf_w,
@@ -458,8 +457,7 @@ bool LunarWM_xr_init(LunarWM *this)
.type = XR_TYPE_SWAPCHAIN_CREATE_INFO, .type = XR_TYPE_SWAPCHAIN_CREATE_INFO,
.next = nullptr, .next = nullptr,
.createFlags = 0, .createFlags = 0,
.usageFlags = XR_SWAPCHAIN_USAGE_SAMPLED_BIT .usageFlags = XR_SWAPCHAIN_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
| XR_SWAPCHAIN_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
.format = swapchain_format_depth, .format = swapchain_format_depth,
.sampleCount = vcv->recommendedSwapchainSampleCount, .sampleCount = vcv->recommendedSwapchainSampleCount,
.width = buf_w, .width = buf_w,