diff options
-rw-r--r-- | .SRCINFO | 62 | ||||
-rw-r--r-- | .gitignore | 12 | ||||
-rw-r--r-- | PKGBUILD | 123 | ||||
-rw-r--r-- | meta_clip_effect.c | 219 | ||||
-rw-r--r-- | meta_clip_effect.h | 20 | ||||
-rw-r--r-- | mr1441.patch | 2549 | ||||
-rw-r--r-- | mutter-rounded.install | 13 | ||||
-rw-r--r-- | rounded_corners.patch | 1900 | ||||
-rw-r--r-- | shader.h | 116 | ||||
-rw-r--r-- | shell-blur-effect.c | 907 | ||||
-rw-r--r-- | shell-blur-effect.h | 57 | ||||
-rw-r--r-- | shell_blur_effect.patch | 462 |
12 files changed, 19 insertions, 6421 deletions
@@ -1,61 +1,9 @@ pkgbase = mutter-rounded - pkgdesc = A window manager for GNOME, with rounded corners patch (integrate mr1441) + pkgdesc = metapackage - migrate to gnome-shell-extension-rounded-window-corners pkgver = 42.3 - pkgrel = 1 - url = https://gitlab.gnome.org/GNOME/mutter - install = mutter-rounded.install - arch = x86_64 - license = GPL - checkdepends = xorg-server-xvfb - checkdepends = wireplumber - checkdepends = python-dbusmock - makedepends = gobject-introspection - makedepends = git - makedepends = egl-wayland - makedepends = meson - makedepends = xorg-server - makedepends = wayland-protocols - makedepends = sysprof - makedepends = gi-docgen - depends = dconf - depends = gobject-introspection-runtime - depends = gsettings-desktop-schemas - depends = libcanberra - depends = startup-notification - depends = zenity - depends = libsm - depends = gnome-desktop - depends = libxkbcommon-x11 - depends = gnome-settings-daemon - depends = libgudev - depends = libinput - depends = pipewire - depends = xorg-xwayland - depends = graphene - depends = libxkbfile - depends = libsysprof-capture - provides = libmutter-10.so - provides = mutter - conflicts = mutter - source = mutter-rounded::git+https://gitlab.gnome.org/GNOME/mutter.git#commit=1903356b45c6c884a0451580f32494ff1288656d - source = mutter_settings::git+https://github.com/yilozt/mutter-rounded-setting - source = rounded_corners.patch - source = shell_blur_effect.patch - source = meta_clip_effect.c - source = meta_clip_effect.h - source = shader.h - source = shell-blur-effect.h - source = shell-blur-effect.c - source = mr1441.patch - sha256sums = SKIP - sha256sums = SKIP - sha256sums = 71a533c3a398068025ade421b4f28dbba46eb408068a922334a64a8e0838aefc - sha256sums = 369390774cf8607f9033a077e0ac76113ffc1c0997627949e087c757a5f41844 - sha256sums = a78e0bdbf4d0b5c8c0f83ede60b531bf0d5d616bfee30293a1f27d32d738dbc6 - sha256sums = 2ec553a260497f0ac0180512201c9819b10159a15fcbc6d5007932d8e2a44844 - sha256sums = f818921dd63cf592663817280c7481eae0852854dd4cd8865ac5fe92423c6fd5 - sha256sums = 8fb024306843153b28db2f5347775ef7e8add1dd846345148a572ad5336e168b - sha256sums = 5093c7afd6ad66c0ee9fa1565ef61109f5edf958d1d32789a34ab41d0112771d - sha256sums = 484604741ae85e778c7054b855b8506e3396759f3eee7a030a5964742b8ace19 + pkgrel = 2 + arch = any pkgname = mutter-rounded + depends = gnome-shell-extension-rounded-window-corners + depends = mutter diff --git a/.gitignore b/.gitignore index 730524f6aa0e..018a3de08144 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,4 @@ -/src -/pkg -/mutter-rounded -/mutter_settings -mutter-settings.tar -mutter_setting -*pkg.tar.zst -mutter-rounded*log +* +!PKGBUILD +!.SRCINFO +!.gitignore @@ -1,118 +1,15 @@ -# Patched package: -# Maintainer: Luo Yi <langisme_at_qq_dot_com> -# Contributor: Joakim Soderlund <joakim.soderlund@gmail.com> +# Maintainer: -# Official package: -# Maintainer: Jan Alexander Steffens (heftig) <heftig@archlinux.org> -# Contributor: Ionut Biru <ibiru@archlinux.org> -# Contributor: Michael Kanis <mkanis_at_gmx_dot_de> - -pkgname=mutter-rounded +_newpkg='gnome-shell-extension-rounded-window-corners' +pkgname='mutter-rounded' pkgver=42.3 -pkgrel=1 -pkgdesc="A window manager for GNOME, with rounded corners patch (integrate mr1441)" -url="https://gitlab.gnome.org/GNOME/mutter" -arch=(x86_64) -license=(GPL) -depends=(dconf gobject-introspection-runtime gsettings-desktop-schemas - libcanberra startup-notification zenity libsm gnome-desktop - libxkbcommon-x11 gnome-settings-daemon libgudev libinput pipewire - xorg-xwayland graphene libxkbfile libsysprof-capture) -makedepends=(gobject-introspection git egl-wayland meson xorg-server - wayland-protocols sysprof gi-docgen) -checkdepends=(xorg-server-xvfb wireplumber python-dbusmock) -provides=(libmutter-10.so mutter) -conflicts=(mutter) -install=mutter-rounded.install - -_commit=1903356b45c6c884a0451580f32494ff1288656d # tags/42.3^0 -_mutter_src="$pkgname::git+https://gitlab.gnome.org/GNOME/mutter.git#commit=$_commit" -_settings_src="mutter_settings::git+https://github.com/yilozt/mutter-rounded-setting" - -source=("$_mutter_src" - "$_settings_src" - "rounded_corners.patch" - "shell_blur_effect.patch" - "meta_clip_effect.c" - "meta_clip_effect.h" - "shader.h" - "shell-blur-effect.h" # https://gitlab.gnome.org/GNOME/gnome-shell/-/raw/${pkgver}/src/shell-blur-effect.h - "shell-blur-effect.c" # https://gitlab.gnome.org/GNOME/gnome-shell/-/raw/${pkgver}/src/shell-blur-effect.c - "mr1441.patch" - ) -sha256sums=('SKIP' - 'SKIP' - '71a533c3a398068025ade421b4f28dbba46eb408068a922334a64a8e0838aefc' - '369390774cf8607f9033a077e0ac76113ffc1c0997627949e087c757a5f41844' - 'a78e0bdbf4d0b5c8c0f83ede60b531bf0d5d616bfee30293a1f27d32d738dbc6' - '2ec553a260497f0ac0180512201c9819b10159a15fcbc6d5007932d8e2a44844' - 'f818921dd63cf592663817280c7481eae0852854dd4cd8865ac5fe92423c6fd5' - '8fb024306843153b28db2f5347775ef7e8add1dd846345148a572ad5336e168b' - '5093c7afd6ad66c0ee9fa1565ef61109f5edf958d1d32789a34ab41d0112771d' - '484604741ae85e778c7054b855b8506e3396759f3eee7a030a5964742b8ace19') - -pkgver() { - cd $pkgname - git describe --tags | sed 's/[^-]*-g/r&/;s/-/+/g' -} - -prepare() { - sed -i '1i\#!/usr/bin/gjs' mutter_settings/dist/mutter_settings.js - mv mutter_settings/dist/mutter_settings.js mutter_settings/dist/mutter_settings - - cd $pkgname - - find -name "*.orig" -exec rm {} \; - cp $srcdir/*.[ch] $srcdir/$pkgname/src - patch -p1 < $srcdir/rounded_corners.patch - patch -p1 < $srcdir/shell_blur_effect.patch - patch -p1 < $srcdir/mr1441.patch -} - -build() { - CFLAGS="${CFLAGS/-O2/-O3} -fno-semantic-interposition" - LDFLAGS+=" -Wl,-Bsymbolic-functions" - - arch-meson $pkgname build \ - -D egl_device=true \ - -D wayland_eglstream=true \ - -D installed_tests=false - meson compile -C build -} - -_check() ( - mkdir -p -m 700 "${XDG_RUNTIME_DIR:=$PWD/runtime-dir}" - glib-compile-schemas "${GSETTINGS_SCHEMA_DIR:=$PWD/build/data}" - export XDG_RUNTIME_DIR GSETTINGS_SCHEMA_DIR - - pipewire & - _p1=$! - - wireplumber & - _p2=$! - - trap "kill $_p1 $_p2; wait" EXIT - - meson test -C build --print-errorlogs -t 3 -) - -check() { - dbus-run-session xvfb-run -s '-nolisten local +iglx -noreset' \ - bash -c "$(declare -f _check); _check" -} +pkgrel=2 +pkgdesc="metapackage - migrate to $_newpkg" +arch=('any') package() { - meson install -C build --destdir "$pkgdir" - - install mutter_settings/dist/mutter_settings $pkgdir/usr/bin/ - - _uuid=pickawindow@lluo.gitlab.com - _schemas=org.gnome.shell.extensions.pickawindow.gschema.xml - - install -d "$pkgdir/usr/share/gnome-shell/extensions/$_uuid" - cp -r mutter_settings/$_uuid/* "$pkgdir/usr/share/gnome-shell/extensions/$_uuid/" - - install -d "$pkgdir/usr/share/glib-2.0/schemas/" - ln -s "/usr/share/gnome-shell/extensions/$_uuid/schemas/$_schemas" \ - "$pkgdir/usr/share/glib-2.0/schemas/" + depends=( + "$_newpkg" + "mutter" + ) } diff --git a/meta_clip_effect.c b/meta_clip_effect.c deleted file mode 100644 index 6f3f488fd13b..000000000000 --- a/meta_clip_effect.c +++ /dev/null @@ -1,219 +0,0 @@ -// for 40.4 - -#include "meta_clip_effect.h" -#include "meta/prefs.h" -#include "shader.h" - -typedef struct { - CoglPipeline *pipeline; - ClutterActor *actor; - cairo_rectangle_int_t bounds; - - int bounds_uniform; - int clip_radius_uniform; - int inner_bounds_uniform; - int inner_clip_radius_uniform; - int pixel_step_uniform; - int skip_uniform; - int border_width_uniform; - int border_brightness_uniform; -} MetaClipEffectPrivate; - -G_DEFINE_TYPE_WITH_PRIVATE(MetaClipEffect, meta_clip_effect, CLUTTER_TYPE_OFFSCREEN_EFFECT) - -static CoglPipeline * -meta_clip_effect_class_create_pipeline(ClutterOffscreenEffect *effect, - CoglTexture *texture) -{ - MetaClipEffect *clip_effect = META_CLIP_EFFECT (effect); - MetaClipEffectPrivate *priv = meta_clip_effect_get_instance_private(clip_effect); - cogl_pipeline_set_layer_texture (priv->pipeline, 0, texture); - - return cogl_object_ref (priv->pipeline); -} - -static void -meta_clip_effect_set_actor(ClutterActorMeta *meta, - ClutterActor *actor) -{ - ClutterActorMetaClass *meta_class - = CLUTTER_ACTOR_META_CLASS(meta_clip_effect_parent_class); - MetaClipEffectPrivate *priv = - meta_clip_effect_get_instance_private(META_CLIP_EFFECT(meta)); - meta_class->set_actor(meta, actor); - priv->actor = clutter_actor_meta_get_actor(meta); -} - -static gboolean -meta_clip_effect_pre_paint (ClutterEffect *effect, - ClutterPaintNode *node, - ClutterPaintContext *paint_context) -{ - gboolean res = - CLUTTER_EFFECT_CLASS (meta_clip_effect_parent_class)->pre_paint(effect, node, paint_context); - MetaClipEffect *clip_effect = META_CLIP_EFFECT (effect); - MetaClipEffectPrivate *priv = - meta_clip_effect_get_instance_private(META_CLIP_EFFECT(clip_effect)); - - // seems CutterOffscreenEffect will set COGL_PIPELINE_FILTER_NEAREST - // as layer filter, force set linear filter before paint now - cogl_pipeline_set_layer_filters (priv->pipeline, - 0, - COGL_PIPELINE_FILTER_LINEAR, - COGL_PIPELINE_FILTER_LINEAR); - return res; -} - -static void -meta_clip_effect_dispose(GObject *gobject) -{ - MetaClipEffect*effect = META_CLIP_EFFECT(gobject); - MetaClipEffectPrivate *priv = - meta_clip_effect_get_instance_private(META_CLIP_EFFECT(effect)); - - if (priv->pipeline != NULL) - { - g_clear_pointer(&priv->pipeline, cogl_object_unref); - } - - G_OBJECT_CLASS (meta_clip_effect_parent_class)->dispose (gobject); -} - -static void -meta_clip_effect_class_init(MetaClipEffectClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - ClutterEffectClass *effect_class = CLUTTER_EFFECT_CLASS (klass); - ClutterOffscreenEffectClass *offscreen_class = CLUTTER_OFFSCREEN_EFFECT_CLASS (klass); - ClutterActorMetaClass *meta_class = CLUTTER_ACTOR_META_CLASS(klass); - - meta_class->set_actor = meta_clip_effect_set_actor; - effect_class->pre_paint = meta_clip_effect_pre_paint; - offscreen_class->create_pipeline = meta_clip_effect_class_create_pipeline; - gobject_class->dispose = meta_clip_effect_dispose; -} - -static void -meta_clip_effect_init(MetaClipEffect *self) -{ - MetaClipEffectClass *klass = META_CLIP_EFFECT_GET_CLASS (self); - MetaClipEffectPrivate *priv = meta_clip_effect_get_instance_private(self); - - if (G_UNLIKELY (klass->base_pipeline == NULL)) - { - CoglSnippet *snippet; - CoglContext *ctx = - clutter_backend_get_cogl_context (clutter_get_default_backend ()); - - klass->base_pipeline = cogl_pipeline_new (ctx); - - snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT, - ROUNDED_CLIP_FRAGMENT_SHADER_DECLARATIONS, - ROUNDED_CLIP_FRAGMENT_SHADER_CODE); - cogl_pipeline_add_snippet (klass->base_pipeline, snippet); - cogl_object_unref (snippet); - - cogl_pipeline_set_layer_null_texture (klass->base_pipeline, 0); - } - - priv->pipeline = cogl_pipeline_copy (klass->base_pipeline); - priv->actor = NULL; - - // get location of uniforms from shader - priv->bounds_uniform = - cogl_pipeline_get_uniform_location(priv->pipeline, "bounds"); - priv->clip_radius_uniform = - cogl_pipeline_get_uniform_location(priv->pipeline, "clip_radius"); - priv->inner_bounds_uniform = - cogl_pipeline_get_uniform_location(priv->pipeline, "inner_bounds"); - priv->inner_clip_radius_uniform = - cogl_pipeline_get_uniform_location(priv->pipeline, "inner_clip_radius"); - priv->pixel_step_uniform = - cogl_pipeline_get_uniform_location(priv->pipeline, "pixel_step"); - priv->skip_uniform = - cogl_pipeline_get_uniform_location(priv->pipeline, "skip"); - priv->border_width_uniform = - cogl_pipeline_get_uniform_location(priv->pipeline, "border_width"); - priv->border_brightness_uniform = - cogl_pipeline_get_uniform_location(priv->pipeline, "border_brightness"); -} - -MetaClipEffect *meta_clip_effect_new(void) -{ - return g_object_new(META_TYPE_CLIP_EFFECT, NULL); -} - -void -meta_clip_effect_set_bounds(MetaClipEffect *effect, - cairo_rectangle_int_t *_bounds, - int padding[4]) -{ - // padding: [left, right, top, bottom] - - MetaClipEffectPrivate *priv = meta_clip_effect_get_instance_private(effect); - - g_return_if_fail(priv->pipeline && priv->actor); - float radius = meta_prefs_get_round_corner_radius(); - float border = meta_prefs_get_border_width(); - float brightness = meta_prefs_get_border_brightness(); - - priv->bounds.x = _bounds->x + padding[0]; - priv->bounds.y = _bounds->y + padding[2]; - priv->bounds.width = _bounds->width - padding[1] - padding[0]; - priv->bounds.height = _bounds->height - padding[2] - padding[3]; - - float x1 = priv->bounds.x; - float y1 = priv->bounds.y; - float x2 = priv->bounds.width + x1; - float y2 = priv->bounds.height + y1; - float w, h; - - clutter_actor_get_size(priv->actor, &w, &h); - - float bounds[] = { x1, y1, x2, y2 }; - - float inner_bounds[] = { x1 + border, y1 + border, x2 - border, y2 - border }; - float inner_radius = radius - border; - if (inner_radius < 0.0f) { - inner_radius = 0.0f; - } - - float pixel_step[] = { 1. / w, 1. / h }; - - cogl_pipeline_set_uniform_float(priv->pipeline, - priv->bounds_uniform, - 4, 1, bounds); - cogl_pipeline_set_uniform_1f(priv->pipeline, - priv->clip_radius_uniform, - radius); - cogl_pipeline_set_uniform_float(priv->pipeline, - priv->inner_bounds_uniform, - 4, 1, inner_bounds); - cogl_pipeline_set_uniform_1f(priv->pipeline, - priv->inner_clip_radius_uniform, - inner_radius); - cogl_pipeline_set_uniform_float(priv->pipeline, - priv->pixel_step_uniform, - 2, 1, pixel_step); - cogl_pipeline_set_uniform_1i(priv->pipeline, priv->skip_uniform, 0); - cogl_pipeline_set_uniform_1f(priv->pipeline, priv->border_width_uniform, border); - cogl_pipeline_set_uniform_1f(priv->pipeline, priv->border_brightness_uniform, brightness); -} - -void -meta_clip_effect_skip(MetaClipEffect *effect) -{ - MetaClipEffectPrivate *priv = meta_clip_effect_get_instance_private(effect); - - g_return_if_fail(priv->pipeline && priv->actor); - - cogl_pipeline_set_uniform_1i(priv->pipeline, priv->skip_uniform, 1); -} - -void -meta_clip_effect_get_bounds(MetaClipEffect *effect, - cairo_rectangle_int_t *bounds) -{ - MetaClipEffectPrivate *priv = meta_clip_effect_get_instance_private(effect); - *bounds = priv->bounds; -} diff --git a/meta_clip_effect.h b/meta_clip_effect.h deleted file mode 100644 index ab20b10871b3..000000000000 --- a/meta_clip_effect.h +++ /dev/null @@ -1,20 +0,0 @@ -// for 40.4 - -#pragma once - -#include <clutter/clutter.h> - -#define META_TYPE_CLIP_EFFECT (meta_clip_effect_get_type()) -G_DECLARE_DERIVABLE_TYPE(MetaClipEffect, meta_clip_effect, META, CLIP_EFFECT, ClutterOffscreenEffect) - -struct _MetaClipEffectClass { - ClutterOffscreenEffectClass parent_class; - CoglPipeline *base_pipeline; - gpointer padding[12]; -}; - -MetaClipEffect *meta_clip_effect_new(void); - -void meta_clip_effect_set_bounds(MetaClipEffect *effect, cairo_rectangle_int_t *bounds, int padding[4]); -void meta_clip_effect_get_bounds(MetaClipEffect *effect, cairo_rectangle_int_t *bounds); -void meta_clip_effect_skip(MetaClipEffect *effect);
\ No newline at end of file diff --git a/mr1441.patch b/mr1441.patch deleted file mode 100644 index ca8a66a39475..000000000000 --- a/mr1441.patch +++ /dev/null @@ -1,2549 +0,0 @@ -Author: Daniel van Vugt <daniel.van.vugt@canonical.com> -Source: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1441 -Commit: bf7030b8b898e621cd3ef535d3daae815dc98134 -Rebase: Fri May 6 16:34:46 2022 +0800 - -diff --git a/clutter/clutter/clutter-frame-clock.c b/clutter/clutter/clutter-frame-clock.c -index 6fa2b2588..7a6444ec4 100644 ---- a/clutter/clutter/clutter-frame-clock.c -+++ b/clutter/clutter/clutter-frame-clock.c -@@ -45,6 +45,8 @@ typedef struct _EstimateQueue - int next_index; - } EstimateQueue; - -+static gboolean triple_buffering_disabled = FALSE; -+ - #define SYNC_DELAY_FALLBACK_FRACTION 0.875 - - typedef struct _ClutterFrameListener -@@ -65,8 +67,9 @@ typedef enum _ClutterFrameClockState - CLUTTER_FRAME_CLOCK_STATE_INIT, - CLUTTER_FRAME_CLOCK_STATE_IDLE, - CLUTTER_FRAME_CLOCK_STATE_SCHEDULED, -- CLUTTER_FRAME_CLOCK_STATE_DISPATCHING, -- CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED, -+ CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE, -+ CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED, -+ CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_TWO, - } ClutterFrameClockState; - - struct _ClutterFrameClock -@@ -96,6 +99,8 @@ struct _ClutterFrameClock - /* Last KMS buffer submission time. */ - int64_t last_flip_time_us; - -+ ClutterFrameHint last_flip_hints; -+ - /* Last few durations between dispatch start and buffer swap. */ - EstimateQueue dispatch_to_swap_us; - /* Last few durations between buffer swap and GPU rendering finish. */ -@@ -228,6 +233,10 @@ void - clutter_frame_clock_notify_presented (ClutterFrameClock *frame_clock, - ClutterFrameInfo *frame_info) - { -+ const char *debug_state = -+ frame_clock->state == CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_TWO ? -+ "Triple buffering" : "Double buffering"; -+ - COGL_TRACE_BEGIN_SCOPED (ClutterFrameClockNotifyPresented, - "Frame Clock (presented)"); - -@@ -289,7 +298,8 @@ clutter_frame_clock_notify_presented (ClutterFrameClock *frame_clock, - frame_info->cpu_time_before_buffer_swap_us; - - CLUTTER_NOTE (FRAME_TIMINGS, -- "dispatch2swap %ld µs, swap2render %ld µs, swap2flip %ld µs", -+ "%s: dispatch2swap %ld µs, swap2render %ld µs, swap2flip %ld µs", -+ debug_state, - dispatch_to_swap_us, - swap_to_rendering_done_us, - swap_to_flip_us); -@@ -303,6 +313,10 @@ clutter_frame_clock_notify_presented (ClutterFrameClock *frame_clock, - - frame_clock->got_measurements_last_frame = TRUE; - } -+ else -+ { -+ CLUTTER_NOTE (FRAME_TIMINGS, "%s", debug_state); -+ } - - if (frame_info->refresh_rate > 1) - { -@@ -317,11 +331,18 @@ clutter_frame_clock_notify_presented (ClutterFrameClock *frame_clock, - case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED: - g_warn_if_reached (); - break; -- case CLUTTER_FRAME_CLOCK_STATE_DISPATCHING: -- case CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED: -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE: - frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_IDLE; - maybe_reschedule_update (frame_clock); - break; -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED: -+ frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED; -+ maybe_reschedule_update (frame_clock); -+ break; -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_TWO: -+ frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE; -+ maybe_reschedule_update (frame_clock); -+ break; - } - } - -@@ -337,11 +358,18 @@ clutter_frame_clock_notify_ready (ClutterFrameClock *frame_clock) - case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED: - g_warn_if_reached (); - break; -- case CLUTTER_FRAME_CLOCK_STATE_DISPATCHING: -- case CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED: -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE: - frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_IDLE; - maybe_reschedule_update (frame_clock); - break; -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED: -+ frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED; -+ maybe_reschedule_update (frame_clock); -+ break; -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_TWO: -+ frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE; -+ maybe_reschedule_update (frame_clock); -+ break; - } - } - -@@ -353,6 +381,7 @@ clutter_frame_clock_compute_max_render_time_us (ClutterFrameClock *frame_clock) - int64_t max_swap_to_rendering_done_us = 0; - int64_t max_swap_to_flip_us = 0; - int64_t max_render_time_us; -+ int buffer_queue_latency_frames = 0; - int i; - - refresh_interval_us = frame_clock->refresh_interval_us; -@@ -375,6 +404,27 @@ clutter_frame_clock_compute_max_render_time_us (ClutterFrameClock *frame_clock) - frame_clock->swap_to_flip_us.values[i]); - } - -+ switch (frame_clock->state) -+ { -+ case CLUTTER_FRAME_CLOCK_STATE_INIT: -+ case CLUTTER_FRAME_CLOCK_STATE_IDLE: -+ case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED: -+ buffer_queue_latency_frames = 0; -+ break; -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE: -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED: -+ buffer_queue_latency_frames = 1; -+ break; -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_TWO: -+ g_warn_if_reached (); -+ buffer_queue_latency_frames = 2; -+ break; -+ } -+ -+ max_swap_to_flip_us -= refresh_interval_us * buffer_queue_latency_frames; -+ if (max_swap_to_flip_us < 0) -+ max_swap_to_flip_us = 0; -+ - /* Max render time shows how early the frame clock needs to be dispatched - * to make it to the predicted next presentation time. It is composed of: - * - An estimate of duration from dispatch start to buffer swap. -@@ -391,8 +441,6 @@ clutter_frame_clock_compute_max_render_time_us (ClutterFrameClock *frame_clock) - frame_clock->vblank_duration_us + - clutter_max_render_time_constant_us; - -- max_render_time_us = CLAMP (max_render_time_us, 0, refresh_interval_us); -- - return max_render_time_us; - } - -@@ -558,8 +606,12 @@ clutter_frame_clock_inhibit (ClutterFrameClock *frame_clock) - frame_clock->pending_reschedule = TRUE; - frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_IDLE; - break; -- case CLUTTER_FRAME_CLOCK_STATE_DISPATCHING: -- case CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED: -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED: -+ frame_clock->pending_reschedule = TRUE; -+ frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE; -+ break; -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE: -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_TWO: - break; - } - -@@ -595,11 +647,17 @@ clutter_frame_clock_schedule_update_now (ClutterFrameClock *frame_clock) - case CLUTTER_FRAME_CLOCK_STATE_INIT: - case CLUTTER_FRAME_CLOCK_STATE_IDLE: - next_update_time_us = g_get_monotonic_time (); -+ frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED; - break; - case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED: -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED: - return; -- case CLUTTER_FRAME_CLOCK_STATE_DISPATCHING: -- case CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED: -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE: -+ next_update_time_us = g_get_monotonic_time (); -+ frame_clock->state = -+ CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED; -+ break; -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_TWO: - frame_clock->pending_reschedule = TRUE; - frame_clock->pending_reschedule_now = TRUE; - return; -@@ -608,7 +666,6 @@ clutter_frame_clock_schedule_update_now (ClutterFrameClock *frame_clock) - g_warn_if_fail (next_update_time_us != -1); - - g_source_set_ready_time (frame_clock->source, next_update_time_us); -- frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED; - frame_clock->is_next_presentation_time_valid = FALSE; - } - -@@ -627,6 +684,7 @@ clutter_frame_clock_schedule_update (ClutterFrameClock *frame_clock) - { - case CLUTTER_FRAME_CLOCK_STATE_INIT: - next_update_time_us = g_get_monotonic_time (); -+ frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED; - break; - case CLUTTER_FRAME_CLOCK_STATE_IDLE: - calculate_next_update_time_us (frame_clock, -@@ -634,11 +692,28 @@ clutter_frame_clock_schedule_update (ClutterFrameClock *frame_clock) - &frame_clock->next_presentation_time_us); - frame_clock->is_next_presentation_time_valid = - (frame_clock->next_presentation_time_us != 0); -+ frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED; - break; - case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED: -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED: - return; -- case CLUTTER_FRAME_CLOCK_STATE_DISPATCHING: -- case CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED: -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE: -+ if (frame_clock->last_flip_hints & CLUTTER_FRAME_HINT_DIRECT_SCANOUT_ATTEMPTED || -+ triple_buffering_disabled) -+ { -+ /* Force double buffering, disable triple buffering */ -+ frame_clock->pending_reschedule = TRUE; -+ return; -+ } -+ -+ calculate_next_update_time_us (frame_clock, -+ &next_update_time_us, -+ &frame_clock->next_presentation_time_us); -+ frame_clock->is_next_presentation_time_valid = -+ (frame_clock->next_presentation_time_us != 0); -+ frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED; -+ break; -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_TWO: - frame_clock->pending_reschedule = TRUE; - return; - } -@@ -646,7 +721,6 @@ clutter_frame_clock_schedule_update (ClutterFrameClock *frame_clock) - g_warn_if_fail (next_update_time_us != -1); - - g_source_set_ready_time (frame_clock->source, next_update_time_us); -- frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED; - } - - static void -@@ -670,7 +744,7 @@ clutter_frame_clock_dispatch (ClutterFrameClock *frame_clock, - frame_clock->refresh_interval_us; - - lateness_us = time_us - ideal_dispatch_time_us; -- if (lateness_us < 0 || lateness_us >= frame_clock->refresh_interval_us) -+ if (lateness_us < 0 || lateness_us >= frame_clock->refresh_interval_us / 4) - frame_clock->last_dispatch_lateness_us = 0; - else - frame_clock->last_dispatch_lateness_us = lateness_us; -@@ -678,7 +752,21 @@ clutter_frame_clock_dispatch (ClutterFrameClock *frame_clock, - frame_clock->last_dispatch_time_us = time_us; - g_source_set_ready_time (frame_clock->source, -1); - -- frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_DISPATCHING; -+ switch (frame_clock->state) -+ { -+ case CLUTTER_FRAME_CLOCK_STATE_INIT: -+ case CLUTTER_FRAME_CLOCK_STATE_IDLE: -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE: -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_TWO: -+ g_warn_if_reached (); -+ return; -+ case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED: -+ frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE; -+ break; -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED: -+ frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_TWO; -+ break; -+ } - - frame_count = frame_clock->frame_count++; - -@@ -703,25 +791,31 @@ clutter_frame_clock_dispatch (ClutterFrameClock *frame_clock, - frame_clock->listener.user_data); - COGL_TRACE_END (ClutterFrameClockFrame); - -- switch (frame_clock->state) -+ switch (result) - { -- case CLUTTER_FRAME_CLOCK_STATE_INIT: -- case CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED: -- g_warn_if_reached (); -+ case CLUTTER_FRAME_RESULT_PENDING_PRESENTED: - break; -- case CLUTTER_FRAME_CLOCK_STATE_IDLE: -- case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED: -- break; -- case CLUTTER_FRAME_CLOCK_STATE_DISPATCHING: -- switch (result) -+ case CLUTTER_FRAME_RESULT_IDLE: -+ /* The frame was aborted; nothing to paint/present */ -+ switch (frame_clock->state) - { -- case CLUTTER_FRAME_RESULT_PENDING_PRESENTED: -- frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED; -+ case CLUTTER_FRAME_CLOCK_STATE_INIT: -+ case CLUTTER_FRAME_CLOCK_STATE_IDLE: -+ case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED: -+ g_warn_if_reached (); - break; -- case CLUTTER_FRAME_RESULT_IDLE: -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE: - frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_IDLE; - maybe_reschedule_update (frame_clock); - break; -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED: -+ frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED; -+ maybe_reschedule_update (frame_clock); -+ break; -+ case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_TWO: -+ frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE; -+ maybe_reschedule_update (frame_clock); -+ break; - } - break; - } -@@ -754,10 +848,12 @@ frame_clock_source_dispatch (GSource *source, - } - - void --clutter_frame_clock_record_flip_time (ClutterFrameClock *frame_clock, -- int64_t flip_time_us) -+clutter_frame_clock_record_flip (ClutterFrameClock *frame_clock, -+ int64_t flip_time_us, -+ ClutterFrameHint hints) - { - frame_clock->last_flip_time_us = flip_time_us; -+ frame_clock->last_flip_hints = hints; - } - - GString * -@@ -888,6 +984,9 @@ clutter_frame_clock_class_init (ClutterFrameClockClass *klass) - { - GObjectClass *object_class = G_OBJECT_CLASS (klass); - -+ if (!g_strcmp0 (g_getenv ("MUTTER_DEBUG_DISABLE_TRIPLE_BUFFERING"), "1")) -+ triple_buffering_disabled = TRUE; -+ - object_class->dispose = clutter_frame_clock_dispose; - - signals[DESTROY] = -diff --git a/clutter/clutter/clutter-frame-clock.h b/clutter/clutter/clutter-frame-clock.h -index 91e6b3a13..d750404d5 100644 ---- a/clutter/clutter/clutter-frame-clock.h -+++ b/clutter/clutter/clutter-frame-clock.h -@@ -34,6 +34,12 @@ typedef enum _ClutterFrameResult - CLUTTER_FRAME_RESULT_IDLE, - } ClutterFrameResult; - -+typedef enum _ClutterFrameHint -+{ -+ CLUTTER_FRAME_HINT_NONE = 0, -+ CLUTTER_FRAME_HINT_DIRECT_SCANOUT_ATTEMPTED = 1 << 0, -+} ClutterFrameHint; -+ - #define CLUTTER_TYPE_FRAME_CLOCK (clutter_frame_clock_get_type ()) - CLUTTER_EXPORT - G_DECLARE_FINAL_TYPE (ClutterFrameClock, clutter_frame_clock, -@@ -90,8 +96,9 @@ void clutter_frame_clock_remove_timeline (ClutterFrameClock *frame_clock, - CLUTTER_EXPORT - float clutter_frame_clock_get_refresh_rate (ClutterFrameClock *frame_clock); - --void clutter_frame_clock_record_flip_time (ClutterFrameClock *frame_clock, -- int64_t flip_time_us); -+void clutter_frame_clock_record_flip (ClutterFrameClock *frame_clock, -+ int64_t flip_time_us, -+ ClutterFrameHint hints); - - GString * clutter_frame_clock_get_max_render_time_debug_info (ClutterFrameClock *frame_clock); - -diff --git a/clutter/clutter/clutter-frame-private.h b/clutter/clutter/clutter-frame-private.h -index e0088564f..06581492f 100644 ---- a/clutter/clutter/clutter-frame-private.h -+++ b/clutter/clutter/clutter-frame-private.h -@@ -24,6 +24,7 @@ struct _ClutterFrame - { - gboolean has_result; - ClutterFrameResult result; -+ ClutterFrameHint hints; - }; - - #define CLUTTER_FRAME_INIT ((ClutterFrame) { 0 }) -diff --git a/clutter/clutter/clutter-frame.c b/clutter/clutter/clutter-frame.c -index 3c708da9d..63ae302af 100644 ---- a/clutter/clutter/clutter-frame.c -+++ b/clutter/clutter/clutter-frame.c -@@ -40,3 +40,16 @@ clutter_frame_set_result (ClutterFrame *frame, - frame->result = result; - frame->has_result = TRUE; - } -+ -+void -+clutter_frame_set_hint (ClutterFrame *frame, -+ ClutterFrameHint hint) -+{ -+ frame->hints |= hint; -+} -+ -+ClutterFrameHint -+clutter_frame_get_hints (ClutterFrame *frame) -+{ -+ return frame->hints; -+} -diff --git a/clutter/clutter/clutter-frame.h b/clutter/clutter/clutter-frame.h -index d3608e81c..06c5f7f28 100644 ---- a/clutter/clutter/clutter-frame.h -+++ b/clutter/clutter/clutter-frame.h -@@ -33,4 +33,11 @@ void clutter_frame_set_result (ClutterFrame *frame, - CLUTTER_EXPORT - gboolean clutter_frame_has_result (ClutterFrame *frame); - -+CLUTTER_EXPORT -+void clutter_frame_set_hint (ClutterFrame *frame, -+ ClutterFrameHint hint); -+ -+CLUTTER_EXPORT -+ClutterFrameHint clutter_frame_get_hints (ClutterFrame *frame); -+ - #endif /* CLUTTER_FRAME_H */ -diff --git a/clutter/clutter/clutter-stage-view.c b/clutter/clutter/clutter-stage-view.c -index 2e47237f0..8f5e896d0 100644 ---- a/clutter/clutter/clutter-stage-view.c -+++ b/clutter/clutter/clutter-stage-view.c -@@ -1191,8 +1191,9 @@ handle_frame_clock_frame (ClutterFrameClock *frame_clock, - - _clutter_stage_window_redraw_view (stage_window, view, &frame); - -- clutter_frame_clock_record_flip_time (frame_clock, -- g_get_monotonic_time ()); -+ clutter_frame_clock_record_flip (frame_clock, -+ g_get_monotonic_time (), -+ clutter_frame_get_hints (&frame)); - - clutter_stage_emit_after_paint (stage, view); - -diff --git a/cogl/cogl/cogl-onscreen-private.h b/cogl/cogl/cogl-onscreen-private.h -index dffe018d2..e0215f750 100644 ---- a/cogl/cogl/cogl-onscreen-private.h -+++ b/cogl/cogl/cogl-onscreen-private.h -@@ -97,4 +97,7 @@ cogl_onscreen_peek_tail_frame_info (CoglOnscreen *onscreen); - COGL_EXPORT CoglFrameInfo * - cogl_onscreen_pop_head_frame_info (CoglOnscreen *onscreen); - -+COGL_EXPORT unsigned int -+cogl_onscreen_count_pending_frames (CoglOnscreen *onscreen); -+ - #endif /* __COGL_ONSCREEN_PRIVATE_H */ -diff --git a/cogl/cogl/cogl-onscreen.c b/cogl/cogl/cogl-onscreen.c -index ff9e1749a..b25b4af4a 100644 ---- a/cogl/cogl/cogl-onscreen.c -+++ b/cogl/cogl/cogl-onscreen.c -@@ -510,6 +510,14 @@ cogl_onscreen_pop_head_frame_info (CoglOnscreen *onscreen) - return g_queue_pop_head (&priv->pending_frame_infos); - } - -+unsigned int -+cogl_onscreen_count_pending_frames (CoglOnscreen *onscreen) -+{ -+ CoglOnscreenPrivate *priv = cogl_onscreen_get_instance_private (onscreen); -+ -+ return g_queue_get_length (&priv->pending_frame_infos); -+} -+ - CoglFrameClosure * - cogl_onscreen_add_frame_callback (CoglOnscreen *onscreen, - CoglFrameCallback callback, -diff --git a/src/backends/meta-stage-impl.c b/src/backends/meta-stage-impl.c -index c45aaf852..683f4ff6c 100644 ---- a/src/backends/meta-stage-impl.c -+++ b/src/backends/meta-stage-impl.c -@@ -720,6 +720,8 @@ meta_stage_impl_redraw_view (ClutterStageWindow *stage_window, - { - g_autoptr (GError) error = NULL; - -+ clutter_frame_set_hint (frame, CLUTTER_FRAME_HINT_DIRECT_SCANOUT_ATTEMPTED); -+ - if (meta_stage_impl_scanout_view (stage_impl, - stage_view, - scanout, -diff --git a/src/backends/native/meta-crtc-kms.c b/src/backends/native/meta-crtc-kms.c -index ad72dba64..24e9b0a6a 100644 ---- a/src/backends/native/meta-crtc-kms.c -+++ b/src/backends/native/meta-crtc-kms.c -@@ -226,7 +226,7 @@ meta_crtc_kms_maybe_set_gamma (MetaCrtcKms *crtc_kms, - if (!gamma) - return; - -- kms_update = meta_kms_ensure_pending_update (kms, kms_device); -+ kms_update = meta_kms_ensure_pending_update_for_crtc (kms, kms_crtc); - meta_kms_update_set_crtc_gamma (kms_update, - kms_crtc, - gamma->size, -diff --git a/src/backends/native/meta-cursor-renderer-native.c b/src/backends/native/meta-cursor-renderer-native.c -index 96c54baf0..f80f31a93 100644 ---- a/src/backends/native/meta-cursor-renderer-native.c -+++ b/src/backends/native/meta-cursor-renderer-native.c -@@ -58,19 +58,6 @@ - #include "wayland/meta-wayland-buffer.h" - #endif - --/* When animating a cursor, we usually call drmModeSetCursor2 once per frame. -- * Though, testing shows that we need to triple buffer the cursor buffer in -- * order to avoid glitches when animating the cursor, at least when running on -- * Intel. The reason for this might be (but is not confirmed to be) due to -- * the user space gbm_bo cache, making us reuse and overwrite the kernel side -- * buffer content before it was scanned out. To avoid this, we keep a user space -- * reference to each buffer we set until at least one frame after it was drawn. -- * In effect, this means we three active cursor gbm_bo's: one that that just has -- * been set, one that was previously set and may or may not have been scanned -- * out, and one pending that will be replaced if the cursor sprite changes. -- */ --#define HW_CURSOR_BUFFER_COUNT 3 -- - static GQuark quark_cursor_sprite = 0; - - typedef struct _CrtcCursorData -@@ -104,19 +91,10 @@ typedef struct _MetaCursorRendererNativeGpuData - uint64_t cursor_height; - } MetaCursorRendererNativeGpuData; - --typedef enum _MetaCursorBufferState --{ -- META_CURSOR_BUFFER_STATE_NONE, -- META_CURSOR_BUFFER_STATE_SET, -- META_CURSOR_BUFFER_STATE_INVALIDATED, --} MetaCursorBufferState; -- - typedef struct _MetaCursorNativeGpuState - { - MetaGpu *gpu; -- unsigned int active_buffer_idx; -- MetaCursorBufferState pending_buffer_state; -- MetaDrmBuffer *buffers[HW_CURSOR_BUFFER_COUNT]; -+ MetaDrmBuffer *buffer; - } MetaCursorNativeGpuState; - - typedef struct _MetaCursorNativePrivate -@@ -197,44 +175,17 @@ meta_cursor_renderer_native_finalize (GObject *object) - G_OBJECT_CLASS (meta_cursor_renderer_native_parent_class)->finalize (object); - } - --static unsigned int --get_pending_cursor_sprite_buffer_index (MetaCursorNativeGpuState *cursor_gpu_state) --{ -- return (cursor_gpu_state->active_buffer_idx + 1) % HW_CURSOR_BUFFER_COUNT; --} -- --static MetaDrmBuffer * --get_pending_cursor_sprite_buffer (MetaCursorNativeGpuState *cursor_gpu_state) --{ -- unsigned int pending_buffer_idx; -- -- pending_buffer_idx = -- get_pending_cursor_sprite_buffer_index (cursor_gpu_state); -- return cursor_gpu_state->buffers[pending_buffer_idx]; --} -- --static MetaDrmBuffer * --get_active_cursor_sprite_buffer (MetaCursorNativeGpuState *cursor_gpu_state) --{ -- return cursor_gpu_state->buffers[cursor_gpu_state->active_buffer_idx]; --} -- - static void --set_pending_cursor_sprite_buffer (MetaCursorSprite *cursor_sprite, -- MetaGpuKms *gpu_kms, -- MetaDrmBuffer *buffer) -+set_cursor_sprite_buffer (MetaCursorSprite *cursor_sprite, -+ MetaGpuKms *gpu_kms, -+ MetaDrmBuffer *buffer) - { - MetaCursorNativePrivate *cursor_priv; - MetaCursorNativeGpuState *cursor_gpu_state; -- unsigned int pending_buffer_idx; - - cursor_priv = ensure_cursor_priv (cursor_sprite); - cursor_gpu_state = ensure_cursor_gpu_state (cursor_priv, gpu_kms); -- -- pending_buffer_idx = -- get_pending_cursor_sprite_buffer_index (cursor_gpu_state); -- cursor_gpu_state->buffers[pending_buffer_idx] = buffer; -- cursor_gpu_state->pending_buffer_state = META_CURSOR_BUFFER_STATE_SET; -+ cursor_gpu_state->buffer = buffer; - } - - static void -@@ -309,10 +260,7 @@ assign_cursor_plane (MetaCursorRendererNative *native, - MetaKmsUpdate *kms_update; - MetaKmsPlaneAssignment *plane_assignment; - -- if (cursor_gpu_state->pending_buffer_state == META_CURSOR_BUFFER_STATE_SET) -- buffer = get_pending_cursor_sprite_buffer (cursor_gpu_state); -- else -- buffer = get_active_cursor_sprite_buffer (cursor_gpu_state); -+ buffer = cursor_gpu_state->buffer; - - kms_crtc = meta_crtc_kms_get_kms_crtc (crtc_kms); - kms_device = meta_kms_crtc_get_device (kms_crtc); -@@ -341,8 +289,8 @@ assign_cursor_plane (MetaCursorRendererNative *native, - flags |= META_KMS_ASSIGN_PLANE_FLAG_FB_UNCHANGED; - - kms_update = -- meta_kms_ensure_pending_update (meta_kms_device_get_kms (kms_device), -- meta_kms_crtc_get_device (kms_crtc)); -+ meta_kms_ensure_pending_update_for_crtc (meta_kms_device_get_kms (kms_device), -+ kms_crtc); - plane_assignment = meta_kms_update_assign_plane (kms_update, - kms_crtc, - cursor_plane, -@@ -363,13 +311,6 @@ assign_cursor_plane (MetaCursorRendererNative *native, - native); - - crtc_cursor_data->buffer = buffer; -- -- if (cursor_gpu_state->pending_buffer_state == META_CURSOR_BUFFER_STATE_SET) -- { -- cursor_gpu_state->active_buffer_idx = -- (cursor_gpu_state->active_buffer_idx + 1) % HW_CURSOR_BUFFER_COUNT; -- cursor_gpu_state->pending_buffer_state = META_CURSOR_BUFFER_STATE_NONE; -- } - } - - static float -@@ -497,7 +438,7 @@ unset_crtc_cursor (MetaCursorRendererNative *native, - MetaKms *kms = meta_kms_device_get_kms (kms_device); - MetaKmsUpdate *kms_update; - -- kms_update = meta_kms_ensure_pending_update (kms, kms_device); -+ kms_update = meta_kms_ensure_pending_update_for_crtc (kms, kms_crtc); - meta_kms_update_unassign_plane (kms_update, kms_crtc, cursor_plane); - } - -@@ -597,19 +538,7 @@ has_valid_cursor_sprite_buffer (MetaCursorSprite *cursor_sprite, - if (!cursor_gpu_state) - return FALSE; - -- switch (cursor_gpu_state->pending_buffer_state) -- { -- case META_CURSOR_BUFFER_STATE_NONE: -- return get_active_cursor_sprite_buffer (cursor_gpu_state) != NULL; -- case META_CURSOR_BUFFER_STATE_SET: -- return TRUE; -- case META_CURSOR_BUFFER_STATE_INVALIDATED: -- return FALSE; -- } -- -- g_assert_not_reached (); -- -- return FALSE; -+ return cursor_gpu_state->buffer != NULL; - } - - static void -@@ -1115,16 +1044,14 @@ unset_crtc_cursor_renderer_privates (MetaGpu *gpu, - static void - cursor_gpu_state_free (MetaCursorNativeGpuState *cursor_gpu_state) - { -- int i; - MetaDrmBuffer *active_buffer; - -- active_buffer = get_active_cursor_sprite_buffer (cursor_gpu_state); -+ active_buffer = cursor_gpu_state->buffer; - if (active_buffer) - unset_crtc_cursor_renderer_privates (cursor_gpu_state->gpu, - active_buffer); - -- for (i = 0; i < HW_CURSOR_BUFFER_COUNT; i++) -- g_clear_object (&cursor_gpu_state->buffers[i]); -+ g_clear_object (&cursor_gpu_state->buffer); - g_free (cursor_gpu_state); - } - -@@ -1161,14 +1088,7 @@ invalidate_cursor_gpu_state (MetaCursorSprite *cursor_sprite) - - g_hash_table_iter_init (&iter, cursor_priv->gpu_states); - while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &cursor_gpu_state)) -- { -- unsigned int pending_buffer_idx; -- -- pending_buffer_idx = get_pending_cursor_sprite_buffer_index (cursor_gpu_state); -- g_clear_object (&cursor_gpu_state->buffers[pending_buffer_idx]); -- cursor_gpu_state->pending_buffer_state = -- META_CURSOR_BUFFER_STATE_INVALIDATED; -- } -+ g_clear_object (&cursor_gpu_state->buffer); - } - - static void -@@ -1404,35 +1324,7 @@ load_cursor_sprite_gbm_buffer_for_gpu (MetaCursorRendererNative *native, - return; - } - -- set_pending_cursor_sprite_buffer (cursor_sprite, gpu_kms, buffer); --} -- --static gboolean --is_cursor_hw_state_valid (MetaCursorSprite *cursor_sprite, -- MetaGpuKms *gpu_kms) --{ -- MetaCursorNativePrivate *cursor_priv; -- MetaCursorNativeGpuState *cursor_gpu_state; -- -- cursor_priv = get_cursor_priv (cursor_sprite); -- if (!cursor_priv) -- return FALSE; -- -- cursor_gpu_state = get_cursor_gpu_state (cursor_priv, gpu_kms); -- if (!cursor_gpu_state) -- return FALSE; -- -- switch (cursor_gpu_state->pending_buffer_state) -- { -- case META_CURSOR_BUFFER_STATE_SET: -- case META_CURSOR_BUFFER_STATE_NONE: -- return TRUE; -- case META_CURSOR_BUFFER_STATE_INVALIDATED: -- return FALSE; -- } -- -- g_assert_not_reached (); -- return FALSE; -+ set_cursor_sprite_buffer (cursor_sprite, gpu_kms, buffer); - } - - static gboolean -@@ -1599,7 +1491,7 @@ realize_cursor_sprite_from_wl_buffer_for_gpu (MetaCursorRenderer *renderer, - if (!cursor_renderer_gpu_data || cursor_renderer_gpu_data->hw_cursor_broken) - return; - -- if (is_cursor_hw_state_valid (cursor_sprite, gpu_kms) && -+ if (has_valid_cursor_sprite_buffer (cursor_sprite, gpu_kms) && - is_cursor_scale_and_transform_valid (renderer, cursor_sprite)) - return; - -@@ -1744,8 +1636,8 @@ realize_cursor_sprite_from_wl_buffer_for_gpu (MetaCursorRenderer *renderer, - return; - } - -- set_pending_cursor_sprite_buffer (cursor_sprite, gpu_kms, -- META_DRM_BUFFER (buffer_gbm)); -+ set_cursor_sprite_buffer (cursor_sprite, gpu_kms, -+ META_DRM_BUFFER (buffer_gbm)); - } - } - #endif -@@ -1769,7 +1661,7 @@ realize_cursor_sprite_from_xcursor_for_gpu (MetaCursorRenderer *renderer, - if (!cursor_renderer_gpu_data || cursor_renderer_gpu_data->hw_cursor_broken) - return; - -- if (is_cursor_hw_state_valid (cursor_sprite, gpu_kms) && -+ if (has_valid_cursor_sprite_buffer (cursor_sprite, gpu_kms) && - is_cursor_scale_and_transform_valid (renderer, cursor_sprite)) - return; - -diff --git a/src/backends/native/meta-kms-crtc.c b/src/backends/native/meta-kms-crtc.c -index 8c2f8d783..f5e7d28d9 100644 ---- a/src/backends/native/meta-kms-crtc.c -+++ b/src/backends/native/meta-kms-crtc.c -@@ -32,6 +32,12 @@ typedef struct _MetaKmsCrtcPropTable - MetaKmsProp props[META_KMS_CRTC_N_PROPS]; - } MetaKmsCrtcPropTable; - -+typedef struct -+{ -+ MetaDrmBuffer *front, *back; -+ gboolean back_is_set; -+} PlaneState; -+ - struct _MetaKmsCrtc - { - GObject parent; -@@ -44,6 +50,8 @@ struct _MetaKmsCrtc - MetaKmsCrtcState current_state; - - MetaKmsCrtcPropTable prop_table; -+ -+ GHashTable *plane_states; - }; - - G_DEFINE_TYPE (MetaKmsCrtc, meta_kms_crtc, G_TYPE_OBJECT) -@@ -460,20 +468,91 @@ meta_kms_crtc_new (MetaKmsImplDevice *impl_device, - return crtc; - } - -+void -+meta_kms_crtc_remember_plane_buffer (MetaKmsCrtc *crtc, -+ uint32_t plane_id, -+ MetaDrmBuffer *buffer) -+{ -+ gpointer key = GUINT_TO_POINTER (plane_id); -+ PlaneState *plane_state; -+ -+ plane_state = g_hash_table_lookup (crtc->plane_states, key); -+ if (plane_state == NULL) -+ { -+ plane_state = g_new0 (PlaneState, 1); -+ g_hash_table_insert (crtc->plane_states, key, plane_state); -+ } -+ -+ plane_state->back_is_set = TRUE; /* note buffer may be NULL */ -+ g_set_object (&plane_state->back, buffer); -+} -+ -+static void -+swap_plane_buffers (gpointer key, -+ gpointer value, -+ gpointer user_data) -+{ -+ PlaneState *plane_state = value; -+ -+ if (plane_state->back_is_set) -+ { -+ g_set_object (&plane_state->front, plane_state->back); -+ g_clear_object (&plane_state->back); -+ plane_state->back_is_set = FALSE; -+ } -+} -+ -+void -+meta_kms_crtc_on_scanout_started (MetaKmsCrtc *crtc) -+{ -+ g_hash_table_foreach (crtc->plane_states, swap_plane_buffers, NULL); -+} -+ -+void -+meta_kms_crtc_release_buffers (MetaKmsCrtc *crtc) -+{ -+ g_hash_table_remove_all (crtc->plane_states); -+} -+ -+static void -+meta_kms_crtc_dispose (GObject *object) -+{ -+ MetaKmsCrtc *crtc = META_KMS_CRTC (object); -+ -+ meta_kms_crtc_release_buffers (crtc); -+ -+ G_OBJECT_CLASS (meta_kms_crtc_parent_class)->dispose (object); -+} -+ - static void - meta_kms_crtc_finalize (GObject *object) - { - MetaKmsCrtc *crtc = META_KMS_CRTC (object); - - clear_gamma_state (&crtc->current_state); -+ g_hash_table_unref (crtc->plane_states); - - G_OBJECT_CLASS (meta_kms_crtc_parent_class)->finalize (object); - } - -+static void -+destroy_plane_state (gpointer data) -+{ -+ PlaneState *plane_state = data; -+ -+ g_clear_object (&plane_state->front); -+ g_clear_object (&plane_state->back); -+ g_free (plane_state); -+} -+ - static void - meta_kms_crtc_init (MetaKmsCrtc *crtc) - { - crtc->current_state.gamma.size = 0; -+ crtc->plane_states = g_hash_table_new_full (NULL, -+ NULL, -+ NULL, -+ destroy_plane_state); - } - - static void -@@ -481,5 +560,6 @@ meta_kms_crtc_class_init (MetaKmsCrtcClass *klass) - { - GObjectClass *object_class = G_OBJECT_CLASS (klass); - -+ object_class->dispose = meta_kms_crtc_dispose; - object_class->finalize = meta_kms_crtc_finalize; - } -diff --git a/src/backends/native/meta-kms-crtc.h b/src/backends/native/meta-kms-crtc.h -index 54801dd96..deafeb61e 100644 ---- a/src/backends/native/meta-kms-crtc.h -+++ b/src/backends/native/meta-kms-crtc.h -@@ -25,6 +25,7 @@ - #include <xf86drmMode.h> - - #include "backends/native/meta-kms-types.h" -+#include "backends/native/meta-drm-buffer.h" - #include "core/util-private.h" - #include "meta/boxes.h" - -@@ -84,4 +85,12 @@ MetaKmsCrtcGamma * meta_kms_crtc_gamma_new (MetaKmsCrtc *crtc, - const uint16_t *green, - const uint16_t *blue); - -+void meta_kms_crtc_remember_plane_buffer (MetaKmsCrtc *crtc, -+ uint32_t plane_id, -+ MetaDrmBuffer *buffer); -+ -+void meta_kms_crtc_on_scanout_started (MetaKmsCrtc *crtc); -+ -+void meta_kms_crtc_release_buffers (MetaKmsCrtc *crtc); -+ - #endif /* META_KMS_CRTC_H */ -diff --git a/src/backends/native/meta-kms-impl-device-atomic.c b/src/backends/native/meta-kms-impl-device-atomic.c -index 73dd8e697..787d05acd 100644 ---- a/src/backends/native/meta-kms-impl-device-atomic.c -+++ b/src/backends/native/meta-kms-impl-device-atomic.c -@@ -431,6 +431,7 @@ process_plane_assignment (MetaKmsImplDevice *impl_device, - { - MetaKmsPlaneAssignment *plane_assignment = update_entry; - MetaKmsPlane *plane = plane_assignment->plane; -+ MetaKmsUpdateFlag flags = (MetaKmsUpdateFlag) user_data; - MetaDrmBuffer *buffer; - MetaKmsFbDamage *fb_damage; - uint32_t prop_id; -@@ -586,6 +587,12 @@ process_plane_assignment (MetaKmsImplDevice *impl_device, - error)) - return FALSE; - } -+ -+ if (!(flags & META_KMS_UPDATE_FLAG_TEST_ONLY)) -+ meta_kms_crtc_remember_plane_buffer (plane_assignment->crtc, -+ meta_kms_plane_get_id (plane), -+ buffer); -+ - return TRUE; - } - -@@ -963,7 +970,7 @@ meta_kms_impl_device_atomic_process_update (MetaKmsImplDevice *impl_device, - req, - blob_ids, - meta_kms_update_get_plane_assignments (update), -- NULL, -+ GUINT_TO_POINTER (flags), - process_plane_assignment, - &error)) - goto err; -diff --git a/src/backends/native/meta-kms-impl-device-simple.c b/src/backends/native/meta-kms-impl-device-simple.c -index ca4ffe245..679dd8600 100644 ---- a/src/backends/native/meta-kms-impl-device-simple.c -+++ b/src/backends/native/meta-kms-impl-device-simple.c -@@ -470,6 +470,8 @@ process_mode_set (MetaKmsImplDevice *impl_device, - return FALSE; - } - -+ meta_kms_crtc_on_scanout_started (crtc); -+ - if (drm_mode) - { - g_hash_table_replace (impl_device_simple->cached_mode_sets, -@@ -534,7 +536,7 @@ is_timestamp_earlier_than (uint64_t ts1, - typedef struct _RetryPageFlipData - { - MetaKmsCrtc *crtc; -- uint32_t fb_id; -+ MetaDrmBuffer *fb; - MetaKmsPageFlipData *page_flip_data; - float refresh_rate; - uint64_t retry_time_us; -@@ -547,6 +549,7 @@ retry_page_flip_data_free (RetryPageFlipData *retry_page_flip_data) - g_assert (!retry_page_flip_data->page_flip_data); - g_clear_pointer (&retry_page_flip_data->custom_page_flip, - meta_kms_custom_page_flip_free); -+ g_clear_object (&retry_page_flip_data->fb); - g_free (retry_page_flip_data); - } - -@@ -614,16 +617,21 @@ retry_page_flips (gpointer user_data) - } - else - { -+ uint32_t fb_id = -+ retry_page_flip_data->fb ? -+ meta_drm_buffer_get_fb_id (retry_page_flip_data->fb) : -+ 0; -+ - meta_topic (META_DEBUG_KMS, - "[simple] Retrying page flip on CRTC %u (%s) with %u", - meta_kms_crtc_get_id (crtc), - meta_kms_impl_device_get_path (impl_device), -- retry_page_flip_data->fb_id); -+ fb_id); - - fd = meta_kms_impl_device_get_fd (impl_device); - ret = drmModePageFlip (fd, - meta_kms_crtc_get_id (crtc), -- retry_page_flip_data->fb_id, -+ fb_id, - DRM_MODE_PAGE_FLIP_EVENT, - retry_page_flip_data->page_flip_data); - } -@@ -710,7 +718,7 @@ retry_page_flips (gpointer user_data) - static void - schedule_retry_page_flip (MetaKmsImplDeviceSimple *impl_device_simple, - MetaKmsCrtc *crtc, -- uint32_t fb_id, -+ MetaDrmBuffer *fb, - float refresh_rate, - MetaKmsPageFlipData *page_flip_data, - MetaKmsCustomPageFlip *custom_page_flip) -@@ -725,7 +733,7 @@ schedule_retry_page_flip (MetaKmsImplDeviceSimple *impl_device_simple, - retry_page_flip_data = g_new0 (RetryPageFlipData, 1); - *retry_page_flip_data = (RetryPageFlipData) { - .crtc = crtc, -- .fb_id = fb_id, -+ .fb = fb ? g_object_ref (fb) : NULL, - .page_flip_data = page_flip_data, - .refresh_rate = refresh_rate, - .retry_time_us = retry_time_us, -@@ -859,6 +867,8 @@ mode_set_fallback (MetaKmsImplDeviceSimple *impl_device_simple, - return FALSE; - } - -+ meta_kms_crtc_on_scanout_started (crtc); -+ - if (!impl_device_simple->mode_set_fallback_feedback_source) - { - GSource *source; -@@ -983,20 +993,20 @@ dispatch_page_flip (MetaKmsImplDevice *impl_device, - cached_mode_set = get_cached_mode_set (impl_device_simple, crtc); - if (cached_mode_set) - { -- uint32_t fb_id; -+ MetaDrmBuffer *fb; - drmModeModeInfo *drm_mode; - float refresh_rate; - - if (plane_assignment) -- fb_id = meta_drm_buffer_get_fb_id (plane_assignment->buffer); -+ fb = plane_assignment->buffer; - else -- fb_id = 0; -+ fb = NULL; - drm_mode = cached_mode_set->drm_mode; - refresh_rate = meta_calculate_drm_mode_refresh_rate (drm_mode); - meta_kms_impl_device_hold_fd (impl_device); - schedule_retry_page_flip (impl_device_simple, - crtc, -- fb_id, -+ fb, - refresh_rate, - page_flip_data, - g_steal_pointer (&custom_page_flip)); -@@ -1286,7 +1296,7 @@ process_plane_assignment (MetaKmsImplDevice *impl_device, - { - case META_KMS_PLANE_TYPE_PRIMARY: - /* Handled as part of the mode-set and page flip. */ -- return TRUE; -+ goto assigned; - case META_KMS_PLANE_TYPE_CURSOR: - if (!process_cursor_plane_assignment (impl_device, update, - plane_assignment, -@@ -1300,7 +1310,7 @@ process_plane_assignment (MetaKmsImplDevice *impl_device, - } - else - { -- return TRUE; -+ goto assigned; - } - case META_KMS_PLANE_TYPE_OVERLAY: - error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_FAILED, -@@ -1313,6 +1323,12 @@ process_plane_assignment (MetaKmsImplDevice *impl_device, - } - - g_assert_not_reached (); -+ -+assigned: -+ meta_kms_crtc_remember_plane_buffer (plane_assignment->crtc, -+ meta_kms_plane_get_id (plane), -+ plane_assignment->buffer); -+ return TRUE; - } - - static gboolean -diff --git a/src/backends/native/meta-kms-impl-device.c b/src/backends/native/meta-kms-impl-device.c -index ec1a0e5a4..afea2c486 100644 ---- a/src/backends/native/meta-kms-impl-device.c -+++ b/src/backends/native/meta-kms-impl-device.c -@@ -1028,8 +1028,12 @@ meta_kms_impl_device_init_mode_setting (MetaKmsImplDevice *impl_device, - void - meta_kms_impl_device_prepare_shutdown (MetaKmsImplDevice *impl_device) - { -+ MetaKmsImplDevicePrivate *priv = -+ meta_kms_impl_device_get_instance_private (impl_device); - MetaKmsImplDeviceClass *klass = META_KMS_IMPL_DEVICE_GET_CLASS (impl_device); - -+ g_list_foreach (priv->crtcs, (GFunc) meta_kms_crtc_release_buffers, NULL); -+ - if (klass->prepare_shutdown) - klass->prepare_shutdown (impl_device); - -diff --git a/src/backends/native/meta-kms-page-flip.c b/src/backends/native/meta-kms-page-flip.c -index 817f4e7c8..148d23740 100644 ---- a/src/backends/native/meta-kms-page-flip.c -+++ b/src/backends/native/meta-kms-page-flip.c -@@ -24,6 +24,7 @@ - #include "backends/native/meta-kms-impl.h" - #include "backends/native/meta-kms-private.h" - #include "backends/native/meta-kms-update.h" -+#include "backends/native/meta-kms-crtc.h" - - typedef struct _MetaKmsPageFlipClosure - { -@@ -149,6 +150,8 @@ meta_kms_page_flip_data_flipped (MetaKms *kms, - - meta_assert_not_in_kms_impl (kms); - -+ meta_kms_crtc_on_scanout_started (page_flip_data->crtc); -+ - for (l = page_flip_data->closures; l; l = l->next) - { - MetaKmsPageFlipClosure *closure = l->data; -diff --git a/src/backends/native/meta-kms-update-private.h b/src/backends/native/meta-kms-update-private.h -index a613cbc5d..1d964ff21 100644 ---- a/src/backends/native/meta-kms-update-private.h -+++ b/src/backends/native/meta-kms-update-private.h -@@ -132,6 +132,12 @@ uint64_t meta_kms_update_get_sequence_number (MetaKmsUpdate *update); - META_EXPORT_TEST - MetaKmsDevice * meta_kms_update_get_device (MetaKmsUpdate *update); - -+gboolean meta_kms_update_includes_crtc (MetaKmsUpdate *update, -+ MetaKmsCrtc *crtc); -+ -+void meta_kms_update_include_crtc (MetaKmsUpdate *update, -+ MetaKmsCrtc *crtc); -+ - void meta_kms_plane_assignment_set_rotation (MetaKmsPlaneAssignment *plane_assignment, - uint64_t rotation); - -diff --git a/src/backends/native/meta-kms-update.c b/src/backends/native/meta-kms-update.c -index 53fc92eb8..0d457c49e 100644 ---- a/src/backends/native/meta-kms-update.c -+++ b/src/backends/native/meta-kms-update.c -@@ -25,12 +25,14 @@ - #include "backends/meta-display-config-shared.h" - #include "backends/native/meta-kms-connector.h" - #include "backends/native/meta-kms-crtc.h" -+#include "backends/native/meta-kms-device.h" - #include "backends/native/meta-kms-mode-private.h" - #include "backends/native/meta-kms-plane.h" - - struct _MetaKmsUpdate - { - MetaKmsDevice *device; -+ GHashTable *crtcs; - - gboolean is_locked; - uint64_t sequence_number; -@@ -149,6 +151,7 @@ static void - meta_kms_plane_assignment_free (MetaKmsPlaneAssignment *plane_assignment) - { - g_clear_pointer (&plane_assignment->fb_damage, meta_kms_fb_damage_free); -+ g_clear_object (&plane_assignment->buffer); - g_free (plane_assignment); - } - -@@ -228,7 +231,7 @@ meta_kms_update_assign_plane (MetaKmsUpdate *update, - .update = update, - .crtc = crtc, - .plane = plane, -- .buffer = buffer, -+ .buffer = g_object_ref (buffer), - .src_rect = src_rect, - .dst_rect = dst_rect, - .flags = flags, -@@ -237,6 +240,8 @@ meta_kms_update_assign_plane (MetaKmsUpdate *update, - update->plane_assignments = g_list_prepend (update->plane_assignments, - plane_assignment); - -+ g_hash_table_add (update->crtcs, crtc); -+ - return plane_assignment; - } - -@@ -262,6 +267,8 @@ meta_kms_update_unassign_plane (MetaKmsUpdate *update, - update->plane_assignments = g_list_prepend (update->plane_assignments, - plane_assignment); - -+ g_hash_table_add (update->crtcs, crtc); -+ - return plane_assignment; - } - -@@ -284,6 +291,8 @@ meta_kms_update_mode_set (MetaKmsUpdate *update, - }; - - update->mode_sets = g_list_prepend (update->mode_sets, mode_set); -+ -+ g_hash_table_add (update->crtcs, crtc); - } - - static MetaKmsConnectorUpdate * -@@ -292,6 +301,8 @@ ensure_connector_update (MetaKmsUpdate *update, - { - GList *l; - MetaKmsConnectorUpdate *connector_update; -+ MetaKmsDevice *device; -+ const MetaKmsConnectorState *state; - - for (l = update->connector_updates; l; l = l->next) - { -@@ -306,6 +317,23 @@ ensure_connector_update (MetaKmsUpdate *update, - - update->connector_updates = g_list_prepend (update->connector_updates, - connector_update); -+ device = meta_kms_connector_get_device (connector); -+ state = meta_kms_connector_get_current_state (connector); -+ if (device && state && state->current_crtc_id) -+ { -+ GList *l; -+ -+ for (l = meta_kms_device_get_crtcs (device); l; l = l->next) -+ { -+ MetaKmsCrtc *kms_crtc = l->data; -+ -+ if (meta_kms_crtc_get_id (kms_crtc) == state->current_crtc_id) -+ { -+ g_hash_table_add (update->crtcs, kms_crtc); -+ break; -+ } -+ } -+ } - - return connector_update; - } -@@ -402,6 +430,8 @@ meta_kms_update_set_crtc_gamma (MetaKmsUpdate *update, - gamma = meta_kms_crtc_gamma_new (crtc, size, red, green, blue); - - update->crtc_gammas = g_list_prepend (update->crtc_gammas, gamma); -+ -+ g_hash_table_add (update->crtcs, crtc); - } - - void -@@ -665,6 +695,20 @@ meta_kms_update_get_device (MetaKmsUpdate *update) - return update->device; - } - -+gboolean -+meta_kms_update_includes_crtc (MetaKmsUpdate *update, -+ MetaKmsCrtc *crtc) -+{ -+ return g_hash_table_contains (update->crtcs, crtc); -+} -+ -+void -+meta_kms_update_include_crtc (MetaKmsUpdate *update, -+ MetaKmsCrtc *crtc) -+{ -+ g_hash_table_add (update->crtcs, crtc); -+} -+ - MetaKmsCustomPageFlip * - meta_kms_update_take_custom_page_flip_func (MetaKmsUpdate *update) - { -@@ -693,12 +737,15 @@ meta_kms_update_new (MetaKmsDevice *device) - update->device = device; - update->sequence_number = sequence_number++; - -+ update->crtcs = g_hash_table_new (NULL, NULL); -+ - return update; - } - - void - meta_kms_update_free (MetaKmsUpdate *update) - { -+ g_hash_table_destroy (update->crtcs); - g_list_free_full (update->result_listeners, - (GDestroyNotify) meta_kms_result_listener_free); - g_list_free_full (update->plane_assignments, -diff --git a/src/backends/native/meta-kms.c b/src/backends/native/meta-kms.c -index 052ec8a65..f05cbf9df 100644 ---- a/src/backends/native/meta-kms.c -+++ b/src/backends/native/meta-kms.c -@@ -23,6 +23,7 @@ - #include "backends/native/meta-kms-private.h" - - #include "backends/native/meta-backend-native.h" -+#include "backends/native/meta-kms-crtc.h" - #include "backends/native/meta-kms-device-private.h" - #include "backends/native/meta-kms-impl.h" - #include "backends/native/meta-kms-update-private.h" -@@ -177,10 +178,17 @@ struct _MetaKms - - GList *pending_callbacks; - guint callback_source_id; -+ -+ gboolean shutting_down; - }; - - G_DEFINE_TYPE (MetaKms, meta_kms, G_TYPE_OBJECT) - -+static MetaKmsFeedback * -+meta_kms_post_update_sync (MetaKms *kms, -+ MetaKmsUpdate *update, -+ MetaKmsUpdateFlag flags); -+ - void - meta_kms_discard_pending_updates (MetaKms *kms) - { -@@ -247,23 +255,115 @@ meta_kms_take_pending_update (MetaKms *kms, - return NULL; - } - -+MetaKmsUpdate * -+meta_kms_ensure_pending_update_for_crtc (MetaKms *kms, -+ MetaKmsCrtc *crtc) -+{ -+ MetaKmsUpdate *update; -+ -+ update = meta_kms_get_pending_update_for_crtc (kms, crtc); -+ if (update == NULL) -+ { -+ update = meta_kms_update_new (meta_kms_crtc_get_device (crtc)); -+ meta_kms_update_include_crtc (update, crtc); -+ meta_kms_add_pending_update (kms, update); -+ } -+ -+ return update; -+} -+ -+static MetaKmsUpdate * -+meta_kms_find_compatible_update_for_crtc (MetaKms *kms, -+ MetaKmsCrtc *crtc, -+ gboolean take) -+{ -+ MetaKmsDevice *device; -+ MetaKmsUpdate *update; -+ GList *l; -+ -+ for (l = kms->pending_updates; l; l = l->next) -+ { -+ update = l->data; -+ if (meta_kms_update_includes_crtc (update, crtc)) -+ goto found; -+ } -+ -+ device = meta_kms_crtc_get_device (crtc); -+ -+ for (l = kms->pending_updates; l; l = l->next) -+ { -+ update = l->data; -+ if (meta_kms_update_get_device (update) == device && -+ meta_kms_update_get_mode_sets (update)) -+ goto found; -+ } -+ -+ return NULL; -+ -+found: -+ if (take) -+ kms->pending_updates = g_list_delete_link (kms->pending_updates, l); -+ return update; -+} -+ -+MetaKmsUpdate * -+meta_kms_get_pending_update_for_crtc (MetaKms *kms, -+ MetaKmsCrtc *crtc) -+{ -+ return meta_kms_find_compatible_update_for_crtc (kms, crtc, FALSE); -+} -+ -+static MetaKmsUpdate * -+meta_kms_take_pending_update_for_crtc (MetaKms *kms, -+ MetaKmsCrtc *crtc) -+{ -+ return meta_kms_find_compatible_update_for_crtc (kms, crtc, TRUE); -+} -+ - MetaKmsFeedback * - meta_kms_post_pending_update_sync (MetaKms *kms, - MetaKmsDevice *device, - MetaKmsUpdateFlag flags) - { - MetaKmsUpdate *update; -+ -+ update = meta_kms_take_pending_update (kms, device); -+ if (!update) -+ return NULL; -+ -+ return meta_kms_post_update_sync (kms, update, flags); -+} -+ -+MetaKmsFeedback * -+meta_kms_post_pending_update_for_crtc_sync (MetaKms *kms, -+ MetaKmsCrtc *crtc, -+ MetaKmsUpdateFlag flags) -+{ -+ MetaKmsUpdate *update; -+ -+ update = meta_kms_take_pending_update_for_crtc (kms, crtc); -+ if (!update) -+ return NULL; -+ -+ return meta_kms_post_update_sync (kms, update, flags); -+} -+ -+static MetaKmsFeedback * -+meta_kms_post_update_sync (MetaKms *kms, -+ MetaKmsUpdate *update, -+ MetaKmsUpdateFlag flags) -+{ -+ MetaKmsDevice *device = meta_kms_update_get_device (update); - MetaKmsFeedback *feedback; - GList *result_listeners; - GList *l; - -+ if (kms->shutting_down) -+ return NULL; -+ - COGL_TRACE_BEGIN_SCOPED (MetaKmsPostUpdateSync, - "KMS (post update)"); - -- update = meta_kms_take_pending_update (kms, device); -- if (!update) -- return NULL; -- - meta_kms_update_lock (update); - - feedback = meta_kms_device_process_update_sync (device, update, flags); -@@ -752,6 +852,8 @@ prepare_shutdown_in_impl (MetaKmsImpl *impl, - void - meta_kms_prepare_shutdown (MetaKms *kms) - { -+ kms->shutting_down = TRUE; -+ - meta_kms_run_impl_task_sync (kms, prepare_shutdown_in_impl, NULL, NULL); - flush_callbacks (kms); - } -diff --git a/src/backends/native/meta-kms.h b/src/backends/native/meta-kms.h -index bd9fe5cea..84f1bed49 100644 ---- a/src/backends/native/meta-kms.h -+++ b/src/backends/native/meta-kms.h -@@ -39,9 +39,15 @@ void meta_kms_discard_pending_updates (MetaKms *kms); - MetaKmsUpdate * meta_kms_ensure_pending_update (MetaKms *kms, - MetaKmsDevice *device); - -+MetaKmsUpdate * meta_kms_ensure_pending_update_for_crtc (MetaKms *kms, -+ MetaKmsCrtc *crtc); -+ - MetaKmsUpdate * meta_kms_get_pending_update (MetaKms *kms, - MetaKmsDevice *device); - -+MetaKmsUpdate * meta_kms_get_pending_update_for_crtc (MetaKms *kms, -+ MetaKmsCrtc *crtc); -+ - MetaKmsFeedback * meta_kms_post_pending_update_sync (MetaKms *kms, - MetaKmsDevice *device, - MetaKmsUpdateFlag flags); -@@ -49,6 +55,10 @@ MetaKmsFeedback * meta_kms_post_pending_update_sync (MetaKms *kms, - MetaKmsFeedback * meta_kms_post_test_update_sync (MetaKms *kms, - MetaKmsUpdate *update); - -+MetaKmsFeedback * meta_kms_post_pending_update_for_crtc_sync (MetaKms *kms, -+ MetaKmsCrtc *device, -+ MetaKmsUpdateFlag flags); -+ - void meta_kms_discard_pending_page_flips (MetaKms *kms); - - void meta_kms_notify_modes_set (MetaKms *kms); -diff --git a/src/backends/native/meta-onscreen-native.c b/src/backends/native/meta-onscreen-native.c -index 36d6e291e..fbe3e26ca 100644 ---- a/src/backends/native/meta-onscreen-native.c -+++ b/src/backends/native/meta-onscreen-native.c -@@ -67,13 +67,12 @@ typedef struct _MetaOnscreenNativeSecondaryGpuState - - struct { - struct gbm_surface *surface; -- MetaDrmBuffer *current_fb; -- MetaDrmBuffer *next_fb; - } gbm; - - struct { - MetaDrmBufferDumb *current_dumb_fb; - MetaDrmBufferDumb *dumb_fbs[2]; -+ MetaDrmBuffer *source_fbs[2]; - } cpu; - - gboolean noted_primary_gpu_copy_ok; -@@ -94,8 +93,8 @@ struct _MetaOnscreenNative - - struct { - struct gbm_surface *surface; -- MetaDrmBuffer *current_fb; - MetaDrmBuffer *next_fb; -+ MetaDrmBuffer *stalled_fb; - } gbm; - - #ifdef HAVE_EGL_DEVICE -@@ -107,69 +106,25 @@ struct _MetaOnscreenNative - #endif - - MetaRendererView *view; -+ -+ unsigned int swaps_pending; -+ struct { -+ int *rectangles; /* 4 x n_rectangles */ -+ int n_rectangles; -+ } next_post; - }; - - G_DEFINE_TYPE (MetaOnscreenNative, meta_onscreen_native, - COGL_TYPE_ONSCREEN_EGL) - -+static void -+try_post_latest_swap (CoglOnscreen *onscreen); -+ - static gboolean - init_secondary_gpu_state (MetaRendererNative *renderer_native, - CoglOnscreen *onscreen, - GError **error); - --static void --swap_secondary_drm_fb (CoglOnscreen *onscreen) --{ -- MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen); -- MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state; -- -- secondary_gpu_state = onscreen_native->secondary_gpu_state; -- if (!secondary_gpu_state) -- return; -- -- g_set_object (&secondary_gpu_state->gbm.current_fb, -- secondary_gpu_state->gbm.next_fb); -- g_clear_object (&secondary_gpu_state->gbm.next_fb); --} -- --static void --free_current_secondary_bo (CoglOnscreen *onscreen) --{ -- MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen); -- MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state; -- -- secondary_gpu_state = onscreen_native->secondary_gpu_state; -- if (!secondary_gpu_state) -- return; -- -- g_clear_object (&secondary_gpu_state->gbm.current_fb); --} -- --static void --free_current_bo (CoglOnscreen *onscreen) --{ -- MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen); -- -- g_clear_object (&onscreen_native->gbm.current_fb); -- free_current_secondary_bo (onscreen); --} -- --static void --meta_onscreen_native_swap_drm_fb (CoglOnscreen *onscreen) --{ -- MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen); -- -- if (!onscreen_native->gbm.next_fb) -- return; -- -- free_current_bo (onscreen); -- -- g_set_object (&onscreen_native->gbm.current_fb, onscreen_native->gbm.next_fb); -- g_clear_object (&onscreen_native->gbm.next_fb); -- -- swap_secondary_drm_fb (onscreen); --} -- - static void - maybe_update_frame_info (MetaCrtc *crtc, - CoglFrameInfo *frame_info, -@@ -205,7 +160,7 @@ meta_onscreen_native_notify_frame_complete (CoglOnscreen *onscreen) - - info = cogl_onscreen_pop_head_frame_info (onscreen); - -- g_assert (!cogl_onscreen_peek_head_frame_info (onscreen)); -+ g_assert (info); - - _cogl_onscreen_notify_frame_sync (onscreen, info); - _cogl_onscreen_notify_complete (onscreen, info); -@@ -234,7 +189,7 @@ notify_view_crtc_presented (MetaRendererView *view, - maybe_update_frame_info (crtc, frame_info, time_us, flags, sequence); - - meta_onscreen_native_notify_frame_complete (onscreen); -- meta_onscreen_native_swap_drm_fb (onscreen); -+ try_post_latest_swap (onscreen); - } - - static int64_t -@@ -296,6 +251,7 @@ page_flip_feedback_ready (MetaKmsCrtc *kms_crtc, - frame_info->flags |= COGL_FRAME_INFO_FLAG_SYMBOLIC; - - meta_onscreen_native_notify_frame_complete (onscreen); -+ try_post_latest_swap (onscreen); - } - - static void -@@ -345,7 +301,7 @@ page_flip_feedback_discarded (MetaKmsCrtc *kms_crtc, - frame_info->flags |= COGL_FRAME_INFO_FLAG_SYMBOLIC; - - meta_onscreen_native_notify_frame_complete (onscreen); -- meta_onscreen_native_swap_drm_fb (onscreen); -+ try_post_latest_swap (onscreen); - } - - static const MetaKmsPageFlipListenerVtable page_flip_listener_vtable = { -@@ -406,18 +362,40 @@ custom_egl_stream_page_flip (gpointer custom_page_flip_data, - } - #endif /* HAVE_EGL_DEVICE */ - --void --meta_onscreen_native_dummy_power_save_page_flip (CoglOnscreen *onscreen) -+static void -+drop_stalled_swap (CoglOnscreen *onscreen) - { -+ MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen); - CoglFrameInfo *frame_info; - -- meta_onscreen_native_swap_drm_fb (onscreen); -+ /* Remember we can't compare stalled_fb because it's not used by -+ * META_RENDERER_NATIVE_MODE_EGL_DEVICE. So we judge stalled to be whenever -+ * swaps_pending > 1. -+ */ -+ if (onscreen_native->swaps_pending <= 1) -+ return; -+ -+ onscreen_native->swaps_pending--; -+ -+ g_clear_object (&onscreen_native->gbm.stalled_fb); - - frame_info = cogl_onscreen_peek_tail_frame_info (onscreen); - frame_info->flags |= COGL_FRAME_INFO_FLAG_SYMBOLIC; - meta_onscreen_native_notify_frame_complete (onscreen); - } - -+void -+meta_onscreen_native_dummy_power_save_page_flip (CoglOnscreen *onscreen) -+{ -+ drop_stalled_swap (onscreen); -+ -+ /* If the monitor just woke up and the shell is fully idle (has nothing -+ * more to swap) then we just woke to an indefinitely black screen. Let's -+ * fix that using the last swap (which is never classified as "stalled"). -+ */ -+ try_post_latest_swap (onscreen); -+} -+ - static void - meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen, - MetaRendererView *view, -@@ -436,8 +414,7 @@ meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen, - MetaKmsDevice *kms_device; - MetaKms *kms; - MetaKmsUpdate *kms_update; -- MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state = NULL; -- MetaDrmBuffer *buffer; -+ g_autoptr (MetaDrmBuffer) buffer = NULL; - MetaKmsPlaneAssignment *plane_assignment; - - COGL_TRACE_BEGIN_SCOPED (MetaOnscreenNativeFlipCrtcs, -@@ -446,7 +423,7 @@ meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen, - gpu_kms = META_GPU_KMS (meta_crtc_get_gpu (crtc)); - kms_device = meta_gpu_kms_get_kms_device (gpu_kms); - kms = meta_kms_device_get_kms (kms_device); -- kms_update = meta_kms_ensure_pending_update (kms, kms_device); -+ kms_update = meta_kms_ensure_pending_update_for_crtc (kms, kms_crtc); - - g_assert (meta_gpu_kms_is_crtc_active (gpu_kms, crtc)); - -@@ -455,15 +432,7 @@ meta_onscreen_native_flip_crtc (CoglOnscreen *onscreen, - switch (renderer_gpu_data->mode) - { - case META_RENDERER_NATIVE_MODE_GBM: -- if (gpu_kms == render_gpu) -- { -- buffer = onscreen_native->gbm.next_fb; -- } -- else -- { -- secondary_gpu_state = onscreen_native->secondary_gpu_state; -- buffer = secondary_gpu_state->gbm.next_fb; -- } -+ buffer = g_steal_pointer (&onscreen_native->gbm.next_fb); - - plane_assignment = meta_crtc_kms_assign_primary_plane (crtc_kms, - buffer, -@@ -509,7 +478,7 @@ meta_onscreen_native_set_crtc_mode (CoglOnscreen *onscreen, - COGL_TRACE_BEGIN_SCOPED (MetaOnscreenNativeSetCrtcModes, - "Onscreen (set CRTC modes)"); - -- kms_update = meta_kms_ensure_pending_update (kms, kms_device); -+ kms_update = meta_kms_ensure_pending_update_for_crtc (kms, kms_crtc); - - switch (renderer_gpu_data->mode) - { -@@ -535,13 +504,41 @@ meta_onscreen_native_set_crtc_mode (CoglOnscreen *onscreen, - kms_update); - } - -+static void -+hold_primary_gpu_fb_for_secondary_gpu_scanout (MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state, -+ MetaDrmBuffer *primary_gpu_fb, -+ MetaDrmBuffer *secondary_gpu_fb) -+{ -+ if (META_IS_DRM_BUFFER_DUMB (secondary_gpu_fb)) -+ { -+ MetaDrmBufferDumb *dumb_fb = META_DRM_BUFFER_DUMB (secondary_gpu_fb); -+ int i; -+ const int n = G_N_ELEMENTS (secondary_gpu_state->cpu.dumb_fbs); -+ -+ for (i = 0; i < n; i++) -+ { -+ if (dumb_fb == secondary_gpu_state->cpu.dumb_fbs[i]) -+ { -+ g_set_object (&secondary_gpu_state->cpu.source_fbs[i], -+ primary_gpu_fb); -+ break; -+ } -+ } -+ -+ g_warn_if_fail (i < n); -+ } -+} -+ - static void - secondary_gpu_release_dumb (MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state) - { - unsigned i; - - for (i = 0; i < G_N_ELEMENTS (secondary_gpu_state->cpu.dumb_fbs); i++) -- g_clear_object (&secondary_gpu_state->cpu.dumb_fbs[i]); -+ { -+ g_clear_object (&secondary_gpu_state->cpu.dumb_fbs[i]); -+ g_clear_object (&secondary_gpu_state->cpu.source_fbs[i]); -+ } - } - - static void -@@ -566,8 +563,6 @@ secondary_gpu_state_free (MetaOnscreenNativeSecondaryGpuState *secondary_gpu_sta - NULL); - } - -- g_clear_object (&secondary_gpu_state->gbm.current_fb); -- g_clear_object (&secondary_gpu_state->gbm.next_fb); - g_clear_pointer (&secondary_gpu_state->gbm.surface, gbm_surface_destroy); - - secondary_gpu_release_dumb (secondary_gpu_state); -@@ -575,11 +570,11 @@ secondary_gpu_state_free (MetaOnscreenNativeSecondaryGpuState *secondary_gpu_sta - g_free (secondary_gpu_state); - } - --static gboolean -+static MetaDrmBuffer * - import_shared_framebuffer (CoglOnscreen *onscreen, -- MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state) -+ MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state, -+ MetaDrmBuffer *primary_gpu_fb) - { -- MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen); - MetaRenderDevice *render_device; - g_autoptr (GError) error = NULL; - MetaDrmBuffer *imported_buffer; -@@ -587,7 +582,7 @@ import_shared_framebuffer (CoglOnscreen *onscreen, - render_device = secondary_gpu_state->renderer_gpu_data->render_device; - imported_buffer = - meta_render_device_import_dma_buf (render_device, -- onscreen_native->gbm.next_fb, -+ primary_gpu_fb, - &error); - if (!imported_buffer) - { -@@ -601,16 +596,9 @@ import_shared_framebuffer (CoglOnscreen *onscreen, - META_SHARED_FRAMEBUFFER_IMPORT_STATUS_NONE); - secondary_gpu_state->import_status = - META_SHARED_FRAMEBUFFER_IMPORT_STATUS_FAILED; -- return FALSE; -+ return NULL; - } - -- /* -- * next_fb may already contain a fallback buffer, so clear it only -- * when we are sure to succeed. -- */ -- g_clear_object (&secondary_gpu_state->gbm.next_fb); -- secondary_gpu_state->gbm.next_fb = imported_buffer; -- - if (secondary_gpu_state->import_status == - META_SHARED_FRAMEBUFFER_IMPORT_STATUS_NONE) - { -@@ -627,16 +615,16 @@ import_shared_framebuffer (CoglOnscreen *onscreen, - - secondary_gpu_state->import_status = - META_SHARED_FRAMEBUFFER_IMPORT_STATUS_OK; -- return TRUE; -+ return imported_buffer; - } - --static void -+static MetaDrmBuffer * - copy_shared_framebuffer_gpu (CoglOnscreen *onscreen, - MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state, - MetaRendererNativeGpuData *renderer_gpu_data, -- gboolean *egl_context_changed) -+ gboolean *egl_context_changed, -+ MetaDrmBuffer *primary_gpu_fb) - { -- MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen); - MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native; - MetaEgl *egl = meta_renderer_native_get_egl (renderer_native); - MetaGles3 *gles3 = meta_renderer_native_get_gles3 (renderer_native); -@@ -652,9 +640,6 @@ copy_shared_framebuffer_gpu (CoglOnscreen *onscreen, - COGL_TRACE_BEGIN_SCOPED (CopySharedFramebufferSecondaryGpu, - "FB Copy (secondary GPU)"); - -- g_warn_if_fail (secondary_gpu_state->gbm.next_fb == NULL); -- g_clear_object (&secondary_gpu_state->gbm.next_fb); -- - render_device = renderer_gpu_data->render_device; - egl_display = meta_render_device_get_egl_display (render_device); - -@@ -667,13 +652,13 @@ copy_shared_framebuffer_gpu (CoglOnscreen *onscreen, - { - g_warning ("Failed to make current: %s", error->message); - g_error_free (error); -- return; -+ return NULL; - } - - *egl_context_changed = TRUE; - - -- buffer_gbm = META_DRM_BUFFER_GBM (onscreen_native->gbm.next_fb); -+ buffer_gbm = META_DRM_BUFFER_GBM (primary_gpu_fb); - bo = meta_drm_buffer_gbm_get_bo (buffer_gbm); - if (!meta_renderer_native_gles3_blit_shared_bo (egl, - gles3, -@@ -685,7 +670,7 @@ copy_shared_framebuffer_gpu (CoglOnscreen *onscreen, - { - g_warning ("Failed to blit shared framebuffer: %s", error->message); - g_error_free (error); -- return; -+ return NULL; - } - - if (!meta_egl_swap_buffers (egl, -@@ -695,7 +680,7 @@ copy_shared_framebuffer_gpu (CoglOnscreen *onscreen, - { - g_warning ("Failed to swap buffers: %s", error->message); - g_error_free (error); -- return; -+ return NULL; - } - - use_modifiers = meta_renderer_native_use_modifiers (renderer_native); -@@ -715,10 +700,10 @@ copy_shared_framebuffer_gpu (CoglOnscreen *onscreen, - g_warning ("meta_drm_buffer_gbm_new_lock_front failed: %s", - error->message); - g_error_free (error); -- return; -+ return NULL; - } - -- secondary_gpu_state->gbm.next_fb = META_DRM_BUFFER (buffer_gbm); -+ return META_DRM_BUFFER (buffer_gbm); - } - - static MetaDrmBufferDumb * -@@ -733,7 +718,7 @@ secondary_gpu_get_next_dumb_buffer (MetaOnscreenNativeSecondaryGpuState *seconda - return secondary_gpu_state->cpu.dumb_fbs[0]; - } - --static gboolean -+static MetaDrmBuffer * - copy_shared_framebuffer_primary_gpu (CoglOnscreen *onscreen, - MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state, - const int *rectangles, -@@ -759,13 +744,13 @@ copy_shared_framebuffer_primary_gpu (CoglOnscreen *onscre - - if (!secondary_gpu_state || - secondary_gpu_state->egl_surface == EGL_NO_SURFACE) -- return FALSE; -+ return NULL; - - primary_gpu = meta_renderer_native_get_primary_gpu (renderer_native); - primary_gpu_data = - meta_renderer_native_get_gpu_data (renderer_native, primary_gpu); - if (!primary_gpu_data->secondary.has_EGL_EXT_image_dma_buf_import_modifiers) -- return FALSE; -+ return NULL; - - buffer_dumb = secondary_gpu_get_next_dumb_buffer (secondary_gpu_state); - buffer = META_DRM_BUFFER (buffer_dumb); -@@ -788,7 +773,7 @@ copy_shared_framebuffer_primary_gpu (CoglOnscreen *onscre - { - meta_topic (META_DEBUG_KMS, - "Failed to create DMA buffer: %s", error->message); -- return FALSE; -+ return NULL; - } - - dmabuf_fb = -@@ -806,7 +791,7 @@ copy_shared_framebuffer_primary_gpu (CoglOnscreen *onscre - meta_topic (META_DEBUG_KMS, - "Failed to create DMA buffer for blitting: %s", - error->message); -- return FALSE; -+ return NULL; - } - /* Limit the number of individual copies to 16 */ - #define MAX_RECTS 16 -@@ -819,7 +804,7 @@ copy_shared_framebuffer_primary_gpu (CoglOnscreen *onscre - &error)) - { - g_object_unref (dmabuf_fb); -- return FALSE; -+ return NULL; - } - } - else -@@ -836,20 +821,19 @@ copy_shared_framebuffer_primary_gpu (CoglOnscreen *onscre - &error)) - { - g_object_unref (dmabuf_fb); -- return FALSE; -+ return NULL; - } - } - } - - g_object_unref (dmabuf_fb); - -- g_set_object (&secondary_gpu_state->gbm.next_fb, buffer); - secondary_gpu_state->cpu.current_dumb_fb = buffer_dumb; - -- return TRUE; -+ return g_object_ref (buffer); - } - --static void -+static MetaDrmBuffer * - copy_shared_framebuffer_cpu (CoglOnscreen *onscreen, - MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state, - MetaRendererNativeGpuData *renderer_gpu_data) -@@ -901,17 +885,19 @@ copy_shared_framebuffer_cpu (CoglOnscreen *onscreen, - - cogl_object_unref (dumb_bitmap); - -- g_set_object (&secondary_gpu_state->gbm.next_fb, buffer); - secondary_gpu_state->cpu.current_dumb_fb = buffer_dumb; -+ -+ return g_object_ref (buffer); - } - --static void -+static MetaDrmBuffer * - update_secondary_gpu_state_pre_swap_buffers (CoglOnscreen *onscreen, - const int *rectangles, - int n_rectangles) - { - MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen); - MetaOnscreenNativeSecondaryGpuState *secondary_gpu_state; -+ MetaDrmBuffer *copy = NULL; - - COGL_TRACE_BEGIN_SCOPED (MetaRendererNativeGpuStatePreSwapBuffers, - "Onscreen (secondary gpu pre-swap-buffers)"); -@@ -937,10 +923,11 @@ update_secondary_gpu_state_pre_swap_buffers (CoglOnscreen *onscreen, - /* prepare fallback */ - G_GNUC_FALLTHROUGH; - case META_SHARED_FRAMEBUFFER_COPY_MODE_PRIMARY: -- if (!copy_shared_framebuffer_primary_gpu (onscreen, -- secondary_gpu_state, -- rectangles, -- n_rectangles)) -+ copy = copy_shared_framebuffer_primary_gpu (onscreen, -+ secondary_gpu_state, -+ rectangles, -+ n_rectangles); -+ if (!copy) - { - if (!secondary_gpu_state->noted_primary_gpu_copy_failed) - { -@@ -950,9 +937,9 @@ update_secondary_gpu_state_pre_swap_buffers (CoglOnscreen *onscreen, - secondary_gpu_state->noted_primary_gpu_copy_failed = TRUE; - } - -- copy_shared_framebuffer_cpu (onscreen, -- secondary_gpu_state, -- renderer_gpu_data); -+ copy = copy_shared_framebuffer_cpu (onscreen, -+ secondary_gpu_state, -+ renderer_gpu_data); - } - else if (!secondary_gpu_state->noted_primary_gpu_copy_ok) - { -@@ -964,11 +951,15 @@ update_secondary_gpu_state_pre_swap_buffers (CoglOnscreen *onscreen, - break; - } - } -+ -+ return copy; - } - - static void --update_secondary_gpu_state_post_swap_buffers (CoglOnscreen *onscreen, -- gboolean *egl_context_changed) -+update_secondary_gpu_state_post_swap_buffers (CoglOnscreen *onscreen, -+ gboolean *egl_context_changed, -+ MetaDrmBuffer *primary_gpu_fb, -+ MetaDrmBuffer **secondary_gpu_fb) - { - MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen); - MetaRendererNative *renderer_native = onscreen_native->renderer_native; -@@ -981,6 +972,7 @@ update_secondary_gpu_state_post_swap_buffers (CoglOnscreen *onscreen, - if (secondary_gpu_state) - { - MetaRendererNativeGpuData *renderer_gpu_data; -+ g_autoptr (MetaDrmBuffer) next_fb = NULL; - - renderer_gpu_data = - meta_renderer_native_get_gpu_data (renderer_native, -@@ -988,23 +980,30 @@ update_secondary_gpu_state_post_swap_buffers (CoglOnscreen *onscreen, - switch (renderer_gpu_data->secondary.copy_mode) - { - case META_SHARED_FRAMEBUFFER_COPY_MODE_ZERO: -- if (import_shared_framebuffer (onscreen, secondary_gpu_state)) -+ next_fb = import_shared_framebuffer (onscreen, -+ secondary_gpu_state, -+ primary_gpu_fb); -+ if (next_fb) - break; -- -- /* The fallback was prepared in pre_swap_buffers */ -+ /* The fallback was prepared in pre_swap_buffers and is currently -+ * in secondary_gpu_fb. -+ */ - renderer_gpu_data->secondary.copy_mode = - META_SHARED_FRAMEBUFFER_COPY_MODE_PRIMARY; - G_GNUC_FALLTHROUGH; - case META_SHARED_FRAMEBUFFER_COPY_MODE_PRIMARY: -- /* Done before eglSwapBuffers. */ -+ next_fb = g_object_ref (*secondary_gpu_fb); - break; - case META_SHARED_FRAMEBUFFER_COPY_MODE_SECONDARY_GPU: -- copy_shared_framebuffer_gpu (onscreen, -- secondary_gpu_state, -- renderer_gpu_data, -- egl_context_changed); -+ next_fb = copy_shared_framebuffer_gpu (onscreen, -+ secondary_gpu_state, -+ renderer_gpu_data, -+ egl_context_changed, -+ primary_gpu_fb); - break; - } -+ -+ g_set_object (secondary_gpu_fb, next_fb); - } - } - -@@ -1038,34 +1037,39 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, - CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys; - MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform; - MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native; -- MetaRenderer *renderer = META_RENDERER (renderer_native); -- MetaBackend *backend = meta_renderer_get_backend (renderer); -- MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend); -- MetaMonitorManager *monitor_manager = -- meta_backend_get_monitor_manager (backend); -- MetaKms *kms = meta_backend_native_get_kms (backend_native); - MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen); - MetaGpuKms *render_gpu = onscreen_native->render_gpu; - MetaDeviceFile *render_device_file; - ClutterFrame *frame = user_data; - CoglOnscreenClass *parent_class; - gboolean egl_context_changed = FALSE; -- MetaPowerSave power_save_mode; - g_autoptr (GError) error = NULL; - MetaDrmBufferFlags buffer_flags; - MetaDrmBufferGbm *buffer_gbm; -- MetaKmsCrtc *kms_crtc; -- MetaKmsDevice *kms_device; -- MetaKmsUpdateFlag flags; -- g_autoptr (MetaKmsFeedback) kms_feedback = NULL; -- const GError *feedback_error; -+ g_autoptr (MetaDrmBuffer) primary_gpu_fb = NULL; -+ g_autoptr (MetaDrmBuffer) secondary_gpu_fb = NULL; -+ size_t rectangles_size; - - COGL_TRACE_BEGIN_SCOPED (MetaRendererNativeSwapBuffers, - "Onscreen (swap-buffers)"); - -- update_secondary_gpu_state_pre_swap_buffers (onscreen, -- rectangles, -- n_rectangles); -+ if (meta_is_topic_enabled (META_DEBUG_KMS)) -+ { -+ unsigned int frames_pending = -+ cogl_onscreen_count_pending_frames (onscreen); -+ -+ meta_topic (META_DEBUG_KMS, -+ "Swap buffers: %u frames pending (%s-buffering)", -+ frames_pending, -+ frames_pending == 1 ? "double" : -+ frames_pending == 2 ? "triple" : -+ "?"); -+ } -+ -+ secondary_gpu_fb = -+ update_secondary_gpu_state_pre_swap_buffers (onscreen, -+ rectangles, -+ n_rectangles); - - parent_class = COGL_ONSCREEN_CLASS (meta_onscreen_native_parent_class); - parent_class->swap_buffers_with_damage (onscreen, -@@ -1081,9 +1085,6 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, - switch (renderer_gpu_data->mode) - { - case META_RENDERER_NATIVE_MODE_GBM: -- g_warn_if_fail (onscreen_native->gbm.next_fb == NULL); -- g_clear_object (&onscreen_native->gbm.next_fb); -- - buffer_flags = META_DRM_BUFFER_FLAG_NONE; - if (!meta_renderer_native_use_modifiers (renderer_native)) - buffer_flags |= META_DRM_BUFFER_FLAG_DISABLE_MODIFIERS; -@@ -1101,7 +1102,12 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, - return; - } - -- onscreen_native->gbm.next_fb = META_DRM_BUFFER (buffer_gbm); -+ primary_gpu_fb = META_DRM_BUFFER (g_steal_pointer (&buffer_gbm)); -+ -+ g_object_set_data_full (G_OBJECT (primary_gpu_fb), -+ "gbm_surface owner", -+ g_object_ref (onscreen), -+ (GDestroyNotify) g_object_unref); - - break; - case META_RENDERER_NATIVE_MODE_SURFACELESS: -@@ -1113,7 +1119,46 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, - #endif - } - -- update_secondary_gpu_state_post_swap_buffers (onscreen, &egl_context_changed); -+ update_secondary_gpu_state_post_swap_buffers (onscreen, -+ &egl_context_changed, -+ primary_gpu_fb, -+ &secondary_gpu_fb); -+ -+ switch (renderer_gpu_data->mode) -+ { -+ case META_RENDERER_NATIVE_MODE_GBM: -+ if (onscreen_native->gbm.next_fb != NULL) -+ { -+ g_warn_if_fail (onscreen_native->gbm.stalled_fb == NULL); -+ drop_stalled_swap (onscreen); -+ g_assert (onscreen_native->gbm.stalled_fb == NULL); -+ onscreen_native->gbm.stalled_fb = -+ g_steal_pointer (&onscreen_native->gbm.next_fb); -+ } -+ -+ if (onscreen_native->secondary_gpu_state) -+ { -+ g_set_object (&onscreen_native->gbm.next_fb, secondary_gpu_fb); -+ hold_primary_gpu_fb_for_secondary_gpu_scanout ( -+ onscreen_native->secondary_gpu_state, -+ primary_gpu_fb, -+ secondary_gpu_fb); -+ } -+ else -+ { -+ g_set_object (&onscreen_native->gbm.next_fb, primary_gpu_fb); -+ } -+ break; -+ case META_RENDERER_NATIVE_MODE_SURFACELESS: -+ break; -+#ifdef HAVE_EGL_DEVICE -+ case META_RENDERER_NATIVE_MODE_EGL_DEVICE: -+ break; -+#endif -+ } -+ -+ clutter_frame_set_result (frame, -+ CLUTTER_FRAME_RESULT_PENDING_PRESENTED); - - /* - * If we changed EGL context, cogl will have the wrong idea about what is -@@ -1124,23 +1169,71 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, - if (egl_context_changed) - _cogl_winsys_egl_ensure_current (cogl_display); - -+ rectangles_size = n_rectangles * 4 * sizeof (int); -+ onscreen_native->next_post.rectangles = -+ g_realloc (onscreen_native->next_post.rectangles, rectangles_size); -+ memcpy (onscreen_native->next_post.rectangles, rectangles, rectangles_size); -+ onscreen_native->next_post.n_rectangles = n_rectangles; -+ -+ onscreen_native->swaps_pending++; -+ try_post_latest_swap (onscreen); -+} -+ -+static void -+try_post_latest_swap (CoglOnscreen *onscreen) -+{ -+ CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); -+ CoglContext *cogl_context = cogl_framebuffer_get_context (framebuffer); -+ CoglRenderer *cogl_renderer = cogl_context->display->renderer; -+ CoglRendererEGL *cogl_renderer_egl = cogl_renderer->winsys; -+ MetaRendererNativeGpuData *renderer_gpu_data = cogl_renderer_egl->platform; -+ MetaRendererNative *renderer_native = renderer_gpu_data->renderer_native; -+ MetaRenderer *renderer = META_RENDERER (renderer_native); -+ MetaBackend *backend = meta_renderer_get_backend (renderer); -+ MetaBackendNative *backend_native = META_BACKEND_NATIVE (backend); -+ MetaMonitorManager *monitor_manager = -+ meta_backend_get_monitor_manager (backend); -+ MetaKms *kms = meta_backend_native_get_kms (backend_native); -+ MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen); -+ MetaPowerSave power_save_mode; -+ MetaCrtcKms *crtc_kms = META_CRTC_KMS (onscreen_native->crtc); -+ MetaKmsCrtc *kms_crtc = meta_crtc_kms_get_kms_crtc (crtc_kms); -+ MetaKmsDevice *kms_device = meta_kms_crtc_get_device (kms_crtc); -+ MetaKmsUpdateFlag flags; -+ g_autoptr (MetaKmsFeedback) kms_feedback = NULL; -+ const GError *feedback_error; -+ unsigned int frames_pending = cogl_onscreen_count_pending_frames (onscreen); -+ -+ if (onscreen_native->swaps_pending == 0) -+ return; -+ -+ g_assert (frames_pending >= onscreen_native->swaps_pending); -+ - power_save_mode = meta_monitor_manager_get_power_save_mode (monitor_manager); - if (power_save_mode == META_POWER_SAVE_ON) - { -+ unsigned int posts_pending; -+ -+ posts_pending = frames_pending - onscreen_native->swaps_pending; -+ if (posts_pending > 0) -+ return; /* wait for the next frame notification and then try again */ -+ -+ drop_stalled_swap (onscreen); -+ g_return_if_fail (onscreen_native->swaps_pending > 0); -+ onscreen_native->swaps_pending--; -+ - ensure_crtc_modes (onscreen); - meta_onscreen_native_flip_crtc (onscreen, - onscreen_native->view, - onscreen_native->crtc, - META_KMS_PAGE_FLIP_LISTENER_FLAG_NONE, -- rectangles, -- n_rectangles); -+ onscreen_native->next_post.rectangles, -+ onscreen_native->next_post.n_rectangles); - } - else - { - meta_renderer_native_queue_power_save_page_flip (renderer_native, - onscreen); -- clutter_frame_set_result (frame, -- CLUTTER_FRAME_RESULT_PENDING_PRESENTED); - return; - } - -@@ -1158,9 +1251,6 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, - "Postponing primary plane composite update for CRTC %u (%s)", - meta_kms_crtc_get_id (kms_crtc), - meta_kms_device_get_path (kms_device)); -- -- clutter_frame_set_result (frame, -- CLUTTER_FRAME_RESULT_PENDING_PRESENTED); - return; - } - else if (meta_renderer_native_has_pending_mode_set (renderer_native)) -@@ -1170,8 +1260,6 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, - - meta_renderer_native_notify_mode_sets_reset (renderer_native); - meta_renderer_native_post_mode_set_updates (renderer_native); -- clutter_frame_set_result (frame, -- CLUTTER_FRAME_RESULT_PENDING_PRESENTED); - return; - } - break; -@@ -1184,8 +1272,6 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, - { - meta_renderer_native_notify_mode_sets_reset (renderer_native); - meta_renderer_native_post_mode_set_updates (renderer_native); -- clutter_frame_set_result (frame, -- CLUTTER_FRAME_RESULT_PENDING_PRESENTED); - return; - } - break; -@@ -1198,18 +1284,16 @@ meta_onscreen_native_swap_buffers_with_damage (CoglOnscreen *onscreen, - meta_kms_device_get_path (kms_device)); - - flags = META_KMS_UPDATE_FLAG_NONE; -- kms_feedback = meta_kms_post_pending_update_sync (kms, kms_device, flags); -+ kms_feedback = meta_kms_post_pending_update_for_crtc_sync (kms, -+ kms_crtc, -+ flags); -+ g_return_if_fail (kms_feedback != NULL); - - switch (meta_kms_feedback_get_result (kms_feedback)) - { - case META_KMS_FEEDBACK_PASSED: -- clutter_frame_set_result (frame, -- CLUTTER_FRAME_RESULT_PENDING_PRESENTED); - break; - case META_KMS_FEEDBACK_FAILED: -- clutter_frame_set_result (frame, -- CLUTTER_FRAME_RESULT_PENDING_PRESENTED); -- - feedback_error = meta_kms_feedback_get_error (kms_feedback); - if (!g_error_matches (feedback_error, - G_IO_ERROR, -@@ -1296,6 +1380,18 @@ meta_onscreen_native_direct_scanout (CoglOnscreen *onscreen, - return FALSE; - } - -+ /* Our direct scanout frame counts as 1, so more than that means we would -+ * be jumping the queue (and post would fail). -+ */ -+ if (cogl_onscreen_count_pending_frames (onscreen) > 1) -+ { -+ g_set_error_literal (error, -+ COGL_SCANOUT_ERROR, -+ COGL_SCANOUT_ERROR_INHIBITED, -+ "Direct scanout is inhibited during triple buffering"); -+ return FALSE; -+ } -+ - renderer_gpu_data = meta_renderer_native_get_gpu_data (renderer_native, - render_gpu); - -@@ -1348,7 +1444,9 @@ meta_onscreen_native_direct_scanout (CoglOnscreen *onscreen, - meta_kms_device_get_path (kms_device)); - - flags = META_KMS_UPDATE_FLAG_PRESERVE_ON_ERROR; -- kms_feedback = meta_kms_post_pending_update_sync (kms, kms_device, flags); -+ kms_feedback = meta_kms_post_pending_update_for_crtc_sync (kms, -+ kms_crtc, -+ flags); - switch (meta_kms_feedback_get_result (kms_feedback)) - { - case META_KMS_FEEDBACK_PASSED: -@@ -1362,7 +1460,6 @@ meta_onscreen_native_direct_scanout (CoglOnscreen *onscreen, - G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED)) - break; - -- g_clear_object (&onscreen_native->gbm.next_fb); - g_propagate_error (error, g_error_copy (feedback_error)); - return FALSE; - } -@@ -1398,7 +1495,10 @@ meta_onscreen_native_finish_frame (CoglOnscreen *onscreen, - g_autoptr (MetaKmsFeedback) kms_feedback = NULL; - const GError *error; - -- kms_update = meta_kms_get_pending_update (kms, kms_device); -+ if (cogl_onscreen_count_pending_frames (onscreen) > 0) -+ return; -+ -+ kms_update = meta_kms_get_pending_update_for_crtc (kms, kms_crtc); - if (!kms_update) - { - clutter_frame_set_result (frame, CLUTTER_FRAME_RESULT_IDLE); -@@ -1413,9 +1513,9 @@ meta_onscreen_native_finish_frame (CoglOnscreen *onscreen, - g_object_unref); - - flags = META_KMS_UPDATE_FLAG_NONE; -- kms_feedback = meta_kms_post_pending_update_sync (kms, -- kms_device, -- flags); -+ kms_feedback = meta_kms_post_pending_update_for_crtc_sync (kms, -+ kms_crtc, -+ flags); - switch (meta_kms_feedback_get_result (kms_feedback)) - { - case META_KMS_FEEDBACK_PASSED: -@@ -1437,6 +1537,17 @@ meta_onscreen_native_finish_frame (CoglOnscreen *onscreen, - } - } - -+void -+meta_onscreen_native_discard_pending_swaps (CoglOnscreen *onscreen) -+{ -+ MetaOnscreenNative *onscreen_native = META_ONSCREEN_NATIVE (onscreen); -+ -+ onscreen_native->swaps_pending = 0; -+ -+ g_clear_object (&onscreen_native->gbm.stalled_fb); -+ g_clear_object (&onscreen_native->gbm.next_fb); -+} -+ - static gboolean - should_surface_be_sharable (CoglOnscreen *onscreen) - { -@@ -1985,6 +2096,21 @@ pick_secondary_gpu_framebuffer_format_for_cpu (CoglOnscreen *onscreen) - return DRM_FORMAT_INVALID; - } - -+static void -+dumb_toggle_notify (gpointer data, -+ GObject *object, -+ gboolean is_last_ref) -+{ -+ MetaDrmBuffer **source_fb = data; -+ -+ g_return_if_fail (source_fb != NULL); -+ if (is_last_ref && *source_fb) -+ { -+ g_return_if_fail (META_IS_DRM_BUFFER (*source_fb)); -+ g_clear_object (source_fb); -+ } -+} -+ - static gboolean - init_secondary_gpu_state_cpu_copy_mode (MetaRendererNative *renderer_native, - CoglOnscreen *onscreen, -@@ -2041,6 +2167,12 @@ init_secondary_gpu_state_cpu_copy_mode (MetaRendererNative *renderer_nat - } - - secondary_gpu_state->cpu.dumb_fbs[i] = META_DRM_BUFFER_DUMB (dumb_buffer); -+ g_object_add_toggle_ref (G_OBJECT (dumb_buffer), -+ dumb_toggle_notify, -+ &secondary_gpu_state->cpu.source_fbs[i]); -+ -+ /* It was incremented higher than we need by add_toggle_ref */ -+ g_object_unref (dumb_buffer); - } - - /* -@@ -2130,7 +2262,7 @@ meta_onscreen_native_new (MetaRendererNative *renderer_native, - onscreen_native->renderer_native = renderer_native; - onscreen_native->render_gpu = render_gpu; - onscreen_native->output = output; -- onscreen_native->crtc = crtc; -+ onscreen_native->crtc = g_object_ref (crtc); - - return onscreen_native; - } -@@ -2151,7 +2283,6 @@ meta_onscreen_native_dispose (GObject *object) - { - case META_RENDERER_NATIVE_MODE_GBM: - g_clear_object (&onscreen_native->gbm.next_fb); -- free_current_bo (onscreen); - break; - case META_RENDERER_NATIVE_MODE_SURFACELESS: - g_assert_not_reached (); -@@ -2179,9 +2310,12 @@ meta_onscreen_native_dispose (GObject *object) - - G_OBJECT_CLASS (meta_onscreen_native_parent_class)->dispose (object); - -+ g_clear_object (&onscreen_native->crtc); - g_clear_pointer (&onscreen_native->gbm.surface, gbm_surface_destroy); - g_clear_pointer (&onscreen_native->secondary_gpu_state, - secondary_gpu_state_free); -+ g_clear_pointer (&onscreen_native->next_post.rectangles, g_free); -+ onscreen_native->next_post.n_rectangles = 0; - } - - static void -diff --git a/src/backends/native/meta-onscreen-native.h b/src/backends/native/meta-onscreen-native.h -index 3a85ace26..676c4c445 100644 ---- a/src/backends/native/meta-onscreen-native.h -+++ b/src/backends/native/meta-onscreen-native.h -@@ -40,6 +40,8 @@ void meta_onscreen_native_finish_frame (CoglOnscreen *onscreen, - - void meta_onscreen_native_dummy_power_save_page_flip (CoglOnscreen *onscreen); - -+void meta_onscreen_native_discard_pending_swaps (CoglOnscreen *onscreen); -+ - gboolean meta_onscreen_native_is_buffer_scanout_compatible (CoglOnscreen *onscreen, - MetaDrmBuffer *fb); - -diff --git a/src/backends/native/meta-renderer-native.c b/src/backends/native/meta-renderer-native.c -index d538cc25a..6ad3dba3b 100644 ---- a/src/backends/native/meta-renderer-native.c -+++ b/src/backends/native/meta-renderer-native.c -@@ -661,12 +661,18 @@ static gboolean - dummy_power_save_page_flip_cb (gpointer user_data) - { - MetaRendererNative *renderer_native = user_data; -+ GList *old_list = -+ g_steal_pointer (&renderer_native->power_save_page_flip_onscreens); - -- g_list_foreach (renderer_native->power_save_page_flip_onscreens, -+ g_list_foreach (old_list, - (GFunc) meta_onscreen_native_dummy_power_save_page_flip, - NULL); -- g_clear_list (&renderer_native->power_save_page_flip_onscreens, -+ g_clear_list (&old_list, - g_object_unref); -+ -+ if (renderer_native->power_save_page_flip_onscreens != NULL) -+ return G_SOURCE_CONTINUE; -+ - renderer_native->power_save_page_flip_source_id = 0; - - return G_SOURCE_REMOVE; -@@ -678,6 +684,9 @@ meta_renderer_native_queue_power_save_page_flip (MetaRendererNative *renderer_na - { - const unsigned int timeout_ms = 100; - -+ if (g_list_find (renderer_native->power_save_page_flip_onscreens, onscreen)) -+ return; -+ - if (!renderer_native->power_save_page_flip_source_id) - { - renderer_native->power_save_page_flip_source_id = -@@ -1386,6 +1395,26 @@ meta_renderer_native_create_view (MetaRenderer *renderer, - return view; - } - -+static void -+discard_pending_swaps (MetaRenderer *renderer) -+{ -+ GList *views = meta_renderer_get_views (renderer);; -+ GList *l; -+ -+ for (l = views; l; l = l->next) -+ { -+ ClutterStageView *stage_view = l->data; -+ CoglFramebuffer *fb = clutter_stage_view_get_onscreen (stage_view); -+ CoglOnscreen *onscreen; -+ -+ if (!COGL_IS_ONSCREEN (fb)) -+ continue; -+ -+ onscreen = COGL_ONSCREEN (fb); -+ meta_onscreen_native_discard_pending_swaps (onscreen); -+ } -+} -+ - static void - keep_current_onscreens_alive (MetaRenderer *renderer) - { -@@ -1414,6 +1443,7 @@ meta_renderer_native_rebuild_views (MetaRenderer *renderer) - MetaRendererClass *parent_renderer_class = - META_RENDERER_CLASS (meta_renderer_native_parent_class); - -+ discard_pending_swaps (renderer); - meta_kms_discard_pending_page_flips (kms); - meta_kms_discard_pending_updates (kms); -
\ No newline at end of file diff --git a/mutter-rounded.install b/mutter-rounded.install deleted file mode 100644 index 4e2f5c19a4dc..000000000000 --- a/mutter-rounded.install +++ /dev/null @@ -1,13 +0,0 @@ -tip() { - echo -e "\n" - echo -e "\033[31m === use 'mutter_settings' command to set window rounded radius. === \033[0m" - echo -e "\n" -} - -post_install() { - tip -} - -post_upgrade() { - tip -} diff --git a/rounded_corners.patch b/rounded_corners.patch deleted file mode 100644 index 7da1f9410ac7..000000000000 --- a/rounded_corners.patch +++ /dev/null @@ -1,1900 +0,0 @@ -diff --git a/data/org.gnome.mutter.gschema.xml.in b/data/org.gnome.mutter.gschema.xml.in -index c014b749f..692bd5c80 100644 ---- a/data/org.gnome.mutter.gschema.xml.in -+++ b/data/org.gnome.mutter.gschema.xml.in -@@ -10,6 +10,92 @@ - <schema id="org.gnome.mutter" path="/org/gnome/mutter/" - gettext-domain="@GETTEXT_DOMAIN@"> - -+ <key name="blur-sigmal" type="i"> -+ <default>20</default> -+ <range min="0" max="100"/> -+ <summary>Blur sigmal</summary> -+ </key> -+ -+ <key name="blur-brightness" type="i"> -+ <default>100</default> -+ <range min="0" max="100"/> -+ <summary>Blur brightness</summary> -+ </key> -+ -+ <key name="blur-list" type="as"> -+ <default>[]</default> -+ <summary>windows will enable blur effect</summary> -+ </key> -+ -+ <key name="blur-window-opacity" type="i"> -+ <default>80</default> -+ <range min="0" max="100"/> -+ <summary>Blur Window opacity</summary> -+ </key> -+ -+ <key name="border-width" type="i"> -+ <default>0</default> -+ <range min="0" max="100"/> -+ <summary>Window border</summary> -+ </key> -+ -+ <key name="border-brightness" type="i"> -+ <default>40</default> -+ <range min="0" max="100"/> -+ <summary>Window border brightness</summary> -+ </key> -+ -+ <key name="round-corners-radius" type="i"> -+ <default>12</default> -+ <range min="2" max="100"/> -+ <summary>Round Corners Radius</summary> -+ </key> -+ -+ <key name="clip-edge-padding" type="s"> -+ <default>"{\"global\": [0, 0, 0, 0], \"apps\": {}}"</default> -+ <summary>padding of window will be clipped</summary> -+ <description> -+ A JSON string, Represents the clipping range of the window edge. -+ The array represents the clipping range of the four sides (left, -+ right, top, bottom) of the window. -+ -+ The key of "apps" object represent the instance part of the window's -+ `WM_CLASS` property, as same as the output of `xprop WM_CLASS|cut -d -+ \" -f 2` -+ -+ This is a example: -+ -+ { -+ 'global': [1, 2, 3, 4], -+ 'apps': { -+ 'code': [5, 6, 7, 8], -+ 'typora': [9, 10, 11, 12] -+ } -+ } -+ -+ For all window, cut the left, right, top and bottom sides by 1, 2 -+ , 3 and 4 pixels respectively. But for Visual Studio Code and -+ Typora, we will cut different pixels. -+ </description> -+ </key> -+ -+ <key name="black-list" type="as"> -+ <default>["qq.exe", "tim.exe"]</default> -+ <summary>window here will not be rounded</summary> -+ <description> -+ The contents of the list represent the instance part of the window's -+ `WM_CLASS`, as same as the output of `xprop WM_CLASS|cut -d \" -f 2` -+ </description> -+ </key> -+ -+ <key name="rounded-in-maximized" type="b"> -+ <default>false</default> -+ <summary>Enable rounded corners when windows maximized</summary> -+ <description> -+ When true, the windows will always be clipped when be maximized. -+ </description> -+ </key> -+ - <key name="overlay-key" type="s"> - <default>'Super_L'</default> - <summary>Modifier to use for extended window management operations</summary> -diff --git a/src/compositor/compositor-private.h b/src/compositor/compositor-private.h -index d3b3145a3..e11efb9f6 100644 ---- a/src/compositor/compositor-private.h -+++ b/src/compositor/compositor-private.h -@@ -77,6 +77,8 @@ gboolean meta_compositor_is_switching_workspace (MetaCompositor *compositor); - void meta_compositor_grab_begin (MetaCompositor *compositor); - void meta_compositor_grab_end (MetaCompositor *compositor); - -+void meta_compositor_update_blur_behind(MetaCompositor *compositor); -+ - /* - * This function takes a 64 bit time stamp from the monotonic clock, and clamps - * it to the scope of the X server clock, without losing the granularity. -diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c -index 6f4982553..ce4184776 100644 ---- a/src/compositor/compositor.c -+++ b/src/compositor/compositor.c -@@ -85,6 +85,8 @@ - #include "wayland/meta-wayland-private.h" - #endif - -+#include "core/meta-workspace-manager-private.h" -+ - enum - { - PROP_0, -@@ -513,6 +515,10 @@ meta_compositor_add_window (MetaCompositor *compositor, - * before we first paint. - */ - priv->windows = g_list_append (priv->windows, window_actor); -+ -+ if (window->client_type == META_WINDOW_CLIENT_TYPE_X11) -+ meta_window_actor_create_blur_actor(window_actor); -+ - sync_actor_stacking (compositor); - } - -@@ -559,6 +565,7 @@ meta_compositor_queue_frame_drawn (MetaCompositor *compositor, - MetaWindowActor *window_actor = meta_window_actor_from_window (window); - - meta_window_actor_queue_frame_drawn (window_actor, no_delay_frame); -+ meta_compositor_update_blur_behind(compositor); - } - - void -@@ -907,6 +914,20 @@ meta_compositor_sync_stack (MetaCompositor *compositor, - - sync_actor_stacking (compositor); - -+ MetaWorkspaceManager *manager = priv->display->workspace_manager; -+ MetaWorkspace *active_workspace = manager->active_workspace; -+ -+ for (GList *l = priv->windows; l; l = l->next) -+ { -+ MetaWindow *window = meta_window_actor_get_meta_window(l->data); -+ MetaWorkspace *workspace = meta_window_get_workspace(window); -+ if (workspace == active_workspace) -+ { -+ meta_window_actor_set_blur_behind(l->data); -+ meta_window_actor_update_blur_position_size(l->data); -+ } -+ } -+ - update_top_window_actor (compositor); - } - -@@ -923,7 +944,17 @@ meta_compositor_sync_window_geometry (MetaCompositor *compositor, - changes = meta_window_actor_sync_actor_geometry (window_actor, did_placement); - - if (changes & META_WINDOW_ACTOR_CHANGE_SIZE) -+ { -+ if (meta_window_actor_should_clip(window_actor)) -+ meta_window_actor_update_clipped_bounds(window_actor); - meta_plugin_manager_event_size_changed (priv->plugin_mgr, window_actor); -+ meta_window_actor_update_blur_position_size(window_actor); -+ } -+ -+ if (changes & META_WINDOW_ACTOR_CHANGE_POSITION) -+ meta_window_actor_update_blur_position_size(window_actor); -+ -+ meta_compositor_update_blur_behind(compositor); - } - - static void -@@ -1099,6 +1130,49 @@ meta_compositor_get_property (GObject *object, - } - } - -+static void -+prefs_changed_cb(MetaPreference pref, -+ gpointer user_data) -+{ -+ MetaCompositor *compositor = user_data; -+ MetaCompositorPrivate *priv = -+ meta_compositor_get_instance_private (compositor); -+ GList *l; -+ -+ for (l = priv->windows; l; l = l->next) -+ { -+ switch (pref) -+ { -+ case META_PREF_CORNER_RADIUS: -+ case META_PREF_CLIP_EDGE_PADDING: -+ case META_PREF_BORDER_WIDTH: -+ case META_PREF_BORDER_BRIGHTNESS: -+ if (pref == META_PREF_CLIP_EDGE_PADDING) -+ meta_window_actor_update_clip_padding (l->data); -+ -+ meta_window_actor_update_clipped_bounds (l->data); -+ meta_window_actor_update_glsl (l->data); -+ clutter_actor_queue_redraw (CLUTTER_ACTOR (l->data)); -+ break; -+ case META_PREF_BLUR_SIGMAL: -+ meta_window_actor_update_blur_sigmal (l->data); -+ break; -+ case META_PREF_BLUR_BRIGHTNESS: -+ meta_window_actor_update_blur_brightness (l->data); -+ break; -+ case META_PREF_BLUR_WINDOW_OPACITY: -+ meta_window_actor_update_blur_window_opacity (l->data); -+ break; -+ case META_PREF_ROUNDED_IN_MAXIMIZED: -+ meta_window_actor_update_glsl (l->data); -+ meta_window_actor_update_blur_position_size(l->data); -+ break; -+ default: -+ break; -+ } -+ } -+} -+ - static void - meta_compositor_init (MetaCompositor *compositor) - { -@@ -1135,6 +1209,8 @@ meta_compositor_constructed (GObject *object) - - priv->laters = meta_laters_new (compositor); - -+ meta_prefs_add_listener(prefs_changed_cb, compositor); -+ - G_OBJECT_CLASS (meta_compositor_parent_class)->constructed (object); - } - -@@ -1155,6 +1231,8 @@ meta_compositor_dispose (GObject *object) - - g_clear_pointer (&priv->windows, g_list_free); - -+ meta_prefs_remove_listener(prefs_changed_cb, compositor); -+ - G_OBJECT_CLASS (meta_compositor_parent_class)->dispose (object); - } - -@@ -1498,3 +1576,20 @@ meta_compositor_get_laters (MetaCompositor *compositor) - - return priv->laters; - } -+ -+void meta_compositor_update_blur_behind(MetaCompositor *compositor) -+{ -+ MetaCompositorPrivate *priv = -+ meta_compositor_get_instance_private (compositor); -+ -+ MetaWorkspaceManager *manager = priv->display->workspace_manager; -+ MetaWorkspace *active_workspace = manager->active_workspace; -+ -+ for (GList *l = priv->windows; l; l = l->next) -+ { -+ MetaWindow *window = meta_window_actor_get_meta_window(l->data); -+ MetaWorkspace *workspace = meta_window_get_workspace(window); -+ if (workspace == active_workspace) -+ meta_window_actor_set_blur_behind(l->data); -+ } -+} -diff --git a/src/compositor/meta-window-actor-private.h b/src/compositor/meta-window-actor-private.h -index 8aa206bb8..5a8b35c19 100644 ---- a/src/compositor/meta-window-actor-private.h -+++ b/src/compositor/meta-window-actor-private.h -@@ -106,4 +106,15 @@ void meta_window_actor_update_regions (MetaWindowActor *self); - - gboolean meta_window_actor_can_freeze_commits (MetaWindowActor *self); - -+gboolean meta_window_actor_should_clip (MetaWindowActor *self); -+void meta_window_actor_update_clipped_bounds (MetaWindowActor *window_actor); -+void meta_window_actor_update_glsl (MetaWindowActor *self); -+void meta_window_actor_get_corner_rect (MetaWindowActor *self, MetaRectangle *rect); -+void meta_window_actor_update_clip_padding (MetaWindowActor *self); -+void meta_window_actor_create_blur_actor (MetaWindowActor *self); -+void meta_window_actor_set_blur_behind (MetaWindowActor *self); -+void meta_window_actor_update_blur_position_size (MetaWindowActor *self); -+void meta_window_actor_update_blur_sigmal (MetaWindowActor *self); -+void meta_window_actor_update_blur_brightness (MetaWindowActor *self); -+void meta_window_actor_update_blur_window_opacity (MetaWindowActor *self); - #endif /* META_WINDOW_ACTOR_PRIVATE_H */ -diff --git a/src/compositor/meta-window-actor-wayland.c b/src/compositor/meta-window-actor-wayland.c -index e1f341048..ae34238a5 100644 ---- a/src/compositor/meta-window-actor-wayland.c -+++ b/src/compositor/meta-window-actor-wayland.c -@@ -24,10 +24,36 @@ - #include "compositor/meta-window-actor-wayland.h" - #include "meta/meta-window-actor.h" - #include "wayland/meta-wayland-surface.h" -+#include "meta/meta-shadow-factory.h" -+#include "ui/frames.h" -+#include "compositor/compositor-private.h" - - struct _MetaWindowActorWayland - { - MetaWindowActor parent; -+ -+ /* copy from meta-window-actor-x11.c */ -+ MetaShadow *focused_shadow; -+ MetaShadow *unfocused_shadow; -+ gboolean recompute_focused_shadow; -+ gboolean recompute_unfocused_shadow; -+ -+ /* The region we should clip to when painting the shadow */ -+ cairo_region_t *shadow_clip; -+ /* The frame region */ -+ cairo_region_t *frame_bounds; -+ /* A region that matches the shape of the window, including frame bounds */ -+ cairo_region_t *shape_region; -+ -+ MetaWindowShape *shadow_shape; -+ -+ gboolean need_reshape; -+ -+ MetaShadowFactory *shadow_factory; -+ gulong shadow_factory_changed_handler_id; -+ gulong size_changed_id; -+ gulong repaint_scheduled_id; -+ - }; - - G_DEFINE_TYPE (MetaWindowActorWayland, meta_window_actor_wayland, META_TYPE_WINDOW_ACTOR) -@@ -109,18 +135,54 @@ meta_window_actor_wayland_get_scanout_candidate (MetaWindowActor *actor) - return topmost_surface_actor; - } - -+static void -+surface_size_changed (MetaSurfaceActor *actor, -+ gpointer user_data) -+{ -+ MetaWindowActorWayland *actor_wayland = META_WINDOW_ACTOR_WAYLAND (user_data); -+ actor_wayland->need_reshape = TRUE; -+} -+ -+static void -+surface_repaint_scheduled (MetaSurfaceActor *actor, -+ gpointer user_data) -+{ -+ MetaWindowActorWayland *actor_wayland = META_WINDOW_ACTOR_WAYLAND (user_data); -+ MetaWindow *window = meta_window_actor_get_meta_window (META_WINDOW_ACTOR(actor_wayland)); -+ meta_compositor_update_blur_behind( meta_display_get_compositor (window->display)); -+} -+ -+ - static void - meta_window_actor_wayland_assign_surface_actor (MetaWindowActor *actor, - MetaSurfaceActor *surface_actor) - { - MetaWindowActorClass *parent_class = - META_WINDOW_ACTOR_CLASS (meta_window_actor_wayland_parent_class); -+ MetaSurfaceActor *prev_surface_actor; -+ MetaWindowActorWayland *actor_wayland = META_WINDOW_ACTOR_WAYLAND (actor); -+ - - g_warn_if_fail (!meta_window_actor_get_surface (actor)); - -+ prev_surface_actor = meta_window_actor_get_surface (actor); -+ if (prev_surface_actor) -+ g_clear_signal_handler (&META_WINDOW_ACTOR_WAYLAND (actor)->size_changed_id, -+ prev_surface_actor); -+ - parent_class->assign_surface_actor (actor, surface_actor); - - meta_window_actor_wayland_rebuild_surface_tree (actor); -+ -+ actor_wayland->size_changed_id = -+ g_signal_connect (surface_actor, "size-changed", -+ G_CALLBACK (surface_size_changed), -+ actor_wayland); -+ -+ actor_wayland->repaint_scheduled_id = -+ g_signal_connect (surface_actor, "repaint-scheduled", -+ G_CALLBACK (surface_repaint_scheduled), -+ actor_wayland); - } - - static void -@@ -136,10 +198,287 @@ meta_window_actor_wayland_queue_frame_drawn (MetaWindowActor *actor, - { - } - -+static const char * -+get_shadow_class (MetaWindowActorWayland *actor_x11) -+{ -+ MetaWindow *window = -+ meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor_x11)); -+ MetaWindowType window_type; -+ -+ window_type = meta_window_get_window_type (window); -+ switch (window_type) -+ { -+ case META_WINDOW_DROPDOWN_MENU: -+ case META_WINDOW_COMBO: -+ return "dropdown-menu"; -+ case META_WINDOW_POPUP_MENU: -+ return "popup-menu"; -+ default: -+ { -+ MetaFrameType frame_type; -+ -+ frame_type = meta_window_get_frame_type (window); -+ return meta_frame_type_to_string (frame_type); -+ } -+ } -+} -+ -+static void -+invalidate_shadow (MetaWindowActorWayland *actor_wayland) -+{ -+ actor_wayland->recompute_focused_shadow = TRUE; -+ actor_wayland->recompute_unfocused_shadow = TRUE; -+ -+ if (meta_window_actor_is_frozen (META_WINDOW_ACTOR (actor_wayland))) -+ return; -+ -+ clutter_actor_queue_redraw (CLUTTER_ACTOR (actor_wayland)); -+ clutter_actor_invalidate_paint_volume (CLUTTER_ACTOR (actor_wayland)); -+} -+ -+static void -+update_shape_region (MetaWindowActorWayland *actor_wayland) -+{ -+ MetaWindow *window = -+ meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor_wayland)); -+ cairo_region_t *region = NULL; -+ cairo_rectangle_int_t client_area; -+ -+ if (meta_window_actor_should_clip(META_WINDOW_ACTOR(actor_wayland)) && !window->frame) -+ { -+ meta_window_actor_get_corner_rect(META_WINDOW_ACTOR(actor_wayland), &client_area); -+ region = cairo_region_create_rectangle(&client_area); -+ } -+ else -+ { -+ return; -+ } -+ -+ g_clear_pointer (&actor_wayland->shape_region, cairo_region_destroy); -+ actor_wayland->shape_region = region; -+ -+ g_clear_pointer (&actor_wayland->shadow_shape, meta_window_shape_unref); -+ -+ invalidate_shadow (actor_wayland); -+} -+ -+static cairo_region_t * -+meta_window_get_clipped_frame_bounds(MetaWindow *window) -+{ -+ g_return_val_if_fail(window, NULL); -+ -+ MetaWindowActor *actor = meta_window_actor_from_window(window); -+ if (actor && !window->frame_bounds) -+ { -+ MetaRectangle rect; -+ meta_window_actor_get_corner_rect(actor, &rect); -+ window->frame_bounds = -+ meta_ui_frame_get_bounds_clipped(&rect, -+ meta_prefs_get_round_corner_radius()); -+ } -+ return window->frame_bounds; -+} -+ -+static void -+update_frame_bounds (MetaWindowActorWayland *actor_wayland) -+{ -+ MetaWindow *window = -+ meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor_wayland)); -+ -+ g_clear_pointer (&actor_wayland->frame_bounds, cairo_region_destroy); -+ -+ if (meta_window_actor_should_clip(META_WINDOW_ACTOR(actor_wayland))) -+ actor_wayland->frame_bounds = -+ cairo_region_copy(meta_window_get_clipped_frame_bounds(window)); -+} -+ -+static void -+get_shape_bounds (MetaWindowActorWayland *actor_wayland, -+ cairo_rectangle_int_t *bounds) -+{ -+ cairo_region_get_extents (actor_wayland->shape_region, bounds); -+} -+ -+static void -+check_needs_shadow (MetaWindowActorWayland *actor_wayland) -+{ -+ MetaWindow *window = -+ meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor_wayland)); -+ MetaShadow *old_shadow = NULL; -+ MetaShadow **shadow_location; -+ gboolean recompute_shadow; -+ gboolean should_have_shadow; -+ gboolean appears_focused; -+ -+ should_have_shadow = -+ meta_window_actor_should_clip (META_WINDOW_ACTOR (actor_wayland)); -+ appears_focused = meta_window_appears_focused (window); -+ -+ if (appears_focused) -+ { -+ recompute_shadow = actor_wayland->recompute_focused_shadow; -+ actor_wayland->recompute_focused_shadow = FALSE; -+ shadow_location = &actor_wayland->focused_shadow; -+ } -+ else -+ { -+ recompute_shadow = actor_wayland->recompute_unfocused_shadow; -+ actor_wayland->recompute_unfocused_shadow = FALSE; -+ shadow_location = &actor_wayland->unfocused_shadow; -+ } -+ -+ if (!should_have_shadow || recompute_shadow) -+ { -+ if (*shadow_location != NULL) -+ { -+ old_shadow = *shadow_location; -+ *shadow_location = NULL; -+ } -+ } -+ -+ if (!*shadow_location && should_have_shadow) -+ { -+ MetaShadowFactory *factory = actor_wayland->shadow_factory; -+ const char *shadow_class = get_shadow_class (actor_wayland); -+ cairo_rectangle_int_t shape_bounds; -+ -+ if (!actor_wayland->shadow_shape) -+ { -+ actor_wayland->shadow_shape = -+ meta_window_shape_new (actor_wayland->shape_region); -+ } -+ -+ get_shape_bounds (actor_wayland, &shape_bounds); -+ *shadow_location = -+ meta_shadow_factory_get_shadow (factory, -+ actor_wayland->shadow_shape, -+ shape_bounds.width, shape_bounds.height, -+ shadow_class, appears_focused); -+ } -+ -+ if (old_shadow) -+ meta_shadow_unref (old_shadow); -+} -+ -+static void -+get_shadow_params (MetaWindowActorWayland *actor_wayland, -+ gboolean appears_focused, -+ MetaShadowParams *params) -+{ -+ const char *shadow_class = get_shadow_class (actor_wayland); -+ -+ meta_shadow_factory_get_params (actor_wayland->shadow_factory, -+ shadow_class, appears_focused, -+ params); -+} -+ -+static gboolean -+clip_shadow_under_window (MetaWindowActorWayland *actor_wayland) -+{ -+ return TRUE; -+} -+ - static void - meta_window_actor_wayland_before_paint (MetaWindowActor *actor, - ClutterStageView *stage_view) - { -+ MetaWindowActorWayland *actor_wayland = META_WINDOW_ACTOR_WAYLAND (actor); -+ -+ if (meta_window_actor_should_clip (actor)) -+ { -+ update_frame_bounds (actor_wayland); -+ if (actor_wayland->need_reshape) -+ { -+ update_shape_region (actor_wayland); -+ actor_wayland->need_reshape = FALSE; -+ } -+ check_needs_shadow (actor_wayland); -+ } -+} -+ -+static void -+get_shadow_bounds (MetaWindowActorWayland *actor_x11, -+ gboolean appears_focused, -+ cairo_rectangle_int_t *bounds) -+{ -+ MetaShadow *shadow; -+ cairo_rectangle_int_t shape_bounds; -+ MetaShadowParams params; -+ -+ shadow = appears_focused ? actor_x11->focused_shadow -+ : actor_x11->unfocused_shadow; -+ -+ get_shape_bounds (actor_x11, &shape_bounds); -+ get_shadow_params (actor_x11, appears_focused, ¶ms); -+ -+ meta_shadow_get_bounds (shadow, -+ params.x_offset + shape_bounds.x, -+ params.y_offset + shape_bounds.y, -+ shape_bounds.width, -+ shape_bounds.height, -+ bounds); -+} -+ -+/* Copy from ./meta-window-actor-x11.c -+ * to draw shadows for rounded wayland clients -+ * because oragin shadows has been cutted out -+ */ -+static void -+meta_window_actor_wayland_paint (ClutterActor *actor, -+ ClutterPaintContext *paint_context) -+{ -+ MetaWindowActorWayland *actor_wayland = META_WINDOW_ACTOR_WAYLAND (actor); -+ MetaWindow *window; -+ gboolean appears_focused; -+ MetaShadow *shadow; -+ -+ window = meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor_wayland)); -+ appears_focused = meta_window_appears_focused (window); -+ shadow = appears_focused ? actor_wayland->focused_shadow -+ : actor_wayland->unfocused_shadow; -+ -+ if (shadow && meta_window_actor_should_clip (META_WINDOW_ACTOR (actor_wayland))) -+ { -+ MetaShadowParams params; -+ cairo_rectangle_int_t shape_bounds; -+ cairo_region_t *clip = actor_wayland->shadow_clip; -+ CoglFramebuffer *framebuffer; -+ -+ meta_window_actor_get_corner_rect(META_WINDOW_ACTOR(actor_wayland), &shape_bounds); -+ get_shadow_params (actor_wayland, appears_focused, ¶ms); -+ -+ /* The frame bounds are already subtracted from actor_wayland->shadow_clip -+ * if that exists. -+ */ -+ if (!clip && clip_shadow_under_window (actor_wayland)) -+ { -+ cairo_rectangle_int_t bounds; -+ -+ get_shadow_bounds (actor_wayland, appears_focused, &bounds); -+ clip = cairo_region_create_rectangle (&bounds); -+ -+ if (actor_wayland->frame_bounds) -+ cairo_region_subtract (clip, actor_wayland->frame_bounds); -+ } -+ -+ framebuffer = clutter_paint_context_get_framebuffer (paint_context); -+ meta_shadow_paint (shadow, -+ framebuffer, -+ params.x_offset + shape_bounds.x, -+ params.y_offset + shape_bounds.y, -+ shape_bounds.width, -+ shape_bounds.height, -+ (clutter_actor_get_paint_opacity (actor) * -+ params.opacity * window->opacity) / (255 * 255), -+ clip, -+ clip_shadow_under_window (actor_wayland)); -+ -+ if (clip && clip != actor_wayland->shadow_clip) -+ cairo_region_destroy (clip); -+ } -+ -+ CLUTTER_ACTOR_CLASS (meta_window_actor_wayland_parent_class)->paint (actor, -+ paint_context); - } - - static void -@@ -170,12 +509,29 @@ meta_window_actor_wayland_can_freeze_commits (MetaWindowActor *actor) - return FALSE; - } - -+static void -+meta_window_actor_wayland_constructed (GObject *object) -+{ -+ MetaWindowActorWayland *actor_wayland = META_WINDOW_ACTOR_WAYLAND (object); -+ -+ /* -+ * Start off with an empty shape region to maintain the invariant that it's -+ * always set. -+ */ -+ actor_wayland->shape_region = cairo_region_create (); -+ -+ G_OBJECT_CLASS (meta_window_actor_wayland_parent_class)->constructed (object); -+} -+ -+ - static void - meta_window_actor_wayland_dispose (GObject *object) - { - MetaWindowActor *window_actor = META_WINDOW_ACTOR (object); - MetaSurfaceActor *surface_actor = - meta_window_actor_get_surface (window_actor); -+ MetaWindowActorWayland *actor_wayland = META_WINDOW_ACTOR_WAYLAND (object); -+ - g_autoptr (GList) children = NULL; - GList *l; - -@@ -188,7 +544,19 @@ meta_window_actor_wayland_dispose (GObject *object) - child_actor != CLUTTER_ACTOR (surface_actor)) - clutter_actor_remove_child (CLUTTER_ACTOR (window_actor), child_actor); - } -- -+ -+ g_clear_pointer (&actor_wayland->shape_region, cairo_region_destroy); -+ g_clear_pointer (&actor_wayland->shadow_clip, cairo_region_destroy); -+ g_clear_pointer (&actor_wayland->frame_bounds, cairo_region_destroy); -+ -+ g_clear_pointer (&actor_wayland->focused_shadow, meta_shadow_unref); -+ g_clear_pointer (&actor_wayland->unfocused_shadow, meta_shadow_unref); -+ g_clear_pointer (&actor_wayland->shadow_shape, meta_window_shape_unref); -+ -+ g_clear_signal_handler (&actor_wayland->size_changed_id, surface_actor); -+ g_clear_signal_handler (&actor_wayland->repaint_scheduled_id, surface_actor); -+ g_clear_signal_handler (&actor_wayland->shadow_factory_changed_handler_id, -+ actor_wayland->shadow_factory); - G_OBJECT_CLASS (meta_window_actor_wayland_parent_class)->dispose (object); - } - -@@ -196,6 +564,7 @@ static void - meta_window_actor_wayland_class_init (MetaWindowActorWaylandClass *klass) - { - MetaWindowActorClass *window_actor_class = META_WINDOW_ACTOR_CLASS (klass); -+ ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - window_actor_class->get_scanout_candidate = meta_window_actor_wayland_get_scanout_candidate; -@@ -209,10 +578,19 @@ meta_window_actor_wayland_class_init (MetaWindowActorWaylandClass *klass) - window_actor_class->update_regions = meta_window_actor_wayland_update_regions; - window_actor_class->can_freeze_commits = meta_window_actor_wayland_can_freeze_commits; - -+ actor_class->paint = meta_window_actor_wayland_paint; -+ -+ object_class->constructed = meta_window_actor_wayland_constructed; - object_class->dispose = meta_window_actor_wayland_dispose; - } - - static void - meta_window_actor_wayland_init (MetaWindowActorWayland *self) - { -+ self->shadow_factory = meta_shadow_factory_get_default (); -+ self->shadow_factory_changed_handler_id = -+ g_signal_connect_swapped (self->shadow_factory, -+ "changed", -+ G_CALLBACK (invalidate_shadow), -+ self); - } -diff --git a/src/compositor/meta-window-actor-x11.c b/src/compositor/meta-window-actor-x11.c -index 82eaa428b..3d3bb2178 100644 ---- a/src/compositor/meta-window-actor-x11.c -+++ b/src/compositor/meta-window-actor-x11.c -@@ -142,7 +142,8 @@ surface_repaint_scheduled (MetaSurfaceActor *actor, - gpointer user_data) - { - MetaWindowActorX11 *actor_x11 = META_WINDOW_ACTOR_X11 (user_data); -- -+ MetaWindow *window = meta_window_actor_get_meta_window (META_WINDOW_ACTOR(actor_x11)); -+ meta_compositor_update_blur_behind( meta_display_get_compositor (window->display)); - actor_x11->repaint_scheduled = TRUE; - } - -@@ -458,6 +459,8 @@ surface_size_changed (MetaSurfaceActor *actor, - MetaWindowActorX11 *actor_x11 = META_WINDOW_ACTOR_X11 (user_data); - - meta_window_actor_x11_update_shape (actor_x11); -+ -+ meta_window_actor_update_glsl(META_WINDOW_ACTOR(actor_x11)); - } - - static void -@@ -596,6 +599,9 @@ has_shadow (MetaWindowActorX11 *actor_x11) - if (meta_window_get_frame (window)) - return TRUE; - -+ if (meta_window_actor_should_clip(META_WINDOW_ACTOR(actor_x11))) -+ return TRUE; -+ - /* - * Do not add shadows to non-opaque (ARGB32) windows, as we can't easily - * generate shadows for them. -@@ -752,6 +758,8 @@ clip_shadow_under_window (MetaWindowActorX11 *actor_x11) - - if (window->frame) - return TRUE; -+ if (meta_window_actor_should_clip(META_WINDOW_ACTOR(actor_x11))) -+ return TRUE; - - return meta_window_actor_is_opaque (META_WINDOW_ACTOR (actor_x11)); - } -@@ -1094,6 +1102,11 @@ update_shape_region (MetaWindowActorX11 *actor_x11) - { - region = cairo_region_reference (window->shape_region); - } -+ else if (meta_window_actor_should_clip(META_WINDOW_ACTOR(actor_x11)) && !window->frame) -+ { -+ meta_window_actor_get_corner_rect(META_WINDOW_ACTOR(actor_x11), &client_area); -+ region = cairo_region_create_rectangle(&client_area); -+ } - else - { - /* If we don't have a shape on the server, that means that -@@ -1101,7 +1114,7 @@ update_shape_region (MetaWindowActorX11 *actor_x11) - * entire window. */ - region = cairo_region_create_rectangle (&client_area); - } -- -+ - if (window->shape_region || window->frame) - build_and_scan_frame_mask (actor_x11, region); - -@@ -1209,6 +1222,23 @@ update_opaque_region (MetaWindowActorX11 *actor_x11) - cairo_region_destroy (opaque_region); - } - -+static cairo_region_t * -+meta_window_get_clipped_frame_bounds(MetaWindow *window) -+{ -+ g_return_val_if_fail(window, NULL); -+ -+ MetaWindowActor *actor = meta_window_actor_from_window(window); -+ if (actor && !window->frame_bounds) -+ { -+ MetaRectangle rect; -+ meta_window_actor_get_corner_rect(actor, &rect); -+ window->frame_bounds = -+ meta_ui_frame_get_bounds_clipped(&rect, -+ meta_prefs_get_round_corner_radius()); -+ } -+ return window->frame_bounds; -+} -+ - static void - update_frame_bounds (MetaWindowActorX11 *actor_x11) - { -@@ -1216,8 +1246,13 @@ update_frame_bounds (MetaWindowActorX11 *actor_x11) - meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor_x11)); - - g_clear_pointer (&actor_x11->frame_bounds, cairo_region_destroy); -- actor_x11->frame_bounds = -- cairo_region_copy (meta_window_get_frame_bounds (window)); -+ -+ if (meta_window_actor_should_clip(META_WINDOW_ACTOR(actor_x11))) -+ actor_x11->frame_bounds = -+ cairo_region_copy(meta_window_get_clipped_frame_bounds(window)); -+ else -+ actor_x11->frame_bounds = -+ cairo_region_copy (meta_window_get_frame_bounds (window)); - } - - static void -@@ -1362,7 +1397,10 @@ meta_window_actor_x11_paint (ClutterActor *actor, - cairo_region_t *clip = actor_x11->shadow_clip; - CoglFramebuffer *framebuffer; - -- get_shape_bounds (actor_x11, &shape_bounds); -+ if (meta_window_actor_should_clip(META_WINDOW_ACTOR(actor_x11))) -+ meta_window_actor_get_corner_rect(META_WINDOW_ACTOR(actor_x11), &shape_bounds); -+ else -+ get_shape_bounds (actor_x11, &shape_bounds); - get_shadow_params (actor_x11, appears_focused, ¶ms); - - /* The frame bounds are already subtracted from actor_x11->shadow_clip -diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c -index ae1fa4d90..a5a5286fa 100644 ---- a/src/compositor/meta-window-actor.c -+++ b/src/compositor/meta-window-actor.c -@@ -41,6 +41,9 @@ - #include "wayland/meta-wayland-surface.h" - #endif - -+#include "meta_clip_effect.h" -+#include "shell-blur-effect.h" -+ - typedef enum - { - INITIALLY_FROZEN, -@@ -55,6 +58,15 @@ typedef struct _MetaWindowActorPrivate - - MetaSurfaceActor *surface; - -+ MetaClipEffect *round_clip_effect; -+ gboolean effect_setuped; -+ gboolean should_clip; -+ int clip_padding[4]; -+ ClutterActor *blur_actor; -+ MetaShellBlurEffect *blur_effect; -+ -+ ulong visible_changed_id; -+ ulong wm_class_changed_id; - int geometry_scale; - - /* -@@ -121,6 +133,246 @@ G_DEFINE_ABSTRACT_TYPE_WITH_CODE (MetaWindowActor, meta_window_actor, CLUTTER_TY - G_IMPLEMENT_INTERFACE (META_TYPE_CULLABLE, cullable_iface_init) - G_IMPLEMENT_INTERFACE (META_TYPE_SCREEN_CAST_WINDOW, screen_cast_window_iface_init)); - -+static gboolean _meta_window_actor_should_clip(MetaWindowActor *self); -+ -+static MetaClipEffect* -+create_clip_effect(MetaWindowActor *self) -+{ -+ MetaWindowActorPrivate *priv = meta_window_actor_get_instance_private(self); -+ if ((priv->should_clip = _meta_window_actor_should_clip(self))) -+ return meta_clip_effect_new(); -+ else -+ return NULL; -+} -+ -+void -+meta_window_actor_update_blur_position_size(MetaWindowActor *self) -+{ -+ MetaWindowActorPrivate *priv = -+ meta_window_actor_get_instance_private (self); -+ -+ if (!priv->blur_actor) -+ return; -+ -+ MetaRectangle buf_rect; -+ MetaRectangle frame_rect; -+ meta_window_get_frame_rect (priv->window, &frame_rect); -+ meta_window_get_buffer_rect (priv->window, &buf_rect); -+ -+ if ((meta_window_get_maximized (priv->window) && !meta_prefs_get_rounded_in_maximized()) || -+ meta_window_is_fullscreen (priv->window)) -+ { -+ clutter_actor_set_position (priv->blur_actor, -+ frame_rect.x, -+ frame_rect.y); -+ clutter_actor_set_size (priv->blur_actor, -+ frame_rect.width, -+ frame_rect.height); -+ meta_shell_blur_effect_set_skip (priv->blur_effect, true); -+ } -+ else -+ { -+ clutter_actor_set_position (priv->blur_actor, -+ frame_rect.x + priv->clip_padding[0] - 1, -+ frame_rect.y + priv->clip_padding[2] - 1); -+ clutter_actor_set_size (priv->blur_actor, -+ frame_rect.width - priv->clip_padding[0] - priv->clip_padding[1] + 1, -+ frame_rect.height - priv->clip_padding[2] - priv->clip_padding[3] + 1); -+ meta_shell_blur_effect_set_skip (priv->blur_effect, false); -+ } -+} -+ -+void -+meta_window_actor_set_blur_behind (MetaWindowActor *self) -+{ -+ MetaWindowActorPrivate *priv = -+ meta_window_actor_get_instance_private (self); -+ -+ if (!priv->blur_actor) -+ return; -+ -+ ClutterActor *parent = clutter_actor_get_parent (CLUTTER_ACTOR(self)); -+ clutter_actor_set_child_below_sibling (parent, priv->blur_actor, CLUTTER_ACTOR(self)); -+} -+ -+static gboolean -+meta_window_is_normal (MetaWindowActor *actor) -+{ -+ MetaWindowActorPrivate *priv = meta_window_actor_get_instance_private (actor); -+ MetaWindowType type = meta_window_get_window_type (priv->window); -+ -+switch (type) -+ { -+ case META_WINDOW_NORMAL: -+ case META_WINDOW_DIALOG: -+ case META_WINDOW_MODAL_DIALOG: -+ case META_WINDOW_SPLASHSCREEN: -+ return TRUE; -+ default: -+ return FALSE; -+ } -+} -+ -+ -+/* -+ * in xwayland, `res-name` property of MetaWindow (WM_CLASS_INSTANCE property) -+ * is empty when MetaWindow has been added to MetaWindowActor. So we have to -+ * create create blur actor in on_wm_class_changed callback. -+ * -+ * in xorg, `res-name` property of MetaWindow has been setted when MetaWindow, -+ * so we can create blur actor when window actor be created. -+ */ -+void -+meta_window_actor_create_blur_actor (MetaWindowActor *self) -+{ -+ MetaWindowActorPrivate *priv = -+ meta_window_actor_get_instance_private (self); -+ -+ if (!meta_window_is_normal (self)) -+ return; -+ if (!meta_prefs_in_blur_list (priv->window->res_name)) -+ return; -+ if (priv->blur_actor != NULL) -+ return; -+ -+ priv->blur_actor = clutter_actor_new (); -+ priv->blur_effect = meta_shell_blur_effect_new (); -+ -+ meta_shell_blur_effect_set_brightness (priv->blur_effect, -+ meta_prefs_get_blur_brightness()); -+ meta_shell_blur_effect_set_sigma (priv->blur_effect, -+ meta_prefs_get_blur_sigmal()); -+ meta_shell_blur_effect_set_mode (priv->blur_effect, SHELL_BLUR_MODE_BACKGROUND); -+ clutter_actor_add_effect_with_name (priv->blur_actor, -+ "ShellBlurEffect", -+ CLUTTER_EFFECT(priv->blur_effect)); -+ -+ ClutterActor *parent = clutter_actor_get_parent (CLUTTER_ACTOR(self)); -+ clutter_actor_insert_child_below (parent, priv->blur_actor, CLUTTER_ACTOR(self)); -+ int opa = meta_prefs_get_blur_window_opacity(); -+ meta_window_set_opacity(priv->window, opa); -+} -+ -+static void -+check_meta_window_surface_actor(MetaWindowActor *self) -+{ -+ MetaWindowActorPrivate *priv = meta_window_actor_get_instance_private(self); -+ MetaSurfaceActor *surface = meta_window_actor_get_surface(self); -+ -+ if (!priv->effect_setuped && surface && priv->round_clip_effect) -+ { -+ clutter_actor_add_effect_with_name(CLUTTER_ACTOR(surface), -+ "Rounded Corners Effect(Surface)", -+ CLUTTER_EFFECT(priv->round_clip_effect)); -+ priv->effect_setuped = true; -+ } -+} -+ -+void -+meta_window_actor_update_glsl(MetaWindowActor *self) -+{ -+ MetaRectangle frame_rect; -+ MetaRectangle buf_rect; -+ MetaWindow *window = meta_window_actor_get_meta_window(self); -+ MetaWindowActorPrivate *priv = meta_window_actor_get_instance_private(self); -+ -+ if(!priv->round_clip_effect) -+ return; -+ -+ check_meta_window_surface_actor(self); -+ -+ if (!meta_window_actor_should_clip(self)) -+ { -+ meta_clip_effect_skip(priv->round_clip_effect); -+ return; -+ } -+ -+ meta_window_get_frame_rect(window, &frame_rect); -+ meta_window_get_buffer_rect(window, &buf_rect); -+ -+ cairo_rectangle_int_t bounds; -+ bounds.x = frame_rect.x - buf_rect.x; -+ bounds.y = frame_rect.y - buf_rect.y; -+ bounds.width = frame_rect.width; -+ bounds.height = frame_rect.height; -+ -+ if (bounds.width <= 0 || bounds.height <= 0) -+ return; -+ -+ if (priv->clip_padding[0] == -1 && window->res_name) -+ meta_prefs_get_clip_edge_padding(window->res_name, priv->clip_padding); -+ -+ meta_clip_effect_set_bounds(priv->round_clip_effect, &bounds, priv->clip_padding); -+} -+ -+static gboolean -+_meta_window_actor_should_clip(MetaWindowActor *self) -+{ -+ MetaWindowActorPrivate *priv = meta_window_actor_get_instance_private (self); -+ MetaWindow *window = priv->window; -+ -+ if (meta_prefs_in_black_list(window->res_name)) -+ { -+ return FALSE; -+ } -+ -+ return meta_window_is_normal(self); -+} -+ -+gboolean -+meta_window_actor_should_clip(MetaWindowActor *self) -+{ -+ MetaWindowActorPrivate *priv = meta_window_actor_get_instance_private (self); -+ -+ return priv->should_clip && -+ !((meta_window_get_maximized(priv->window) && !meta_prefs_get_rounded_in_maximized()) -+ || meta_window_is_fullscreen(priv->window)); -+} -+ -+void -+meta_window_actor_get_corner_rect(MetaWindowActor *self, -+ MetaRectangle *rect) -+{ -+ MetaWindowActorPrivate *priv = meta_window_actor_get_instance_private(self); -+ g_return_if_fail(priv->round_clip_effect); -+ meta_clip_effect_get_bounds(priv->round_clip_effect, rect); -+} -+ -+void meta_window_actor_update_clip_padding(MetaWindowActor *self) -+{ -+ MetaWindowActorPrivate *priv = meta_window_actor_get_instance_private(self); -+ if(priv->round_clip_effect) -+ meta_prefs_get_clip_edge_padding(priv->window->res_name, -+ priv->clip_padding); -+} -+ -+void -+meta_window_actor_update_blur_sigmal (MetaWindowActor *self) -+{ -+ MetaWindowActorPrivate *priv = meta_window_actor_get_instance_private(self); -+ if (priv->blur_actor) -+ meta_shell_blur_effect_set_sigma (priv->blur_effect, -+ meta_prefs_get_blur_sigmal()); -+} -+ -+void -+meta_window_actor_update_blur_brightness (MetaWindowActor *self) -+{ -+ MetaWindowActorPrivate *priv = meta_window_actor_get_instance_private(self); -+ if (priv->blur_actor) -+ meta_shell_blur_effect_set_brightness (priv->blur_effect, -+ meta_prefs_get_blur_brightness()); -+} -+ -+void -+meta_window_actor_update_blur_window_opacity (MetaWindowActor *self) -+{ -+ MetaWindowActorPrivate *priv = meta_window_actor_get_instance_private(self); -+ if (priv->blur_actor) -+ meta_window_set_opacity (priv->window, -+ meta_prefs_get_blur_window_opacity()); -+} -+ - static void - meta_window_actor_class_init (MetaWindowActorClass *klass) - { -@@ -219,6 +471,11 @@ meta_window_actor_init (MetaWindowActor *self) - meta_window_actor_get_instance_private (self); - - priv->geometry_scale = 1; -+ priv->effect_setuped = FALSE; -+ priv->clip_padding[0] = -1; -+ -+ priv->blur_actor = NULL; -+ priv->blur_effect = NULL; - } - - static void -@@ -371,6 +628,11 @@ meta_window_actor_real_assign_surface_actor (MetaWindowActor *self, - meta_window_actor_set_frozen (self, TRUE); - else - meta_window_actor_sync_thawed_state (self); -+ -+ if (priv->blur_actor) -+ { -+ meta_window_actor_update_opacity (self); -+ } - } - - void -@@ -402,6 +664,32 @@ init_surface_actor (MetaWindowActor *self) - meta_window_actor_assign_surface_actor (self, surface_actor); - } - -+static void -+on_visible_changed (MetaWindowActor *self) -+{ -+ MetaWindowActorPrivate *priv = meta_window_actor_get_instance_private (self); -+ -+ if (!priv->blur_actor) -+ return; -+ -+ if (priv->visible && !meta_window_actor_effect_in_progress (self)) -+ clutter_actor_show(priv->blur_actor); -+ else -+ clutter_actor_hide(priv->blur_actor); -+} -+ -+static void -+on_wm_class_changed (MetaWindow *self, -+ gpointer user_data) -+{ -+ MetaWindowActor *actor = meta_window_actor_from_window (self); -+ MetaWindowActorPrivate *priv = meta_window_actor_get_instance_private (actor); -+ -+ priv->round_clip_effect = create_clip_effect(actor); -+ meta_window_actor_create_blur_actor(actor); -+ g_clear_signal_handler(&priv->wm_class_changed_id, self); -+} -+ - static void - meta_window_actor_constructed (GObject *object) - { -@@ -409,6 +697,7 @@ meta_window_actor_constructed (GObject *object) - MetaWindowActorPrivate *priv = - meta_window_actor_get_instance_private (self); - MetaWindow *window = priv->window; -+ MetaWindowClientType type = meta_window_get_client_type (window); - - priv->compositor = window->display->compositor; - -@@ -427,6 +716,15 @@ meta_window_actor_constructed (GObject *object) - priv->first_frame_state = DRAWING_FIRST_FRAME; - - meta_window_actor_sync_actor_geometry (self, priv->window->placed); -+ -+ if (type == META_WINDOW_CLIENT_TYPE_WAYLAND) -+ { -+ priv->wm_class_changed_id = -+ g_signal_connect (window, "notify::wm-class", G_CALLBACK (on_wm_class_changed), object); -+ } -+ -+ priv->visible_changed_id = -+ g_signal_connect (object, "notify::visible", G_CALLBACK (on_visible_changed), NULL); - } - - static void -@@ -445,6 +743,7 @@ meta_window_actor_dispose (GObject *object) - - priv->disposed = TRUE; - -+ g_clear_signal_handler(&priv->visible_changed_id, object); - meta_compositor_remove_window_actor (compositor, self); - - g_clear_object (&priv->window); -@@ -473,6 +772,8 @@ meta_window_actor_set_property (GObject *object, - { - case PROP_META_WINDOW: - priv->window = g_value_dup_object (value); -+ if (priv->window->client_type == META_WINDOW_CLIENT_TYPE_X11) -+ priv->round_clip_effect = create_clip_effect(self); - g_signal_connect_object (priv->window, "notify::appears-focused", - G_CALLBACK (window_appears_focused_notify), self, 0); - break; -@@ -603,6 +904,7 @@ meta_window_actor_effect_in_progress (MetaWindowActor *self) - meta_window_actor_get_instance_private (self); - - return (priv->minimize_in_progress || -+ priv->unminimize_in_progress || - priv->size_change_in_progress || - priv->map_in_progress || - priv->destroy_in_progress); -@@ -621,6 +923,47 @@ is_freeze_thaw_effect (MetaPluginEffect event) - } - } - -+static void -+meta_window_actor_remove_blur (MetaWindowActor *self) -+{ -+ MetaWindowActorPrivate *priv = -+ meta_window_actor_get_instance_private (self); -+ -+ if (!priv->blur_actor) -+ return; -+ -+ ClutterActor *parent = clutter_actor_get_parent (CLUTTER_ACTOR (self)); -+ clutter_actor_remove_effect (priv->blur_actor, CLUTTER_EFFECT (priv->blur_effect)); -+ clutter_actor_remove_child (parent, priv->blur_actor); -+} -+ -+static void -+meta_window_actor_hide_blur (MetaWindowActor *self) -+{ -+ MetaWindowActorPrivate *priv = -+ meta_window_actor_get_instance_private (self); -+ -+ if (!priv->blur_actor) -+ return; -+ -+ clutter_actor_hide(priv->blur_actor); -+} -+ -+static void -+meta_window_actor_show_blur (MetaWindowActor *self) -+{ -+ MetaWindowActorPrivate *priv = -+ meta_window_actor_get_instance_private (self); -+ -+ if (!priv->blur_actor) -+ return; -+ -+ if (priv->visible && !meta_window_actor_effect_in_progress (self)) -+ clutter_actor_show(priv->blur_actor); -+ else -+ clutter_actor_hide(priv->blur_actor); -+} -+ - static gboolean - start_simple_effect (MetaWindowActor *self, - MetaPluginEffect event) -@@ -640,15 +983,33 @@ start_simple_effect (MetaWindowActor *self, - case META_PLUGIN_NONE: - return FALSE; - case META_PLUGIN_MINIMIZE: -+ if (priv->round_clip_effect) -+ { -+ meta_window_actor_hide_blur(self); -+ } - counter = &priv->minimize_in_progress; - break; - case META_PLUGIN_UNMINIMIZE: -+ if (priv->round_clip_effect) -+ { -+ meta_window_actor_hide_blur(self); -+ } - counter = &priv->unminimize_in_progress; - break; - case META_PLUGIN_MAP: -+ if (priv->round_clip_effect) -+ { -+ meta_window_actor_hide_blur(self); -+ } - counter = &priv->map_in_progress; - break; - case META_PLUGIN_DESTROY: -+ if (priv->round_clip_effect) -+ { -+ clutter_actor_remove_effect (CLUTTER_ACTOR(self), -+ CLUTTER_EFFECT(priv->round_clip_effect)); -+ meta_window_actor_remove_blur(self); -+ } - counter = &priv->destroy_in_progress; - break; - case META_PLUGIN_SIZE_CHANGE: -@@ -697,6 +1058,7 @@ meta_window_actor_after_effects (MetaWindowActor *self) - g_signal_emit (self, signals[EFFECTS_COMPLETED], 0); - meta_window_actor_sync_visibility (self); - meta_window_actor_sync_actor_geometry (self, FALSE); -+ meta_window_actor_show_blur(self); - } - - clutter_stage_repick_device (stage, clutter_seat_get_pointer (seat)); -@@ -818,6 +1180,19 @@ meta_window_actor_queue_destroy (MetaWindowActor *self) - clutter_actor_destroy (CLUTTER_ACTOR (self)); - } - -+void -+meta_window_actor_update_clipped_bounds(MetaWindowActor *window_actor) -+{ -+ MetaWindowActorPrivate *priv = -+ meta_window_actor_get_instance_private(window_actor); -+ MetaWindow *window = priv->window; -+ -+ if (window && window->frame_bounds) { -+ cairo_region_destroy(window->frame_bounds); -+ window->frame_bounds = NULL; -+ } -+} -+ - MetaWindowActorChanges - meta_window_actor_sync_actor_geometry (MetaWindowActor *self, - gboolean did_placement) -@@ -1046,7 +1421,7 @@ meta_window_actor_sync_visibility (MetaWindowActor *self) - - if (CLUTTER_ACTOR_IS_VISIBLE (self) != priv->visible) - { -- if (priv->visible) -+ if (priv->visible && !priv->unminimize_in_progress) - clutter_actor_show (CLUTTER_ACTOR (self)); - else - clutter_actor_hide (CLUTTER_ACTOR (self)); -diff --git a/src/core/prefs.c b/src/core/prefs.c -index 536d9dd57..1889b27a7 100644 ---- a/src/core/prefs.c -+++ b/src/core/prefs.c -@@ -33,6 +33,8 @@ - #include <string.h> - #include <stdlib.h> - -+#include <json-glib/json-glib.h> -+ - #include "compositor/meta-plugin-manager.h" - #include "core/keybindings-private.h" - #include "core/meta-accel-parse.h" -@@ -120,6 +122,18 @@ static gboolean show_fallback_app_menu = TRUE; - static GDesktopVisualBellType visual_bell_type = G_DESKTOP_VISUAL_BELL_FULLSCREEN_FLASH; - static MetaButtonLayout button_layout; - -+static int round_corner_radius = 8; -+static int border_width = 0; -+static int border_brightness = 40; -+static int blur_sigmal = 20; -+static int blur_window_opacity = 80; -+static int blur_brightness = 100; -+static gboolean rounded_in_maximized = FALSE; -+static JsonNode *clip_edge_padding = NULL; -+/* NULL-terminated array */ -+static char **black_list = NULL; -+static char **blur_list = NULL; -+ - /* NULL-terminated array */ - static char **workspace_names = NULL; - -@@ -150,6 +164,7 @@ static gboolean mouse_button_mods_handler (GVariant*, gpointer*, gpointer); - static gboolean button_layout_handler (GVariant*, gpointer*, gpointer); - static gboolean overlay_key_handler (GVariant*, gpointer*, gpointer); - static gboolean locate_pointer_key_handler (GVariant*, gpointer*, gpointer); -+static gboolean clip_edge_padding_handler (GVariant*, gpointer*, gpointer); - - static gboolean iso_next_group_handler (GVariant*, gpointer*, gpointer); - -@@ -401,6 +416,13 @@ static MetaBoolPreference preferences_bool[] = - }, - &locate_pointer_is_enabled, - }, -+ { -+ { "rounded-in-maximized", -+ SCHEMA_MUTTER, -+ META_PREF_ROUNDED_IN_MAXIMIZED, -+ }, -+ &rounded_in_maximized, -+ }, - { { NULL, 0, 0 }, NULL }, - }; - -@@ -454,6 +476,15 @@ static MetaStringPreference preferences_string[] = - locate_pointer_key_handler, - NULL, - }, -+ { -+ { -+ "clip-edge-padding", -+ SCHEMA_MUTTER, -+ META_PREF_CLIP_EDGE_PADDING, -+ }, -+ clip_edge_padding_handler, -+ NULL, -+ }, - { { NULL, 0, 0 }, NULL }, - }; - -@@ -475,6 +506,22 @@ static MetaStringArrayPreference preferences_string_array[] = - iso_next_group_handler, - NULL, - }, -+ { -+ { "black-list", -+ SCHEMA_MUTTER, -+ META_PREF_BLACK_LIST, -+ }, -+ NULL, -+ &black_list, -+ }, -+ { -+ { "blur-list", -+ SCHEMA_MUTTER, -+ META_PREF_BLUR_LIST, -+ }, -+ NULL, -+ &blur_list, -+ }, - { { NULL, 0, 0 }, NULL }, - }; - -@@ -515,6 +562,54 @@ static MetaIntPreference preferences_int[] = - }, - &cursor_size - }, -+ { -+ { -+ "round-corners-radius", -+ SCHEMA_MUTTER, -+ META_PREF_CORNER_RADIUS, -+ }, -+ &round_corner_radius, -+ }, -+ { -+ { -+ "border-width", -+ SCHEMA_MUTTER, -+ META_PREF_BORDER_WIDTH, -+ }, -+ &border_width, -+ }, -+ { -+ { -+ "border-brightness", -+ SCHEMA_MUTTER, -+ META_PREF_BORDER_BRIGHTNESS, -+ }, -+ &border_brightness, -+ }, -+ { -+ { -+ "blur-sigmal", -+ SCHEMA_MUTTER, -+ META_PREF_BLUR_SIGMAL, -+ }, -+ &blur_sigmal, -+ }, -+ { -+ { -+ "blur-brightness", -+ SCHEMA_MUTTER, -+ META_PREF_BLUR_BRIGHTNESS, -+ }, -+ &blur_brightness, -+ }, -+ { -+ { -+ "blur-window-opacity", -+ SCHEMA_MUTTER, -+ META_PREF_BLUR_WINDOW_OPACITY, -+ }, -+ &blur_window_opacity, -+ }, - { { NULL, 0, 0 }, NULL }, - }; - -@@ -1588,6 +1683,81 @@ locate_pointer_key_handler (GVariant *value, - return TRUE; - } - -+static gboolean -+clip_edge_padding_handler (GVariant *value, -+ gpointer *result, -+ gpointer data) -+{ -+ /* json string looks like this: -+ * -+ * { -+ * // array represent the clip padding of window: [left, right, top, bottom] -+ * "global": [1, 1, 1, 1], -+ * // special app settings, -+ * "apps": { -+ * // second part in `WM_CLASS` property of a window -+ * "Typora": [0, 0, 0, 0], -+ * ... -+ * } -+ * } -+ */ -+ -+ JsonNode *json; -+ JsonObject *obj; -+ JsonArray *arr; -+ JsonNode *element; -+ JsonObject *apps_obj; -+ GList *app_names; -+ -+ const char *string_value; -+ GError *error = NULL; -+ -+ *result = NULL; -+ string_value = g_variant_get_string(value, NULL); -+ json = json_from_string(string_value, &error); -+ -+ if (error) -+ { -+ meta_topic(META_DEBUG_PREFS, "Failed to parse value for clip-edge-padding: %s", error->message); -+ g_error_free(error); -+ return FALSE; -+ } -+ -+ if (!JSON_NODE_HOLDS_OBJECT(json)) -+ goto failed; -+ -+ obj = json_node_get_object(json); -+ arr = json_object_get_array_member(obj, "global"); -+ if (!arr || json_array_get_length(arr) != 4) -+ goto failed; -+ -+ if (!(element = json_object_get_member(obj, "apps"))) -+ goto failed; -+ if (!JSON_NODE_HOLDS_OBJECT(element)) -+ goto failed; -+ apps_obj = json_node_get_object(element); -+ -+ app_names = json_object_get_members(apps_obj); -+ for (GList *l = app_names; l != NULL; l = l->next) -+ { -+ arr = json_object_get_array_member(apps_obj, l->data); -+ if (!arr || json_array_get_length(arr) != 4) -+ goto failed; -+ } -+ -+ if (clip_edge_padding != NULL) -+ json_node_unref(clip_edge_padding); -+ clip_edge_padding = json; -+ queue_changed(META_PREF_CLIP_EDGE_PADDING); -+ -+ return TRUE; -+ -+failed: -+ meta_topic(META_DEBUG_PREFS, "Failed to parse value for clip-edge-padding"); -+ json_node_unref(json); -+ return FALSE; -+} -+ - static gboolean - iso_next_group_handler (GVariant *value, - gpointer *result, -@@ -1759,6 +1929,36 @@ meta_preference_to_string (MetaPreference pref) - - case META_PREF_CHECK_ALIVE_TIMEOUT: - return "CHECK_ALIVE_TIMEOUT"; -+ -+ case META_PREF_CORNER_RADIUS: -+ return "CORNER_RADIUS"; -+ -+ case META_PREF_CLIP_EDGE_PADDING: -+ return "CLIP_EDGE_PADDING"; -+ -+ case META_PREF_BLACK_LIST: -+ return "BLACK_LIST"; -+ -+ case META_PREF_BORDER_WIDTH: -+ return "BORDER_WIDTH"; -+ -+ case META_PREF_BORDER_BRIGHTNESS: -+ return "BORDER_BRIGHTNESS"; -+ -+ case META_PREF_BLUR_SIGMAL: -+ return "BLUR_SIGMAL"; -+ -+ case META_PREF_BLUR_BRIGHTNESS: -+ return "BLUR_BRIGHTNESS"; -+ -+ case META_PREF_BLUR_LIST: -+ return "BLUR_LIST"; -+ -+ case META_PREF_BLUR_WINDOW_OPACITY: -+ return "BLUR_WINDOW_OPACITY"; -+ -+ case META_PREF_ROUNDED_IN_MAXIMIZED: -+ return "ROUNDED_IN_MAXIMIZED"; - } - - return "(unknown)"; -@@ -2227,3 +2427,100 @@ meta_prefs_set_force_fullscreen (gboolean whether) - { - force_fullscreen = whether; - } -+ -+int -+meta_prefs_get_round_corner_radius (void) -+{ -+ return round_corner_radius; -+} -+ -+#define SET_PADDING(arr, v0, v1, v2, v3) \ -+ { (arr)[0] = (v0); (arr)[1] = (v1); (arr)[2] = (v2); (arr)[3] = (v3); } -+ -+void -+meta_prefs_get_clip_edge_padding (const char *name, int padding[4]) -+{ -+ JsonObject *obj; -+ JsonArray *arr; -+ -+ if (!clip_edge_padding || !name) { -+ SET_PADDING(padding, 0, 0, 0, 0); -+ return; -+ } -+ -+ obj = json_node_get_object(clip_edge_padding); -+ arr = json_object_get_array_member(obj, "global"); -+ obj = json_object_get_object_member(obj, "apps"); -+ -+ if (json_object_has_member(obj, name)) -+ arr = json_object_get_array_member(obj, name); -+ -+ // array: { left, right, top, bottom } -+ SET_PADDING(padding, -+ json_array_get_int_element(arr, 0) + 1, -+ json_array_get_int_element(arr, 1), -+ json_array_get_int_element(arr, 2) + 1, -+ json_array_get_int_element(arr, 3)); -+} -+ -+gboolean -+meta_prefs_in_black_list(const char *name) -+{ -+ g_return_val_if_fail(black_list, FALSE); -+ -+ int len = g_strv_length(black_list); -+ -+ for (int i = 0; i < len; i++) -+ if (g_strcmp0(name, black_list[i]) == 0) -+ return TRUE; -+ return FALSE; -+} -+ -+int -+meta_prefs_get_border_width(void) -+{ -+ return border_width; -+} -+ -+double -+meta_prefs_get_border_brightness(void) -+{ -+ return (double) border_brightness * 0.01; -+} -+ -+int -+meta_prefs_get_blur_sigmal(void) -+{ -+ return blur_sigmal; -+} -+ -+double -+meta_prefs_get_blur_brightness(void) -+{ -+ return (double) blur_brightness * 0.01; -+} -+ -+int -+meta_prefs_get_blur_window_opacity(void) -+{ -+ return blur_window_opacity * 255 * 0.01; -+} -+ -+gboolean -+meta_prefs_get_rounded_in_maximized(void) -+{ -+ return rounded_in_maximized; -+} -+ -+gboolean -+meta_prefs_in_blur_list(const char *name) -+{ -+ g_return_val_if_fail(blur_list, FALSE); -+ -+ int len = g_strv_length(blur_list); -+ -+ for (int i = 0; i < len; i++) -+ if (g_strcmp0(name, blur_list[i]) == 0) -+ return TRUE; -+ return FALSE; -+} -diff --git a/src/meson.build b/src/meson.build -index 13a69c1a6..10e29db76 100644 ---- a/src/meson.build -+++ b/src/meson.build -@@ -173,6 +173,18 @@ if get_option('verbose') - ] - endif - -+libshell_enums = gnome.mkenums_simple('shell-enum-types', -+ sources: [ -+ 'shell-blur-effect.h', -+ ] -+) -+ -+libshell_src = [ -+ libshell_enums, -+ 'shell-blur-effect.h', -+ 'shell-blur-effect.c', -+] -+ - mutter_sources = [ - 'backends/edid.h', - 'backends/edid-parse.c', -@@ -462,6 +474,8 @@ mutter_sources = [ - 'x11/window-x11-private.h', - 'x11/xprops.c', - 'x11/xprops.h', -+ 'meta_clip_effect.c', -+ 'meta_clip_effect.h', - ] - - if have_egl_device -@@ -1016,7 +1030,8 @@ subdir('meta') - mutter_built_sources += mutter_enum_types - - libmutter = shared_library(libmutter_name, -- mutter_sources, -+ # mutter_sources, -+ mutter_sources + libshell_src, - mutter_built_sources, - version: '0.0.0', - soversion: 0, -diff --git a/src/meta/prefs.h b/src/meta/prefs.h -index 227de68bf..f005f47e8 100644 ---- a/src/meta/prefs.h -+++ b/src/meta/prefs.h -@@ -106,6 +106,17 @@ typedef enum - META_PREF_DRAG_THRESHOLD, - META_PREF_LOCATE_POINTER, - META_PREF_CHECK_ALIVE_TIMEOUT, -+ -+ META_PREF_CORNER_RADIUS, -+ META_PREF_CLIP_EDGE_PADDING, -+ META_PREF_BLACK_LIST, -+ META_PREF_BORDER_WIDTH, -+ META_PREF_BORDER_BRIGHTNESS, -+ META_PREF_BLUR_SIGMAL, -+ META_PREF_BLUR_BRIGHTNESS, -+ META_PREF_BLUR_LIST, -+ META_PREF_BLUR_WINDOW_OPACITY, -+ META_PREF_ROUNDED_IN_MAXIMIZED, - } MetaPreference; - - typedef void (* MetaPrefsChangedFunc) (MetaPreference pref, -@@ -233,6 +244,36 @@ int meta_prefs_get_draggable_border_width (void); - META_EXPORT - int meta_prefs_get_drag_threshold (void); - -+META_EXPORT -+int meta_prefs_get_round_corner_radius (void); -+ -+META_EXPORT -+void meta_prefs_get_clip_edge_padding (const char *name, int padding[4]); -+ -+META_EXPORT -+gboolean meta_prefs_in_black_list(const char *name); -+ -+META_EXPORT -+int meta_prefs_get_border_width(void); -+ -+META_EXPORT -+double meta_prefs_get_border_brightness(void); -+ -+META_EXPORT -+int meta_prefs_get_blur_sigmal(void); -+ -+META_EXPORT -+double meta_prefs_get_blur_brightness(void); -+ -+META_EXPORT -+int meta_prefs_get_blur_window_opacity(void); -+ -+META_EXPORT -+gboolean meta_prefs_get_rounded_in_maximized(void); -+ -+META_EXPORT -+gboolean meta_prefs_in_blur_list(const char *name); -+ - /** - * MetaKeyBindingAction: - * @META_KEYBINDING_ACTION_NONE: FILLME -diff --git a/src/ui/frames.c b/src/ui/frames.c -index cf90d477b..f82d653fd 100644 ---- a/src/ui/frames.c -+++ b/src/ui/frames.c -@@ -711,6 +711,27 @@ meta_ui_frame_get_bounds (MetaUIFrame *frame) - return get_visible_region (frame, &fgeom); - } - -+cairo_region_t * -+meta_ui_frame_get_bounds_clipped (const MetaRectangle *bounds, -+ float radius) -+{ -+ MetaFrameGeometry fgeom; -+ -+ fgeom.borders.invisible.left = bounds->x; -+ fgeom.borders.invisible.top = bounds->y; -+ fgeom.borders.invisible.bottom = 0; -+ fgeom.borders.invisible.right = 0; -+ fgeom.width = bounds->width + bounds->x; -+ fgeom.height = bounds->height + bounds->y; -+ -+ fgeom.top_left_corner_rounded_radius = radius; -+ fgeom.top_right_corner_rounded_radius = radius; -+ fgeom.bottom_left_corner_rounded_radius = radius; -+ fgeom.bottom_right_corner_rounded_radius = radius; -+ -+ return get_visible_region (NULL, &fgeom); -+} -+ - void - meta_ui_frame_move_resize (MetaUIFrame *frame, - int x, int y, int width, int height) -diff --git a/src/ui/frames.h b/src/ui/frames.h -index 89b399265..8262f0446 100644 ---- a/src/ui/frames.h -+++ b/src/ui/frames.h -@@ -139,6 +139,10 @@ void meta_ui_frame_get_borders (MetaUIFrame *frame, - - cairo_region_t * meta_ui_frame_get_bounds (MetaUIFrame *frame); - -+cairo_region_t * -+meta_ui_frame_get_bounds_clipped (const MetaRectangle *bounds, -+ float radius); -+ - void meta_ui_frame_get_mask (MetaUIFrame *frame, - cairo_rectangle_int_t *frame_rect, - cairo_t *cr); -diff --git a/src/wayland/meta-window-wayland.c b/src/wayland/meta-window-wayland.c -index 2b389bfbf..cbd04cc41 100644 ---- a/src/wayland/meta-window-wayland.c -+++ b/src/wayland/meta-window-wayland.c -@@ -1073,6 +1073,9 @@ meta_window_wayland_finish_move_resize (MetaWindow *window, - gravity = META_GRAVITY_STATIC; - meta_window_move_resize_internal (window, flags, gravity, rect); - -+ if (flags & META_MOVE_RESIZE_RESIZE_ACTION) -+ meta_window_actor_update_glsl(meta_window_actor_from_window(window)); -+ - g_clear_pointer (&acked_configuration, meta_wayland_window_configuration_free); - } - diff --git a/shader.h b/shader.h deleted file mode 100644 index 6a3340fcce69..000000000000 --- a/shader.h +++ /dev/null @@ -1,116 +0,0 @@ -#pragma once - -/* - * copied from src/compositor/meta-background-content.c - * see: https://gitlab.gnome.org/GNOME/mutter/-/blob/858b5c12b1f55043964c2e2bd30de8cf112e76d2/src/compositor/meta-background-content.c#L138 - */ -#define ROUNDED_CLIP_FRAGMENT_SHADER_FUNCS \ -"float \n"\ -"rounded_rect_coverage (vec2 p, vec4 bounds, float clip_radius) \n"\ -"{ \n"\ -" // Outside the bounds \n"\ -" if (p.x < bounds.x || p.x > bounds.z \n"\ -" || p.y < bounds.y || p.y > bounds.w ) { \n"\ -" return 0.0; \n"\ -" } \n"\ -" float center_left = bounds.x + clip_radius; \n"\ -" float center_right = bounds.z - clip_radius; \n"\ -" float center_x; \n"\ -" \n"\ -" if (p.x < center_left) \n"\ -" center_x = center_left; \n"\ -" else if (p.x > center_right) \n"\ -" center_x = center_right; \n"\ -" else \n"\ -" return 1.0; // The vast majority of pixels exit early here \n"\ -" \n"\ -" float center_top = bounds.y + clip_radius; \n"\ -" float center_bottom = bounds.w - clip_radius; \n"\ -" float center_y; \n"\ -" \n"\ -" if (p.y < center_top) \n"\ -" center_y = center_top; \n"\ -" else if (p.y > center_bottom) \n"\ -" center_y = center_bottom; \n"\ -" else \n"\ -" return 1.0; \n"\ -" \n"\ -" vec2 delta = p - vec2 (center_x, center_y); \n"\ -" float dist_squared = dot (delta, delta); \n"\ -" \n"\ -" // Fully outside the circle \n"\ -" float outer_radius = clip_radius + 0.5; \n"\ -" if (dist_squared >= (outer_radius * outer_radius)) \n"\ -" return 0.0; \n"\ -" \n"\ -" // Fully inside the circle \n"\ -" float inner_radius = clip_radius - 0.5; \n"\ -" if (dist_squared <= (inner_radius * inner_radius)) \n"\ -" return 1.0; \n"\ -" \n"\ -" \n"\ -" // Only pixels on the edge of the curve need expensive antialiasing \n"\ -" return outer_radius - sqrt (dist_squared); \n"\ -"} \n" - -#define ROUNDED_CLIP_FRAGMENT_SHADER_VARS \ -"uniform vec4 bounds; // x, y: top left; z, w: bottom right \n"\ -"uniform float clip_radius; \n"\ -"uniform vec4 inner_bounds; \n"\ -"uniform float inner_clip_radius; \n"\ -"uniform vec2 pixel_step; \n"\ -"uniform int skip; \n"\ -"uniform float border_width; \n"\ -"uniform float border_brightness; \n" - -/* used by src/meta_clip_effect.c */ -#define ROUNDED_CLIP_FRAGMENT_SHADER_DECLARATIONS \ -ROUNDED_CLIP_FRAGMENT_SHADER_VARS \ -ROUNDED_CLIP_FRAGMENT_SHADER_FUNCS - -/* used by src/meta_clip_effect.c */ -#define ROUNDED_CLIP_FRAGMENT_SHADER_CODE \ -"if (skip == 0) { \n"\ -" vec2 texture_coord = cogl_tex_coord0_in.xy / pixel_step; \n"\ -" \n"\ -" float outer_alpha = rounded_rect_coverage (texture_coord, \n"\ -" bounds, \n"\ -" clip_radius); \n"\ -" if (border_width > 0.0) { \n"\ -" float inner_alpha = rounded_rect_coverage (texture_coord, \n"\ -" inner_bounds, \n"\ -" inner_clip_radius); \n"\ -" float border_alpha = clamp (outer_alpha - inner_alpha, 0.0, 1.0) \n"\ -" * cogl_color_out.a; \n"\ -" \n"\ -" cogl_color_out *= smoothstep (0.0, 0.6, inner_alpha); \n"\ -" cogl_color_out = mix (cogl_color_out, \n"\ -" vec4(vec3(border_brightness), 1.0), \n"\ -" border_alpha); \n"\ -" } else { \n"\ -" cogl_color_out = cogl_color_out * outer_alpha; \n"\ -" } \n"\ -"} \n" - -#define ROUNDED_CLIP_FRAGMENT_SHADER_VARS_BLUR \ -"uniform vec4 bounds; // x, y: top left; w, v: bottom right \n"\ -"uniform float clip_radius; \n"\ -"uniform vec2 pixel_step; \n"\ -"uniform int skip; \n"\ -"uniform float brightness; \n" - -/* used by shell-blur-effect.c */ -#define ROUNDED_CLIP_FRAGMENT_SHADER_DECLARATIONS_BLUR \ -ROUNDED_CLIP_FRAGMENT_SHADER_VARS_BLUR \ -ROUNDED_CLIP_FRAGMENT_SHADER_FUNCS - -/* used by shell-blur-effect.c */ -#define ROUNDED_CLIP_FRAGMENT_SHADER_CODE_BLUR \ -"if (skip == 0) { \n"\ -" vec2 texture_coord = cogl_tex_coord0_in.xy / pixel_step; \n"\ -" \n"\ -" cogl_color_out *= rounded_rect_coverage (texture_coord, \n"\ -" bounds, \n"\ -" clip_radius); \n"\ -"} \n"\ -"cogl_color_out.rgb *= brightness; \n" diff --git a/shell-blur-effect.c b/shell-blur-effect.c deleted file mode 100644 index 0d4bb458a87d..000000000000 --- a/shell-blur-effect.c +++ /dev/null @@ -1,907 +0,0 @@ -/* shell-blur-effect.c - * - * Copyright 2019 Georges Basile Stavracas Neto <georges.stavracas@gmail.com> - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -#include "shell-blur-effect.h" - -#include "shell-enum-types.h" - -/** - * SECTION:shell-blur-effect - * @short_description: Blur effect for actors - * - * #ShellBlurEffect is a blur implementation based on Clutter. It also has - * an optional brightness property. - * - * # Modes - * - * #ShellBlurEffect can work in @SHELL_BLUR_MODE_BACKGROUND and @SHELL_BLUR_MODE_ACTOR - * modes. The actor mode blurs the actor itself, and all of its children. The - * background mode blurs the pixels beneath the actor, but not the actor itself. - * - * @SHELL_BLUR_MODE_BACKGROUND can be computationally expensive, since the contents - * beneath the actor cannot be cached, so beware of the performance implications - * of using this blur mode. - */ - -static const gchar *brightness_glsl_declarations = -"uniform float brightness; \n"; - -static const gchar *brightness_glsl = -" cogl_color_out.rgb *= brightness; \n"; - -#define MIN_DOWNSCALE_SIZE 256.f -#define MAX_SIGMA 6.f - -typedef enum -{ - ACTOR_PAINTED = 1 << 0, - BLUR_APPLIED = 1 << 1, -} CacheFlags; - -typedef struct -{ - CoglFramebuffer *framebuffer; - CoglPipeline *pipeline; - CoglTexture *texture; -} FramebufferData; - -struct _ShellBlurEffect -{ - ClutterEffect parent_instance; - - ClutterActor *actor; - - unsigned int tex_width; - unsigned int tex_height; - - /* The cached contents */ - FramebufferData actor_fb; - CacheFlags cache_flags; - - FramebufferData background_fb; - FramebufferData brightness_fb; - int brightness_uniform; - - ShellBlurMode mode; - float downscale_factor; - float brightness; - int sigma; -}; - -G_DEFINE_TYPE (ShellBlurEffect, shell_blur_effect, CLUTTER_TYPE_EFFECT) - -enum { - PROP_0, - PROP_SIGMA, - PROP_BRIGHTNESS, - PROP_MODE, - N_PROPS -}; - -static GParamSpec *properties [N_PROPS] = { NULL, }; - -static CoglPipeline* -create_base_pipeline (void) -{ - static CoglPipeline *base_pipeline = NULL; - - if (G_UNLIKELY (base_pipeline == NULL)) - { - CoglContext *ctx = - clutter_backend_get_cogl_context (clutter_get_default_backend ()); - - base_pipeline = cogl_pipeline_new (ctx); - cogl_pipeline_set_layer_null_texture (base_pipeline, 0); - cogl_pipeline_set_layer_filters (base_pipeline, - 0, - COGL_PIPELINE_FILTER_LINEAR, - COGL_PIPELINE_FILTER_LINEAR); - cogl_pipeline_set_layer_wrap_mode (base_pipeline, - 0, - COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE); - } - - return cogl_pipeline_copy (base_pipeline); -} - -static CoglPipeline* -create_brightness_pipeline (void) -{ - static CoglPipeline *brightness_pipeline = NULL; - - if (G_UNLIKELY (brightness_pipeline == NULL)) - { - CoglSnippet *snippet; - - brightness_pipeline = create_base_pipeline (); - - snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT, - brightness_glsl_declarations, - brightness_glsl); - cogl_pipeline_add_snippet (brightness_pipeline, snippet); - cogl_object_unref (snippet); - } - - return cogl_pipeline_copy (brightness_pipeline); -} - - -static void -update_brightness (ShellBlurEffect *self, - uint8_t paint_opacity) -{ - cogl_pipeline_set_color4ub (self->brightness_fb.pipeline, - paint_opacity, - paint_opacity, - paint_opacity, - paint_opacity); - - if (self->brightness_uniform > -1) - { - cogl_pipeline_set_uniform_1f (self->brightness_fb.pipeline, - self->brightness_uniform, - self->brightness); - } -} - -static void -setup_projection_matrix (CoglFramebuffer *framebuffer, - float width, - float height) -{ - graphene_matrix_t projection; - - graphene_matrix_init_translate (&projection, - &GRAPHENE_POINT3D_INIT (-width / 2.0, - -height / 2.0, - 0.f)); - graphene_matrix_scale (&projection, 2.0 / width, -2.0 / height, 1.f); - - cogl_framebuffer_set_projection_matrix (framebuffer, &projection); -} - -static gboolean -update_fbo (FramebufferData *data, - unsigned int width, - unsigned int height, - float downscale_factor) -{ - CoglContext *ctx = - clutter_backend_get_cogl_context (clutter_get_default_backend ()); - - g_clear_pointer (&data->texture, cogl_object_unref); - g_clear_object (&data->framebuffer); - - float new_width = floorf (width / downscale_factor); - float new_height = floorf (height / downscale_factor); - - data->texture = cogl_texture_2d_new_with_size (ctx, new_width, new_height); - if (!data->texture) - return FALSE; - - cogl_pipeline_set_layer_texture (data->pipeline, 0, data->texture); - - data->framebuffer = - COGL_FRAMEBUFFER (cogl_offscreen_new_with_texture (data->texture)); - if (!data->framebuffer) - { - g_warning ("%s: Unable to create an Offscreen buffer", G_STRLOC); - return FALSE; - } - - setup_projection_matrix (data->framebuffer, new_width, new_height); - - return TRUE; -} - -static gboolean -update_actor_fbo (ShellBlurEffect *self, - unsigned int width, - unsigned int height, - float downscale_factor) -{ - if (self->tex_width == width && - self->tex_height == height && - self->downscale_factor == downscale_factor && - self->actor_fb.framebuffer) - { - return TRUE; - } - - self->cache_flags &= ~ACTOR_PAINTED; - - return update_fbo (&self->actor_fb, width, height, downscale_factor); -} - -static gboolean -update_brightness_fbo (ShellBlurEffect *self, - unsigned int width, - unsigned int height, - float downscale_factor) -{ - if (self->tex_width == width && - self->tex_height == height && - self->downscale_factor == downscale_factor && - self->brightness_fb.framebuffer) - { - return TRUE; - } - - return update_fbo (&self->brightness_fb, - width, height, - downscale_factor); -} - -static gboolean -update_background_fbo (ShellBlurEffect *self, - unsigned int width, - unsigned int height) -{ - if (self->tex_width == width && - self->tex_height == height && - self->background_fb.framebuffer) - { - return TRUE; - } - - return update_fbo (&self->background_fb, width, height, 1.0); -} - -static void -clear_framebuffer_data (FramebufferData *fb_data) -{ - g_clear_pointer (&fb_data->texture, cogl_object_unref); - g_clear_object (&fb_data->framebuffer); -} - -static float -calculate_downscale_factor (float width, - float height, - float sigma) -{ - float downscale_factor = 1.0; - float scaled_width = width; - float scaled_height = height; - float scaled_sigma = sigma; - - /* This is the algorithm used by Firefox; keep downscaling until either the - * blur radius is lower than the threshold, or the downscaled texture is too - * small. - */ - while (scaled_sigma > MAX_SIGMA && - scaled_width > MIN_DOWNSCALE_SIZE && - scaled_height > MIN_DOWNSCALE_SIZE) - { - downscale_factor *= 2.f; - - scaled_width = width / downscale_factor; - scaled_height = height / downscale_factor; - scaled_sigma = sigma / downscale_factor; - } - - return downscale_factor; -} - -static void -shell_blur_effect_set_actor (ClutterActorMeta *meta, - ClutterActor *actor) -{ - ShellBlurEffect *self = SHELL_BLUR_EFFECT (meta); - ClutterActorMetaClass *meta_class; - - meta_class = CLUTTER_ACTOR_META_CLASS (shell_blur_effect_parent_class); - meta_class->set_actor (meta, actor); - - /* clear out the previous state */ - clear_framebuffer_data (&self->actor_fb); - clear_framebuffer_data (&self->background_fb); - clear_framebuffer_data (&self->brightness_fb); - - /* we keep a back pointer here, to avoid going through the ActorMeta */ - self->actor = clutter_actor_meta_get_actor (meta); -} - -static void -update_actor_box (ShellBlurEffect *self, - ClutterPaintContext *paint_context, - ClutterActorBox *source_actor_box) -{ - ClutterStageView *stage_view; - float box_scale_factor = 1.0f; - float origin_x, origin_y; - float width, height; - - switch (self->mode) - { - case SHELL_BLUR_MODE_ACTOR: - clutter_actor_get_allocation_box (self->actor, source_actor_box); - break; - - case SHELL_BLUR_MODE_BACKGROUND: - stage_view = clutter_paint_context_get_stage_view (paint_context); - - clutter_actor_get_transformed_position (self->actor, &origin_x, &origin_y); - clutter_actor_get_transformed_size (self->actor, &width, &height); - - if (stage_view) - { - cairo_rectangle_int_t stage_view_layout; - - box_scale_factor = clutter_stage_view_get_scale (stage_view); - clutter_stage_view_get_layout (stage_view, &stage_view_layout); - - origin_x -= stage_view_layout.x; - origin_y -= stage_view_layout.y; - } - else - { - /* If we're drawing off stage, just assume scale = 1, this won't work - * with stage-view scaling though. - */ - } - - clutter_actor_box_set_origin (source_actor_box, origin_x, origin_y); - clutter_actor_box_set_size (source_actor_box, width, height); - - clutter_actor_box_scale (source_actor_box, box_scale_factor); - break; - } - - clutter_actor_box_clamp_to_pixel (source_actor_box); -} - -static void -add_blurred_pipeline (ShellBlurEffect *self, - ClutterPaintNode *node, - uint8_t paint_opacity) -{ - g_autoptr (ClutterPaintNode) pipeline_node = NULL; - float width, height; - - /* Use the untransformed actor size here, since the framebuffer itself already - * has the actor transform matrix applied. - */ - clutter_actor_get_size (self->actor, &width, &height); - - update_brightness (self, paint_opacity); - - pipeline_node = clutter_pipeline_node_new (self->brightness_fb.pipeline); - clutter_paint_node_set_static_name (pipeline_node, "ShellBlurEffect (final)"); - clutter_paint_node_add_child (node, pipeline_node); - - clutter_paint_node_add_rectangle (pipeline_node, - &(ClutterActorBox) { - 0.f, 0.f, - width, - height, - }); -} - -static ClutterPaintNode * -create_blur_nodes (ShellBlurEffect *self, - ClutterPaintNode *node, - uint8_t paint_opacity) -{ - g_autoptr (ClutterPaintNode) brightness_node = NULL; - g_autoptr (ClutterPaintNode) blur_node = NULL; - float width; - float height; - - clutter_actor_get_size (self->actor, &width, &height); - - update_brightness (self, paint_opacity); - brightness_node = clutter_layer_node_new_to_framebuffer (self->brightness_fb.framebuffer, - self->brightness_fb.pipeline); - clutter_paint_node_set_static_name (brightness_node, "ShellBlurEffect (brightness)"); - clutter_paint_node_add_child (node, brightness_node); - clutter_paint_node_add_rectangle (brightness_node, - &(ClutterActorBox) { - 0.f, 0.f, - width, height, - }); - - blur_node = clutter_blur_node_new (self->tex_width / self->downscale_factor, - self->tex_height / self->downscale_factor, - self->sigma / self->downscale_factor); - clutter_paint_node_set_static_name (blur_node, "ShellBlurEffect (blur)"); - clutter_paint_node_add_child (brightness_node, blur_node); - clutter_paint_node_add_rectangle (blur_node, - &(ClutterActorBox) { - 0.f, 0.f, - cogl_texture_get_width (self->brightness_fb.texture), - cogl_texture_get_height (self->brightness_fb.texture), - }); - - self->cache_flags |= BLUR_APPLIED; - - return g_steal_pointer (&blur_node); -} - -static void -paint_background (ShellBlurEffect *self, - ClutterPaintNode *node, - ClutterPaintContext *paint_context, - ClutterActorBox *source_actor_box) -{ - g_autoptr (ClutterPaintNode) background_node = NULL; - g_autoptr (ClutterPaintNode) blit_node = NULL; - CoglFramebuffer *src; - float transformed_x; - float transformed_y; - float transformed_width; - float transformed_height; - - clutter_actor_box_get_origin (source_actor_box, - &transformed_x, - &transformed_y); - clutter_actor_box_get_size (source_actor_box, - &transformed_width, - &transformed_height); - - /* Background layer node */ - background_node = - clutter_layer_node_new_to_framebuffer (self->background_fb.framebuffer, - self->background_fb.pipeline); - clutter_paint_node_set_static_name (background_node, "ShellBlurEffect (background)"); - clutter_paint_node_add_child (node, background_node); - clutter_paint_node_add_rectangle (background_node, - &(ClutterActorBox) { - 0.f, 0.f, - self->tex_width / self->downscale_factor, - self->tex_height / self->downscale_factor, - }); - - /* Blit node */ - src = clutter_paint_context_get_framebuffer (paint_context); - blit_node = clutter_blit_node_new (src); - clutter_paint_node_set_static_name (blit_node, "ShellBlurEffect (blit)"); - clutter_paint_node_add_child (background_node, blit_node); - clutter_blit_node_add_blit_rectangle (CLUTTER_BLIT_NODE (blit_node), - transformed_x, - transformed_y, - 0, 0, - transformed_width, - transformed_height); -} - -static gboolean -update_framebuffers (ShellBlurEffect *self, - ClutterPaintContext *paint_context, - ClutterActorBox *source_actor_box) -{ - gboolean updated = FALSE; - float downscale_factor; - float height = -1; - float width = -1; - - clutter_actor_box_get_size (source_actor_box, &width, &height); - - downscale_factor = calculate_downscale_factor (width, height, self->sigma); - - updated = update_actor_fbo (self, width, height, downscale_factor) && - update_brightness_fbo (self, width, height, downscale_factor); - - if (self->mode == SHELL_BLUR_MODE_BACKGROUND) - updated = updated && update_background_fbo (self, width, height); - - self->tex_width = width; - self->tex_height = height; - self->downscale_factor = downscale_factor; - - return updated; -} - -static void -add_actor_node (ShellBlurEffect *self, - ClutterPaintNode *node, - int opacity) -{ - g_autoptr (ClutterPaintNode) actor_node = NULL; - - actor_node = clutter_actor_node_new (self->actor, opacity); - clutter_paint_node_add_child (node, actor_node); -} - -static void -paint_actor_offscreen (ShellBlurEffect *self, - ClutterPaintNode *node, - ClutterEffectPaintFlags flags) -{ - gboolean actor_dirty; - - actor_dirty = (flags & CLUTTER_EFFECT_PAINT_ACTOR_DIRTY) != 0; - - /* The actor offscreen framebuffer is updated already */ - if (actor_dirty || !(self->cache_flags & ACTOR_PAINTED)) - { - g_autoptr (ClutterPaintNode) transform_node = NULL; - g_autoptr (ClutterPaintNode) layer_node = NULL; - graphene_matrix_t transform; - - /* Layer node */ - layer_node = clutter_layer_node_new_to_framebuffer (self->actor_fb.framebuffer, - self->actor_fb.pipeline); - clutter_paint_node_set_static_name (layer_node, "ShellBlurEffect (actor offscreen)"); - clutter_paint_node_add_child (node, layer_node); - clutter_paint_node_add_rectangle (layer_node, - &(ClutterActorBox) { - 0.f, 0.f, - self->tex_width / self->downscale_factor, - self->tex_height / self->downscale_factor, - }); - - /* Transform node */ - graphene_matrix_init_scale (&transform, - 1.f / self->downscale_factor, - 1.f / self->downscale_factor, - 1.f); - transform_node = clutter_transform_node_new (&transform); - clutter_paint_node_set_static_name (transform_node, "ShellBlurEffect (downscale)"); - clutter_paint_node_add_child (layer_node, transform_node); - - /* Actor node */ - add_actor_node (self, transform_node, 255); - - self->cache_flags |= ACTOR_PAINTED; - } - else - { - g_autoptr (ClutterPaintNode) pipeline_node = NULL; - - pipeline_node = clutter_pipeline_node_new (self->actor_fb.pipeline); - clutter_paint_node_set_static_name (pipeline_node, - "ShellBlurEffect (actor texture)"); - clutter_paint_node_add_child (node, pipeline_node); - clutter_paint_node_add_rectangle (pipeline_node, - &(ClutterActorBox) { - 0.f, 0.f, - self->tex_width / self->downscale_factor, - self->tex_height / self->downscale_factor, - }); - } -} - -static gboolean -needs_repaint (ShellBlurEffect *self, - ClutterEffectPaintFlags flags) -{ - gboolean actor_cached; - gboolean blur_cached; - gboolean actor_dirty; - - actor_dirty = (flags & CLUTTER_EFFECT_PAINT_ACTOR_DIRTY) != 0; - blur_cached = (self->cache_flags & BLUR_APPLIED) != 0; - actor_cached = (self->cache_flags & ACTOR_PAINTED) != 0; - - switch (self->mode) - { - case SHELL_BLUR_MODE_ACTOR: - return actor_dirty || !blur_cached || !actor_cached; - - case SHELL_BLUR_MODE_BACKGROUND: - return TRUE; - } - - return TRUE; -} - -static void -shell_blur_effect_paint_node (ClutterEffect *effect, - ClutterPaintNode *node, - ClutterPaintContext *paint_context, - ClutterEffectPaintFlags flags) -{ - ShellBlurEffect *self = SHELL_BLUR_EFFECT (effect); - uint8_t paint_opacity; - - g_assert (self->actor != NULL); - - if (self->sigma > 0) - { - g_autoptr (ClutterPaintNode) blur_node = NULL; - - switch (self->mode) - { - case SHELL_BLUR_MODE_ACTOR: - paint_opacity = clutter_actor_get_paint_opacity (self->actor); - break; - - case SHELL_BLUR_MODE_BACKGROUND: - paint_opacity = 255; - break; - - default: - g_assert_not_reached(); - break; - } - - if (needs_repaint (self, flags)) - { - ClutterActorBox source_actor_box; - - update_actor_box (self, paint_context, &source_actor_box); - - /* Failing to create or update the offscreen framebuffers prevents - * the entire effect to be applied. - */ - if (!update_framebuffers (self, paint_context, &source_actor_box)) - goto fail; - - blur_node = create_blur_nodes (self, node, paint_opacity); - - switch (self->mode) - { - case SHELL_BLUR_MODE_ACTOR: - paint_actor_offscreen (self, blur_node, flags); - break; - - case SHELL_BLUR_MODE_BACKGROUND: - paint_background (self, blur_node, paint_context, &source_actor_box); - break; - } - } - else - { - /* Use the cached pipeline if no repaint is needed */ - add_blurred_pipeline (self, node, paint_opacity); - } - - /* Background blur needs to paint the actor after painting the blurred - * background. - */ - switch (self->mode) - { - case SHELL_BLUR_MODE_ACTOR: - break; - - case SHELL_BLUR_MODE_BACKGROUND: - add_actor_node (self, node, -1); - break; - } - - return; - } - -fail: - /* When no blur is applied, or the offscreen framebuffers - * couldn't be created, fallback to simply painting the actor. - */ - add_actor_node (self, node, -1); -} - -static void -shell_blur_effect_finalize (GObject *object) -{ - ShellBlurEffect *self = (ShellBlurEffect *)object; - - clear_framebuffer_data (&self->actor_fb); - clear_framebuffer_data (&self->background_fb); - clear_framebuffer_data (&self->brightness_fb); - - g_clear_pointer (&self->actor_fb.pipeline, cogl_object_unref); - g_clear_pointer (&self->background_fb.pipeline, cogl_object_unref); - g_clear_pointer (&self->brightness_fb.pipeline, cogl_object_unref); - - G_OBJECT_CLASS (shell_blur_effect_parent_class)->finalize (object); -} - -static void -shell_blur_effect_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - ShellBlurEffect *self = SHELL_BLUR_EFFECT (object); - - switch (prop_id) - { - case PROP_SIGMA: - g_value_set_int (value, self->sigma); - break; - - case PROP_BRIGHTNESS: - g_value_set_float (value, self->brightness); - break; - - case PROP_MODE: - g_value_set_enum (value, self->mode); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } -} - -static void -shell_blur_effect_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - ShellBlurEffect *self = SHELL_BLUR_EFFECT (object); - - switch (prop_id) - { - case PROP_SIGMA: - shell_blur_effect_set_sigma (self, g_value_get_int (value)); - break; - - case PROP_BRIGHTNESS: - shell_blur_effect_set_brightness (self, g_value_get_float (value)); - break; - - case PROP_MODE: - shell_blur_effect_set_mode (self, g_value_get_enum (value)); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } -} - -static void -shell_blur_effect_class_init (ShellBlurEffectClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - ClutterActorMetaClass *meta_class = CLUTTER_ACTOR_META_CLASS (klass); - ClutterEffectClass *effect_class = CLUTTER_EFFECT_CLASS (klass); - - object_class->finalize = shell_blur_effect_finalize; - object_class->get_property = shell_blur_effect_get_property; - object_class->set_property = shell_blur_effect_set_property; - - meta_class->set_actor = shell_blur_effect_set_actor; - - effect_class->paint_node = shell_blur_effect_paint_node; - - properties[PROP_SIGMA] = - g_param_spec_int ("sigma", - "Sigma", - "Sigma", - 0, G_MAXINT, 0, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); - - properties[PROP_BRIGHTNESS] = - g_param_spec_float ("brightness", - "Brightness", - "Brightness", - 0.f, 1.f, 1.f, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); - - properties[PROP_MODE] = - g_param_spec_enum ("mode", - "Blur mode", - "Blur mode", - SHELL_TYPE_BLUR_MODE, - SHELL_BLUR_MODE_ACTOR, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); - - g_object_class_install_properties (object_class, N_PROPS, properties); -} - -static void -shell_blur_effect_init (ShellBlurEffect *self) -{ - self->mode = SHELL_BLUR_MODE_ACTOR; - self->sigma = 0; - self->brightness = 1.f; - - self->actor_fb.pipeline = create_base_pipeline (); - self->background_fb.pipeline = create_base_pipeline (); - self->brightness_fb.pipeline = create_brightness_pipeline (); - self->brightness_uniform = - cogl_pipeline_get_uniform_location (self->brightness_fb.pipeline, "brightness"); -} - -ShellBlurEffect * -shell_blur_effect_new (void) -{ - return g_object_new (SHELL_TYPE_BLUR_EFFECT, NULL); -} - -int -shell_blur_effect_get_sigma (ShellBlurEffect *self) -{ - g_return_val_if_fail (SHELL_IS_BLUR_EFFECT (self), -1); - - return self->sigma; -} - -void -shell_blur_effect_set_sigma (ShellBlurEffect *self, - int sigma) -{ - g_return_if_fail (SHELL_IS_BLUR_EFFECT (self)); - - if (self->sigma == sigma) - return; - - self->sigma = sigma; - self->cache_flags &= ~BLUR_APPLIED; - - if (self->actor) - clutter_effect_queue_repaint (CLUTTER_EFFECT (self)); - - g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SIGMA]); -} - -float -shell_blur_effect_get_brightness (ShellBlurEffect *self) -{ - g_return_val_if_fail (SHELL_IS_BLUR_EFFECT (self), FALSE); - - return self->brightness; -} - -void -shell_blur_effect_set_brightness (ShellBlurEffect *self, - float brightness) -{ - g_return_if_fail (SHELL_IS_BLUR_EFFECT (self)); - - if (self->brightness == brightness) - return; - - self->brightness = brightness; - self->cache_flags &= ~BLUR_APPLIED; - - if (self->actor) - clutter_effect_queue_repaint (CLUTTER_EFFECT (self)); - - g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_BRIGHTNESS]); -} - -ShellBlurMode -shell_blur_effect_get_mode (ShellBlurEffect *self) -{ - g_return_val_if_fail (SHELL_IS_BLUR_EFFECT (self), -1); - - return self->mode; -} - -void -shell_blur_effect_set_mode (ShellBlurEffect *self, - ShellBlurMode mode) -{ - g_return_if_fail (SHELL_IS_BLUR_EFFECT (self)); - - if (self->mode == mode) - return; - - self->mode = mode; - self->cache_flags &= ~BLUR_APPLIED; - - switch (mode) - { - case SHELL_BLUR_MODE_ACTOR: - clear_framebuffer_data (&self->background_fb); - break; - - case SHELL_BLUR_MODE_BACKGROUND: - default: - /* Do nothing */ - break; - } - - if (self->actor) - clutter_effect_queue_repaint (CLUTTER_EFFECT (self)); - - g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MODE]); -} diff --git a/shell-blur-effect.h b/shell-blur-effect.h deleted file mode 100644 index a7486ccde09b..000000000000 --- a/shell-blur-effect.h +++ /dev/null @@ -1,57 +0,0 @@ -/* shell-blur-effect.h - * - * Copyright 2019 Georges Basile Stavracas Neto <georges.stavracas@gmail.com> - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -#pragma once - -#include <clutter/clutter.h> - -G_BEGIN_DECLS - -/** - * ShellBlurMode: - * @SHELL_BLUR_MODE_ACTOR: blur the actor contents, and its children - * @SHELL_BLUR_MODE_BACKGROUND: blur what's beneath the actor - * - * The mode of blurring of the effect. - */ -typedef enum -{ - SHELL_BLUR_MODE_ACTOR, - SHELL_BLUR_MODE_BACKGROUND, -} ShellBlurMode; - -#define SHELL_TYPE_BLUR_EFFECT (shell_blur_effect_get_type()) -G_DECLARE_FINAL_TYPE (ShellBlurEffect, shell_blur_effect, SHELL, BLUR_EFFECT, ClutterEffect) - -ShellBlurEffect *shell_blur_effect_new (void); - -int shell_blur_effect_get_sigma (ShellBlurEffect *self); -void shell_blur_effect_set_sigma (ShellBlurEffect *self, - int sigma); - -float shell_blur_effect_get_brightness (ShellBlurEffect *self); -void shell_blur_effect_set_brightness (ShellBlurEffect *self, - float brightness); - -ShellBlurMode shell_blur_effect_get_mode (ShellBlurEffect *self); -void shell_blur_effect_set_mode (ShellBlurEffect *self, - ShellBlurMode mode); - -G_END_DECLS diff --git a/shell_blur_effect.patch b/shell_blur_effect.patch deleted file mode 100644 index e2ed3edfae0b..000000000000 --- a/shell_blur_effect.patch +++ /dev/null @@ -1,462 +0,0 @@ -diff -Narup a/src/shell-blur-effect.c b/src/shell-blur-effect.c ---- a/src/shell-blur-effect.c 2022-03-31 10:47:02.847618301 +0800 -+++ b/src/shell-blur-effect.c 2022-03-31 10:47:02.847618301 +0800 -@@ -22,6 +22,9 @@ - - #include "shell-enum-types.h" - -+#include "meta/prefs.h" -+#include "shader.h" -+ - /** - * SECTION:shell-blur-effect - * @short_description: Blur effect for actors -@@ -40,12 +43,6 @@ - * of using this blur mode. - */ - --static const gchar *brightness_glsl_declarations = --"uniform float brightness; \n"; -- --static const gchar *brightness_glsl = --" cogl_color_out.rgb *= brightness; \n"; -- - #define MIN_DOWNSCALE_SIZE 256.f - #define MAX_SIGMA 6.f - -@@ -62,7 +59,7 @@ typedef struct - CoglTexture *texture; - } FramebufferData; - --struct _ShellBlurEffect -+struct _MetaShellBlurEffect - { - ClutterEffect parent_instance; - -@@ -78,6 +75,11 @@ struct _ShellBlurEffect - FramebufferData background_fb; - FramebufferData brightness_fb; - int brightness_uniform; -+ int bounds_uniform; -+ int clip_radius_uniform; -+ int pixel_step_uniform; -+ int skip_uniform; -+ gboolean skip; - - ShellBlurMode mode; - float downscale_factor; -@@ -85,7 +87,7 @@ struct _ShellBlurEffect - int sigma; - }; - --G_DEFINE_TYPE (ShellBlurEffect, shell_blur_effect, CLUTTER_TYPE_EFFECT) -+G_DEFINE_TYPE (MetaShellBlurEffect, meta_shell_blur_effect, CLUTTER_TYPE_EFFECT) - - enum { - PROP_0, -@@ -133,8 +135,8 @@ create_brightness_pipeline (void) - brightness_pipeline = create_base_pipeline (); - - snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT, -- brightness_glsl_declarations, -- brightness_glsl); -+ ROUNDED_CLIP_FRAGMENT_SHADER_DECLARATIONS_BLUR, -+ ROUNDED_CLIP_FRAGMENT_SHADER_CODE_BLUR); - cogl_pipeline_add_snippet (brightness_pipeline, snippet); - cogl_object_unref (snippet); - } -@@ -144,7 +146,7 @@ create_brightness_pipeline (void) - - - static void --update_brightness (ShellBlurEffect *self, -+update_brightness (MetaShellBlurEffect *self, - uint8_t paint_opacity) - { - cogl_pipeline_set_color4ub (self->brightness_fb.pipeline, -@@ -155,9 +157,29 @@ update_brightness (ShellBlurEffect *self - - if (self->brightness_uniform > -1) - { -+ cogl_pipeline_set_uniform_1i (self->brightness_fb.pipeline, -+ self->skip_uniform, self->skip); - cogl_pipeline_set_uniform_1f (self->brightness_fb.pipeline, - self->brightness_uniform, - self->brightness); -+ if (self->skip) -+ return; -+ -+ float width = self->tex_width; -+ float height = self->tex_height; -+ float radius = meta_prefs_get_round_corner_radius(); -+ float bounds[] = { 0.0, 0.0, width, height }; -+ float pixel_step[] = { 1.0 / width, 1.0 / height }; -+ -+ cogl_pipeline_set_uniform_float (self->brightness_fb.pipeline, -+ self->bounds_uniform, -+ 4, 1, bounds); -+ cogl_pipeline_set_uniform_1f (self->brightness_fb.pipeline, -+ self->clip_radius_uniform, -+ radius); -+ cogl_pipeline_set_uniform_float (self->brightness_fb.pipeline, -+ self->pixel_step_uniform, -+ 2, 1, pixel_step); - } - } - -@@ -212,7 +234,7 @@ update_fbo (FramebufferData *data, - } - - static gboolean --update_actor_fbo (ShellBlurEffect *self, -+update_actor_fbo (MetaShellBlurEffect *self, - unsigned int width, - unsigned int height, - float downscale_factor) -@@ -231,7 +253,7 @@ update_actor_fbo (ShellBlurEffect *self, - } - - static gboolean --update_brightness_fbo (ShellBlurEffect *self, -+update_brightness_fbo (MetaShellBlurEffect *self, - unsigned int width, - unsigned int height, - float downscale_factor) -@@ -250,7 +272,7 @@ update_brightness_fbo (ShellBlurEffect * - } - - static gboolean --update_background_fbo (ShellBlurEffect *self, -+update_background_fbo (MetaShellBlurEffect *self, - unsigned int width, - unsigned int height) - { -@@ -303,10 +325,10 @@ static void - shell_blur_effect_set_actor (ClutterActorMeta *meta, - ClutterActor *actor) - { -- ShellBlurEffect *self = SHELL_BLUR_EFFECT (meta); -+ MetaShellBlurEffect *self = META_SHELL_BLUR_EFFECT (meta); - ClutterActorMetaClass *meta_class; - -- meta_class = CLUTTER_ACTOR_META_CLASS (shell_blur_effect_parent_class); -+ meta_class = CLUTTER_ACTOR_META_CLASS (meta_shell_blur_effect_parent_class); - meta_class->set_actor (meta, actor); - - /* clear out the previous state */ -@@ -319,7 +341,7 @@ shell_blur_effect_set_actor (ClutterActo - } - - static void --update_actor_box (ShellBlurEffect *self, -+update_actor_box (MetaShellBlurEffect *self, - ClutterPaintContext *paint_context, - ClutterActorBox *source_actor_box) - { -@@ -368,7 +390,7 @@ update_actor_box (ShellBlurEffect *s - } - - static void --add_blurred_pipeline (ShellBlurEffect *self, -+add_blurred_pipeline (MetaShellBlurEffect *self, - ClutterPaintNode *node, - uint8_t paint_opacity) - { -@@ -395,7 +417,7 @@ add_blurred_pipeline (ShellBlurEffect * - } - - static ClutterPaintNode * --create_blur_nodes (ShellBlurEffect *self, -+create_blur_nodes (MetaShellBlurEffect *self, - ClutterPaintNode *node, - uint8_t paint_opacity) - { -@@ -435,7 +457,7 @@ create_blur_nodes (ShellBlurEffect *sel - } - - static void --paint_background (ShellBlurEffect *self, -+paint_background (MetaShellBlurEffect *self, - ClutterPaintNode *node, - ClutterPaintContext *paint_context, - ClutterActorBox *source_actor_box) -@@ -482,7 +504,7 @@ paint_background (ShellBlurEffect *s - } - - static gboolean --update_framebuffers (ShellBlurEffect *self, -+update_framebuffers (MetaShellBlurEffect *self, - ClutterPaintContext *paint_context, - ClutterActorBox *source_actor_box) - { -@@ -509,7 +531,7 @@ update_framebuffers (ShellBlurEffect - } - - static void --add_actor_node (ShellBlurEffect *self, -+add_actor_node (MetaShellBlurEffect *self, - ClutterPaintNode *node, - int opacity) - { -@@ -520,7 +542,7 @@ add_actor_node (ShellBlurEffect *self, - } - - static void --paint_actor_offscreen (ShellBlurEffect *self, -+paint_actor_offscreen (MetaShellBlurEffect *self, - ClutterPaintNode *node, - ClutterEffectPaintFlags flags) - { -@@ -579,7 +601,7 @@ paint_actor_offscreen (ShellBlurEffect - } - - static gboolean --needs_repaint (ShellBlurEffect *self, -+needs_repaint (MetaShellBlurEffect *self, - ClutterEffectPaintFlags flags) - { - gboolean actor_cached; -@@ -608,7 +630,7 @@ shell_blur_effect_paint_node (ClutterEff - ClutterPaintContext *paint_context, - ClutterEffectPaintFlags flags) - { -- ShellBlurEffect *self = SHELL_BLUR_EFFECT (effect); -+ MetaShellBlurEffect *self = META_SHELL_BLUR_EFFECT (effect); - uint8_t paint_opacity; - - g_assert (self->actor != NULL); -@@ -689,7 +711,7 @@ fail: - static void - shell_blur_effect_finalize (GObject *object) - { -- ShellBlurEffect *self = (ShellBlurEffect *)object; -+ MetaShellBlurEffect *self = (MetaShellBlurEffect *)object; - - clear_framebuffer_data (&self->actor_fb); - clear_framebuffer_data (&self->background_fb); -@@ -699,7 +721,7 @@ shell_blur_effect_finalize (GObject *obj - g_clear_pointer (&self->background_fb.pipeline, cogl_object_unref); - g_clear_pointer (&self->brightness_fb.pipeline, cogl_object_unref); - -- G_OBJECT_CLASS (shell_blur_effect_parent_class)->finalize (object); -+ G_OBJECT_CLASS (meta_shell_blur_effect_parent_class)->finalize (object); - } - - static void -@@ -708,7 +730,7 @@ shell_blur_effect_get_property (GObject - GValue *value, - GParamSpec *pspec) - { -- ShellBlurEffect *self = SHELL_BLUR_EFFECT (object); -+ MetaShellBlurEffect *self = META_SHELL_BLUR_EFFECT (object); - - switch (prop_id) - { -@@ -735,20 +757,20 @@ shell_blur_effect_set_property (GObject - const GValue *value, - GParamSpec *pspec) - { -- ShellBlurEffect *self = SHELL_BLUR_EFFECT (object); -+ MetaShellBlurEffect *self = META_SHELL_BLUR_EFFECT (object); - - switch (prop_id) - { - case PROP_SIGMA: -- shell_blur_effect_set_sigma (self, g_value_get_int (value)); -+ meta_shell_blur_effect_set_sigma (self, g_value_get_int (value)); - break; - - case PROP_BRIGHTNESS: -- shell_blur_effect_set_brightness (self, g_value_get_float (value)); -+ meta_shell_blur_effect_set_brightness (self, g_value_get_float (value)); - break; - - case PROP_MODE: -- shell_blur_effect_set_mode (self, g_value_get_enum (value)); -+ meta_shell_blur_effect_set_mode (self, g_value_get_enum (value)); - break; - - default: -@@ -757,7 +779,7 @@ shell_blur_effect_set_property (GObject - } - - static void --shell_blur_effect_class_init (ShellBlurEffectClass *klass) -+meta_shell_blur_effect_class_init (MetaShellBlurEffectClass *klass) - { - GObjectClass *object_class = G_OBJECT_CLASS (klass); - ClutterActorMetaClass *meta_class = CLUTTER_ACTOR_META_CLASS (klass); -@@ -797,38 +819,48 @@ shell_blur_effect_class_init (ShellBlurE - } - - static void --shell_blur_effect_init (ShellBlurEffect *self) -+meta_shell_blur_effect_init (MetaShellBlurEffect *self) - { - self->mode = SHELL_BLUR_MODE_ACTOR; - self->sigma = 0; - self->brightness = 1.f; -+ self->skip = false; - - self->actor_fb.pipeline = create_base_pipeline (); - self->background_fb.pipeline = create_base_pipeline (); - self->brightness_fb.pipeline = create_brightness_pipeline (); - self->brightness_uniform = - cogl_pipeline_get_uniform_location (self->brightness_fb.pipeline, "brightness"); -+ self->bounds_uniform = -+ cogl_pipeline_get_uniform_location (self->brightness_fb.pipeline, "bounds"); -+ self->clip_radius_uniform = -+ cogl_pipeline_get_uniform_location (self->brightness_fb.pipeline, "clip_radius"); -+ self->pixel_step_uniform = -+ cogl_pipeline_get_uniform_location (self->brightness_fb.pipeline, "pixel_step"); -+ self->skip_uniform = -+ cogl_pipeline_get_uniform_location (self->brightness_fb.pipeline, "skip"); -+ - } - --ShellBlurEffect * --shell_blur_effect_new (void) -+MetaShellBlurEffect * -+meta_shell_blur_effect_new (void) - { -- return g_object_new (SHELL_TYPE_BLUR_EFFECT, NULL); -+ return g_object_new (META_SHELL_TYPE_BLUR_EFFECT, NULL); - } - - int --shell_blur_effect_get_sigma (ShellBlurEffect *self) -+meta_shell_blur_effect_get_sigma (MetaShellBlurEffect *self) - { -- g_return_val_if_fail (SHELL_IS_BLUR_EFFECT (self), -1); -+ g_return_val_if_fail (META_IS_SHELL_BLUR_EFFECT (self), -1); - - return self->sigma; - } - - void --shell_blur_effect_set_sigma (ShellBlurEffect *self, -+meta_shell_blur_effect_set_sigma (MetaShellBlurEffect *self, - int sigma) - { -- g_return_if_fail (SHELL_IS_BLUR_EFFECT (self)); -+ g_return_if_fail (META_IS_SHELL_BLUR_EFFECT (self)); - - if (self->sigma == sigma) - return; -@@ -843,18 +875,18 @@ shell_blur_effect_set_sigma (ShellBlurEf - } - - float --shell_blur_effect_get_brightness (ShellBlurEffect *self) -+meta_shell_blur_effect_get_brightness (MetaShellBlurEffect *self) - { -- g_return_val_if_fail (SHELL_IS_BLUR_EFFECT (self), FALSE); -+ g_return_val_if_fail (META_IS_SHELL_BLUR_EFFECT (self), FALSE); - - return self->brightness; - } - - void --shell_blur_effect_set_brightness (ShellBlurEffect *self, -+meta_shell_blur_effect_set_brightness (MetaShellBlurEffect *self, - float brightness) - { -- g_return_if_fail (SHELL_IS_BLUR_EFFECT (self)); -+ g_return_if_fail (META_IS_SHELL_BLUR_EFFECT (self)); - - if (self->brightness == brightness) - return; -@@ -869,18 +901,18 @@ shell_blur_effect_set_brightness (ShellB - } - - ShellBlurMode --shell_blur_effect_get_mode (ShellBlurEffect *self) -+meta_shell_blur_effect_get_mode (MetaShellBlurEffect *self) - { -- g_return_val_if_fail (SHELL_IS_BLUR_EFFECT (self), -1); -+ g_return_val_if_fail (META_IS_SHELL_BLUR_EFFECT (self), -1); - - return self->mode; - } - - void --shell_blur_effect_set_mode (ShellBlurEffect *self, -+meta_shell_blur_effect_set_mode (MetaShellBlurEffect *self, - ShellBlurMode mode) - { -- g_return_if_fail (SHELL_IS_BLUR_EFFECT (self)); -+ g_return_if_fail (META_IS_SHELL_BLUR_EFFECT (self)); - - if (self->mode == mode) - return; -@@ -905,3 +937,17 @@ shell_blur_effect_set_mode (ShellBlurEff - - g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MODE]); - } -+ -+void meta_shell_blur_effect_set_skip (MetaShellBlurEffect *self, -+ gboolean skip) -+{ -+ g_return_if_fail (META_IS_SHELL_BLUR_EFFECT (self)); -+ -+ if (self->skip == skip) -+ return; -+ -+ self->skip = skip; -+ -+ if (self->actor) -+ clutter_effect_queue_repaint (CLUTTER_EFFECT (self)); -+} -diff -Narup a/src/shell-blur-effect.h b/src/shell-blur-effect.h ---- a/src/shell-blur-effect.h 2022-03-31 10:47:02.847618301 +0800 -+++ b/src/shell-blur-effect.h 2022-03-31 10:47:02.847618301 +0800 -@@ -20,6 +20,10 @@ - - #pragma once - -+/* -+ * have to rename the type, to avoide conflicts with gnome shell -+ */ -+ - #include <clutter/clutter.h> - - G_BEGIN_DECLS -@@ -37,21 +41,24 @@ typedef enum - SHELL_BLUR_MODE_BACKGROUND, - } ShellBlurMode; - --#define SHELL_TYPE_BLUR_EFFECT (shell_blur_effect_get_type()) --G_DECLARE_FINAL_TYPE (ShellBlurEffect, shell_blur_effect, SHELL, BLUR_EFFECT, ClutterEffect) -+#define META_SHELL_TYPE_BLUR_EFFECT (meta_shell_blur_effect_get_type()) -+G_DECLARE_FINAL_TYPE (MetaShellBlurEffect, meta_shell_blur_effect, META, SHELL_BLUR_EFFECT, ClutterEffect) -+ -+MetaShellBlurEffect *meta_shell_blur_effect_new (void); -+ -+int meta_shell_blur_effect_get_sigma (MetaShellBlurEffect *self); -+void meta_shell_blur_effect_set_sigma (MetaShellBlurEffect *self, -+ int sigma); -+ -+float meta_shell_blur_effect_get_brightness (MetaShellBlurEffect *self); -+void meta_shell_blur_effect_set_brightness (MetaShellBlurEffect *self, -+ float brightness); - --ShellBlurEffect *shell_blur_effect_new (void); -+ShellBlurMode meta_shell_blur_effect_get_mode (MetaShellBlurEffect *self); -+void meta_shell_blur_effect_set_mode (MetaShellBlurEffect *self, -+ ShellBlurMode mode); - --int shell_blur_effect_get_sigma (ShellBlurEffect *self); --void shell_blur_effect_set_sigma (ShellBlurEffect *self, -- int sigma); -- --float shell_blur_effect_get_brightness (ShellBlurEffect *self); --void shell_blur_effect_set_brightness (ShellBlurEffect *self, -- float brightness); -- --ShellBlurMode shell_blur_effect_get_mode (ShellBlurEffect *self); --void shell_blur_effect_set_mode (ShellBlurEffect *self, -- ShellBlurMode mode); -+void meta_shell_blur_effect_set_skip (MetaShellBlurEffect *self, -+ gboolean skip); - - G_END_DECLS |