This is an automated email from the git hooks/post-receive script.
git pushed a commit to branch wl/real-browser
in repository enlightenment.
View the commit online.
commit 349bce3e4e278423c6425cb8389817ca53a81b6c
Author: Cedric BAIL <[email protected]>
AuthorDate: Sun Aug 16 23:37:02 2026 -0600
e_pixmap - a deferred buffer release has to actually happen
Deferring a release while a render is in flight (cd3c2d4d4) stopped the
compositor crashing and started something worse for the user: browsers froze.
Brave passed the browser matrix 0 to 2 times in 4. Its wire log says why - not
one wl_buffer.release in the whole session. It attached a buffer, never got it
back, ran out, and stopped drawing. From outside that looks like a browser
ignoring a configure, which is what it was diagnosed as twice.
Deferred buffers went onto cp->free_buffers, and the only thing that emptied
that list was e_pixmap_image_clear, which runs from the post-render job for
clients that were rendered again afterwards. A client whose window has just
stopped changing is precisely the one that will not be rendered again - so the
buffers it is waiting for are held by the frame that stopped needing them.
So keep the pixmaps that owe a release on a list of their own, and flush them
all once the renderer has genuinely finished. That is RENDER_POST, not
RENDER_FLUSH_POST: with async rendering the flush only means the drawing has
been handed to a worker thread, and the whole point of the deferral is that
the worker is still reading. e_comp_canvas already has a RENDER_POST handler,
and its comment already says that is where a shm buffer actually gets read.
A/B, four runs each: with the deferral and no flush, Brave 0/4. Without the
deferral at all, 4/4 - and the resize crash back. With the flush, 4/4 and no
crash. Firefox 4/4, Chromium 3/4, no cores in any of it, and
test_client_move - the interactive resize that the deferral exists for - passes
three for three.
wl-globals, all eleven protocol tests and e_wlcs_driver pass.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
---
src/bin/e_comp_canvas.c | 5 +++++
src/bin/e_comp_wl.c | 4 ++++
src/bin/e_pixmap.c | 30 ++++++++++++++++++++++++++++++
src/bin/e_pixmap.h | 1 +
src/modules/wl_desktop_shell/xdg.c | 2 ++
5 files changed, 42 insertions(+)
diff --git a/src/bin/e_comp_canvas.c b/src/bin/e_comp_canvas.c
index 215ae8d3a..92e08586e 100644
--- a/src/bin/e_comp_canvas.c
+++ b/src/bin/e_comp_canvas.c
@@ -91,6 +91,11 @@ _e_comp_canvas_render_track_post(void *data EINA_UNUSED, Evas *e EINA_UNUSED, vo
* are back on solid ground and it can post the error. */
e_comp_wl_shm_fault_check();
+ /* And release every buffer whose release was put off while this render was
+ * in flight. RENDER_POST rather than the flush, because with async
+ * rendering the flush only means the drawing was handed to a worker. */
+ e_pixmap_deferred_flush();
+
if (conf->fps_show)
{
int info[4] = { E_COMP_FRAME_EVENT_RENDER_END, 0, 0, 0 };
diff --git a/src/bin/e_comp_wl.c b/src/bin/e_comp_wl.c
index dff5a8ff2..40cd25cbd 100644
--- a/src/bin/e_comp_wl.c
+++ b/src/bin/e_comp_wl.c
@@ -2107,6 +2107,10 @@ _e_comp_wl_surface_state_commit(E_Client *ec, E_Comp_Wl_Surface_State *state)
if (!_e_comp_wl_viewport_state_check(ec, state)) return;
ec->comp_data->in_commit = 1;
+ if (ec->comp_data->shell.set.maximize || ec->comp_data->shell.set.unmaximize)
+ fprintf(stderr, "DBG commit: set.max=%d set.unmax=%d ecmax=0x%x\n",
+ ec->comp_data->shell.set.maximize, ec->comp_data->shell.set.unmaximize,
+ ec->maximized);
/* Latch the viewport before anything reads a size. set_source and
* set_destination are double buffered like the rest of the surface state,
diff --git a/src/bin/e_pixmap.c b/src/bin/e_pixmap.c
index dc6713656..bb018596c 100644
--- a/src/bin/e_pixmap.c
+++ b/src/bin/e_pixmap.c
@@ -20,6 +20,16 @@
#include <sys/mman.h>
static Eina_Hash *pixmaps[2] = {NULL};
+#ifdef HAVE_WAYLAND
+/* Pixmaps holding buffers whose release was put off because a render was in
+ * flight. Kept as a list of its own so the flush can find them: the buffers
+ * used to be drained only by e_pixmap_image_clear, which runs for the clients
+ * that were rendered again afterwards - and a client whose window has stopped
+ * changing is exactly the one that will not be. It then never gets its buffers
+ * back, runs out, and stops drawing, which from outside looks like a browser
+ * ignoring a configure. */
+static Eina_List *_deferred_pixmaps = NULL;
+#endif
static Eina_Hash *aliases[2] = {NULL};
struct _E_Pixmap
@@ -195,6 +205,8 @@ _e_pixmap_wayland_buffer_release(E_Pixmap *cp, E_Comp_Wl_Buffer *buffer)
wl_signal_add(&buffer->destroy_signal,
&buffer->deferred_destroy_listener);
cp->free_buffers = eina_list_append(cp->free_buffers, buffer);
+ if (!eina_list_data_find(_deferred_pixmaps, cp))
+ _deferred_pixmaps = eina_list_append(_deferred_pixmaps, cp);
return;
}
@@ -233,6 +245,23 @@ _e_pixmap_wl_buffers_free(E_Pixmap *cp)
}
}
+/* Every buffer whose release was put off, released now. Called once the
+ * renderer has genuinely finished - RENDER_POST, not the flush - so the
+ * deferral has served its purpose and holding on any longer only starves the
+ * client. */
+E_API void
+e_pixmap_deferred_flush(void)
+{
+#ifdef HAVE_WAYLAND
+ Eina_List *l = _deferred_pixmaps;
+ E_Pixmap *cp;
+
+ _deferred_pixmaps = NULL;
+ EINA_LIST_FREE(l, cp)
+ _e_pixmap_wl_buffers_free(cp);
+#endif
+}
+
static void
_e_pixmap_wayland_image_clear(E_Pixmap *cp)
{
@@ -300,6 +329,7 @@ _e_pixmap_free(E_Pixmap *cp)
* listeners, so the crash lands later and somewhere else - in
* wl_signal_emit, calling a notify that is no longer a function. */
_e_pixmap_wl_buffers_free(cp);
+ _deferred_pixmaps = eina_list_remove(_deferred_pixmaps, cp);
if (cp->buffer_destroy_listener.notify)
{
wl_list_remove(&cp->buffer_destroy_listener.link);
diff --git a/src/bin/e_pixmap.h b/src/bin/e_pixmap.h
index afd5065a3..5f802ba5b 100644
--- a/src/bin/e_pixmap.h
+++ b/src/bin/e_pixmap.h
@@ -32,6 +32,7 @@ E_API void e_pixmap_dirty(E_Pixmap *cp);
E_API Eina_Bool e_pixmap_refresh(E_Pixmap *cp);
E_API Eina_Bool e_pixmap_size_changed(E_Pixmap *cp, int w, int h);
E_API Eina_Bool e_pixmap_size_get(E_Pixmap *cp, int *w, int *h);
+E_API void e_pixmap_deferred_flush(void);
E_API void e_pixmap_client_set(E_Pixmap *cp, E_Client *ec);
E_API E_Client *e_pixmap_client_get(E_Pixmap *cp);
E_API E_Pixmap *e_pixmap_find(E_Pixmap_Type type, ...);
diff --git a/src/modules/wl_desktop_shell/xdg.c b/src/modules/wl_desktop_shell/xdg.c
index f8b0c37aa..ff6bd102d 100644
--- a/src/modules/wl_desktop_shell/xdg.c
+++ b/src/modules/wl_desktop_shell/xdg.c
@@ -628,6 +628,7 @@ _xdg_shell_surface_send_configure(struct wl_resource *resource, Eina_Bool fullsc
_e_xdg_toplevel_configure_bounds_send(resource, ec);
serial = wl_display_next_serial(e_comp_wl->wl.disp);
+ fprintf(stderr, "DBG send=%u %dx%d max=%d pending=0x%x\n", serial, width, height, maximized, pending);
xdg_toplevel_send_configure(resource, width, height, &states);
{
Pending_State *ps;
@@ -835,6 +836,7 @@ _e_xdg_surface_cb_ack_configure(struct wl_client *client EINA_UNUSED, struct wl_
EINA_LIST_FOREACH_SAFE(shd->pending, l, ll, ps)
{
if (ps->serial > serial) break;
+ fprintf(stderr, "DBG ack=%u ps=%u state=0x%x\n", serial, ps->serial, ps->state);
if (ps->state & STATE_FULLSCREEN)
{
ec->comp_data->shell.set.fullscreen = 1;
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.