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.
This commit is contained in:
Benjamin Otte 2024-07-09 21:07:15 +02:00
parent b9ecae84f5
commit ae3efb2d2f
7 changed files with 101 additions and 13 deletions

View File

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

View File

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

View File

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

View File

@ -6,6 +6,8 @@
#include <graphene.h>
#include <gsk/gskroundedrect.h>
#include "gdk/gdkdihedralprivate.h"
G_BEGIN_DECLS
typedef enum {
@ -53,6 +55,7 @@ gboolean gsk_gpu_clip_intersect_rounded_rect (GskGpuC
const GskRoundedRect *rounded) G_GNUC_WARN_UNUSED_RESULT;
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,

View File

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

View File

@ -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;
}
}
}
/*<private>
* gsk_rounded_rect_is_circular:
* @self: the `GskRoundedRect` to check

View File

@ -2,6 +2,8 @@
#include "gskroundedrect.h"
#include "gdk/gdkdihedralprivate.h"
#include <cairo.h>
G_BEGIN_DECLS
@ -40,6 +42,9 @@ void gsk_rounded_rect_scale_affine (GskRoundedRect
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;