244
src/LunarWM.c
244
src/LunarWM.c
@@ -1,5 +1,6 @@
|
||||
#include "LunarWM.h"
|
||||
|
||||
#include "RayExt.h"
|
||||
#include "common.h"
|
||||
|
||||
#include <assert.h>
|
||||
@@ -21,6 +22,7 @@
|
||||
#include <wayland-egl.h>
|
||||
#include <wayland-server-core.h>
|
||||
|
||||
#include <wlr/backend/headless.h>
|
||||
#include <wlr/backend/session.h>
|
||||
#include <wlr/backend/wayland.h>
|
||||
#include <wlr/render/allocator.h>
|
||||
@@ -662,6 +664,157 @@ static void new_xdg_toplevel_listener_notify(
|
||||
}
|
||||
}
|
||||
|
||||
struct vo_client_res {
|
||||
struct wl_resource *res;
|
||||
struct wl_list link; // vo_client_res.link
|
||||
};
|
||||
|
||||
static void vo_send_initial(struct virtual_output *vo, struct wl_resource *res)
|
||||
{
|
||||
// wl_output v1..v4 ordering: geometry, mode, scale (v2+), name/desc (v4),
|
||||
// done (v2+)
|
||||
wl_output_send_geometry(res, vo->x, vo->y, vo->phys_w_mm, vo->phys_h_mm,
|
||||
vo->subpixel, vo->make, vo->model, vo->transform);
|
||||
|
||||
uint32_t flags = WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
|
||||
wl_output_send_mode(res, flags, vo->width, vo->height, vo->refresh_mhz);
|
||||
|
||||
if (wl_resource_get_version(res) >= 2)
|
||||
wl_output_send_scale(res, vo->scale);
|
||||
|
||||
if (wl_resource_get_version(res) >= 4) {
|
||||
wl_output_send_name(res, vo->name);
|
||||
wl_output_send_description(res, vo->desc);
|
||||
}
|
||||
|
||||
if (wl_resource_get_version(res) >= 2)
|
||||
wl_output_send_done(res);
|
||||
}
|
||||
|
||||
static void vo_resource_destroy(struct wl_resource *res)
|
||||
{
|
||||
struct vo_client_res *cr = wl_resource_get_user_data(res);
|
||||
if (!cr)
|
||||
return;
|
||||
wl_list_remove(&cr->link);
|
||||
free(cr);
|
||||
}
|
||||
|
||||
// wl_output requests (only release exists in v3+)
|
||||
static void output_release(struct wl_client *client, struct wl_resource *res)
|
||||
{
|
||||
(void)client;
|
||||
wl_resource_destroy(res);
|
||||
}
|
||||
|
||||
static const struct wl_output_interface output_impl = {
|
||||
.release = output_release,
|
||||
};
|
||||
|
||||
static void vo_bind(
|
||||
struct wl_client *client, void *data, uint32_t version, uint32_t id)
|
||||
{
|
||||
struct virtual_output *vo = data;
|
||||
uint32_t ver = version;
|
||||
if (ver > 4)
|
||||
ver = 4; // we implement up to v4
|
||||
|
||||
struct wl_resource *res
|
||||
= wl_resource_create(client, &wl_output_interface, ver, id);
|
||||
if (!res) {
|
||||
wl_client_post_no_memory(client);
|
||||
return;
|
||||
}
|
||||
|
||||
struct vo_client_res *cr = calloc(1, sizeof *cr);
|
||||
if (!cr) {
|
||||
wl_client_post_no_memory(client);
|
||||
wl_resource_destroy(res);
|
||||
return;
|
||||
}
|
||||
cr->res = res;
|
||||
wl_resource_set_implementation(res, &output_impl, cr, vo_resource_destroy);
|
||||
wl_list_insert(&vo->clients, &cr->link);
|
||||
|
||||
vo_send_initial(vo, res);
|
||||
}
|
||||
|
||||
static void vo_broadcast_mode(struct virtual_output *vo)
|
||||
{
|
||||
struct vo_client_res *cr;
|
||||
wl_list_for_each(cr, &vo->clients, link)
|
||||
{
|
||||
struct wl_resource *res = cr->res;
|
||||
uint32_t flags = WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
|
||||
wl_output_send_mode(res, flags, vo->width, vo->height, vo->refresh_mhz);
|
||||
if (wl_resource_get_version(res) >= 2)
|
||||
wl_output_send_done(res);
|
||||
}
|
||||
}
|
||||
|
||||
static void vo_broadcast_scale(struct virtual_output *vo)
|
||||
{
|
||||
struct vo_client_res *cr;
|
||||
wl_list_for_each(cr, &vo->clients, link)
|
||||
{
|
||||
struct wl_resource *res = cr->res;
|
||||
if (wl_resource_get_version(res) >= 2) {
|
||||
wl_output_send_scale(res, vo->scale);
|
||||
wl_output_send_done(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void vo_destroy(struct virtual_output *vo)
|
||||
{
|
||||
// destroy client resources
|
||||
struct vo_client_res *cr, *tmp;
|
||||
wl_list_for_each_safe(cr, tmp, &vo->clients, link)
|
||||
{
|
||||
wl_resource_destroy(cr->res); // calls vo_resource_destroy
|
||||
}
|
||||
if (vo->global) {
|
||||
wl_global_destroy(vo->global);
|
||||
vo->global = NULL;
|
||||
}
|
||||
free(vo);
|
||||
}
|
||||
|
||||
static struct virtual_output *vo_create(struct wl_display *display,
|
||||
char const *name, char const *desc, int32_t w, int32_t h,
|
||||
int32_t refresh_mhz, int32_t scale, char const *make, char const *model)
|
||||
{
|
||||
struct virtual_output *vo = calloc(1, sizeof *vo);
|
||||
if (!vo)
|
||||
return NULL;
|
||||
vo->display = display;
|
||||
wl_list_init(&vo->clients);
|
||||
|
||||
vo->x = 0;
|
||||
vo->y = 0;
|
||||
vo->phys_w_mm = 0;
|
||||
vo->phys_h_mm = 0; // unknown; set if you care
|
||||
vo->width = w;
|
||||
vo->height = h;
|
||||
vo->refresh_mhz = refresh_mhz;
|
||||
vo->scale = scale > 0 ? scale : 1;
|
||||
vo->subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN;
|
||||
vo->transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
vo->make = make ? make : "Lunar";
|
||||
vo->model = model ? model : "Virtual";
|
||||
vo->name = name;
|
||||
vo->desc = desc ? desc : name;
|
||||
|
||||
vo->global
|
||||
= wl_global_create(display, &wl_output_interface, 4, vo, vo_bind);
|
||||
if (!vo->global) {
|
||||
free(vo);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return vo;
|
||||
}
|
||||
|
||||
static bool init_wayland(LunarWM *this)
|
||||
{
|
||||
wlr_log_init(WLR_DEBUG, nullptr);
|
||||
@@ -1413,10 +1566,36 @@ static bool init_xr(LunarWM *this)
|
||||
|
||||
static void sync_config(LunarWM *this)
|
||||
{
|
||||
UnloadTexture(this->renderer.hud_rt.texture);
|
||||
this->renderer.hud_rt.texture.id = 0;
|
||||
this->renderer.hud_rt.texture.width = 0;
|
||||
this->renderer.hud_rt.texture.height = 0;
|
||||
if (this->cman->cfg.cubemap) {
|
||||
Skybox_init(&this->renderer.skybox, this->cman->cfg.cubemap);
|
||||
} else {
|
||||
Skybox_destroy(&this->renderer.skybox);
|
||||
}
|
||||
|
||||
if (IsTextureValid(this->renderer.hud_rt.texture)) {
|
||||
UnloadTexture(this->renderer.hud_rt.texture);
|
||||
this->renderer.hud_rt.texture.id = 0;
|
||||
this->renderer.hud_rt.texture.width = 0;
|
||||
this->renderer.hud_rt.texture.height = 0;
|
||||
}
|
||||
|
||||
if (this->wayland.custom_out_virtual) {
|
||||
vo_destroy(this->wayland.custom_out_virtual);
|
||||
this->wayland.custom_out_virtual = NULL;
|
||||
}
|
||||
if (this->wayland.custom_out_hud) {
|
||||
vo_destroy(this->wayland.custom_out_hud);
|
||||
this->wayland.custom_out_hud = NULL;
|
||||
}
|
||||
|
||||
int vw = (int)this->cman->cfg.displays.virtual.resolution.x;
|
||||
int vh = (int)this->cman->cfg.displays.virtual.resolution.y;
|
||||
int hud = this->cman->cfg.displays.hud.size;
|
||||
|
||||
this->wayland.custom_out_virtual = vo_create(this->wayland.display,
|
||||
"Virtual", "Virtual output", vw, vh, 60000, 1, "LunarWM", "Virtual");
|
||||
this->wayland.custom_out_hud = vo_create(this->wayland.display, "HUD",
|
||||
"HUD output", hud, hud, 60000, 1, "LunarWM", "HUD");
|
||||
}
|
||||
|
||||
extern char **environ;
|
||||
@@ -1523,7 +1702,6 @@ bool LunarWM_init(LunarWM *this)
|
||||
lua_setglobal(L, "lunar");
|
||||
|
||||
config_manager_reload(this->cman);
|
||||
sync_config(this);
|
||||
|
||||
this->renderer.center = this->cman->cfg.space.initial_center;
|
||||
}
|
||||
@@ -1562,6 +1740,8 @@ bool LunarWM_init(LunarWM *this)
|
||||
return false;
|
||||
}
|
||||
|
||||
sync_config(this);
|
||||
|
||||
this->initialized = true;
|
||||
|
||||
return true;
|
||||
@@ -1651,6 +1831,15 @@ static void cleanup_wayland(LunarWM *this)
|
||||
{
|
||||
assert(this);
|
||||
|
||||
if (this->wayland.custom_out_virtual) {
|
||||
vo_destroy(this->wayland.custom_out_virtual);
|
||||
this->wayland.custom_out_virtual = NULL;
|
||||
}
|
||||
if (this->wayland.custom_out_hud) {
|
||||
vo_destroy(this->wayland.custom_out_hud);
|
||||
this->wayland.custom_out_hud = NULL;
|
||||
}
|
||||
|
||||
if (this->wayland.xwayland) {
|
||||
wlr_xwayland_destroy(this->wayland.xwayland);
|
||||
this->wayland.xwayland = NULL;
|
||||
@@ -2004,7 +2193,7 @@ void render_hud(LunarWM *this, float /*dt*/, int hud_size)
|
||||
|
||||
void render_3d(LunarWM *this, float /*dt*/)
|
||||
{
|
||||
DrawGrid(10, 1);
|
||||
Skybox_draw(this->renderer.skybox, (Vector3) { 0, 0, 0 });
|
||||
|
||||
rlDisableBackfaceCulling();
|
||||
for (size_t i = 0; i < vector_size(this->wayland.v_toplevels); i++) {
|
||||
@@ -2033,7 +2222,7 @@ void render_3d(LunarWM *this, float /*dt*/)
|
||||
jl->pose.position.y,
|
||||
jl->pose.position.z,
|
||||
};
|
||||
DrawSphere(pos, jl->radius, RED);
|
||||
DrawSphere(pos, jl->radius, (Color) { 255, 0, 0, 255 });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2133,13 +2322,14 @@ static bool render_layer(LunarWM *this, LunarWM_RenderLayerInfo *info, float dt)
|
||||
auto const head_view = MatrixInvert(xr_matrix(headLoc.pose));
|
||||
|
||||
// per-eye projection + view-offset
|
||||
Matrix const proj_r = xr_projection_matrix(views[0].fov);
|
||||
Matrix const proj_l = xr_projection_matrix(views[1].fov);
|
||||
Matrix const view_off_l
|
||||
= MatrixMultiply(xr_matrix(views[0].pose), head_view);
|
||||
Matrix const view_off_r
|
||||
= MatrixMultiply(xr_matrix(views[1].pose), head_view);
|
||||
|
||||
Matrix const proj_r = xr_projection_matrix(views[0].fov);
|
||||
Matrix const proj_l = xr_projection_matrix(views[1].fov);
|
||||
|
||||
int const hud_size = this->cman->cfg.displays.hud.size;
|
||||
if (!IsTextureValid(this->renderer.hud_rt.texture)) {
|
||||
this->renderer.hud_rt = LoadRenderTexture(hud_size, hud_size);
|
||||
@@ -2154,10 +2344,15 @@ static bool render_layer(LunarWM *this, LunarWM_RenderLayerInfo *info, float dt)
|
||||
}
|
||||
|
||||
// draw
|
||||
BeginTextureMode(this->renderer.tmp_rt);
|
||||
|
||||
if (!IsTextureValid(this->renderer.main_rt.texture)) {
|
||||
this->renderer.main_rt = LoadRenderTexture(eye_w * view_count, eye_h);
|
||||
}
|
||||
|
||||
BeginTextureMode(this->renderer.main_rt);
|
||||
|
||||
rlEnableStereoRender();
|
||||
rlSetMatrixProjectionStereo(proj_r, proj_l); // right, left (yes)
|
||||
rlSetMatrixProjectionStereo(proj_r, proj_l);
|
||||
rlSetMatrixViewOffsetStereo(view_off_r, view_off_l);
|
||||
|
||||
glViewport(0, 0, (GLsizei)eye_w * view_count, (GLsizei)eye_h);
|
||||
@@ -2202,6 +2397,33 @@ static bool render_layer(LunarWM *this, LunarWM_RenderLayerInfo *info, float dt)
|
||||
rlDisableStereoRender();
|
||||
EndTextureMode();
|
||||
|
||||
if (!IsShaderValid(this->renderer.linear_srgb)) {
|
||||
static char const linear_srgb[] = {
|
||||
#embed "../assets/linear_srgb.fs"
|
||||
, 0
|
||||
};
|
||||
this->renderer.linear_srgb = LoadShaderFromMemory(NULL, linear_srgb);
|
||||
}
|
||||
|
||||
BeginTextureMode(this->renderer.tmp_rt);
|
||||
BeginShaderMode(this->renderer.linear_srgb);
|
||||
DrawTexturePro(this->renderer.main_rt.texture,
|
||||
(Rectangle) {
|
||||
0,
|
||||
0,
|
||||
this->renderer.main_rt.texture.width,
|
||||
-this->renderer.main_rt.texture.height,
|
||||
},
|
||||
(Rectangle) {
|
||||
0,
|
||||
0,
|
||||
this->renderer.tmp_rt.texture.width,
|
||||
this->renderer.tmp_rt.texture.height,
|
||||
},
|
||||
(Vector2) { 0, 0 }, 0, WHITE);
|
||||
EndShaderMode();
|
||||
EndTextureMode();
|
||||
|
||||
// release swapchain images
|
||||
XrSwapchainImageReleaseInfo const ri
|
||||
= { .type = XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO };
|
||||
|
||||
Reference in New Issue
Block a user