gpu: Add a conic gradient shader

This commit is contained in:
Benjamin Otte 2023-12-27 01:20:47 +01:00
parent 0c32a94d8e
commit 0e9b967bf9
6 changed files with 269 additions and 1 deletions

View File

@ -0,0 +1,91 @@
#include "config.h"
#include "gskgpuconicgradientopprivate.h"
#include "gskgpuframeprivate.h"
#include "gskgpuprintprivate.h"
#include "gskrectprivate.h"
#include "gpu/shaders/gskgpuconicgradientinstance.h"
typedef struct _GskGpuConicGradientOp GskGpuConicGradientOp;
struct _GskGpuConicGradientOp
{
GskGpuShaderOp op;
};
static void
gsk_gpu_conic_gradient_op_print (GskGpuOp *op,
GskGpuFrame *frame,
GString *string,
guint indent)
{
GskGpuShaderOp *shader = (GskGpuShaderOp *) op;
GskGpuConicgradientInstance *instance;
instance = (GskGpuConicgradientInstance *) gsk_gpu_frame_get_vertex_data (frame, shader->vertex_offset);
gsk_gpu_print_op (string, indent, "conic-gradient");
gsk_gpu_print_rect (string, instance->rect);
gsk_gpu_print_newline (string);
}
static const GskGpuShaderOpClass GSK_GPU_CONIC_GRADIENT_OP_CLASS = {
{
GSK_GPU_OP_SIZE (GskGpuConicGradientOp),
GSK_GPU_STAGE_SHADER,
gsk_gpu_shader_op_finish,
gsk_gpu_conic_gradient_op_print,
#ifdef GDK_RENDERING_VULKAN
gsk_gpu_shader_op_vk_command,
#endif
gsk_gpu_shader_op_gl_command
},
"gskgpuconicgradient",
sizeof (GskGpuConicgradientInstance),
#ifdef GDK_RENDERING_VULKAN
&gsk_gpu_conicgradient_info,
#endif
gsk_gpu_conicgradient_setup_vao
};
void
gsk_gpu_conic_gradient_op (GskGpuFrame *frame,
GskGpuShaderClip clip,
const graphene_rect_t *rect,
const graphene_point_t *center,
float angle,
const graphene_point_t *offset,
const GskColorStop *stops,
gsize n_stops)
{
GskGpuConicgradientInstance *instance;
g_assert (n_stops > 1);
g_assert (n_stops <= 7);
gsk_gpu_shader_op_alloc (frame,
&GSK_GPU_CONIC_GRADIENT_OP_CLASS,
clip,
NULL,
&instance);
gsk_gpu_rect_to_float (rect, offset, instance->rect);
gsk_gpu_point_to_float (center, offset, instance->center);
instance->angle = angle;
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,22 @@
#pragma once
#include "gskgpushaderopprivate.h"
#include "gskrendernode.h"
#include <graphene.h>
G_BEGIN_DECLS
void gsk_gpu_conic_gradient_op (GskGpuFrame *frame,
GskGpuShaderClip clip,
const graphene_rect_t *rect,
const graphene_point_t *center,
float angle,
const graphene_point_t *offset,
const GskColorStop *stops,
gsize n_stops);
G_END_DECLS

View File

@ -12,6 +12,7 @@
#include "gskgpucolorizeopprivate.h"
#include "gskgpucolormatrixopprivate.h"
#include "gskgpucoloropprivate.h"
#include "gskgpuconicgradientopprivate.h"
#include "gskgpudescriptorsprivate.h"
#include "gskgpudeviceprivate.h"
#include "gskgpuframeprivate.h"
@ -2186,6 +2187,33 @@ gsk_gpu_node_processor_create_radial_gradient_pattern (GskGpuPatternWriter *self
return TRUE;
}
static void
gsk_gpu_node_processor_conic_gradient_op (GskGpuNodeProcessor *self,
GskRenderNode *node,
const GskColorStop *stops,
gsize n_stops)
{
gsk_gpu_conic_gradient_op (self->frame,
gsk_gpu_clip_get_shader_clip (&self->clip, &self->offset, &node->bounds),
&node->bounds,
gsk_conic_gradient_node_get_center (node),
gsk_conic_gradient_node_get_angle (node),
&self->offset,
stops,
n_stops);
}
static void
gsk_gpu_node_processor_add_conic_gradient_node (GskGpuNodeProcessor *self,
GskRenderNode *node)
{
gsk_gpu_node_processor_add_gradient_node (self,
node,
gsk_conic_gradient_node_get_color_stops (node, NULL),
gsk_conic_gradient_node_get_n_color_stops (node),
gsk_gpu_node_processor_conic_gradient_op);
}
static gboolean
gsk_gpu_node_processor_create_conic_gradient_pattern (GskGpuPatternWriter *self,
GskRenderNode *node)
@ -3172,7 +3200,7 @@ static const struct
[GSK_CONIC_GRADIENT_NODE] = {
0,
GSK_GPU_HANDLE_OPACITY,
gsk_gpu_node_processor_add_node_as_pattern,
gsk_gpu_node_processor_add_conic_gradient_node,
gsk_gpu_node_processor_create_conic_gradient_pattern,
},
[GSK_BORDER_NODE] = {

View File

@ -0,0 +1,125 @@
#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) vec2 _center;
PASS_FLAT(12) float _angle;
#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) vec2 in_center;
IN(11) float in_angle;
void
run (out vec2 pos)
{
Rect r = rect_from_gsk (in_rect);
pos = rect_get_position (r);
_pos = pos;
_rect = r;
_center = in_center;
_angle = in_angle;
_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 = atan (pos.y, pos.x);
offset = degrees (offset + _angle) / 360.0;
offset = fract (offset);
return color_premultiply (get_gradient_color (offset));
}
void
run (out vec4 color,
out vec2 position)
{
float alpha = rect_coverage (_rect, _pos);
vec2 conic_pos = _pos / GSK_GLOBAL_SCALE - _center;
color = alpha * get_gradient_color_at (conic_pos);
position = _pos;
}
#endif

View File

@ -19,6 +19,7 @@ gsk_private_gpu_shaders = files([
'gskgpucolor.glsl',
'gskgpucolorize.glsl',
'gskgpucolormatrix.glsl',
'gskgpuconicgradient.glsl',
'gskgpulineargradient.glsl',
'gskgpumask.glsl',
'gskgpuroundedcolor.glsl',

View File

@ -83,6 +83,7 @@ gsk_private_sources = files([
'gpu/gskgpucolorizeop.c',
'gpu/gskgpucolormatrixop.c',
'gpu/gskgpucolorop.c',
'gpu/gskgpuconicgradientop.c',
'gpu/gskgpudescriptors.c',
'gpu/gskgpudownloadop.c',
'gpu/gskgpudevice.c',