gpu: Add a radial gradient shader

This is mainly copy/paste, so now this almost identical gradient code
exists 3 times.
That's kinda suboptimal.
This commit is contained in:
Benjamin Otte
2023-12-27 04:01:11 +01:00
parent ac6d854a3a
commit 58953432d3
6 changed files with 294 additions and 2 deletions

View File

@@ -21,6 +21,7 @@
#include "gskgpulineargradientopprivate.h"
#include "gskgpumaskopprivate.h"
#include "gskgpumipmapopprivate.h"
#include "gskgpuradialgradientopprivate.h"
#include "gskgpurenderpassopprivate.h"
#include "gskgpuroundedcoloropprivate.h"
#include "gskgpuscissoropprivate.h"
@@ -2164,6 +2165,39 @@ gsk_gpu_node_processor_create_linear_gradient_pattern (GskGpuPatternWriter *self
return TRUE;
}
static void
gsk_gpu_node_processor_radial_gradient_op (GskGpuNodeProcessor *self,
GskRenderNode *node,
const GskColorStop *stops,
gsize n_stops)
{
gsk_gpu_radial_gradient_op (self->frame,
gsk_gpu_clip_get_shader_clip (&self->clip, &self->offset, &node->bounds),
GSK_RENDER_NODE_TYPE (node) == GSK_REPEATING_RADIAL_GRADIENT_NODE,
&node->bounds,
gsk_radial_gradient_node_get_center (node),
&GRAPHENE_POINT_INIT (
gsk_radial_gradient_node_get_hradius (node),
gsk_radial_gradient_node_get_vradius (node)
),
gsk_radial_gradient_node_get_start (node),
gsk_radial_gradient_node_get_end (node),
&self->offset,
stops,
n_stops);
}
static void
gsk_gpu_node_processor_add_radial_gradient_node (GskGpuNodeProcessor *self,
GskRenderNode *node)
{
gsk_gpu_node_processor_add_gradient_node (self,
node,
gsk_radial_gradient_node_get_color_stops (node, NULL),
gsk_radial_gradient_node_get_n_color_stops (node),
gsk_gpu_node_processor_radial_gradient_op);
}
static gboolean
gsk_gpu_node_processor_create_radial_gradient_pattern (GskGpuPatternWriter *self,
GskRenderNode *node)
@@ -3188,13 +3222,13 @@ static const struct
[GSK_RADIAL_GRADIENT_NODE] = {
0,
GSK_GPU_HANDLE_OPACITY,
gsk_gpu_node_processor_add_node_as_pattern,
gsk_gpu_node_processor_add_radial_gradient_node,
gsk_gpu_node_processor_create_radial_gradient_pattern,
},
[GSK_REPEATING_RADIAL_GRADIENT_NODE] = {
0,
GSK_GPU_HANDLE_OPACITY,
gsk_gpu_node_processor_add_node_as_pattern,
gsk_gpu_node_processor_add_radial_gradient_node,
gsk_gpu_node_processor_create_radial_gradient_pattern,
},
[GSK_CONIC_GRADIENT_NODE] = {

View File

@@ -0,0 +1,100 @@
#include "config.h"
#include "gskgpuradialgradientopprivate.h"
#include "gskgpuframeprivate.h"
#include "gskgpuprintprivate.h"
#include "gskrectprivate.h"
#include "gpu/shaders/gskgpuradialgradientinstance.h"
typedef struct _GskGpuRadialGradientOp GskGpuRadialGradientOp;
struct _GskGpuRadialGradientOp
{
GskGpuShaderOp op;
};
static void
gsk_gpu_radial_gradient_op_print (GskGpuOp *op,
GskGpuFrame *frame,
GString *string,
guint indent)
{
GskGpuShaderOp *shader = (GskGpuShaderOp *) op;
GskGpuRadialgradientInstance *instance;
instance = (GskGpuRadialgradientInstance *) gsk_gpu_frame_get_vertex_data (frame, shader->vertex_offset);
if (instance->repeating)
gsk_gpu_print_op (string, indent, "repeating-radial-gradient");
else
gsk_gpu_print_op (string, indent, "radial-gradient");
gsk_gpu_print_rect (string, instance->rect);
gsk_gpu_print_newline (string);
}
static const GskGpuShaderOpClass GSK_GPU_RADIAL_GRADIENT_OP_CLASS = {
{
GSK_GPU_OP_SIZE (GskGpuRadialGradientOp),
GSK_GPU_STAGE_SHADER,
gsk_gpu_shader_op_finish,
gsk_gpu_radial_gradient_op_print,
#ifdef GDK_RENDERING_VULKAN
gsk_gpu_shader_op_vk_command,
#endif
gsk_gpu_shader_op_gl_command
},
"gskgpuradialgradient",
sizeof (GskGpuRadialgradientInstance),
#ifdef GDK_RENDERING_VULKAN
&gsk_gpu_radialgradient_info,
#endif
gsk_gpu_radialgradient_setup_vao
};
void
gsk_gpu_radial_gradient_op (GskGpuFrame *frame,
GskGpuShaderClip clip,
gboolean repeating,
const graphene_rect_t *rect,
const graphene_point_t *center,
const graphene_point_t *radius,
float start,
float end,
const graphene_point_t *offset,
const GskColorStop *stops,
gsize n_stops)
{
GskGpuRadialgradientInstance *instance;
g_assert (n_stops > 1);
g_assert (n_stops <= 7);
gsk_gpu_shader_op_alloc (frame,
&GSK_GPU_RADIAL_GRADIENT_OP_CLASS,
clip,
NULL,
&instance);
instance->repeating = repeating;
gsk_gpu_rect_to_float (rect, offset, instance->rect);
gsk_gpu_point_to_float (center, offset, instance->center_radius);
gsk_gpu_point_to_float (radius, graphene_point_zero(), &instance->center_radius[2]);
instance->startend[0] = start;
instance->startend[1] = end;
gsk_gpu_rgba_to_float (&stops[MIN (n_stops - 1, 6)].color, instance->color6);
instance->offsets1[2] = stops[MIN (n_stops - 1, 6)].offset;
gsk_gpu_rgba_to_float (&stops[MIN (n_stops - 1, 5)].color, instance->color5);
instance->offsets1[1] = stops[MIN (n_stops - 1, 5)].offset;
gsk_gpu_rgba_to_float (&stops[MIN (n_stops - 1, 4)].color, instance->color4);
instance->offsets1[0] = stops[MIN (n_stops - 1, 4)].offset;
gsk_gpu_rgba_to_float (&stops[MIN (n_stops - 1, 3)].color, instance->color3);
instance->offsets0[3] = stops[MIN (n_stops - 1, 3)].offset;
gsk_gpu_rgba_to_float (&stops[MIN (n_stops - 1, 2)].color, instance->color2);
instance->offsets0[2] = stops[MIN (n_stops - 1, 2)].offset;
gsk_gpu_rgba_to_float (&stops[1].color, instance->color1);
instance->offsets0[1] = stops[1].offset;
gsk_gpu_rgba_to_float (&stops[0].color, instance->color0);
instance->offsets0[0] = stops[0].offset;
}

View File

@@ -0,0 +1,25 @@
#pragma once
#include "gskgpushaderopprivate.h"
#include "gskrendernode.h"
#include <graphene.h>
G_BEGIN_DECLS
void gsk_gpu_radial_gradient_op (GskGpuFrame *frame,
GskGpuShaderClip clip,
gboolean repeating,
const graphene_rect_t *rect,
const graphene_point_t *center,
const graphene_point_t *radius,
float start,
float end,
const graphene_point_t *offset,
const GskColorStop *stops,
gsize n_stops);
G_END_DECLS

View File

@@ -0,0 +1,131 @@
#include "common.glsl"
PASS(0) vec2 _pos;
PASS_FLAT(1) Rect _rect;
PASS_FLAT(2) vec4 _color0;
PASS_FLAT(3) vec4 _color1;
PASS_FLAT(4) vec4 _color2;
PASS_FLAT(5) vec4 _color3;
PASS_FLAT(6) vec4 _color4;
PASS_FLAT(7) vec4 _color5;
PASS_FLAT(8) vec4 _color6;
PASS_FLAT(9) vec4 _offsets0;
PASS_FLAT(10) vec3 _offsets1;
PASS_FLAT(11) vec4 _center_radius;
PASS_FLAT(12) vec2 _startend;
PASS_FLAT(13) uint _repeating;
#ifdef GSK_VERTEX_SHADER
IN(0) vec4 in_rect;
IN(1) vec4 in_color0;
IN(2) vec4 in_color1;
IN(3) vec4 in_color2;
IN(4) vec4 in_color3;
IN(5) vec4 in_color4;
IN(6) vec4 in_color5;
IN(7) vec4 in_color6;
IN(8) vec4 in_offsets0;
IN(9) vec3 in_offsets1;
IN(10) vec4 in_center_radius;
IN(11) vec2 in_startend;
IN(12) uint in_repeating;
void
run (out vec2 pos)
{
Rect r = rect_from_gsk (in_rect);
pos = rect_get_position (r);
_pos = pos;
_rect = r;
_center_radius = in_center_radius;
_startend = in_startend;
_repeating = in_repeating;
_color0 = in_color0;
_color1 = in_color1;
_color2 = in_color2;
_color3 = in_color3;
_color4 = in_color4;
_color5 = in_color5;
_color6 = in_color6;
_offsets0 = in_offsets0;
_offsets1 = in_offsets1;
}
#endif
#ifdef GSK_FRAGMENT_SHADER
vec4
get_gradient_color (float offset)
{
vec4 color;
if (offset <= _offsets0[3])
{
if (offset <= _offsets0[1])
{
if (offset <= _offsets0[0])
color = _color0;
else
color = mix (_color0, _color1, (offset - _offsets0[0]) / (_offsets0[1] - _offsets0[0]));
}
else
{
if (offset <= _offsets0[2])
color = mix (_color1, _color2, (offset - _offsets0[1]) / (_offsets0[2] - _offsets0[1]));
else
color = mix (_color2, _color3, (offset - _offsets0[2]) / (_offsets0[3] - _offsets0[2]));
}
}
else
{
if (offset <= _offsets1[1])
{
if (offset <= _offsets1[0])
color = mix (_color3, _color4, (offset - _offsets0[3]) / (_offsets1[0] - _offsets0[3]));
else
color = mix (_color4, _color5, (offset - _offsets1[0]) / (_offsets1[1] - _offsets1[0]));
}
else
{
if (offset <= _offsets1[2])
color = mix (_color5, _color6, (offset - _offsets1[1]) / (_offsets1[2] - _offsets1[1]));
else
color = _color6;
}
}
return color;
}
vec4
get_gradient_color_at (vec2 pos)
{
float offset = length (pos / _center_radius.zw);
offset = (offset - _startend.x) / (_startend.y - _startend.x);
if (_repeating != 0u)
offset = fract (offset);
else
offset = clamp (offset, 0.0, 1.0);
return color_premultiply (get_gradient_color (offset));
}
void
run (out vec4 color,
out vec2 position)
{
float alpha = rect_coverage (_rect, _pos);
color = alpha * get_gradient_color_at (_pos / GSK_GLOBAL_SCALE - _center_radius.xy);
position = _pos;
}
#endif

View File

@@ -22,6 +22,7 @@ gsk_private_gpu_shaders = files([
'gskgpuconicgradient.glsl',
'gskgpulineargradient.glsl',
'gskgpumask.glsl',
'gskgpuradialgradient.glsl',
'gskgpuroundedcolor.glsl',
'gskgpustraightalpha.glsl',
'gskgputexture.glsl',

View File

@@ -96,6 +96,7 @@ gsk_private_sources = files([
'gpu/gskgpunodeprocessor.c',
'gpu/gskgpuop.c',
'gpu/gskgpuprint.c',
'gpu/gskgpuradialgradientop.c',
'gpu/gskgpurenderer.c',
'gpu/gskgpurenderpassop.c',
'gpu/gskgpuroundedcolorop.c',