gpu: Add a border shader

Pretty much a copy of the Vulkan border shader.

A notable change is that the input arguments are changed, because GL
gets confused if you put a mat4 at the end.
This commit is contained in:
Benjamin Otte 2023-09-10 23:19:42 +02:00
parent 16c804c5e3
commit 3efe1bef93
9 changed files with 341 additions and 2 deletions

132
gsk/gpu/gskgpuborderop.c Normal file
View File

@ -0,0 +1,132 @@
#include "config.h"
#include "gskgpuborderopprivate.h"
#include "gskgpuframeprivate.h"
#include "gskgpuprintprivate.h"
#include "gskgpushaderopprivate.h"
#include "gsk/gskroundedrectprivate.h"
#include "gpu/shaders/gskgpuborderinstance.h"
typedef struct _GskGpuBorderOp GskGpuBorderOp;
struct _GskGpuBorderOp
{
GskGpuShaderOp op;
};
static void
gsk_gpu_border_op_finish (GskGpuOp *op)
{
}
static gboolean
color_equal (const float *color1,
const float *color2)
{
return gdk_rgba_equal (&(GdkRGBA) { color1[0], color1[1], color1[2], color1[3] },
&(GdkRGBA) { color1[0], color1[1], color1[2], color1[3] });
}
static void
gsk_gpu_border_op_print (GskGpuOp *op,
GskGpuFrame *frame,
GString *string,
guint indent)
{
GskGpuShaderOp *shader = (GskGpuShaderOp *) op;
GskGpuBorderInstance *instance;
instance = (GskGpuBorderInstance *) gsk_gpu_frame_get_vertex_data (frame, shader->vertex_offset);
gsk_gpu_print_op (string, indent, "border");
gsk_gpu_print_rounded_rect (string, instance->outline);
gsk_gpu_print_rgba (string, (const float *) &instance->border_colors[0]);
if (!color_equal (&instance->border_colors[12], &instance->border_colors[0]) ||
!color_equal (&instance->border_colors[8], &instance->border_colors[0]) ||
!color_equal (&instance->border_colors[4], &instance->border_colors[0]))
{
gsk_gpu_print_rgba (string, &instance->border_colors[4]);
gsk_gpu_print_rgba (string, &instance->border_colors[8]);
gsk_gpu_print_rgba (string, &instance->border_colors[12]);
}
g_string_append_printf (string, "%g ", instance->border_widths[0]);
if (instance->border_widths[0] != instance->border_widths[1] ||
instance->border_widths[0] != instance->border_widths[2] ||
instance->border_widths[0] != instance->border_widths[3])
{
g_string_append_printf (string, "%g %g %g ",
instance->border_widths[1],
instance->border_widths[2],
instance->border_widths[3]);
}
gsk_gpu_print_newline (string);
}
#ifdef GDK_RENDERING_VULKAN
static GskGpuOp *
gsk_gpu_border_op_vk_command (GskGpuOp *op,
GskGpuFrame *frame,
VkRenderPass render_pass,
VkFormat format,
VkCommandBuffer command_buffer)
{
return gsk_gpu_shader_op_vk_command_n (op, frame, render_pass, format, command_buffer, 8);
}
#endif
static GskGpuOp *
gsk_gpu_border_op_gl_command (GskGpuOp *op,
GskGpuFrame *frame,
gsize flip_y)
{
return gsk_gpu_shader_op_gl_command_n (op, frame, flip_y, 8);
}
static const GskGpuShaderOpClass GSK_GPU_BORDER_OP_CLASS = {
{
GSK_GPU_OP_SIZE (GskGpuBorderOp),
GSK_GPU_STAGE_SHADER,
gsk_gpu_border_op_finish,
gsk_gpu_border_op_print,
#ifdef GDK_RENDERING_VULKAN
gsk_gpu_border_op_vk_command,
#endif
gsk_gpu_border_op_gl_command
},
"gskgpuborder",
sizeof (GskGpuBorderInstance),
#ifdef GDK_RENDERING_VULKAN
&gsk_gpu_border_info,
#endif
gsk_gpu_border_setup_vao
};
void
gsk_gpu_border_op (GskGpuFrame *frame,
GskGpuShaderClip clip,
const GskRoundedRect *outline,
const graphene_point_t *offset,
const float widths[4],
const GdkRGBA colors[4])
{
GskGpuBorderInstance *instance;
guint i;
gsk_gpu_shader_op_alloc (frame,
&GSK_GPU_BORDER_OP_CLASS,
clip,
&instance);
gsk_rounded_rect_to_float (outline, offset, instance->outline);
for (i = 0; i < 4; i++)
{
instance->border_widths[i] = widths[i];
gsk_gpu_rgba_to_float (&colors[i], &instance->border_colors[4 * i]);
}
}

View File

@ -0,0 +1,19 @@
#pragma once
#include "gskgputypesprivate.h"
#include "gsktypes.h"
#include <graphene.h>
G_BEGIN_DECLS
void gsk_gpu_border_op (GskGpuFrame *frame,
GskGpuShaderClip clip,
const GskRoundedRect *outline,
const graphene_point_t *offset,
const float widths[4],
const GdkRGBA colors[4]);
G_END_DECLS

View File

@ -2,6 +2,7 @@
#include "gskgpunodeprocessorprivate.h"
#include "gskgpuborderopprivate.h"
#include "gskgpuclipprivate.h"
#include "gskgpudeviceprivate.h"
#include "gskgpuframeprivate.h"
@ -696,6 +697,18 @@ gsk_gpu_node_processor_create_color_pattern (GskGpuNodeProcessor *self,
return TRUE;
}
static void
gsk_gpu_node_processor_add_border_node (GskGpuNodeProcessor *self,
GskRenderNode *node)
{
gsk_gpu_border_op (self->frame,
gsk_gpu_clip_get_shader_clip (&self->clip, &self->offset, &node->bounds),
gsk_border_node_get_outline (node),
&self->offset,
gsk_border_node_get_widths (node),
gsk_border_node_get_colors (node));
}
static void
gsk_gpu_node_processor_add_texture_node (GskGpuNodeProcessor *self,
GskRenderNode *node)
@ -1042,7 +1055,7 @@ static const struct
},
[GSK_BORDER_NODE] = {
0,
NULL,
gsk_gpu_node_processor_add_border_node,
NULL,
},
[GSK_TEXTURE_NODE] = {

View File

@ -70,5 +70,15 @@ GskGpuOp * gsk_gpu_shader_op_gl_command (GskGpuO
GskGpuFrame *frame,
gsize flip_y);
static inline void
gsk_gpu_rgba_to_float (const GdkRGBA *rgba,
float values[4])
{
values[0] = rgba->red;
values[1] = rgba->green;
values[2] = rgba->blue;
values[3] = rgba->alpha;
}
G_END_DECLS

View File

@ -51,6 +51,66 @@ rect_get_position (Rect rect)
return pos;
}
vec2
border_get_position (RoundedRect outline,
vec4 border_widths)
{
uint slice_index = uint (GSK_VERTEX_INDEX) / 6u;
uint vert_index = uint (GSK_VERTEX_INDEX) % 6u;
vec4 corner_widths = max (outline.corner_widths, border_widths.wyyw);
vec4 corner_heights = max (outline.corner_heights, border_widths.xxzz);
Rect rect;
switch (slice_index)
{
case SLICE_TOP_LEFT:
rect = Rect (outline.bounds.xyxy + vec4 (0.0, 0.0, corner_widths[TOP_LEFT], corner_heights[TOP_LEFT]));
rect = rect_round_larger (rect);
rect.bounds = rect.bounds.xwzy;
break;
case SLICE_TOP:
rect = Rect (vec4 (outline.bounds.x + corner_widths[TOP_LEFT], outline.bounds.y,
outline.bounds.z - corner_widths[TOP_RIGHT], outline.bounds.y + border_widths[TOP]));
rect = rect_round_smaller_larger (rect);
break;
case SLICE_TOP_RIGHT:
rect = Rect (outline.bounds.zyzy + vec4 (- corner_widths[TOP_RIGHT], 0.0, 0.0, corner_heights[TOP_RIGHT]));
rect = rect_round_larger (rect);
break;
case SLICE_RIGHT:
rect = Rect (vec4 (outline.bounds.z - border_widths[RIGHT], outline.bounds.y + corner_widths[TOP_RIGHT],
outline.bounds.z, outline.bounds.w - corner_widths[BOTTOM_RIGHT]));
rect = rect_round_larger_smaller (rect);
break;
case SLICE_BOTTOM_RIGHT:
rect = Rect (outline.bounds.zwzw + vec4 (- corner_widths[BOTTOM_RIGHT], - corner_heights[BOTTOM_RIGHT], 0.0, 0.0));
rect = rect_round_larger (rect);
rect.bounds = rect.bounds.zyxw;
break;
case SLICE_BOTTOM:
rect = Rect (vec4 (outline.bounds.x + corner_widths[BOTTOM_LEFT], outline.bounds.w - border_widths[BOTTOM],
outline.bounds.z - corner_widths[BOTTOM_RIGHT], outline.bounds.w));
rect = rect_round_smaller_larger (rect);
break;
case SLICE_BOTTOM_LEFT:
rect = Rect (outline.bounds.xwxw + vec4 (0.0, - corner_heights[BOTTOM_LEFT], corner_widths[BOTTOM_LEFT], 0.0));
rect = rect_round_larger (rect);
rect.bounds = rect.bounds.zwxy;
break;
case SLICE_LEFT:
rect = Rect (vec4 (outline.bounds.x + border_widths[LEFT], outline.bounds.y + corner_widths[TOP_LEFT],
outline.bounds.x, outline.bounds.w - corner_widths[BOTTOM_LEFT]));
rect = rect_round_larger_smaller (rect);
break;
}
vec2 pos = mix (rect.bounds.xy, rect.bounds.zw, offsets[vert_index]);
return pos;
}
vec2
scale_tex_coord (vec2 in_pos,
Rect in_rect,

View File

@ -17,4 +17,23 @@
#define GSK_GPU_PATTERN_REPEATING_RADIAL_GRADIENT 9u
#define GSK_GPU_PATTERN_CONIC_GRADIENT 10u
#define TOP 0u
#define RIGHT 1u
#define BOTTOM 2u
#define LEFT 3u
#define TOP_LEFT 0u
#define TOP_RIGHT 1u
#define BOTTOM_RIGHT 2u
#define BOTTOM_LEFT 3u
#define SLICE_TOP_LEFT 0u
#define SLICE_TOP 1u
#define SLICE_TOP_RIGHT 2u
#define SLICE_RIGHT 3u
#define SLICE_BOTTOM_RIGHT 4u
#define SLICE_BOTTOM 5u
#define SLICE_BOTTOM_LEFT 6u
#define SLICE_LEFT 7u
#endif

View File

@ -0,0 +1,84 @@
#include "common.glsl"
PASS(0) vec2 _pos;
PASS_FLAT(1) vec4 _color;
PASS_FLAT(2) RoundedRect _outside;
PASS_FLAT(5) RoundedRect _inside;
#ifdef GSK_VERTEX_SHADER
IN(0) mat4 in_border_colors;
IN(4) mat3x4 in_outline;
IN(7) vec4 in_border_widths;
vec4
compute_color (void)
{
uint triangle_index = uint (GSK_VERTEX_INDEX) / 3u;
uint index;
switch (triangle_index)
{
case 2u * SLICE_TOP_LEFT + 1u:
case 2u * SLICE_TOP:
case 2u * SLICE_TOP + 1u:
case 2u * SLICE_TOP_RIGHT:
index = TOP;
break;
case 2u * SLICE_TOP_RIGHT + 1u:
case 2u * SLICE_RIGHT:
case 2u * SLICE_RIGHT + 1u:
case 2u * SLICE_BOTTOM_RIGHT:
index = RIGHT;
break;
case 2u * SLICE_BOTTOM_RIGHT + 1u:
case 2u * SLICE_BOTTOM:
case 2u * SLICE_BOTTOM + 1u:
case 2u * SLICE_BOTTOM_LEFT:
index = BOTTOM;
break;
case 2u * SLICE_BOTTOM_LEFT + 1u:
case 2u * SLICE_LEFT:
case 2u * SLICE_LEFT + 1u:
case 2u * SLICE_TOP_LEFT:
index = LEFT;
break;
}
return color_premultiply (in_border_colors[index]);
}
void
run (out vec2 pos)
{
vec4 border_widths = in_border_widths * push.scale.yxyx;
RoundedRect outside = rounded_rect_from_gsk (in_outline);
RoundedRect inside = rounded_rect_shrink (outside, border_widths);
pos = border_get_position (outside, border_widths);
_pos = pos;
_color = compute_color ();
_outside = outside;
_inside = inside;
}
#endif
#ifdef GSK_FRAGMENT_SHADER
void
run (out vec4 color,
out vec2 position)
{
float alpha = clamp (rounded_rect_coverage (_outside, _pos) -
rounded_rect_coverage (_inside, _pos),
0.0, 1.0);
position = _pos;
color = _color * alpha;
}
#endif

View File

@ -12,8 +12,9 @@ gsk_private_gpu_include_shaders = files([
])
gsk_private_gpu_shaders = files([
'gskgpuuber.glsl',
'gskgpuborder.glsl',
'gskgputexture.glsl',
'gskgpuuber.glsl',
])
gsk_private_gpu_shader_headers = []

View File

@ -72,6 +72,7 @@ gsk_private_sources = files([
'gpu/gskglframe.c',
'gpu/gskglimage.c',
'gpu/gskgpublitop.c',
'gpu/gskgpuborderop.c',
'gpu/gskgpubuffer.c',
'gpu/gskgpubufferwriter.c',
'gpu/gskgpuclip.c',