gpu: Add linear gradients to pattern shader
This copy/pastes the gist of the Vulkan gradient renderer.
This commit is contained in:
@@ -105,6 +105,19 @@ gsk_gpu_buffer_writer_append_vec4 (GskGpuBufferWriter *self,
|
||||
gsk_gpu_buffer_writer_append (self, G_ALIGNOF (float), (guchar *) f, sizeof (f));
|
||||
}
|
||||
|
||||
void
|
||||
gsk_gpu_buffer_writer_append_point (GskGpuBufferWriter *self,
|
||||
const graphene_point_t *point,
|
||||
const graphene_point_t *offset)
|
||||
{
|
||||
float f[2];
|
||||
|
||||
f[0] = point->x + offset->x;
|
||||
f[1] = point->y + offset->y;
|
||||
|
||||
gsk_gpu_buffer_writer_append (self, G_ALIGNOF (float), (guchar *) f, sizeof (f));
|
||||
}
|
||||
|
||||
void
|
||||
gsk_gpu_buffer_writer_append_rect (GskGpuBufferWriter *self,
|
||||
const graphene_rect_t *rect,
|
||||
@@ -125,3 +138,13 @@ gsk_gpu_buffer_writer_append_rgba (GskGpuBufferWriter *self,
|
||||
|
||||
gsk_gpu_buffer_writer_append (self, G_ALIGNOF (float), (guchar *) f, sizeof (f));
|
||||
}
|
||||
|
||||
void
|
||||
gsk_gpu_buffer_writer_append_color_stops (GskGpuBufferWriter *self,
|
||||
const GskColorStop *stops,
|
||||
gsize n_stops)
|
||||
{
|
||||
gsk_gpu_buffer_writer_append_uint (self, n_stops);
|
||||
gsk_gpu_buffer_writer_append (self, G_ALIGNOF (float), (guchar *) stops, sizeof (GskColorStop) * n_stops);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "gskgputypesprivate.h"
|
||||
#include "gskrendernode.h"
|
||||
|
||||
#include <graphene.h>
|
||||
|
||||
@@ -44,10 +45,16 @@ void gsk_gpu_buffer_writer_append_matrix (GskGpuB
|
||||
const graphene_matrix_t *matrix);
|
||||
void gsk_gpu_buffer_writer_append_vec4 (GskGpuBufferWriter *self,
|
||||
const graphene_vec4_t *vec4);
|
||||
void gsk_gpu_buffer_writer_append_point (GskGpuBufferWriter *self,
|
||||
const graphene_point_t *point,
|
||||
const graphene_point_t *offset);
|
||||
void gsk_gpu_buffer_writer_append_rect (GskGpuBufferWriter *self,
|
||||
const graphene_rect_t *rect,
|
||||
const graphene_point_t *offset);
|
||||
void gsk_gpu_buffer_writer_append_rgba (GskGpuBufferWriter *self,
|
||||
const GdkRGBA *rgba);
|
||||
void gsk_gpu_buffer_writer_append_color_stops (GskGpuBufferWriter *self,
|
||||
const GskColorStop *stops,
|
||||
gsize n_stops);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
@@ -766,6 +766,32 @@ gsk_gpu_node_processor_create_texture_pattern (GskGpuNodeProcessor *self,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gsk_gpu_node_processor_create_linear_gradient_pattern (GskGpuNodeProcessor *self,
|
||||
GskGpuBufferWriter *writer,
|
||||
GskRenderNode *node,
|
||||
GskGpuShaderImage *images,
|
||||
gsize n_images,
|
||||
gsize *out_n_images)
|
||||
{
|
||||
if (gsk_render_node_get_node_type (node) == GSK_REPEATING_LINEAR_GRADIENT_NODE)
|
||||
gsk_gpu_buffer_writer_append_uint (writer, GSK_GPU_PATTERN_REPEATING_LINEAR_GRADIENT);
|
||||
else
|
||||
gsk_gpu_buffer_writer_append_uint (writer, GSK_GPU_PATTERN_LINEAR_GRADIENT);
|
||||
|
||||
gsk_gpu_buffer_writer_append_point (writer,
|
||||
gsk_linear_gradient_node_get_start (node),
|
||||
&self->offset);
|
||||
gsk_gpu_buffer_writer_append_point (writer,
|
||||
gsk_linear_gradient_node_get_end (node),
|
||||
&self->offset);
|
||||
gsk_gpu_buffer_writer_append_color_stops (writer,
|
||||
gsk_linear_gradient_node_get_color_stops (node, NULL),
|
||||
gsk_linear_gradient_node_get_n_color_stops (node));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gsk_gpu_node_processor_create_glyph_pattern (GskGpuNodeProcessor *self,
|
||||
GskGpuBufferWriter *writer,
|
||||
@@ -944,13 +970,13 @@ static const struct
|
||||
},
|
||||
[GSK_LINEAR_GRADIENT_NODE] = {
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
gsk_gpu_node_processor_add_node_as_pattern,
|
||||
gsk_gpu_node_processor_create_linear_gradient_pattern,
|
||||
},
|
||||
[GSK_REPEATING_LINEAR_GRADIENT_NODE] = {
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
gsk_gpu_node_processor_add_node_as_pattern,
|
||||
gsk_gpu_node_processor_create_linear_gradient_pattern,
|
||||
},
|
||||
[GSK_RADIAL_GRADIENT_NODE] = {
|
||||
0,
|
||||
|
||||
@@ -34,5 +34,7 @@ typedef enum {
|
||||
GSK_GPU_PATTERN_TEXTURE,
|
||||
GSK_GPU_PATTERN_COLOR_MATRIX,
|
||||
GSK_GPU_PATTERN_GLYPHS,
|
||||
GSK_GPU_PATTERN_LINEAR_GRADIENT,
|
||||
GSK_GPU_PATTERN_REPEATING_LINEAR_GRADIENT,
|
||||
} GskGpuPatternType;
|
||||
|
||||
|
||||
@@ -11,5 +11,7 @@
|
||||
#define GSK_GPU_PATTERN_TEXTURE 3u
|
||||
#define GSK_GPU_PATTERN_COLOR_MATRIX 4u
|
||||
#define GSK_GPU_PATTERN_GLYPHS 5u
|
||||
#define GSK_GPU_PATTERN_LINEAR_GRADIENT 6u
|
||||
#define GSK_GPU_PATTERN_REPEATING_LINEAR_GRADIENT 7u
|
||||
|
||||
#endif
|
||||
|
||||
147
gsk/gpu/shaders/gradient.glsl
Normal file
147
gsk/gpu/shaders/gradient.glsl
Normal file
@@ -0,0 +1,147 @@
|
||||
#ifndef _GRADIENT_
|
||||
#define _GRADIENT_
|
||||
|
||||
#ifdef GSK_FRAGMENT_SHADER
|
||||
|
||||
#include "common.glsl"
|
||||
|
||||
struct Gradient
|
||||
{
|
||||
int n_stops;
|
||||
uint offset;
|
||||
};
|
||||
|
||||
float
|
||||
gradient_read_offset (Gradient self,
|
||||
int i)
|
||||
{
|
||||
return gsk_get_float (self.offset + uint(i) * 5u);
|
||||
}
|
||||
|
||||
vec4
|
||||
gradient_read_color (Gradient self,
|
||||
int i)
|
||||
{
|
||||
uint u = uint (clamp (i, 0, self.n_stops - 1));
|
||||
return vec4 (gsk_get_float (self.offset + u * 5u + 1u),
|
||||
gsk_get_float (self.offset + u * 5u + 2u),
|
||||
gsk_get_float (self.offset + u * 5u + 3u),
|
||||
gsk_get_float (self.offset + u * 5u + 4u));
|
||||
}
|
||||
|
||||
vec4
|
||||
gradient_get_color_for_range_unscaled (Gradient self,
|
||||
float start,
|
||||
float end)
|
||||
{
|
||||
vec4 result = vec4 (0.0);
|
||||
float offset;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < self.n_stops; i++)
|
||||
{
|
||||
offset = gradient_read_offset (self, i);
|
||||
if (offset >= start)
|
||||
break;
|
||||
}
|
||||
if (i == self.n_stops)
|
||||
offset = 1.0;
|
||||
|
||||
float last_offset = i > 0 ? gradient_read_offset (self, i - 1) : 0.0;
|
||||
vec4 last_color = gradient_read_color (self, i - 1);
|
||||
vec4 color = gradient_read_color (self, i);
|
||||
if (last_offset < start)
|
||||
{
|
||||
last_color = mix (last_color, color, (start - last_offset) / (offset - last_offset));
|
||||
last_offset = start;
|
||||
}
|
||||
if (end <= start)
|
||||
return last_color;
|
||||
|
||||
for (; i < self.n_stops; i++)
|
||||
{
|
||||
offset = gradient_read_offset (self, i);
|
||||
color = gradient_read_color (self, i);
|
||||
if (offset >= end)
|
||||
break;
|
||||
result += 0.5 * (color + last_color) * (offset - last_offset);
|
||||
last_offset = offset;
|
||||
last_color = color;
|
||||
}
|
||||
if (i == self.n_stops)
|
||||
{
|
||||
offset = 1.0;
|
||||
color = gradient_read_color (self, i);
|
||||
}
|
||||
if (offset > end)
|
||||
{
|
||||
color = mix (last_color, color, (end - last_offset) / (offset - last_offset));
|
||||
offset = end;
|
||||
}
|
||||
result += 0.5 * (color + last_color) * (offset - last_offset);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
vec4
|
||||
gradient_get_color_repeating (Gradient self,
|
||||
float start,
|
||||
float end)
|
||||
{
|
||||
vec4 c;
|
||||
|
||||
if (floor (end) > floor (start))
|
||||
{
|
||||
float fract_end = fract(end);
|
||||
float fract_start = fract(start);
|
||||
float n = floor (end) - floor (start);
|
||||
if (fract_end > fract_start + 0.01)
|
||||
c = gradient_get_color_for_range_unscaled (self, fract_start, fract_end);
|
||||
else if (fract_start > fract_end + 0.01)
|
||||
c = - gradient_get_color_for_range_unscaled (self, fract_end, fract_start);
|
||||
c += gradient_get_color_for_range_unscaled (self, 0.0, 1.0) * n;
|
||||
}
|
||||
else
|
||||
{
|
||||
start = fract (start);
|
||||
end = fract (end);
|
||||
c = gradient_get_color_for_range_unscaled (self, start, end);
|
||||
}
|
||||
c /= end - start;
|
||||
|
||||
return color_premultiply (c);
|
||||
}
|
||||
|
||||
vec4
|
||||
gradient_get_color (Gradient self,
|
||||
float start,
|
||||
float end)
|
||||
{
|
||||
vec4 c;
|
||||
|
||||
start = clamp (start, 0.0, 1.0);
|
||||
end = clamp (end, 0.0, 1.0);
|
||||
c = gradient_get_color_for_range_unscaled (self, start, end);
|
||||
if (end > start)
|
||||
c /= end - start;
|
||||
|
||||
return color_premultiply (c);
|
||||
}
|
||||
|
||||
uint
|
||||
gradient_get_size (Gradient self)
|
||||
{
|
||||
return uint (self.n_stops) * 5u + 1u;
|
||||
}
|
||||
|
||||
Gradient
|
||||
gradient_new (uint offset)
|
||||
{
|
||||
Gradient self = Gradient (gsk_get_int (offset),
|
||||
offset + 1u);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#endif /* GSK_FRAGMENT_SHADER */
|
||||
#endif /* __GRADIENT__ */
|
||||
@@ -5,6 +5,7 @@ gsk_private_gpu_include_shaders = files([
|
||||
'common-vulkan.glsl',
|
||||
'ellipse.glsl',
|
||||
'enums.glsl',
|
||||
'gradient.glsl',
|
||||
'pattern.glsl',
|
||||
'rect.glsl',
|
||||
'roundedrect.glsl',
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define _PATTERN_
|
||||
|
||||
#include "common.glsl"
|
||||
#include "gradient.glsl"
|
||||
#include "rect.glsl"
|
||||
|
||||
#ifdef GSK_FRAGMENT_SHADER
|
||||
@@ -22,6 +23,12 @@ read_float (inout uint reader)
|
||||
return result;
|
||||
}
|
||||
|
||||
vec2
|
||||
read_vec2 (inout uint reader)
|
||||
{
|
||||
return vec2 (read_float (reader), read_float (reader));
|
||||
}
|
||||
|
||||
vec4
|
||||
read_vec4 (inout uint reader)
|
||||
{
|
||||
@@ -37,18 +44,27 @@ read_rect (inout uint reader)
|
||||
mat4
|
||||
read_mat4 (inout uint reader)
|
||||
{
|
||||
mat4 result = mat4 (gsk_get_float (reader + 0), gsk_get_float (reader + 1),
|
||||
gsk_get_float (reader + 2), gsk_get_float (reader + 3),
|
||||
gsk_get_float (reader + 4), gsk_get_float (reader + 5),
|
||||
gsk_get_float (reader + 6), gsk_get_float (reader + 7),
|
||||
gsk_get_float (reader + 8), gsk_get_float (reader + 9),
|
||||
gsk_get_float (reader + 10), gsk_get_float (reader + 11),
|
||||
gsk_get_float (reader + 12), gsk_get_float (reader + 13),
|
||||
gsk_get_float (reader + 14), gsk_get_float (reader + 15));
|
||||
reader += 16;
|
||||
mat4 result = mat4 (gsk_get_float (reader + 0u), gsk_get_float (reader + 1u),
|
||||
gsk_get_float (reader + 2u), gsk_get_float (reader + 3u),
|
||||
gsk_get_float (reader + 4u), gsk_get_float (reader + 5u),
|
||||
gsk_get_float (reader + 6u), gsk_get_float (reader + 7u),
|
||||
gsk_get_float (reader + 8u), gsk_get_float (reader + 9u),
|
||||
gsk_get_float (reader + 10u), gsk_get_float (reader + 11u),
|
||||
gsk_get_float (reader + 12u), gsk_get_float (reader + 13u),
|
||||
gsk_get_float (reader + 14u), gsk_get_float (reader + 15u));
|
||||
reader += 16u;
|
||||
return result;
|
||||
}
|
||||
|
||||
Gradient
|
||||
read_gradient (inout uint reader)
|
||||
{
|
||||
Gradient gradient = gradient_new (reader);
|
||||
reader += gradient_get_size (gradient);
|
||||
|
||||
return gradient;
|
||||
}
|
||||
|
||||
void
|
||||
opacity_pattern (inout uint reader,
|
||||
inout vec4 color,
|
||||
@@ -108,6 +124,26 @@ texture_pattern (inout uint reader,
|
||||
return texture (gsk_get_texture (tex_id), (pos - push.scale * tex_rect.xy) / (push.scale * tex_rect.zw));
|
||||
}
|
||||
|
||||
vec4
|
||||
linear_gradient_pattern (inout uint reader,
|
||||
vec2 pos,
|
||||
bool repeating)
|
||||
{
|
||||
vec2 start = read_vec2 (reader) * push.scale;
|
||||
vec2 end = read_vec2 (reader) * push.scale;
|
||||
Gradient gradient = read_gradient (reader);
|
||||
|
||||
vec2 line = end - start;
|
||||
float line_length = dot (line, line);
|
||||
float offset = dot (pos - start, line) / line_length;
|
||||
float d_offset = 0.5 * fwidth (offset);
|
||||
|
||||
if (repeating)
|
||||
return gradient_get_color_repeating (gradient, offset - d_offset, offset + d_offset);
|
||||
else
|
||||
return gradient_get_color (gradient, offset - d_offset, offset + d_offset);
|
||||
}
|
||||
|
||||
vec4
|
||||
color_pattern (inout uint reader)
|
||||
{
|
||||
@@ -145,6 +181,12 @@ pattern (uint reader,
|
||||
case GSK_GPU_PATTERN_OPACITY:
|
||||
opacity_pattern (reader, color, pos);
|
||||
break;
|
||||
case GSK_GPU_PATTERN_LINEAR_GRADIENT:
|
||||
color = linear_gradient_pattern (reader, pos, false);
|
||||
break;
|
||||
case GSK_GPU_PATTERN_REPEATING_LINEAR_GRADIENT:
|
||||
color = linear_gradient_pattern (reader, pos, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user