diff --git a/gsk/gpu/gskgpuborderop.c b/gsk/gpu/gskgpuborderop.c new file mode 100644 index 0000000000..e6de690e40 --- /dev/null +++ b/gsk/gpu/gskgpuborderop.c @@ -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]); + } +} + diff --git a/gsk/gpu/gskgpuborderopprivate.h b/gsk/gpu/gskgpuborderopprivate.h new file mode 100644 index 0000000000..1142fab1c6 --- /dev/null +++ b/gsk/gpu/gskgpuborderopprivate.h @@ -0,0 +1,19 @@ +#pragma once + +#include "gskgputypesprivate.h" +#include "gsktypes.h" + +#include + +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 + diff --git a/gsk/gpu/gskgpunodeprocessor.c b/gsk/gpu/gskgpunodeprocessor.c index b72d7e2031..dc979b4213 100644 --- a/gsk/gpu/gskgpunodeprocessor.c +++ b/gsk/gpu/gskgpunodeprocessor.c @@ -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] = { diff --git a/gsk/gpu/gskgpushaderopprivate.h b/gsk/gpu/gskgpushaderopprivate.h index 02b432c953..6d285c27d3 100644 --- a/gsk/gpu/gskgpushaderopprivate.h +++ b/gsk/gpu/gskgpushaderopprivate.h @@ -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 diff --git a/gsk/gpu/shaders/common.glsl b/gsk/gpu/shaders/common.glsl index 9311d3c83f..5c59fd4a8e 100644 --- a/gsk/gpu/shaders/common.glsl +++ b/gsk/gpu/shaders/common.glsl @@ -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, diff --git a/gsk/gpu/shaders/enums.glsl b/gsk/gpu/shaders/enums.glsl index 9948d84063..472d9cc5c9 100644 --- a/gsk/gpu/shaders/enums.glsl +++ b/gsk/gpu/shaders/enums.glsl @@ -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 diff --git a/gsk/gpu/shaders/gskgpuborder.glsl b/gsk/gpu/shaders/gskgpuborder.glsl new file mode 100644 index 0000000000..57f23d9ef8 --- /dev/null +++ b/gsk/gpu/shaders/gskgpuborder.glsl @@ -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 diff --git a/gsk/gpu/shaders/meson.build b/gsk/gpu/shaders/meson.build index 9289258e9d..4d510fee4d 100644 --- a/gsk/gpu/shaders/meson.build +++ b/gsk/gpu/shaders/meson.build @@ -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 = [] diff --git a/gsk/meson.build b/gsk/meson.build index fd8e7b7394..27fdf41487 100644 --- a/gsk/meson.build +++ b/gsk/meson.build @@ -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',