diff --git a/gsk/gpu/gskgpunodeprocessor.c b/gsk/gpu/gskgpunodeprocessor.c index b137356742..4aca520a63 100644 --- a/gsk/gpu/gskgpunodeprocessor.c +++ b/gsk/gpu/gskgpunodeprocessor.c @@ -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] = { diff --git a/gsk/gpu/gskgpuradialgradientop.c b/gsk/gpu/gskgpuradialgradientop.c new file mode 100644 index 0000000000..de409dd7e3 --- /dev/null +++ b/gsk/gpu/gskgpuradialgradientop.c @@ -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; +} diff --git a/gsk/gpu/gskgpuradialgradientopprivate.h b/gsk/gpu/gskgpuradialgradientopprivate.h new file mode 100644 index 0000000000..cdf694fb9f --- /dev/null +++ b/gsk/gpu/gskgpuradialgradientopprivate.h @@ -0,0 +1,25 @@ +#pragma once + +#include "gskgpushaderopprivate.h" + +#include "gskrendernode.h" + +#include + +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 + diff --git a/gsk/gpu/shaders/gskgpuradialgradient.glsl b/gsk/gpu/shaders/gskgpuradialgradient.glsl new file mode 100644 index 0000000000..a538a00991 --- /dev/null +++ b/gsk/gpu/shaders/gskgpuradialgradient.glsl @@ -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 diff --git a/gsk/gpu/shaders/meson.build b/gsk/gpu/shaders/meson.build index 8d34cdf46b..b094d61857 100644 --- a/gsk/gpu/shaders/meson.build +++ b/gsk/gpu/shaders/meson.build @@ -22,6 +22,7 @@ gsk_private_gpu_shaders = files([ 'gskgpuconicgradient.glsl', 'gskgpulineargradient.glsl', 'gskgpumask.glsl', + 'gskgpuradialgradient.glsl', 'gskgpuroundedcolor.glsl', 'gskgpustraightalpha.glsl', 'gskgputexture.glsl', diff --git a/gsk/meson.build b/gsk/meson.build index 5e6e2a3127..00ec1cb8ce 100644 --- a/gsk/meson.build +++ b/gsk/meson.build @@ -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',