gpu: Add repeat nodes

They're done using the pattern shader.

The pattern shader now gained a stack where vec4's can be pushed and
popped back later, which allows storing the position before computing
the new position inside the repeat node's child.
This commit is contained in:
Benjamin Otte 2023-09-17 07:30:50 +02:00
parent b7a8c2207e
commit 0876089f8f
6 changed files with 131 additions and 5 deletions

View File

@ -17,7 +17,7 @@
#define DEFAULT_VERTEX_BUFFER_SIZE 128 * 1024
/* GL_MAX_UNIFORM_BLOCK_SIZE is at 16384 */
#define DEFAULT_STORAGE_BUFFER_SIZE 16 * 1024
#define DEFAULT_STORAGE_BUFFER_SIZE 16 * 1024 * 64
#define GDK_ARRAY_NAME gsk_gpu_ops
#define GDK_ARRAY_TYPE_NAME GskGpuOps

View File

@ -111,6 +111,7 @@ struct _GskGpuPatternWriter
graphene_rect_t bounds;
graphene_point_t offset;
graphene_vec2_t scale;
guint stack;
GskGpuBufferWriter writer;
GskGpuPatternImages images;
@ -246,14 +247,33 @@ gsk_gpu_pattern_writer_init (GskGpuPatternWriter *self,
bounds->size.height);
self->offset = *offset;
self->scale = *scale;
self->stack = 0;
gsk_gpu_frame_write_buffer_memory (frame, &self->writer);
gsk_gpu_pattern_images_init (&self->images);
}
static gboolean
gsk_gpu_pattern_writer_push_stack (GskGpuPatternWriter *self)
{
if (self->stack >= GSK_GPU_PATTERN_STACK_SIZE)
return FALSE;
self->stack++;
return TRUE;
}
static void
gsk_gpu_pattern_writer_pop_stack (GskGpuPatternWriter *self)
{
g_assert (self->stack > 0);
self->stack--;
}
static void
gsk_gpu_pattern_writer_finish (GskGpuPatternWriter *self)
{
g_assert (self->stack == 0);
gsk_gpu_pattern_images_clear (&self->images);
}
@ -1164,12 +1184,60 @@ gsk_gpu_node_processor_add_subsurface_node (GskGpuNodeProcessor *self,
gsk_gpu_node_processor_add_node (self, gsk_subsurface_node_get_child (node));
}
static gboolean
gsk_gpu_node_processor_create_repeat_pattern (GskGpuPatternWriter *self,
GskRenderNode *node)
{
GskRenderNode *child;
const graphene_rect_t *child_bounds;
graphene_rect_t old_bounds;
child = gsk_repeat_node_get_child (node);
child_bounds = gsk_repeat_node_get_child_bounds (node);
if (gsk_rect_is_empty (child_bounds))
{
gsk_gpu_buffer_writer_append_uint (&self->writer, GSK_GPU_PATTERN_COLOR);
gsk_gpu_buffer_writer_append_rgba (&self->writer, &(GdkRGBA) { 0, 0, 0, 0 });
return TRUE;
}
if (!gsk_gpu_pattern_writer_push_stack (self))
return FALSE;
gsk_gpu_buffer_writer_append_uint (&self->writer, GSK_GPU_PATTERN_REPEAT_PUSH);
gsk_gpu_buffer_writer_append_rect (&self->writer, child_bounds, &self->offset);
old_bounds = self->bounds;
self->bounds = GRAPHENE_RECT_INIT (child_bounds->origin.x + self->offset.x,
child_bounds->origin.y + self->offset.y,
child_bounds->size.width,
child_bounds->size.height);
if (!gsk_gpu_node_processor_create_node_pattern (self, child))
{
gsk_gpu_pattern_writer_pop_stack (self);
return FALSE;
}
self->bounds = old_bounds;
if (!gsk_rect_contains_rect (&child->bounds, child_bounds))
{
gsk_gpu_buffer_writer_append_uint (&self->writer, GSK_GPU_PATTERN_CLIP);
gsk_gpu_buffer_writer_append_rect (&self->writer, &child->bounds, &self->offset);
}
gsk_gpu_buffer_writer_append_uint (&self->writer, GSK_GPU_PATTERN_POSITION_POP);
gsk_gpu_pattern_writer_pop_stack (self);
return TRUE;
}
static gboolean
gsk_gpu_node_processor_create_subsurface_pattern (GskGpuPatternWriter *self,
GskRenderNode *node)
{
return gsk_gpu_node_processor_create_node_pattern (self,
gsk_subsurface_node_get_child (node));
return gsk_gpu_node_processor_create_node_pattern (self, gsk_subsurface_node_get_child (node));
}
static void
@ -1284,8 +1352,8 @@ static const struct
},
[GSK_REPEAT_NODE] = {
0,
NULL,
NULL,
gsk_gpu_node_processor_add_node_as_pattern,
gsk_gpu_node_processor_create_repeat_pattern
},
[GSK_CLIP_NODE] = {
GSK_GPU_GLOBAL_MATRIX | GSK_GPU_GLOBAL_SCALE | GSK_GPU_GLOBAL_CLIP | GSK_GPU_GLOBAL_SCISSOR,

View File

@ -4,6 +4,8 @@
#include "gdk/gdkmemoryformatprivate.h"
#define GSK_GPU_PATTERN_STACK_SIZE 16
typedef struct _GskGpuBuffer GskGpuBuffer;
typedef struct _GskGpuDevice GskGpuDevice;
typedef struct _GskGpuFrame GskGpuFrame;
@ -41,5 +43,7 @@ typedef enum {
GSK_GPU_PATTERN_CONIC_GRADIENT,
GSK_GPU_PATTERN_CLIP,
GSK_GPU_PATTERN_ROUNDED_CLIP,
GSK_GPU_PATTERN_REPEAT_PUSH,
GSK_GPU_PATTERN_POSITION_POP,
} GskGpuPatternType;

View File

@ -1,6 +1,8 @@
#ifndef _ENUMS_
#define _ENUMS_
#define GSK_GPU_PATTERN_STACK_SIZE 16
#define GSK_GPU_SHADER_CLIP_NONE 0u
#define GSK_GPU_SHADER_CLIP_RECT 1u
#define GSK_GPU_SHADER_CLIP_ROUNDED 2u
@ -18,6 +20,8 @@
#define GSK_GPU_PATTERN_CONIC_GRADIENT 10u
#define GSK_GPU_PATTERN_CLIP 11u
#define GSK_GPU_PATTERN_ROUNDED_CLIP 12u
#define GSK_GPU_PATTERN_REPEAT_PUSH 13u
#define GSK_GPU_PATTERN_POSITION_POP 14u
#define TOP 0u
#define RIGHT 1u

View File

@ -7,6 +7,23 @@
#ifdef GSK_FRAGMENT_SHADER
vec4 stack[GSK_GPU_PATTERN_STACK_SIZE];
uint stack_size = 0u;
void
stack_push (vec4 data)
{
stack[stack_size] = data;
stack_size++;
}
vec4
stack_pop (void)
{
stack_size--;
return stack[stack_size];
}
uint
read_uint (inout uint reader)
{
@ -102,6 +119,27 @@ color_matrix_pattern (inout uint reader,
color = color_premultiply (color);
}
void
repeat_push_pattern (inout uint reader,
inout vec2 pos)
{
stack_push (vec4 (pos, 0.0, 0.0));
Rect bounds = read_rect (reader);
vec2 size = rect_size (bounds);
pos = mod (pos - bounds.bounds.xy, size);
/* make sure we have a positive result */
pos = mix (pos, pos + size, lessThan (pos, vec2 (0.0)));
pos += bounds.bounds.xy;
}
void
position_pop_pattern (inout uint reader,
inout vec2 pos)
{
pos = stack_pop ().xy;
}
vec4
glyphs_pattern (inout uint reader,
vec2 pos)
@ -250,6 +288,12 @@ pattern (uint reader,
case GSK_GPU_PATTERN_CLIP:
clip_pattern (reader, color, pos);
break;
case GSK_GPU_PATTERN_REPEAT_PUSH:
repeat_push_pattern (reader, pos);
break;
case GSK_GPU_PATTERN_POSITION_POP:
position_pop_pattern (reader, pos);
break;
}
}
}

View File

@ -75,6 +75,12 @@ gsk_rect_intersection (const graphene_rect_t *r1,
}
}
static inline gboolean G_GNUC_PURE
gsk_rect_is_empty (const graphene_rect_t *rect)
{
return rect->size.width == 0 || rect->size.height == 0;
}
static inline void
gsk_rect_to_float (const graphene_rect_t *rect,
float values[4])