render: replace EGL/OpenGL pipeline with wl_shm shared memory

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: If73c9ac16c2a31e211c2cda2b0ce2c586a6a6964
This commit is contained in:
raf 2026-05-01 14:09:18 +03:00
commit a838f86731
Signed by: NotAShelf
GPG key ID: 29D95B64378DB4BF
3 changed files with 42 additions and 30 deletions

1
include/chroma.h vendored
View file

@ -212,6 +212,7 @@ int chroma_surface_create(chroma_state_t *state, chroma_output_t *output);
void chroma_surface_destroy(chroma_output_t *output);
int chroma_buffer_create(chroma_state_t *state, chroma_output_t *output);
void chroma_buffer_destroy(chroma_output_t *output);
void chroma_buffer_unmap(chroma_output_t *output);
int chroma_render_wallpaper(chroma_state_t *state, chroma_output_t *output);
// Layer shell functions

View file

@ -137,9 +137,7 @@ static int assign_wallpaper_to_output(chroma_state_t *state,
old_filter_quality != output->filter_quality ||
old_anchor != output->anchor || old_anchor_x != output->anchor_x ||
old_anchor_y != output->anchor_y)) {
chroma_log("DEBUG",
"Configuration changed for output %u",
output->id);
chroma_log("DEBUG", "Configuration changed for output %u", output->id);
}
} else {
output->config_loaded = false;
@ -158,8 +156,8 @@ static int assign_wallpaper_to_output(chroma_state_t *state,
// Render wallpaper
int ret = chroma_render_wallpaper(state, output);
if (ret != CHROMA_OK) {
chroma_log("ERROR", "Failed to render wallpaper for output %u: %s", output->id,
chroma_error_string(ret));
chroma_log("ERROR", "Failed to render wallpaper for output %u: %s",
output->id, chroma_error_string(ret));
return ret;
}

View file

@ -33,6 +33,22 @@ void chroma_buffer_destroy(chroma_output_t *output) {
}
}
// Unmap client-side memory while keeping the wl_buffer proxy alive.
// The compositor retains its own fd reference and mapping, so the
// wallpaper remains visible after this call.
void chroma_buffer_unmap(chroma_output_t *output) {
if (!output || !output->shm_data) {
return;
}
if (munmap(output->shm_data, output->shm_size) < 0) {
chroma_log("WARN", "munmap failed: %s", strerror(errno));
}
output->shm_data = NULL;
output->shm_size = 0;
output->shm_stride = 0;
}
// Create shared memory buffer for an output
int chroma_buffer_create(chroma_state_t *state, chroma_output_t *output) {
if (!state || !output || !state->shm) {
@ -80,8 +96,7 @@ int chroma_buffer_create(chroma_state_t *state, chroma_output_t *output) {
// Fill with black
memset(data, 0, size);
struct wl_shm_pool *pool =
wl_shm_create_pool(state->shm, fd, (int32_t)size);
struct wl_shm_pool *pool = wl_shm_create_pool(state->shm, fd, (int32_t)size);
if (!pool) {
chroma_log("ERROR", "wl_shm_create_pool failed");
munmap(data, size);
@ -109,8 +124,7 @@ int chroma_buffer_create(chroma_state_t *state, chroma_output_t *output) {
}
// Sample a pixel from image data (grayscale, grayscale+alpha, RGB, or RGBA)
static inline uint32_t sample_pixel(const chroma_image_t *image, int x,
int y) {
static inline uint32_t sample_pixel(const chroma_image_t *image, int x, int y) {
if (!image || !image->data || x < 0 || y < 0 || x >= image->width ||
y >= image->height) {
return 0xFF000000; // black with full alpha
@ -147,8 +161,7 @@ static inline uint32_t sample_pixel(const chroma_image_t *image, int x,
}
// Draw scaled image into the shared memory buffer
static void draw_scaled_image(chroma_output_t *output,
chroma_image_t *image) {
static void draw_scaled_image(chroma_output_t *output, chroma_image_t *image) {
if (!output || !image || !output->shm_data) {
return;
}
@ -263,10 +276,8 @@ static void draw_scaled_image(chroma_output_t *output,
default: {
if (img_w <= out_w && img_h <= out_h) {
// Image fits entirely - position with anchor
float offset_x =
(anchor_x / 100.0f) * ((float)out_w - (float)img_w);
float offset_y =
(anchor_y / 100.0f) * ((float)out_h - (float)img_h);
float offset_x = (anchor_x / 100.0f) * ((float)out_w - (float)img_w);
float offset_y = (anchor_y / 100.0f) * ((float)out_h - (float)img_h);
for (int y = 0; y < img_h; y++) {
for (int x = 0; x < img_w; x++) {
@ -279,10 +290,8 @@ static void draw_scaled_image(chroma_output_t *output,
}
} else {
// Image is larger than output - clip with anchor
float src_offset_x =
(anchor_x / 100.0f) * ((float)img_w - (float)out_w);
float src_offset_y =
(anchor_y / 100.0f) * ((float)img_h - (float)out_h);
float src_offset_x = (anchor_x / 100.0f) * ((float)img_w - (float)out_w);
float src_offset_y = (anchor_y / 100.0f) * ((float)img_h - (float)out_h);
if (src_offset_x < 0)
src_offset_x = 0;
@ -333,19 +342,16 @@ int chroma_surface_create(chroma_state_t *state, chroma_output_t *output) {
}
// Configure layer surface
zwlr_layer_surface_v1_set_size(output->layer_surface,
(uint32_t)output->width,
zwlr_layer_surface_v1_set_size(output->layer_surface, (uint32_t)output->width,
(uint32_t)output->height);
zwlr_layer_surface_v1_set_anchor(
output->layer_surface,
ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP |
ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT |
ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM |
ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT);
zwlr_layer_surface_v1_set_anchor(output->layer_surface,
ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP |
ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT |
ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM |
ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT);
zwlr_layer_surface_v1_set_exclusive_zone(output->layer_surface, -1);
zwlr_layer_surface_v1_set_keyboard_interactivity(
output->layer_surface,
ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE);
output->layer_surface, ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE);
// Add layer surface listener
zwlr_layer_surface_v1_add_listener(
@ -417,11 +423,18 @@ int chroma_render_wallpaper(chroma_state_t *state, chroma_output_t *output) {
wl_surface_damage_buffer(output->surface, 0, 0, output->width,
output->height);
wl_surface_commit(output->surface);
wl_display_flush(state->display);
if (wl_display_flush(state->display) < 0) {
chroma_log("ERROR", "Failed to flush Wayland display for output %u: %s",
output->id, strerror(errno));
return CHROMA_ERROR_WAYLAND;
}
chroma_log("INFO", "Rendered wallpaper to output %u (%dx%d)", output->id,
output->width, output->height);
// Unmap client-side memory; compositor keeps its own fd reference
chroma_buffer_unmap(output);
// Release image reference and free CPU data if no longer needed
if (output->image) {
chroma_image_t *image = output->image;