wayland: Use wl_surface_damage_buffer() in Cairo
authorBenjamin Otte <otte@redhat.com>
Sat, 29 Apr 2023 03:07:03 +0000 (05:07 +0200)
committerBenjamin Otte <otte@redhat.com>
Sat, 29 Apr 2023 03:07:03 +0000 (05:07 +0200)
... when it is available.

Also introduce the new function gdk_rectangle_transform_affine(), which
looks like overkill for this purpose, but I'm about to use it elsewhere.

gdk/gdkrectangleprivate.h [new file with mode: 0644]
gdk/wayland/gdksurface-wayland.c

diff --git a/gdk/gdkrectangleprivate.h b/gdk/gdkrectangleprivate.h
new file mode 100644 (file)
index 0000000..b7857d5
--- /dev/null
@@ -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
+
index a4049bab721b1d60680adab18a6224aa759a42ac..483ccec8a2aa237262af6daac2ecf9d9f70996d1 100644 (file)
@@ -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);
+        }
     }
 }