]> git.mdlowis.com Git - proto/labwc.git/commitdiff
Restore nested resize
authorConsolatis <35009135+Consolatis@users.noreply.github.com>
Mon, 30 Jan 2023 04:30:24 +0000 (05:30 +0100)
committerJohan Malm <johanmalm@users.noreply.github.com>
Mon, 27 Nov 2023 21:01:53 +0000 (21:01 +0000)
Chases: 756ecf8ee9f1e75bc7b8297dc84f97c7d699174b
backend/wayland: use request_state when toplevel is resized

Chases: 3ef68a484243555b020200c6f95246d994932c3f
backend/x11: use request_state when window is resized

Ref: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/2693

We now delay requested resolution changes by the backend until
the next frame event which causes us to render the new content
on the already enlarged buffer. Before this change, an empty
(black) buffer would have been shown instead before the next
frame event caused a new render of the actual contents.

Keep commiting the new state and then scheduling a frame event
would not help as due to the commit call it would still show an
empty buffer in the meantime.

Just modifying wlr_output->pending wouldn't work either because
wlr_scene_output_commit() *completely* ignores it (and it will
be removed in future wlroots commits). For this reason we move
to wlr_scene_output_build_state() directly because it allows us
to supply the current wlr_output->pending state and thus apply
any resolution change in lockstep with new rendering. Result:
No more flickering in the wayland backend and resizing is again
smooth as butter.

This prevents constant flicker while resizing
when running nested via the wayland backend.

For the X11 backend (can be tested via `WLR_BACKENDS=x11 labwc`),
it is still rather janky but at least doesn't cause endless self-
resizing anymore.

include/common/scene-helpers.h
include/labwc.h
meson.build
src/common/scene-helpers.c
src/output.c

index 4eddf98ccfac71f1ac5c3d38c70dc9256790ef01..98c1bbd6a8dbd04406f4bb52a10911537e890b26 100644 (file)
@@ -2,10 +2,13 @@
 #ifndef LABWC_SCENE_HELPERS_H
 #define LABWC_SCENE_HELPERS_H
 
+#include <stdbool.h>
+
 struct wlr_scene_node;
 struct wlr_scene_rect;
 struct wlr_scene_tree;
 struct wlr_surface;
+struct wlr_scene_output;
 
 struct wlr_scene_rect *lab_wlr_scene_get_rect(struct wlr_scene_node *node);
 struct wlr_scene_tree *lab_scene_tree_from_node(struct wlr_scene_node *node);
@@ -18,4 +21,7 @@ struct wlr_surface *lab_wlr_surface_from_node(struct wlr_scene_node *node);
  */
 struct wlr_scene_node *lab_wlr_scene_get_prev_node(struct wlr_scene_node *node);
 
+/* A variant of wlr_scene_output_commit() that respects wlr_output->pending */
+bool lab_wlr_scene_output_commit(struct wlr_scene_output *scene_output);
+
 #endif /* LABWC_SCENE_HELPERS_H */
index efd12d86061bd83ba5a16bf866f63d524ae51f31..f3f0a2a72133c069c897b5869fb01d51162aeb1c 100644 (file)
@@ -339,6 +339,7 @@ struct output {
 
        struct wl_listener destroy;
        struct wl_listener frame;
+       struct wl_listener request_state;
 
        bool leased;
 };
index 22b99da4db22c382e986f11e0ff12989baf3066d..a80bf565ce0cf48eaebad3cbed39f771f363f37d 100644 (file)
@@ -68,6 +68,7 @@ glib = dependency('glib-2.0')
 cairo = dependency('cairo')
 pangocairo = dependency('pangocairo')
 input = dependency('libinput', version: '>=1.14')
+pixman = dependency('pixman-1')
 math = cc.find_library('m')
 png = dependency('libpng')
 svg = dependency('librsvg-2.0', version: '>=2.46', required: false)
@@ -111,6 +112,7 @@ labwc_deps = [
   drm,
   pangocairo,
   input,
+  pixman,
   math,
   png,
 ]
index 815bde3a217791f9e80e0109de24f93b111bcf1f..7f9a7d0b79af436d094088e436618bb5008ec699 100644 (file)
@@ -1,7 +1,9 @@
 // SPDX-License-Identifier: GPL-2.0-only
 
 #include <assert.h>
+#include <wlr/types/wlr_output.h>
 #include <wlr/types/wlr_scene.h>
+#include <wlr/util/log.h>
 #include "common/scene-helpers.h"
 
 struct wlr_scene_rect *
@@ -45,3 +47,38 @@ lab_wlr_scene_get_prev_node(struct wlr_scene_node *node)
        }
        return prev;
 }
+
+/*
+ * This is a copy of wlr_scene_output_commit()
+ * as it doesn't use the pending state at all.
+ */
+bool
+lab_wlr_scene_output_commit(struct wlr_scene_output *scene_output)
+{
+       assert(scene_output);
+       struct wlr_output *wlr_output = scene_output->output;
+       struct wlr_output_state *state = &wlr_output->pending;
+
+       if (!wlr_output->needs_frame && !pixman_region32_not_empty(
+                       &scene_output->damage_ring.current)) {
+               return false;
+       }
+       if (!wlr_scene_output_build_state(scene_output, state, NULL)) {
+               wlr_log(WLR_ERROR, "Failed to build output state for %s",
+                       wlr_output->name);
+               return false;
+       }
+       if (!wlr_output_commit(wlr_output)) {
+               wlr_log(WLR_ERROR, "Failed to commit output %s",
+                       wlr_output->name);
+               return false;
+       }
+       /*
+        * FIXME: Remove the following line as soon as
+        * https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4253
+        * is merged. At that point wlr_scene handles damage tracking internally
+        * again.
+        */
+       wlr_damage_ring_rotate(&scene_output->damage_ring);
+       return true;
+}
index 4b2e6c90de629e900de141de9fd21ec151e75911..f3e639c5f0550b73a34d542d865d818410e12f2a 100644 (file)
@@ -18,6 +18,7 @@
 #include <wlr/util/log.h>
 #include "common/macros.h"
 #include "common/mem.h"
+#include "common/scene-helpers.h"
 #include "labwc.h"
 #include "layers.h"
 #include "node.h"
@@ -31,12 +32,11 @@ output_frame_notify(struct wl_listener *listener, void *data)
        if (!output_is_usable(output)) {
                return;
        }
-
-       wlr_scene_output_commit(output->scene_output, NULL);
-
-       struct timespec now = { 0 };
-       clock_gettime(CLOCK_MONOTONIC, &now);
-       wlr_scene_output_send_frame_done(output->scene_output, &now);
+       if (lab_wlr_scene_output_commit(output->scene_output)) {
+               struct timespec now = { 0 };
+               clock_gettime(CLOCK_MONOTONIC, &now);
+               wlr_scene_output_send_frame_done(output->scene_output, &now);
+       }
 }
 
 static void
@@ -48,6 +48,7 @@ output_destroy_notify(struct wl_listener *listener, void *data)
        wl_list_remove(&output->link);
        wl_list_remove(&output->frame.link);
        wl_list_remove(&output->destroy.link);
+       wl_list_remove(&output->request_state.link);
 
        for (size_t i = 0; i < ARRAY_SIZE(output->layer_tree); i++) {
                wlr_scene_node_destroy(&output->layer_tree[i]->node);
@@ -70,6 +71,44 @@ output_destroy_notify(struct wl_listener *listener, void *data)
        free(output);
 }
 
+static void
+output_request_state_notify(struct wl_listener *listener, void *data)
+{
+       /* This ensures nested backends can be resized */
+       struct output *output = wl_container_of(listener, output, request_state);
+       const struct wlr_output_event_request_state *event = data;
+       struct wlr_output_state *pending = &output->wlr_output->pending;
+
+       if (!pending->committed) {
+               /* No pending changes, just use the supplied state as new pending */
+               wlr_output_state_copy(pending, event->state);
+               wlr_output_schedule_frame(output->wlr_output);
+               return;
+       }
+
+       if (event->state->committed == WLR_OUTPUT_STATE_MODE) {
+               /* Only the resolution has changed, apply to pending */
+               switch (event->state->mode_type) {
+               case WLR_OUTPUT_STATE_MODE_FIXED:
+                       wlr_output_set_mode(output->wlr_output, event->state->mode);
+                       break;
+               case WLR_OUTPUT_STATE_MODE_CUSTOM:
+                       wlr_output_set_custom_mode(output->wlr_output,
+                               event->state->custom_mode.width,
+                               event->state->custom_mode.height,
+                               event->state->custom_mode.refresh);
+                       break;
+               }
+               wlr_output_schedule_frame(output->wlr_output);
+               return;
+       }
+
+       /* Fallback path for everything that we didn't handle above */
+       if (!wlr_output_commit_state(output->wlr_output, event->state)) {
+               wlr_log(WLR_ERROR, "Backend requested a new state that could not be applied");
+       }
+}
+
 static void do_output_layout_change(struct server *server);
 
 static bool
@@ -180,6 +219,9 @@ new_output_notify(struct wl_listener *listener, void *data)
        output->frame.notify = output_frame_notify;
        wl_signal_add(&wlr_output->events.frame, &output->frame);
 
+       output->request_state.notify = output_request_state_notify;
+       wl_signal_add(&wlr_output->events.request_state, &output->request_state);
+
        wl_list_init(&output->regions);
 
        /*