From ae3efb2d2f5f16ab4a3a0be47d712c152cce0a13 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Tue, 9 Jul 2024 21:07:15 +0200 Subject: [PATCH] gpu: Implement transform support for dihedral transforms This allows handling them without ever needing to offscreen for losing the clip, because the clip can always be transformed. Also, all the optimizations keep working, like occlusion culling, clears, and so on. The main benefit of this work is the ability for offloading to now handle dihedral transforms of the video buffer. The other big advantage is that we can now start our rendering with a dihedral transform from the compositor. --- gdk/gdkdihedral.c | 6 +++++ gdk/gdkdihedralprivate.h | 1 + gsk/gpu/gskgpuclip.c | 5 +++- gsk/gpu/gskgpuclipprivate.h | 11 ++++++--- gsk/gpu/gskgpunodeprocessor.c | 46 +++++++++++++++++++++++++++++++++-- gsk/gskroundedrect.c | 28 +++++++++++++++++++++ gsk/gskroundedrectprivate.h | 17 ++++++++----- 7 files changed, 101 insertions(+), 13 deletions(-) diff --git a/gdk/gdkdihedral.c b/gdk/gdkdihedral.c index 74f5f8b280..f9286a9e61 100644 --- a/gdk/gdkdihedral.c +++ b/gdk/gdkdihedral.c @@ -59,3 +59,9 @@ gdk_dihedral_combine (GdkDihedral first, ((((first & 3) * (((second & 4) >> 1) + 1)) + second) & 3); } +GdkDihedral +gdk_dihedral_invert (GdkDihedral self) +{ + return ((4 - self) * (((self & 4) >> 1) + 1) & 3) | (self & 4); +} + diff --git a/gdk/gdkdihedralprivate.h b/gdk/gdkdihedralprivate.h index a754401fd5..699775d8c2 100644 --- a/gdk/gdkdihedralprivate.h +++ b/gdk/gdkdihedralprivate.h @@ -40,6 +40,7 @@ void gdk_dihedral_get_mat2 (GdkDihedral GdkDihedral gdk_dihedral_combine (GdkDihedral first, GdkDihedral second); +GdkDihedral gdk_dihedral_invert (GdkDihedral self); G_END_DECLS diff --git a/gsk/gpu/gskgpuclip.c b/gsk/gpu/gskgpuclip.c index da297969f7..6cf748bfea 100644 --- a/gsk/gpu/gskgpuclip.c +++ b/gsk/gpu/gskgpuclip.c @@ -168,12 +168,15 @@ gsk_gpu_clip_intersect_rounded_rect (GskGpuClip *dest, void gsk_gpu_clip_scale (GskGpuClip *dest, const GskGpuClip *src, + GdkDihedral dihedral, float scale_x, float scale_y) { + GskRoundedRect tmp; dest->type = src->type; + gsk_rounded_rect_dihedral (&tmp, &src->rect, dihedral); gsk_rounded_rect_scale_affine (&dest->rect, - &src->rect, + &tmp, 1.0f / scale_x, 1.0f / scale_y, 0, 0); } diff --git a/gsk/gpu/gskgpuclipprivate.h b/gsk/gpu/gskgpuclipprivate.h index a83957c1a0..01102d652e 100644 --- a/gsk/gpu/gskgpuclipprivate.h +++ b/gsk/gpu/gskgpuclipprivate.h @@ -6,6 +6,8 @@ #include #include +#include "gdk/gdkdihedralprivate.h" + G_BEGIN_DECLS typedef enum { @@ -51,12 +53,13 @@ gboolean gsk_gpu_clip_intersect_rect (GskGpuC gboolean gsk_gpu_clip_intersect_rounded_rect (GskGpuClip *dest, const GskGpuClip *src, const GskRoundedRect *rounded) G_GNUC_WARN_UNUSED_RESULT; -void gsk_gpu_clip_scale (GskGpuClip *dest, - const GskGpuClip *src, +void gsk_gpu_clip_scale (GskGpuClip *dest, + const GskGpuClip *src, + GdkDihedral dihedral, float scale_x, float scale_y); -gboolean gsk_gpu_clip_transform (GskGpuClip *dest, - const GskGpuClip *src, +gboolean gsk_gpu_clip_transform (GskGpuClip *dest, + const GskGpuClip *src, GskTransform *transform, const graphene_rect_t *viewport) G_GNUC_WARN_UNUSED_RESULT; diff --git a/gsk/gpu/gskgpunodeprocessor.c b/gsk/gpu/gskgpunodeprocessor.c index 8a9f4b4cee..6afb3561b8 100644 --- a/gsk/gpu/gskgpunodeprocessor.c +++ b/gsk/gpu/gskgpunodeprocessor.c @@ -1165,6 +1165,22 @@ gsk_gpu_node_processor_add_first_rounded_clip_node (GskGpuNodeProcessor gsk_rounded_clip_node_get_child (node)); } +static GskTransform * +gsk_transform_dihedral (GskTransform *transform, + GdkDihedral dihedral) +{ + int rotate = dihedral & 3; + int flip = dihedral & 4; + + if (flip) + transform = gsk_transform_scale (transform, -1.0, 1.0); + + if (rotate) + transform = gsk_transform_rotate (transform, rotate * 90.0f); + + return transform; +} + static void gsk_gpu_node_processor_add_transform_node (GskGpuNodeProcessor *self, GskRenderNode *node) @@ -1205,7 +1221,7 @@ gsk_gpu_node_processor_add_transform_node (GskGpuNodeProcessor *self, old_modelview = gsk_transform_ref (self->modelview); gsk_transform_to_affine (transform, &scale_x, &scale_y, &dx, &dy); - gsk_gpu_clip_scale (&self->clip, &old_clip, scale_x, scale_y); + gsk_gpu_clip_scale (&self->clip, &old_clip, GDK_DIHEDRAL_NORMAL, scale_x, scale_y); self->offset.x = (self->offset.x + dx) / scale_x; self->offset.y = (self->offset.y + dy) / scale_y; graphene_vec2_init (&self->scale, fabs (scale_x), fabs (scale_y)); @@ -1217,6 +1233,32 @@ gsk_gpu_node_processor_add_transform_node (GskGpuNodeProcessor *self, break; case GSK_FINE_TRANSFORM_CATEGORY_2D_DIHEDRAL: + { + GdkDihedral dihedral, inverted; + float xx, xy, yx, yy, dx, dy, scale_x, scale_y, old_scale_x, old_scale_y; + + gsk_gpu_clip_init_copy (&old_clip, &self->clip); + old_offset = self->offset; + old_scale = self->scale; + old_modelview = gsk_transform_ref (self->modelview); + + gsk_transform_to_dihedral (transform, &dihedral, &scale_x, &scale_y, &dx, &dy); + inverted = gdk_dihedral_invert (dihedral); + gdk_dihedral_get_mat2 (inverted, &xx, &xy, &yx, &yy); + gsk_gpu_clip_scale (&self->clip, &old_clip, inverted, scale_x, scale_y); + self->offset.x = (self->offset.x + dx) / scale_x; + self->offset.y = (self->offset.y + dy) / scale_y; + self->offset = GRAPHENE_POINT_INIT (xx * self->offset.x + xy * self->offset.y, + yx * self->offset.x + yy * self->offset.y); + old_scale_x = graphene_vec2_get_x (&old_scale); + old_scale_y = graphene_vec2_get_y (&old_scale); + graphene_vec2_init (&self->scale, + fabs (scale_x * (old_scale_x * xx + old_scale_y * yx)), + fabs (scale_y * (old_scale_x * xy + old_scale_y * yy))); + self->modelview = gsk_transform_dihedral (self->modelview, dihedral); + } + break; + case GSK_FINE_TRANSFORM_CATEGORY_2D: case GSK_FINE_TRANSFORM_CATEGORY_UNKNOWN: case GSK_FINE_TRANSFORM_CATEGORY_ANY: @@ -1350,7 +1392,7 @@ gsk_gpu_node_processor_add_first_transform_node (GskGpuNodeProcessor *se old_offset = self->offset; old_scale = self->scale; - gsk_gpu_clip_scale (&self->clip, &old_clip, scale_x, scale_y); + gsk_gpu_clip_scale (&self->clip, &old_clip, GDK_DIHEDRAL_NORMAL, scale_x, scale_y); self->offset.x = (self->offset.x + dx) / scale_x; self->offset.y = (self->offset.y + dy) / scale_y; graphene_vec2_init (&self->scale, fabs (scale_x), fabs (scale_y)); diff --git a/gsk/gskroundedrect.c b/gsk/gskroundedrect.c index 30cc177042..7306bb5d0f 100644 --- a/gsk/gskroundedrect.c +++ b/gsk/gskroundedrect.c @@ -321,6 +321,34 @@ gsk_rounded_rect_scale_affine (GskRoundedRect *dest, } } +void +gsk_rounded_rect_dihedral (GskRoundedRect *dest, + const GskRoundedRect *src, + GdkDihedral dihedral) +{ + guint flip = (dihedral & 2) + (dihedral >> 2); + guint i; + + gsk_rect_dihedral (&src->bounds, dihedral, &dest->bounds); + + if (dihedral & 1) + { + for (i = 0; i < 4; i++) + { + dest->corner[i].width = src->corner[((i + 1) & 3) ^ flip].width; + dest->corner[i].height = src->corner[((i + 1) & 3) ^ flip].height; + } + } + else + { + for (i = 0; i < 4; i++) + { + dest->corner[i].width = src->corner[i ^ flip].height; + dest->corner[i].height = src->corner[i ^ flip].width; + } + } +} + /* * gsk_rounded_rect_is_circular: * @self: the `GskRoundedRect` to check diff --git a/gsk/gskroundedrectprivate.h b/gsk/gskroundedrectprivate.h index 964e0edf84..e83e1aed1c 100644 --- a/gsk/gskroundedrectprivate.h +++ b/gsk/gskroundedrectprivate.h @@ -2,6 +2,8 @@ #include "gskroundedrect.h" +#include "gdk/gdkdihedralprivate.h" + #include G_BEGIN_DECLS @@ -34,12 +36,15 @@ G_STATIC_ASSERT (OPPOSITE_CORNER_Y (GSK_CORNER_BOTTOM_RIGHT) == GSK_CORNER_TOP_R }} -void gsk_rounded_rect_scale_affine (GskRoundedRect *dest, - const GskRoundedRect *src, - float scale_x, - float scale_y, - float dx, - float dy); +void gsk_rounded_rect_scale_affine (GskRoundedRect *dest, + const GskRoundedRect *src, + float scale_x, + float scale_y, + float dx, + float dy); +void gsk_rounded_rect_dihedral (GskRoundedRect *dest, + const GskRoundedRect *src, + GdkDihedral dihedral); gboolean gsk_rounded_rect_is_circular (const GskRoundedRect *self) G_GNUC_PURE;