gskglrenderer: Optimize radial-gradient shader

This commit is contained in:
Fabio Lagalla 2021-01-26 12:32:04 +01:00
parent bbf68c0d9d
commit 5ac7529771
3 changed files with 52 additions and 66 deletions

View File

@ -3050,6 +3050,9 @@ static inline void
apply_radial_gradient_op (const Program *program,
const OpRadialGradient *op)
{
float scale;
float bias;
OP_PRINT (" -> Radial gradient");
if (op->n_color_stops.send)
glUniform1i (program->radial_gradient.num_color_stops_location, op->n_color_stops.value);
@ -3059,10 +3062,12 @@ apply_radial_gradient_op (const Program *program,
op->n_color_stops.value * 5,
(float *)op->color_stops.value);
glUniform1f (program->radial_gradient.start_location, op->start);
glUniform1f (program->radial_gradient.end_location, op->end);
glUniform2f (program->radial_gradient.radius_location, op->radius[0], op->radius[1]);
glUniform2f (program->radial_gradient.center_location, op->center[0], op->center[1]);
scale = 1.0f / (op->end - op->start);
bias = -op->start * scale;
glUniform2f (program->radial_gradient.range_location, scale, bias);
glUniform4f (program->radial_gradient.geometry_location,
op->center[0], op->center[1],
1.0f / op->radius[0], 1.0f / op->radius[1]);
}
static inline void
@ -3374,10 +3379,8 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self,
/* radial gradient */
INIT_PROGRAM_UNIFORM_LOCATION (radial_gradient, color_stops);
INIT_PROGRAM_UNIFORM_LOCATION (radial_gradient, num_color_stops);
INIT_PROGRAM_UNIFORM_LOCATION (radial_gradient, center);
INIT_PROGRAM_UNIFORM_LOCATION (radial_gradient, start);
INIT_PROGRAM_UNIFORM_LOCATION (radial_gradient, end);
INIT_PROGRAM_UNIFORM_LOCATION (radial_gradient, radius);
INIT_PROGRAM_UNIFORM_LOCATION (radial_gradient, geometry);
INIT_PROGRAM_UNIFORM_LOCATION (radial_gradient, range);
/* conic gradient */
INIT_PROGRAM_UNIFORM_LOCATION (conic_gradient, color_stops);

View File

@ -123,10 +123,8 @@ struct _Program
struct {
int num_color_stops_location;
int color_stops_location;
int center_location;
int start_location;
int end_location;
int radius_location;
int geometry_location;
int range_location;
} radial_gradient;
struct {
int num_color_stops_location;

View File

@ -1,31 +1,18 @@
// VERTEX_SHADER
uniform float u_start;
uniform float u_end;
uniform float u_color_stops[6 * 5];
uniform int u_num_color_stops;
uniform vec2 u_radius;
uniform vec2 u_center;
uniform vec4 u_geometry;
_OUT_ vec2 center;
_OUT_ vec4 color_stops[6];
_OUT_ float color_offsets[6];
_OUT_ float start;
_OUT_ float end;
_NOPERSPECTIVE_ _OUT_ vec2 coord;
void main() {
gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
gl_Position = u_projection * (u_modelview * vec4(aPosition, 0.0, 1.0));
center = (u_modelview * vec4(u_center, 0, 1)).xy;
start = u_start;
end = u_end;
vec2 mv0 = u_modelview[0].xy;
vec2 mv1 = u_modelview[1].xy;
vec2 offset = aPosition - u_geometry.xy;
vec2 dir = vec2(dot(mv0, offset),
dot(mv1, offset));
for (int i = 0; i < u_num_color_stops; i ++) {
color_offsets[i] = u_color_stops[(i * 5) + 0];
color_stops[i] = gsk_premultiply(vec4(u_color_stops[(i * 5) + 1],
u_color_stops[(i * 5) + 2],
u_color_stops[(i * 5) + 3],
u_color_stops[(i * 5) + 4]));
}
coord = dir * u_geometry.zw;
}
// FRAGMENT_SHADER:
@ -35,50 +22,48 @@ uniform int u_num_color_stops;
uniform highp int u_num_color_stops;
#endif
uniform vec2 u_radius;
uniform float u_end;
uniform vec2 u_range;
uniform float u_color_stops[6 * 5];
_IN_ vec2 center;
_IN_ vec4 color_stops[6];
_IN_ float color_offsets[6];
_IN_ float start;
_IN_ float end;
_NOPERSPECTIVE_ _IN_ vec2 coord;
// The offsets in the color stops are relative to the
// start and end values of the gradient.
float abs_offset(float offset) {
return start + ((end - start) * offset);
float get_offset(int index) {
return u_color_stops[5 * index];
}
vec4 get_color(int index) {
int base = 5 * index + 1;
return vec4(u_color_stops[base],
u_color_stops[base + 1],
u_color_stops[base + 2],
u_color_stops[base + 3]);
}
void main() {
vec2 pixel = gsk_get_frag_coord();
vec2 rel = (center - pixel) / (u_radius);
float d = sqrt(dot(rel, rel));
// Reverse scale
float offset = length(coord) * u_range.x + u_range.y;
if (d < abs_offset (color_offsets[0])) {
gskSetOutputColor(color_stops[0] * u_alpha);
if (offset < get_offset(0)) {
gskSetOutputColor(gsk_scaled_premultiply(get_color(0), u_alpha));
return;
}
if (d > end) {
gskSetOutputColor(color_stops[u_num_color_stops - 1] * u_alpha);
return;
}
int n = u_num_color_stops - 1;
for (int i = 0; i < n; i++) {
float curr_offset = get_offset(i);
float next_offset = get_offset(i + 1);
vec4 color = vec4(0, 0, 0, 0);
for (int i = 1; i < u_num_color_stops; i++) {
float last_offset = abs_offset(color_offsets[i - 1]);
float this_offset = abs_offset(color_offsets[i]);
if (offset >= curr_offset && offset < next_offset) {
float f = (offset - curr_offset) / (next_offset - curr_offset);
vec4 curr_color = gsk_premultiply(get_color(i));
vec4 next_color = gsk_premultiply(get_color(i + 1));
vec4 color = mix(curr_color, next_color, f);
// We have color_stops[i - 1] at last_offset and color_stops[i] at this_offset.
// We now need to map `d` between those two offsets and simply mix linearly between them
if (d >= last_offset && d <= this_offset) {
float f = (d - last_offset) / (this_offset - last_offset);
color = mix(color_stops[i - 1], color_stops[i], f);
break;
gskSetOutputColor(color * u_alpha);
return;
}
}
gskSetOutputColor(color * u_alpha);
gskSetOutputColor(gsk_scaled_premultiply(get_color(n), u_alpha));
}