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.

Reply via email to