gpu: Make border shader usable for inset/outset

... and use it for those when unblurred.
This commit is contained in:
Benjamin Otte 2023-09-23 07:42:04 +02:00
parent 8043d4d6e0
commit 8271687ef6
6 changed files with 190 additions and 32 deletions

View File

@ -111,6 +111,7 @@ gsk_gpu_border_op (GskGpuFrame *frame,
GskGpuShaderClip clip,
const GskRoundedRect *outline,
const graphene_point_t *offset,
const graphene_point_t *inside_offset,
const float widths[4],
const GdkRGBA colors[4])
{
@ -129,5 +130,7 @@ gsk_gpu_border_op (GskGpuFrame *frame,
instance->border_widths[i] = widths[i];
gsk_gpu_rgba_to_float (&colors[i], &instance->border_colors[4 * i]);
}
instance->offset[0] = inside_offset->x;
instance->offset[1] = inside_offset->y;
}

View File

@ -11,6 +11,7 @@ void gsk_gpu_border_op (GskGpuF
GskGpuShaderClip clip,
const GskRoundedRect *outline,
const graphene_point_t *offset,
const graphene_point_t *inside_offset,
const float widths[4],
const GdkRGBA colors[4]);

View File

@ -1070,6 +1070,7 @@ gsk_gpu_node_processor_add_border_node (GskGpuNodeProcessor *self,
gsk_gpu_clip_get_shader_clip (&self->clip, &self->offset, &node->bounds),
gsk_border_node_get_outline (node),
&self->offset,
graphene_point_zero (),
gsk_border_node_get_widths (node),
gsk_border_node_get_colors (node));
}
@ -1137,6 +1138,68 @@ gsk_gpu_node_processor_create_texture_pattern (GskGpuPatternWriter *self,
return TRUE;
}
static void
gsk_gpu_node_processor_add_inset_shadow_node (GskGpuNodeProcessor *self,
GskRenderNode *node)
{
const GdkRGBA *color;
float spread, blur_radius;
spread = gsk_inset_shadow_node_get_spread (node);
color = gsk_inset_shadow_node_get_color (node);
blur_radius = gsk_inset_shadow_node_get_blur_radius (node);
if (blur_radius == 0)
{
gsk_gpu_border_op (self->frame,
gsk_gpu_clip_get_shader_clip (&self->clip, &self->offset, &node->bounds),
gsk_inset_shadow_node_get_outline (node),
&self->offset,
&GRAPHENE_POINT_INIT (gsk_inset_shadow_node_get_dx (node),
gsk_inset_shadow_node_get_dy (node)),
(float[4]) { spread, spread, spread, spread },
(GdkRGBA[4]) { *color, *color, *color, *color });
return;
}
GSK_DEBUG (FALLBACK, "No blurring for inset shadows");
gsk_gpu_node_processor_add_fallback_node (self, node);
}
static void
gsk_gpu_node_processor_add_outset_shadow_node (GskGpuNodeProcessor *self,
GskRenderNode *node)
{
GskRoundedRect outline;
const GdkRGBA *color;
float spread, blur_radius, dx, dy;
spread = gsk_outset_shadow_node_get_spread (node);
color = gsk_outset_shadow_node_get_color (node);
blur_radius = gsk_outset_shadow_node_get_blur_radius (node);
dx = gsk_outset_shadow_node_get_dx (node);
dy = gsk_outset_shadow_node_get_dy (node);
gsk_rounded_rect_init_copy (&outline, gsk_outset_shadow_node_get_outline (node));
gsk_rounded_rect_shrink (&outline, -spread, -spread, -spread, -spread);
graphene_rect_offset (&outline.bounds, dx, dy);
if (blur_radius == 0)
{
gsk_gpu_border_op (self->frame,
gsk_gpu_clip_get_shader_clip (&self->clip, &self->offset, &node->bounds),
&outline,
&self->offset,
&GRAPHENE_POINT_INIT (-dx, -dy),
(float[4]) { spread, spread, spread, spread },
(GdkRGBA[4]) { *color, *color, *color, *color });
return;
}
GSK_DEBUG (FALLBACK, "No blurring for outset shadows");
gsk_gpu_node_processor_add_fallback_node (self, node);
}
static gboolean
gsk_gpu_node_processor_create_linear_gradient_pattern (GskGpuPatternWriter *self,
GskRenderNode *node)
@ -1723,12 +1786,12 @@ static const struct
},
[GSK_INSET_SHADOW_NODE] = {
0,
NULL,
gsk_gpu_node_processor_add_inset_shadow_node,
NULL,
},
[GSK_OUTSET_SHADOW_NODE] = {
0,
NULL,
gsk_gpu_node_processor_add_outset_shadow_node,
NULL,
},
[GSK_TRANSFORM_NODE] = {

View File

@ -54,56 +54,41 @@ rect_get_position (Rect rect)
}
vec2
border_get_position (RoundedRect outline,
vec4 border_widths)
border_get_position (RoundedRect outside,
RoundedRect inside)
{
uint slice_index = uint (GSK_VERTEX_INDEX) / 6u;
uint vert_index = uint (GSK_VERTEX_INDEX) % 6u;
vec4 corner_widths = max (outline.corner_widths, border_widths.wyyw);
vec4 corner_heights = max (outline.corner_heights, border_widths.xxzz);
Rect rect;
Rect rect = rounded_rect_intersection_slice (outside, inside, slice_index);
switch (slice_index)
{
case SLICE_TOP_LEFT:
rect = Rect (outline.bounds.xyxy + vec4 (0.0, 0.0, corner_widths[TOP_LEFT], corner_heights[TOP_LEFT]));
rect = rect_round_larger (rect);
rect.bounds = rect.bounds.xwzy;
break;
case SLICE_TOP:
rect = Rect (vec4 (outline.bounds.x + corner_widths[TOP_LEFT], outline.bounds.y,
outline.bounds.z - corner_widths[TOP_RIGHT], outline.bounds.y + border_widths[TOP]));
rect = rect_round_smaller_larger (rect);
break;
case SLICE_TOP_RIGHT:
rect = Rect (outline.bounds.zyzy + vec4 (- corner_widths[TOP_RIGHT], 0.0, 0.0, corner_heights[TOP_RIGHT]));
rect = rect_round_larger (rect);
break;
case SLICE_RIGHT:
rect = Rect (vec4 (outline.bounds.z - border_widths[RIGHT], outline.bounds.y + corner_widths[TOP_RIGHT],
outline.bounds.z, outline.bounds.w - corner_widths[BOTTOM_RIGHT]));
rect = rect_round_larger_smaller (rect);
break;
case SLICE_BOTTOM_RIGHT:
rect = Rect (outline.bounds.zwzw + vec4 (- corner_widths[BOTTOM_RIGHT], - corner_heights[BOTTOM_RIGHT], 0.0, 0.0));
rect = rect_round_larger (rect);
rect.bounds = rect.bounds.zyxw;
break;
case SLICE_BOTTOM:
rect = Rect (vec4 (outline.bounds.x + corner_widths[BOTTOM_LEFT], outline.bounds.w - border_widths[BOTTOM],
outline.bounds.z - corner_widths[BOTTOM_RIGHT], outline.bounds.w));
rect = rect_round_smaller_larger (rect);
break;
case SLICE_BOTTOM_LEFT:
rect = Rect (outline.bounds.xwxw + vec4 (0.0, - corner_heights[BOTTOM_LEFT], corner_widths[BOTTOM_LEFT], 0.0));
rect = rect_round_larger (rect);
rect.bounds = rect.bounds.zwxy;
break;
case SLICE_LEFT:
rect = Rect (vec4 (outline.bounds.x + border_widths[LEFT], outline.bounds.y + corner_widths[TOP_LEFT],
outline.bounds.x, outline.bounds.w - corner_widths[BOTTOM_LEFT]));
rect = rect_round_larger_smaller (rect);
break;
}
@ -177,7 +162,7 @@ main_clip_rounded (void)
run (color, pos);
RoundedRect clip = RoundedRect(vec4(push.clip_bounds.xy, push.clip_bounds.xy + push.clip_bounds.zw), push.clip_widths, push.clip_heights);
clip = rounded_rect_scale (clip, push.scale);
rounded_rect_scale (clip, push.scale);
float coverage = rounded_rect_coverage (clip, pos);
color *= coverage;

View File

@ -12,6 +12,7 @@ PASS_FLAT(5) RoundedRect _inside;
IN(0) mat4 in_border_colors;
IN(4) mat3x4 in_outline;
IN(7) vec4 in_border_widths;
IN(8) vec2 in_offset;
vec4
compute_color (void)
@ -56,8 +57,9 @@ run (out vec2 pos)
vec4 border_widths = in_border_widths * push.scale.yxyx;
RoundedRect outside = rounded_rect_from_gsk (in_outline);
RoundedRect inside = rounded_rect_shrink (outside, border_widths);
rounded_rect_offset (inside, in_offset);
pos = border_get_position (outside, border_widths);
pos = border_get_position (outside, inside);
_pos = pos;
_color = compute_color ();

View File

@ -50,16 +50,6 @@ rounded_rect_distance (RoundedRect r, vec2 p)
return max (max2.x, max2.y);
}
RoundedRect
rounded_rect_scale (RoundedRect r, vec2 scale)
{
r.bounds *= scale.xyxy;
r.corner_widths *= scale.xxxx;
r.corner_heights *= scale.yyyy;
return r;
}
RoundedRect
rounded_rect_shrink (RoundedRect r, vec4 amount)
{
@ -72,6 +62,120 @@ rounded_rect_shrink (RoundedRect r, vec4 amount)
return RoundedRect (new_bounds, new_widths, new_heights);
}
void
rounded_rect_scale (inout RoundedRect r,
vec2 scale)
{
r.bounds *= scale.xyxy;
r.corner_widths *= scale.xxxx;
r.corner_heights *= scale.yyyy;
}
void
rounded_rect_offset (inout RoundedRect r,
vec2 offset)
{
r.bounds += offset.xyxy;
}
Rect
rounded_rect_intersection_slice (RoundedRect outside,
RoundedRect inside,
uint slice)
{
float left, right, top, bottom;
switch (slice)
{
case SLICE_TOP_LEFT:
return Rect (vec4 (outside.bounds.x,
outside.bounds.y,
max (outside.bounds.x + outside.corner_widths[TOP_LEFT],
inside.bounds.x + inside.corner_widths[TOP_LEFT]),
max (outside.bounds.y + outside.corner_heights[TOP_LEFT],
inside.bounds.y + inside.corner_heights[TOP_LEFT])));
case SLICE_TOP:
left = max (outside.bounds.x + outside.corner_widths[TOP_LEFT],
inside.bounds.x + inside.corner_widths[TOP_LEFT]);
right = min (outside.bounds.z - outside.corner_widths[TOP_RIGHT],
inside.bounds.z - inside.corner_widths[TOP_RIGHT]);
return Rect (vec4 (left,
outside.bounds.y,
max (left, right),
max (outside.bounds.y, inside.bounds.y)));
case SLICE_TOP_RIGHT:
left = max (min (outside.bounds.z - outside.corner_widths[TOP_RIGHT],
inside.bounds.z - inside.corner_widths[TOP_RIGHT]),
max (outside.bounds.x + outside.corner_widths[TOP_LEFT],
inside.bounds.x + inside.corner_widths[TOP_LEFT]));
return Rect (vec4 (left,
outside.bounds.y,
outside.bounds.z,
max (outside.bounds.y + outside.corner_heights[TOP_RIGHT],
inside.bounds.y + inside.corner_heights[TOP_RIGHT])));
case SLICE_RIGHT:
top = max (outside.bounds.y + outside.corner_heights[TOP_RIGHT],
inside.bounds.y + inside.corner_heights[TOP_RIGHT]);
bottom = min (outside.bounds.w - outside.corner_heights[BOTTOM_RIGHT],
inside.bounds.w - inside.corner_heights[BOTTOM_RIGHT]);
return Rect (vec4 (min (outside.bounds.z, inside.bounds.z),
top,
outside.bounds.z,
max (bottom, top)));
case SLICE_BOTTOM_RIGHT:
left = max (min (outside.bounds.z - outside.corner_widths[BOTTOM_RIGHT],
inside.bounds.z - inside.corner_widths[BOTTOM_RIGHT]),
max (outside.bounds.x + outside.corner_widths[BOTTOM_LEFT],
inside.bounds.x + inside.corner_widths[BOTTOM_LEFT]));
bottom = max (min (outside.bounds.w - outside.corner_heights[BOTTOM_RIGHT],
inside.bounds.w - inside.corner_heights[BOTTOM_RIGHT]),
max (outside.bounds.y + outside.corner_heights[TOP_RIGHT],
inside.bounds.y + inside.corner_heights[TOP_RIGHT]));
return Rect (vec4 (left,
bottom,
outside.bounds.z,
outside.bounds.w));
case SLICE_BOTTOM:
left = max (outside.bounds.x + outside.corner_widths[BOTTOM_LEFT],
inside.bounds.x + inside.corner_widths[BOTTOM_LEFT]);
right = min (outside.bounds.z - outside.corner_widths[BOTTOM_RIGHT],
inside.bounds.z - inside.corner_widths[BOTTOM_RIGHT]);
return Rect (vec4 (left,
min (outside.bounds.w, inside.bounds.w),
max (left, right),
outside.bounds.w));
case SLICE_BOTTOM_LEFT:
bottom = max (min (outside.bounds.w - outside.corner_heights[BOTTOM_LEFT],
inside.bounds.w - inside.corner_heights[BOTTOM_LEFT]),
max (outside.bounds.y + outside.corner_heights[TOP_LEFT],
inside.bounds.y + inside.corner_heights[TOP_LEFT]));
return Rect (vec4 (outside.bounds.x,
bottom,
max (outside.bounds.x + outside.corner_widths[BOTTOM_LEFT],
inside.bounds.x + inside.corner_widths[BOTTOM_LEFT]),
outside.bounds.w));
case SLICE_LEFT:
top = max (outside.bounds.y + outside.corner_heights[TOP_LEFT],
inside.bounds.y + inside.corner_heights[TOP_LEFT]);
bottom = min (outside.bounds.w - outside.corner_heights[BOTTOM_LEFT],
inside.bounds.w - inside.corner_heights[BOTTOM_LEFT]);
return Rect (vec4 (outside.bounds.x,
top,
max (outside.bounds.x, inside.bounds.x),
max (bottom, top)));
default:
return Rect (vec4 (0.0));
}
}
#ifdef GSK_FRAGMENT_SHADER
float