render: replace EGL/OpenGL pipeline with wl_shm shared memory

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I15dbcca9d12b5c24ed8c82ecc375f4046a6a6964
This commit is contained in:
raf 2026-05-01 13:47:02 +03:00
commit 5ba4407367
Signed by: NotAShelf
GPG key ID: 29D95B64378DB4BF
6 changed files with 323 additions and 739 deletions

View file

@ -34,7 +34,7 @@ DEBUG_CFLAGS += -D_GNU_SOURCE -DCHROMA_VERSION=\"$(VERSION)-debug\"
DEBUG_CFLAGS += -fsanitize=address -fsanitize=undefined -fno-omit-frame-pointer
# Libraries using pkg-config
PKG_DEPS = wayland-client wayland-egl egl glesv2 wayland-protocols
PKG_DEPS = wayland-client wayland-protocols
CFLAGS += $(shell pkg-config --cflags $(PKG_DEPS))
LDFLAGS += $(shell pkg-config --libs $(PKG_DEPS))
@ -117,7 +117,7 @@ static: $(TARGET)
# Check if required dependencies are available
check-deps:
@echo "Checking dependencies..."
@pkg-config --exists $(PKG_DEPS) || (echo "Missing dependencies. Install: wayland-protocols libwayland-dev libegl1-mesa-dev libgl1-mesa-dev wayland-scanner" && exit 1)
@pkg-config --exists $(PKG_DEPS) || (echo "Missing dependencies. Install: wayland-protocols libwayland-dev wayland-scanner" && exit 1)
@which wayland-scanner >/dev/null || (echo "wayland-scanner not found. Please install wayland-scanner." && exit 1)
@echo "All dependencies found."

37
include/chroma.h vendored
View file

@ -3,14 +3,11 @@
#include "wlr-layer-shell-unstable-v1.h"
#include "xdg-shell.h"
#include <EGL/egl.h>
#include <GLES2/gl2.h>
#include <signal.h>
#include <stdbool.h>
#include <stdint.h>
#include <sys/types.h>
#include <wayland-client.h>
#include <wayland-egl.h>
#include "chroma_version.h"
@ -73,6 +70,7 @@ typedef struct {
int channels;
char path[MAX_PATH_LEN];
bool loaded;
bool data_from_stbi; // true if data was allocated by stbi_load
int ref_count; // Number of outputs using this image
} chroma_image_t;
@ -94,10 +92,14 @@ typedef struct {
// Rendering context
struct wl_surface *surface;
struct zwlr_layer_surface_v1 *layer_surface;
struct wl_egl_window *egl_window;
EGLSurface egl_surface;
uint32_t configure_serial;
// Shared memory buffer
struct wl_buffer *shm_buffer;
void *shm_data;
size_t shm_size;
int shm_stride;
// Associated wallpaper
chroma_image_t *image;
@ -108,15 +110,6 @@ typedef struct {
float anchor_x; // custom X offset (0-100, 50=center)
float anchor_y; // custom Y offset (0-100, 50=center)
bool config_loaded;
// OpenGL resource cache
GLuint texture_id;
GLuint shader_program;
GLuint vbo;
GLuint ebo;
bool gl_resources_initialized;
bool texture_uploaded;
bool vbo_dirty; // track VBO needs update
bool configured; // track if initial configure received
} chroma_output_t;
@ -159,14 +152,7 @@ typedef struct chroma_state {
struct wl_registry *registry;
struct wl_compositor *compositor;
struct zwlr_layer_shell_v1 *layer_shell;
// EGL context
EGLDisplay egl_display;
EGLContext egl_context;
EGLConfig egl_config;
// Shared OpenGL resources
GLuint shader_program;
struct wl_shm *shm;
// Outputs
chroma_output_t outputs[MAX_OUTPUTS];
@ -221,13 +207,12 @@ void chroma_output_description(void *data, struct wl_output *output,
const char *description);
void chroma_output_done(void *data, struct wl_output *output);
// EGL and rendering
int chroma_egl_init(chroma_state_t *state);
void chroma_egl_cleanup(chroma_state_t *state);
// Rendering and surface management
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);
int chroma_render_wallpaper(chroma_state_t *state, chroma_output_t *output);
void chroma_output_invalidate_texture(chroma_output_t *output);
// Layer shell functions
void chroma_layer_surface_configure(void *data,

View file

@ -24,8 +24,6 @@ int chroma_init(chroma_state_t *state) {
// Set initial state
state->running = false;
state->initialized = false;
state->egl_display = EGL_NO_DISPLAY;
state->egl_context = EGL_NO_CONTEXT;
// Initialize stb_image
chroma_image_init_stb();
@ -53,9 +51,6 @@ void chroma_cleanup(chroma_state_t *state) {
// Clean up all images
chroma_images_cleanup(state);
// Clean up EGL
chroma_egl_cleanup(state);
// Clean up Wayland
chroma_wayland_disconnect(state);
@ -104,24 +99,16 @@ static int assign_wallpaper_to_output(chroma_state_t *state,
return CHROMA_ERROR_IMAGE;
}
// Check if image changed and invalidate texture cache if neceessary
// Check if image changed
bool image_changed = (output->image != image);
if (image_changed && output->image) {
chroma_image_release(output->image);
chroma_output_invalidate_texture(output);
output->vbo_dirty = true; // VBO needs update for new image
chroma_log("DEBUG", "Image changed for output %u, invalidated texture",
output->id);
chroma_log("DEBUG", "Image changed for output %u", output->id);
}
// Assign image to output
output->image = image;
// Mark VBO as dirty if image changed
if (image_changed) {
output->vbo_dirty = true;
}
// Store old configuration values for comparison
chroma_scale_mode_t old_scale_mode = output->scale_mode;
chroma_filter_quality_t old_filter_quality = output->filter_quality;
@ -144,16 +131,14 @@ static int assign_wallpaper_to_output(chroma_state_t *state,
output->anchor, (double)output->anchor_x,
(double)output->anchor_y);
// Check if configuration changed and invalidate texture if needed
// Check if configuration changed
if (had_config &&
(old_scale_mode != output->scale_mode ||
old_filter_quality != output->filter_quality ||
old_anchor != output->anchor || old_anchor_x != output->anchor_x ||
old_anchor_y != output->anchor_y)) {
chroma_output_invalidate_texture(output);
output->vbo_dirty = true; // VBO needs update for new scale mode
chroma_log("DEBUG",
"Configuration changed for output %u, invalidated texture",
"Configuration changed for output %u",
output->id);
}
} else {

View file

@ -178,16 +178,6 @@ int main(int argc, char *argv[]) {
}
chroma_log_memory_stats("post-wayland-connect");
// Initialize EGL
ret = chroma_egl_init(&state);
if (ret != CHROMA_OK) {
chroma_log("ERROR", "Failed to initialize EGL: %s",
chroma_error_string(ret));
chroma_cleanup(&state);
return 1;
}
chroma_log_memory_stats("post-egl-init");
chroma_log("INFO", "Chroma daemon initialized successfully");
chroma_log_memory_stats("pre-main-loop");

File diff suppressed because it is too large Load diff

View file

@ -37,6 +37,13 @@ static void registry_global(void *data, struct wl_registry *registry,
"TRACE",
"wlr-layer-shell protocol available, wallpaper support enabled");
}
} else if (strcmp(interface, wl_shm_interface.name) == 0) {
state->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1);
if (!state->shm) {
chroma_log("ERROR", "Failed to bind shm");
} else {
chroma_log("INFO", "Bound shm (version %u)", version);
}
} else if (strcmp(interface, wl_output_interface.name) == 0) {
struct wl_output *output = wl_registry_bind(
registry, id, &wl_output_interface, version < 4 ? version : 4);
@ -91,7 +98,7 @@ static void layer_surface_configure(void *data,
chroma_log("TRACE", "Sent configure acknowledgment for output %u serial %u",
output->id, serial);
// Mark as configured - actual commit happens in render via eglSwapBuffers
// Mark as configured - actual commit happens in render via wl_surface_commit
output->configured = true;
chroma_log("DEBUG", "Acknowledged layer surface configure for output %u",
@ -284,6 +291,13 @@ int chroma_wayland_connect(chroma_state_t *state) {
return CHROMA_ERROR_WAYLAND;
}
// Check if we got shm
if (!state->shm) {
chroma_log("ERROR", "No shm available");
chroma_wayland_disconnect(state);
return CHROMA_ERROR_WAYLAND;
}
chroma_log("INFO", "Connected to Wayland display, found %d outputs",
state->output_count);
return CHROMA_OK;
@ -316,6 +330,11 @@ void chroma_wayland_disconnect(chroma_state_t *state) {
state->layer_shell = NULL;
}
if (state->shm) {
wl_shm_destroy(state->shm);
state->shm = NULL;
}
if (state->compositor) {
wl_compositor_destroy(state->compositor);
state->compositor = NULL;