summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Otte <otte.benjamin@googlemail.com>2023-04-29 03:43:45 +0000
committerBenjamin Otte <otte.benjamin@googlemail.com>2023-04-29 03:43:45 +0000
commitc542351a73538b42bb820324c6590350b14a48b7 (patch)
tree1db6cda423f86d5a5779e07241c0eb8dafb3c19b
parentd1a25178fdda26946441cbc733bdd51d431a5c39 (diff)
parent31983301883d2a17bc5c43819102dec659298265 (diff)
downloadgtk+-c542351a73538b42bb820324c6590350b14a48b7.tar.gz
Merge branch 'wip/otte/for-main' into 'main'
wayland: Use wl_surface_damage_buffer() in Cairo See merge request GNOME/gtk!5886
-rw-r--r--gdk/gdkrectangleprivate.h57
-rw-r--r--gdk/wayland/gdksurface-wayland.c18
-rw-r--r--gsk/gskrendernodeimpl.c33
3 files changed, 104 insertions, 4 deletions
diff --git a/gdk/gdkrectangleprivate.h b/gdk/gdkrectangleprivate.h
new file mode 100644
index 0000000000..b7857d5037
--- /dev/null
+++ b/gdk/gdkrectangleprivate.h
@@ -0,0 +1,57 @@
+#pragma once
+
+#include "gdkrectangle.h"
+
+#include <math.h>
+
+G_BEGIN_DECLS
+
+/*
+ * gdk_rectangle_transform_affine:
+ * @src: the rectangle to transform
+ * @scale_x: scale factor in the X direction. The scale factor
+ * may be negative or 0.
+ * @scale_y: scale factor in the Y direction. The scale factor
+ * may be negative or 0.
+ * @offset_x: offset of result in X direction.
+ * @offset_y: offset of result in Y direction.
+ * @dest: (out caller-allocates): destination rectangle, may be
+ * identical to @src
+ *
+ * Does an affine transform of the source rectangle and stores the
+ * result in the dest rectangle. If the destination rectangle does
+ * not fit on integer bounds, the result will be enlarged to make it
+ * fit.
+ * (Fun fact: This means with a scale of 0 and an offset of 0.5,
+ * the resulting rect will have a width of 1.)
+ *
+ * The width and height of the result will be positive, even if the
+ * src rectangle or the scale were negative.
+ *
+ * This function can be used with the output of
+ * gsk_transform_to_affine().
+ **/
+static inline void
+gdk_rectangle_transform_affine (const GdkRectangle *src,
+ float scale_x,
+ float scale_y,
+ float offset_x,
+ float offset_y,
+ GdkRectangle *dest)
+{
+ float x1, x2, y1, y2;
+
+ x1 = offset_x + src->x * scale_x;
+ x2 = offset_x + (src->x + src->width) * scale_x;
+ y1 = offset_y + src->y * scale_y;
+ y2 = offset_y + (src->y + src->height) * scale_y;
+
+ dest->x = floorf (MIN (x1, x2));
+ dest->y = floorf (MIN (y1, y2));
+ dest->width = ceilf (MAX (x1, x2)) - dest->x;
+ dest->height = ceilf (MAX (y1, y2)) - dest->y;
+}
+
+
+G_END_DECLS
+
diff --git a/gdk/wayland/gdksurface-wayland.c b/gdk/wayland/gdksurface-wayland.c
index a4049bab72..483ccec8a2 100644
--- a/gdk/wayland/gdksurface-wayland.c
+++ b/gdk/wayland/gdksurface-wayland.c
@@ -28,6 +28,7 @@
#include "gdkmonitor-wayland.h"
#include "gdkpopupprivate.h"
#include "gdkprivate-wayland.h"
+#include "gdkrectangleprivate.h"
#include "gdkseat-wayland.h"
#include "gdksurfaceprivate.h"
#include "gdktoplevelprivate.h"
@@ -468,6 +469,7 @@ gdk_wayland_surface_attach_image (GdkSurface *surface,
{
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
cairo_rectangle_int_t rect;
+ uint32_t wl_surface_version;
int i, n;
if (GDK_SURFACE_DESTROYED (surface))
@@ -475,14 +477,15 @@ gdk_wayland_surface_attach_image (GdkSurface *surface,
g_assert (_gdk_wayland_is_shm_surface (cairo_surface));
+ wl_surface_version = wl_surface_get_version (impl->display_server.wl_surface);
+
/* Attach this new buffer to the surface */
wl_surface_attach (impl->display_server.wl_surface,
_gdk_wayland_shm_surface_get_wl_buffer (cairo_surface),
0, 0);
if ((impl->pending_buffer_offset_x || impl->pending_buffer_offset_y) &&
- wl_surface_get_version (impl->display_server.wl_surface) >=
- WL_SURFACE_OFFSET_SINCE_VERSION)
+ wl_surface_version >= WL_SURFACE_OFFSET_SINCE_VERSION)
wl_surface_offset (impl->display_server.wl_surface,
impl->pending_buffer_offset_x,
impl->pending_buffer_offset_y);
@@ -493,7 +496,16 @@ gdk_wayland_surface_attach_image (GdkSurface *surface,
for (i = 0; i < n; i++)
{
cairo_region_get_rectangle (damage, i, &rect);
- wl_surface_damage (impl->display_server.wl_surface, rect.x, rect.y, rect.width, rect.height);
+ if (wl_surface_version >= WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION)
+ {
+ float scale = gdk_surface_get_scale (surface);
+ gdk_rectangle_transform_affine (&rect, scale, scale, 0, 0, &rect);
+ wl_surface_damage_buffer (impl->display_server.wl_surface, rect.x, rect.y, rect.width, rect.height);
+ }
+ else
+ {
+ wl_surface_damage (impl->display_server.wl_surface, rect.x, rect.y, rect.width, rect.height);
+ }
}
}
diff --git a/gsk/gskrendernodeimpl.c b/gsk/gskrendernodeimpl.c
index bde92c1edc..ef31f459c7 100644
--- a/gsk/gskrendernodeimpl.c
+++ b/gsk/gskrendernodeimpl.c
@@ -32,6 +32,7 @@
#include "gdk/gdktextureprivate.h"
#include "gdk/gdkmemoryformatprivate.h"
#include "gdk/gdkprivate.h"
+#include "gdk/gdkrectangleprivate.h"
#include <cairo.h>
#ifdef CAIRO_HAS_SVG_SURFACE
@@ -74,6 +75,25 @@ _graphene_rect_init_from_clip_extents (graphene_rect_t *rect,
graphene_rect_init (rect, x1c, y1c, x2c - x1c, y2c - y1c);
}
+static void
+region_union_region_affine (cairo_region_t *region,
+ const cairo_region_t *sub,
+ float scale_x,
+ float scale_y,
+ float offset_x,
+ float offset_y)
+{
+ cairo_rectangle_int_t rect;
+ int i;
+
+ for (i = 0; i < cairo_region_num_rectangles (sub); i++)
+ {
+ cairo_region_get_rectangle (sub, i, &rect);
+ gdk_rectangle_transform_affine (&rect, scale_x, scale_y, offset_x, offset_y, &rect);
+ cairo_region_union_rectangle (region, &rect);
+ }
+}
+
/* {{{ GSK_COLOR_NODE */
/**
@@ -3354,11 +3374,22 @@ gsk_transform_node_diff (GskRenderNode *node1,
}
break;
+ case GSK_TRANSFORM_CATEGORY_2D_AFFINE:
+ {
+ cairo_region_t *sub;
+ float scale_x, scale_y, dx, dy;
+ gsk_transform_to_affine (self1->transform, &scale_x, &scale_y, &dx, &dy);
+ sub = cairo_region_create ();
+ gsk_render_node_diff (self1->child, self2->child, sub);
+ region_union_region_affine (region, sub, scale_x, scale_y, dx, dy);
+ cairo_region_destroy (sub);
+ }
+ break;
+
case GSK_TRANSFORM_CATEGORY_UNKNOWN:
case GSK_TRANSFORM_CATEGORY_ANY:
case GSK_TRANSFORM_CATEGORY_3D:
case GSK_TRANSFORM_CATEGORY_2D:
- case GSK_TRANSFORM_CATEGORY_2D_AFFINE:
default:
gsk_render_node_diff_impossible (node1, node2, region);
break;