wayland flickering/ghosting fix
All checks were successful
pyrite-dev/milsko/pipeline/head This commit looks good

This commit is contained in:
IoIxD 2026-09-17 07:25:52 +09:00 committed by IoI_xD
commit 1dda7934ce
8 changed files with 82 additions and 46 deletions

View file

@ -261,6 +261,7 @@ if(MW_USE_WAYLAND)
scan_wayland_protocol("unstable" "primary-selection" "-unstable-v1") scan_wayland_protocol("unstable" "primary-selection" "-unstable-v1")
scan_wayland_protocol("unstable" "pointer-constraints" "-unstable-v1") scan_wayland_protocol("unstable" "pointer-constraints" "-unstable-v1")
scan_wayland_protocol("unstable" "relative-pointer" "-unstable-v1") scan_wayland_protocol("unstable" "relative-pointer" "-unstable-v1")
scan_wayland_protocol("staging" "fifo" "-v1")
scan_wayland_protocol_from_file("wlr-layer-shell" "wlr-layer-shell-unstable-v1.xml") scan_wayland_protocol_from_file("wlr-layer-shell" "wlr-layer-shell-unstable-v1.xml")
target_sources( target_sources(

View file

@ -196,6 +196,9 @@ struct _MwLLCairo {
/* The cairo to actually use for draw operations. Typically is front_cairo, but wayland's MwLLBeginDraw can change this to the back_cairo so it can be used to draw window decorations. */ /* The cairo to actually use for draw operations. Typically is front_cairo, but wayland's MwLLBeginDraw can change this to the back_cairo so it can be used to draw window decorations. */
cairo_t* selected_cairo; cairo_t* selected_cairo;
cairo_surface_t* frontbuffer_cs;
cairo_t* frontbuffer_cairo;
int x; int x;
int y; int y;
int width; int width;

View file

@ -207,6 +207,7 @@ MwInline int wayland_load_funcs() {
#include "Wayland/relative-pointer-client-protocol.h" #include "Wayland/relative-pointer-client-protocol.h"
#include "Wayland/xdg-toplevel-icon-client-protocol.h" #include "Wayland/xdg-toplevel-icon-client-protocol.h"
#include "Wayland/wlr-layer-shell-client-protocol.h" #include "Wayland/wlr-layer-shell-client-protocol.h"
#include "Wayland/fifo-client-protocol.h"
#endif #endif
typedef struct wayland_protocol { typedef struct wayland_protocol {
@ -265,6 +266,7 @@ struct _MwLLWaylandShmBuffer {
struct wl_buffer* shm_buffer_back; struct wl_buffer* shm_buffer_back;
struct wl_surface* surface; struct wl_surface* surface;
struct wl_output* output; struct wl_output* output;
struct wp_fifo_v1* fifo;
MwU8* buf; MwU8* buf;
MwU8* buf_back; MwU8* buf_back;
@ -426,9 +428,13 @@ struct _MwLLWayland {
MwBool force_render; MwBool force_render;
MwBool did_event_loop_early; MwBool did_event_loop_early;
MwBool do_cascading_draw;
int cascading_child_num;
MwBool dispatching_resize; MwBool dispatching_resize;
MwBool is_toplevel_menu;
struct _MwLLWaylandShmBuffer framebuffer; struct _MwLLWaylandShmBuffer framebuffer;
struct _MwLLWaylandShmBuffer backbuffer; struct _MwLLWaylandShmBuffer backbuffer;
struct _MwLLWaylandShmBuffer cursor; struct _MwLLWaylandShmBuffer cursor;

View file

@ -66,6 +66,7 @@ if (grep(/^wayland$/, @backends)) {
scan_wayland_protocol("unstable", "primary-selection", "-unstable-v1"); scan_wayland_protocol("unstable", "primary-selection", "-unstable-v1");
scan_wayland_protocol("unstable", "pointer-constraints", "-unstable-v1"); scan_wayland_protocol("unstable", "pointer-constraints", "-unstable-v1");
scan_wayland_protocol("unstable", "relative-pointer", "-unstable-v1"); scan_wayland_protocol("unstable", "relative-pointer", "-unstable-v1");
scan_wayland_protocol("staging", "fifo", "-v1");
scan_wayland_protocol_from_file("wlr-layer-shell", scan_wayland_protocol_from_file("wlr-layer-shell",
"wlr-layer-shell-unstable-v1.xml"); "wlr-layer-shell-unstable-v1.xml");

View file

@ -113,13 +113,16 @@ void MwLLCairoDrawPixmap(struct _MwLLCairo handle, MwRect* rect, MwLLPixmap pixm
void MwLLCairoFrontSetup(struct _MwLLCairo* cairo, MwU8* data, MwU32 width, MwU32 height) { void MwLLCairoFrontSetup(struct _MwLLCairo* cairo, MwU8* data, MwU32 width, MwU32 height) {
if(data) { if(data) {
cairo->front_cs = cairo_image_surface_create_for_data(data, CAIRO_FORMAT_ARGB32, width, height, width * 4); cairo->front_cs = cairo_image_surface_create_for_data(data, CAIRO_FORMAT_ARGB32, width, height, width * 4);
cairo->frontbuffer_cs = cairo_image_surface_create_for_data(data, CAIRO_FORMAT_ARGB32, width, height, width * 4);
} else { } else {
cairo->front_cs = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); cairo->front_cs = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
cairo->frontbuffer_cs = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
} }
cairo->front_cs_back = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); cairo->front_cs_back = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
cairo->front_cairo_back = cairo_create(cairo->front_cs_back); cairo->front_cairo_back = cairo_create(cairo->front_cs_back);
cairo->front_cairo = cairo_create(cairo->front_cs); cairo->front_cairo = cairo_create(cairo->front_cs);
cairo->frontbuffer_cairo = cairo_create(cairo->frontbuffer_cs);
} }
void MwLLCairoBackSetup(struct _MwLLCairo* cairo, MwU8* data, MwU32 width, MwU32 height) { void MwLLCairoBackSetup(struct _MwLLCairo* cairo, MwU8* data, MwU32 width, MwU32 height) {
@ -135,6 +138,8 @@ void MwLLCairoFrontDestroy(struct _MwLLCairo* cairo) {
cairo_destroy(cairo->front_cairo); cairo_destroy(cairo->front_cairo);
cairo_destroy(cairo->front_cairo_back); cairo_destroy(cairo->front_cairo_back);
cairo_surface_destroy(cairo->front_cs); cairo_surface_destroy(cairo->front_cs);
cairo_surface_destroy(cairo->frontbuffer_cs);
cairo_destroy(cairo->frontbuffer_cairo);
}; };
void MwLLCairoBackDestroy(struct _MwLLCairo* cairo) { void MwLLCairoBackDestroy(struct _MwLLCairo* cairo) {
cairo_destroy(cairo->back_cairo); cairo_destroy(cairo->back_cairo);
@ -214,8 +219,8 @@ static void MwLLFreeColorImpl(MwLLColor color) {}
static MwBool lmao = MwFALSE; static MwBool lmao = MwFALSE;
static int MwLLPendingImpl(MwLL handle) { static int MwLLPendingImpl(MwLL handle) {
lmao = !lmao; lmao = !lmao;
return lmao; return lmao;
} }
static void MwLLNextEventImpl(MwLL handle) { static void MwLLNextEventImpl(MwLL handle) {
MwLLDispatch(handle, draw, NULL); MwLLDispatch(handle, draw, NULL);
@ -259,10 +264,10 @@ static void MwLLRaiseImpl(MwLL handle) {}
static void MwLLClipImpl(MwLL handle, MwRect* rect) {} static void MwLLClipImpl(MwLL handle, MwRect* rect) {}
static void MwLLSetupDragAndDropImpl(MwLL handle) {} static void MwLLSetupDragAndDropImpl(MwLL handle) {}
static int MwLLCairoCallInitImpl(void) { static int MwLLCairoCallInitImpl(void) {
if(cairo_load_funcs() != 0) { if(cairo_load_funcs() != 0) {
return 1; return 1;
} }
return 0; return 0;
} }
#include "call.c" #include "call.c"
CALL(Cairo); CALL(Cairo);

View file

@ -10,6 +10,9 @@ void MwLLWaylandFramebufferSetup(struct _MwLLWayland* wayland) {
memset(wayland->framebuffer.buf_back, 0, wayland->framebuffer.buf_size); memset(wayland->framebuffer.buf_back, 0, wayland->framebuffer.buf_size);
if(wayland->configured) if(wayland->configured)
wl_surface_attach(wayland->framebuffer.surface, wayland->framebuffer.shm_buffer, 0, 0); wl_surface_attach(wayland->framebuffer.surface, wayland->framebuffer.shm_buffer, 0, 0);
if(wayland->framebuffer.fifo)
wp_fifo_v1_set_barrier(wayland->framebuffer.fifo);
wl_surface_commit(wayland->framebuffer.surface); wl_surface_commit(wayland->framebuffer.surface);
MwLLWaylandHangUntilConfigured((MwLL)wayland); MwLLWaylandHangUntilConfigured((MwLL)wayland);
@ -38,6 +41,8 @@ void MwLLWaylandBackbufferSetup(struct _MwLLWayland* wayland) {
memset(wayland->backbuffer.buf_back, 255, wayland->backbuffer.buf_size); memset(wayland->backbuffer.buf_back, 255, wayland->backbuffer.buf_size);
if(wayland->configured) if(wayland->configured)
wl_surface_attach(wayland->backbuffer.surface, wayland->backbuffer.shm_buffer, 0, 0); wl_surface_attach(wayland->backbuffer.surface, wayland->backbuffer.shm_buffer, 0, 0);
// if(wayland->framebuffer.fifo)
// wp_fifo_v1_set_barrier(wayland->framebuffer.fifo);
wl_surface_commit(wayland->backbuffer.surface); wl_surface_commit(wayland->backbuffer.surface);
MwLLWaylandHangUntilConfigured((MwLL)wayland); MwLLWaylandHangUntilConfigured((MwLL)wayland);
MwLLWaylandBufferUpdate((MwLL)wayland, &wayland->backbuffer); MwLLWaylandBufferUpdate((MwLL)wayland, &wayland->backbuffer);
@ -119,9 +124,11 @@ void MwLLWaylandBufferUpdate(MwLL self, struct _MwLLWaylandShmBuffer* buffer) {
memcpy(buffer->buf, buffer->buf_back, buffer->buf_size); memcpy(buffer->buf, buffer->buf_back, buffer->buf_size);
if(buffer->surface) { if(buffer->surface) {
// Yes this is needed every time, it's how we fix weston. // Yes this is needed every time, it's how we fix weston.
if(self->wayland.configured) if(self->wayland.configured) {
wl_surface_attach(buffer->surface, buffer->shm_buffer, 0, 0); wl_surface_attach(buffer->surface, buffer->shm_buffer, 0, 0);
}
if(buffer->fifo)
wp_fifo_v1_wait_barrier(buffer->fifo);
wl_surface_commit(buffer->surface); wl_surface_commit(buffer->surface);
} }
} }

View file

@ -749,6 +749,7 @@ static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time
if(self->wayland.backbuffer.surface) { if(self->wayland.backbuffer.surface) {
wl_pointer_set_cursor(self->wayland.pointer, self->wayland.pointer_serial, self->wayland.cursor.surface, 0, 0); wl_pointer_set_cursor(self->wayland.pointer, self->wayland.pointer_serial, self->wayland.cursor.surface, 0, 0);
} }
WAYLAND_EVENT_OP_END(self); WAYLAND_EVENT_OP_END(self);
}; };
@ -1511,6 +1512,21 @@ static void zwlr_layer_shell_v1_interface_destroy(struct _MwLLWayland* wayland,
free(data); free(data);
} }
static wayland_protocol_t* wp_fifo_manager_v1_setup(MwU32 name, struct _MwLLWayland* wayland, MwU32 version) {
wayland_protocol_t* proto = malloc(sizeof(wayland_protocol_t));
proto->context = wl_registry_bind(wayland->registry, name, &wp_fifo_manager_v1_interface, version);
proto->listener = NULL;
return proto;
}
static void wp_fifo_manager_v1_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) {
(void)wayland;
free(data);
}
/* Function for setting up the callbacks/structs that will be registered upon the relevant interfaces being found. */ /* Function for setting up the callbacks/structs that will be registered upon the relevant interfaces being found. */
void MwLLWaylandSetupCallbacks(struct _MwLLWayland* wayland) { void MwLLWaylandSetupCallbacks(struct _MwLLWayland* wayland) {
/* Convience macro for adding the interface functions to the setup map */ /* Convience macro for adding the interface functions to the setup map */
@ -1553,6 +1569,7 @@ void MwLLWaylandSetupCallbacks(struct _MwLLWayland* wayland) {
WL_INTERFACE(xdg_toplevel_icon_manager_v1); WL_INTERFACE(xdg_toplevel_icon_manager_v1);
WL_INTERFACE(wl_subcompositor); WL_INTERFACE(wl_subcompositor);
WL_INTERFACE(wl_seat); WL_INTERFACE(wl_seat);
WL_INTERFACE(wp_fifo_manager_v1);
} else if(wayland->type == MwLL_WAYLAND_POPUP) { } else if(wayland->type == MwLL_WAYLAND_POPUP) {
WL_INTERFACE(wl_seat); WL_INTERFACE(wl_seat);
} else if(wayland->type == MwLL_WAYLAND_LAYER_SURFACE) { } else if(wayland->type == MwLL_WAYLAND_LAYER_SURFACE) {

View file

@ -265,6 +265,10 @@ static void setup_toplevel(MwLL r, int x, int y) {
r->wayland.toplevel->ssurface = wl_subcompositor_get_subsurface(r->wayland.toplevel->scompositor, r->wayland.framebuffer.surface, r->wayland.backbuffer.surface); r->wayland.toplevel->ssurface = wl_subcompositor_get_subsurface(r->wayland.toplevel->scompositor, r->wayland.framebuffer.surface, r->wayland.backbuffer.surface);
wl_subsurface_set_desync(r->wayland.toplevel->ssurface); wl_subsurface_set_desync(r->wayland.toplevel->ssurface);
if(WAYLAND_GET_INTERFACE(r->wayland, wp_fifo_manager_v1) != NULL) {
r->wayland.framebuffer.fifo = wp_fifo_manager_v1_get_fifo(WAYLAND_GET_INTERFACE(r->wayland, wp_fifo_manager_v1)->context, r->wayland.framebuffer.surface);
}
r->wayland.toplevel->xdg_surface = r->wayland.toplevel->xdg_surface =
xdg_wm_base_get_xdg_surface(WAYLAND_GET_INTERFACE(r->wayland, xdg_wm_base)->context, r->wayland.backbuffer.surface); xdg_wm_base_get_xdg_surface(WAYLAND_GET_INTERFACE(r->wayland, xdg_wm_base)->context, r->wayland.backbuffer.surface);
r->wayland.toplevel->xdg_top_level = xdg_surface_get_toplevel(r->wayland.toplevel->xdg_surface); r->wayland.toplevel->xdg_top_level = xdg_surface_get_toplevel(r->wayland.toplevel->xdg_surface);
@ -407,10 +411,13 @@ static void popup_configure(void* data,
if(width < 50) width = 50; if(width < 50) width = 50;
if(height < 50) height = 50; if(height < 50) height = 50;
self->wayland.x = x; self->wayland.x = x;
self->wayland.y = y; self->wayland.y = y;
self->wayland.ww = width;
self->wayland.wh = height; if(!self->wayland.setting_wh) {
self->wayland.ww = width;
self->wayland.wh = height;
}
}; };
static void popup_done(void* data, static void popup_done(void* data,
@ -439,10 +446,11 @@ struct xdg_popup_listener popup_listener = {
static void setup_popup(MwLL r, int x, int y, MwLL parent) { static void setup_popup(MwLL r, int x, int y, MwLL parent) {
char* mw_force_csd = getenv("MW_FORCE_CSD"); char* mw_force_csd = getenv("MW_FORCE_CSD");
MwLL topmost_parent = r->wayland.parent; MwLL topmost_parent = r->wayland.parent;
r->wayland.type = MwLL_WAYLAND_POPUP;
r->wayland.x = x; r->wayland.type = MwLL_WAYLAND_POPUP;
r->wayland.y = y; r->wayland.x = x;
r->wayland.popup = malloc(sizeof(struct _MwLLWaylandPopup)); r->wayland.y = y;
r->wayland.popup = malloc(sizeof(struct _MwLLWaylandPopup));
if(parent) { if(parent) {
MwWidget p = parent->common.user; MwWidget p = parent->common.user;
@ -908,13 +916,8 @@ static void draw_child(MwLL handle, MwLL child) {
cairo_t* c; cairo_t* c;
cairo_surface_t* cs; cairo_surface_t* cs;
cairo_t* selected_cairo; cairo_t* selected_cairo;
MwLL topmost_parent = handle;
if(topmost_parent->wayland.type != MwLL_WAYLAND_POPUP) { draw_children(child);
while(topmost_parent->wayland.parent) {
topmost_parent = topmost_parent->wayland.parent;
}
}
wl_surface_commit(child->wayland.framebuffer.surface); wl_surface_commit(child->wayland.framebuffer.surface);
@ -928,20 +931,18 @@ static void draw_child(MwLL handle, MwLL child) {
cairo_paint(c); cairo_paint(c);
// printf("%d %d\n", child->wayland.x, child->wayland.y);
cairo_set_source_surface(handle->wayland.cairo.front_cairo_back, cs, child->wayland.x, child->wayland.y); cairo_set_source_surface(handle->wayland.cairo.front_cairo_back, cs, child->wayland.x, child->wayland.y);
cairo_paint(handle->wayland.cairo.front_cairo_back); cairo_paint(handle->wayland.cairo.front_cairo_back);
cairo_destroy(c); cairo_destroy(c);
cairo_surface_destroy(cs); cairo_surface_destroy(cs);
draw_children(child);
} }
static void draw_children(MwLL handle) { static void draw_children(MwLL handle) {
wl_surface_damage(handle->wayland.framebuffer.surface, 0, 0, handle->wayland.ww, handle->wayland.wh); wl_surface_damage(handle->wayland.framebuffer.surface, 0, 0, handle->wayland.ww, handle->wayland.wh);
cairo_reset_clip(handle->wayland.cairo.front_cairo_back);
MwLLWaylandChildrenIterate(handle, draw_child); MwLLWaylandChildrenIterate(handle, draw_child);
if(handle->wayland.configured) MwLLWaylandBufferUpdate(handle, &handle->wayland.framebuffer); if(handle->wayland.configured) MwLLWaylandBufferUpdate(handle, &handle->wayland.framebuffer);
@ -949,24 +950,13 @@ static void draw_children(MwLL handle) {
} }
static void frontbuffer_draw(MwLL handle) { static void frontbuffer_draw(MwLL handle) {
cairo_t* c; cairo_t* c = handle->wayland.cairo.frontbuffer_cairo;
cairo_surface_t* cs;
cs = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, handle->wayland.ww, handle->wayland.wh);
c = cairo_create(cs);
cairo_set_source_surface(c, handle->wayland.cairo.front_cs_back, 0, 0); cairo_set_source_surface(c, handle->wayland.cairo.front_cs_back, 0, 0);
cairo_pattern_set_filter(cairo_get_source(c), CAIRO_FILTER_NEAREST); cairo_pattern_set_filter(cairo_get_source(c), CAIRO_FILTER_NEAREST);
cairo_set_operator(handle->wayland.cairo.front_cairo_back, CAIRO_OPERATOR_OVER); cairo_set_operator(handle->wayland.cairo.front_cairo_back, CAIRO_OPERATOR_OVER);
cairo_paint(c); cairo_paint(c);
cairo_set_source_surface(handle->wayland.cairo.front_cairo, cs, 0, 0);
cairo_paint(handle->wayland.cairo.front_cairo);
cairo_destroy(c);
cairo_surface_destroy(cs);
} }
static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) {
@ -1301,10 +1291,17 @@ static void MwLLBeginDrawImpl(MwLL handle) {
} }
static void MwLLEndDrawImpl(MwLL handle) { static void MwLLEndDrawImpl(MwLL handle) {
MwLL root = handle;
while(root->wayland.type == MwLL_WAYLAND_SUBLEVEL && root->wayland.parent) {
root = root->wayland.parent;
}
root->wayland.do_cascading_draw = MwTRUE;
if(handle->wayland.configured) { if(handle->wayland.configured) {
if(handle->wayland.type == MwLL_WAYLAND_TOPLEVEL) { if(handle->wayland.type == MwLL_WAYLAND_TOPLEVEL) {
MwLLWaylandBufferUpdate(handle, &handle->wayland.backbuffer); MwLLWaylandBufferUpdate(handle, &handle->wayland.backbuffer);
} }
MwLLWaylandBufferUpdate(handle, &handle->wayland.framebuffer); MwLLWaylandBufferUpdate(handle, &handle->wayland.framebuffer);
} }
} }
@ -1363,9 +1360,10 @@ static int MwLLPendingImpl(MwLL handle) {
handle->wayland.resizing = 0; handle->wayland.resizing = 0;
if(handle->wayland.type != MwLL_WAYLAND_SUBLEVEL) { if(handle->wayland.do_cascading_draw) {
draw_children(handle); draw_children(handle);
frontbuffer_draw(handle); frontbuffer_draw(handle);
handle->wayland.do_cascading_draw = MwFALSE;
} }
if(handle->wayland.setting_wh) { if(handle->wayland.setting_wh) {
@ -1430,7 +1428,6 @@ static int MwLLPendingImpl(MwLL handle) {
} }
static void MwLLNextEventImpl(MwLL handle) { static void MwLLNextEventImpl(MwLL handle) {
if(!MwWaylandVulkan) { if(!MwWaylandVulkan) {
if(handle->wayland.did_event_loop_early) { if(handle->wayland.did_event_loop_early) {
handle->wayland.did_event_loop_early = MwFALSE; handle->wayland.did_event_loop_early = MwFALSE;
@ -1450,7 +1447,6 @@ static void MwLLNextEventImpl(MwLL handle) {
} }
static void MwLLSetTitleImpl(MwLL handle, const char* title) { static void MwLLSetTitleImpl(MwLL handle, const char* title) {
if(handle->wayland.type == MwLL_WAYLAND_TOPLEVEL) { if(handle->wayland.type == MwLL_WAYLAND_TOPLEVEL) {
xdg_toplevel_set_title(handle->wayland.toplevel->xdg_top_level, title); xdg_toplevel_set_title(handle->wayland.toplevel->xdg_top_level, title);
} }