Merge branch 'wip/otte/for-main' into 'main'

wayland: Use wl_surface_damage_buffer() in Cairo

See merge request GNOME/gtk!5886
This commit is contained in:
Benjamin Otte 2023-04-29 03:43:45 +00:00
commit c542351a73
3 changed files with 104 additions and 4 deletions

57
gdk/gdkrectangleprivate.h Normal file
View File

@ -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

View 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);
}
}
}

View File

@ -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;