mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2025-01-13 14:00:09 +00:00
ngl: Special-case css backgrounds
Recognize a common pattern: A rounded clip with a color node, followed by a border node, with the same outline. This is what CSS backgrounds frequently produce, and we can render it more efficiently with a combined shader.
This commit is contained in:
parent
ed3f0012b1
commit
28de2eecc9
@ -40,6 +40,7 @@ gsk_private_ngl_shaders = [
|
||||
'ngl/resources/blend.glsl',
|
||||
'ngl/resources/repeat.glsl',
|
||||
'ngl/resources/custom.glsl',
|
||||
'ngl/resources/filled_border.glsl',
|
||||
]
|
||||
|
||||
gsk_public_sources = files([
|
||||
|
@ -1010,6 +1010,12 @@ gsk_ngl_command_queue_execute (GskNglCommandQueue *self,
|
||||
sizeof (GskNglDrawVertex),
|
||||
(void *) G_STRUCT_OFFSET (GskNglDrawVertex, color));
|
||||
|
||||
/* 3 = color2 location */
|
||||
glEnableVertexAttribArray (3);
|
||||
glVertexAttribPointer (3, 4, GL_FLOAT, GL_FALSE,
|
||||
sizeof (GskNglDrawVertex),
|
||||
(void *) G_STRUCT_OFFSET (GskNglDrawVertex, color2));
|
||||
|
||||
/* Setup initial scissor clip */
|
||||
if (scissor != NULL)
|
||||
{
|
||||
|
@ -348,6 +348,7 @@ gsk_ngl_driver_load_programs (GskNglDriver *self,
|
||||
gsk_ngl_compiler_bind_attribute (compiler, "aPosition", 0);
|
||||
gsk_ngl_compiler_bind_attribute (compiler, "aUv", 1);
|
||||
gsk_ngl_compiler_bind_attribute (compiler, "aColor", 2);
|
||||
gsk_ngl_compiler_bind_attribute (compiler, "aColor2", 3);
|
||||
|
||||
/* Use XMacros to register all of our programs and their uniforms */
|
||||
#define GSK_NGL_NO_UNIFORMS
|
||||
@ -1046,6 +1047,7 @@ gsk_ngl_driver_lookup_shader (GskNglDriver *self,
|
||||
gsk_ngl_compiler_bind_attribute (compiler, "aPosition", 0);
|
||||
gsk_ngl_compiler_bind_attribute (compiler, "aUv", 1);
|
||||
gsk_ngl_compiler_bind_attribute (compiler, "aColor", 2);
|
||||
gsk_ngl_compiler_bind_attribute (compiler, "aColor2", 3);
|
||||
|
||||
if ((program = gsk_ngl_compiler_compile (compiler, NULL, "", error)))
|
||||
{
|
||||
|
@ -42,6 +42,11 @@ GSK_NGL_DEFINE_PROGRAM (cross_fade,
|
||||
GSK_NGL_ADD_UNIFORM (1, CROSS_FADE_PROGRESS, u_progress)
|
||||
GSK_NGL_ADD_UNIFORM (2, CROSS_FADE_SOURCE2, u_source2))
|
||||
|
||||
GSK_NGL_DEFINE_PROGRAM (filled_border,
|
||||
"/org/gtk/libgsk/ngl/filled_border.glsl",
|
||||
GSK_NGL_ADD_UNIFORM (1, FILLED_BORDER_WIDTHS, u_widths)
|
||||
GSK_NGL_ADD_UNIFORM (2, FILLED_BORDER_OUTLINE_RECT, u_outline_rect))
|
||||
|
||||
GSK_NGL_DEFINE_PROGRAM (inset_shadow,
|
||||
"/org/gtk/libgsk/ngl/inset_shadow.glsl",
|
||||
GSK_NGL_ADD_UNIFORM (1, INSET_SHADOW_SPREAD, u_spread)
|
||||
|
@ -1794,6 +1794,56 @@ gsk_ngl_render_job_visit_border_node (GskNglRenderJob *job,
|
||||
gsk_ngl_render_job_end_draw (job);
|
||||
}
|
||||
|
||||
/* A special case for a pattern that occurs frequently with CSS
|
||||
* backgrounds: two sibling nodes, the first of which is a rounded
|
||||
* clip node with a color node as child, and the second one is a
|
||||
* border node, with the same outline as the clip node. We render
|
||||
* this using the filled_border shader.
|
||||
*/
|
||||
static void
|
||||
gsk_ngl_render_job_visit_css_background (GskNglRenderJob *job,
|
||||
const GskRenderNode *node,
|
||||
const GskRenderNode *node2)
|
||||
{
|
||||
const GskRenderNode *child = gsk_rounded_clip_node_get_child (node);
|
||||
const GdkRGBA *c2 = gsk_color_node_get_color (child);
|
||||
const GdkRGBA *c = gsk_border_node_get_colors (node2);
|
||||
const GskRoundedRect *rounded_outline = gsk_border_node_get_outline (node2);
|
||||
const float *widths = gsk_border_node_get_widths (node2);
|
||||
float min_x = job->offset_x + node2->bounds.origin.x;
|
||||
float min_y = job->offset_y + node2->bounds.origin.y;
|
||||
float max_x = min_x + node2->bounds.size.width;
|
||||
float max_y = min_y + node2->bounds.size.height;
|
||||
GskRoundedRect outline;
|
||||
GskNglDrawVertex *vertices;
|
||||
|
||||
if (node_is_invisible (node2))
|
||||
return;
|
||||
|
||||
gsk_ngl_render_job_transform_rounded_rect (job, rounded_outline, &outline);
|
||||
|
||||
gsk_ngl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, filled_border));
|
||||
|
||||
gsk_ngl_program_set_uniform4fv (job->current_program,
|
||||
UNIFORM_FILLED_BORDER_WIDTHS, 0,
|
||||
1,
|
||||
widths);
|
||||
gsk_ngl_program_set_uniform_rounded_rect (job->current_program,
|
||||
UNIFORM_FILLED_BORDER_OUTLINE_RECT, 0,
|
||||
&outline);
|
||||
|
||||
vertices = gsk_ngl_command_queue_add_vertices (job->command_queue);
|
||||
|
||||
vertices[0] = (GskNglDrawVertex) { { min_x, min_y }, { 0, 0 }, { c[0].red, c[0].green, c[0].blue, c[0].alpha }, { c2->red, c2->green, c2->blue, c2->alpha } };
|
||||
vertices[1] = (GskNglDrawVertex) { { min_x, max_y }, { 0, 0 }, { c[0].red, c[0].green, c[0].blue, c[0].alpha }, { c2->red, c2->green, c2->blue, c2->alpha } };
|
||||
vertices[2] = (GskNglDrawVertex) { { max_x, min_y }, { 0, 0 }, { c[0].red, c[0].green, c[0].blue, c[0].alpha }, { c2->red, c2->green, c2->blue, c2->alpha } };
|
||||
vertices[3] = (GskNglDrawVertex) { { max_x, max_y }, { 0, 0 }, { c[0].red, c[0].green, c[0].blue, c[0].alpha }, { c2->red, c2->green, c2->blue, c2->alpha } };
|
||||
vertices[4] = (GskNglDrawVertex) { { min_x, max_y }, { 0, 0 }, { c[0].red, c[0].green, c[0].blue, c[0].alpha }, { c2->red, c2->green, c2->blue, c2->alpha } };
|
||||
vertices[5] = (GskNglDrawVertex) { { max_x, min_y }, { 0, 0 }, { c[0].red, c[0].green, c[0].blue, c[0].alpha }, { c2->red, c2->green, c2->blue, c2->alpha } };
|
||||
|
||||
gsk_ngl_render_job_end_draw (job);
|
||||
}
|
||||
|
||||
/* Returns TRUE if applying @transform to @bounds
|
||||
* yields an axis-aligned rectangle
|
||||
*/
|
||||
@ -3334,6 +3384,25 @@ gsk_ngl_render_job_visit_node (GskNglRenderJob *job,
|
||||
for (guint i = 0; i < n_children; i++)
|
||||
{
|
||||
const GskRenderNode *child = gsk_container_node_get_child (node, i);
|
||||
|
||||
if (i + 1 < n_children &&
|
||||
job->current_clip->is_fully_contained &&
|
||||
gsk_render_node_get_node_type (child) == GSK_ROUNDED_CLIP_NODE)
|
||||
{
|
||||
const GskRenderNode *grandchild = gsk_rounded_clip_node_get_child (child);
|
||||
const GskRenderNode *child2 = gsk_container_node_get_child (node, i + 1);
|
||||
if (gsk_render_node_get_node_type (grandchild) == GSK_COLOR_NODE &&
|
||||
gsk_render_node_get_node_type (child2) == GSK_BORDER_NODE &&
|
||||
gsk_border_node_get_uniform_color (child2) &&
|
||||
gsk_rounded_rect_equal (gsk_rounded_clip_node_get_clip (child),
|
||||
gsk_border_node_get_outline (child2)))
|
||||
{
|
||||
gsk_ngl_render_job_visit_css_background (job, child, child2);
|
||||
i++; /* skip the border node */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
gsk_ngl_render_job_visit_node (job, child);
|
||||
}
|
||||
}
|
||||
|
@ -56,6 +56,7 @@ struct _GskNglDrawVertex
|
||||
float position[2];
|
||||
float uv[2];
|
||||
float color[4];
|
||||
float color2[4];
|
||||
};
|
||||
|
||||
G_END_DECLS
|
||||
|
47
gsk/ngl/resources/filled_border.glsl
Normal file
47
gsk/ngl/resources/filled_border.glsl
Normal file
@ -0,0 +1,47 @@
|
||||
// VERTEX_SHADER:
|
||||
// filled_border.glsl
|
||||
|
||||
uniform vec4 u_widths;
|
||||
uniform vec4[3] u_outline_rect;
|
||||
|
||||
_OUT_ vec4 outer_color;
|
||||
_OUT_ vec4 inner_color;
|
||||
_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline;
|
||||
_OUT_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline;
|
||||
|
||||
void main() {
|
||||
gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
|
||||
|
||||
outer_color = gsk_scaled_premultiply(aColor, u_alpha);
|
||||
inner_color = gsk_scaled_premultiply(aColor2, u_alpha);
|
||||
|
||||
GskRoundedRect outside = gsk_create_rect(u_outline_rect);
|
||||
GskRoundedRect inside = gsk_rounded_rect_shrink (outside, u_widths);
|
||||
|
||||
gsk_rounded_rect_transform(outside, u_modelview);
|
||||
gsk_rounded_rect_transform(inside, u_modelview);
|
||||
|
||||
gsk_rounded_rect_encode(outside, transformed_outside_outline);
|
||||
gsk_rounded_rect_encode(inside, transformed_inside_outline);
|
||||
}
|
||||
|
||||
// FRAGMENT_SHADER:
|
||||
// filled_border.glsl
|
||||
|
||||
uniform vec4[3] u_outline_rect;
|
||||
|
||||
_IN_ vec4 outer_color;
|
||||
_IN_ vec4 inner_color;
|
||||
_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_outside_outline;
|
||||
_IN_ _GSK_ROUNDED_RECT_UNIFORM_ transformed_inside_outline;
|
||||
|
||||
void main() {
|
||||
vec2 frag = gsk_get_frag_coord();
|
||||
float outer_coverage = gsk_rounded_rect_coverage(gsk_decode_rect(transformed_outside_outline), frag);
|
||||
float inner_coverage = gsk_rounded_rect_coverage(gsk_decode_rect(transformed_inside_outline), frag);
|
||||
|
||||
float alpha = clamp(outer_coverage - inner_coverage, 0.0, 1.0);
|
||||
float alpha2 = clamp(inner_coverage, 0.0, 1.0);
|
||||
|
||||
gskSetOutputColor((outer_color * alpha) + (inner_color * alpha2));
|
||||
}
|
@ -6,11 +6,13 @@ uniform float u_alpha;
|
||||
attribute vec2 aPosition;
|
||||
attribute vec2 aUv;
|
||||
attribute vec4 aColor;
|
||||
attribute vec4 aColor2;
|
||||
_OUT_ vec2 vUv;
|
||||
#else
|
||||
_IN_ vec2 aPosition;
|
||||
_IN_ vec2 aUv;
|
||||
_IN_ vec4 aColor;
|
||||
_IN_ vec4 aColor2;
|
||||
_OUT_ vec2 vUv;
|
||||
#endif
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user