diff options
25 files changed, 385 insertions, 181 deletions
diff --git a/docs/reference/gsk/gsk4-sections.txt b/docs/reference/gsk/gsk4-sections.txt index 0f464bd195..201840b5c2 100644 --- a/docs/reference/gsk/gsk4-sections.txt +++ b/docs/reference/gsk/gsk4-sections.txt @@ -183,6 +183,7 @@ gsk_transform_perspective gsk_transform_equal <SUBSECTION> gsk_transform_transform_bounds +gsk_transform_transform_point <SUBSECTION Private> GSK_TYPE_TRANSFORM gsk_transform_get_type diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c index ddead714c7..65933080c0 100644 --- a/gsk/gl/gskglrenderer.c +++ b/gsk/gl/gskglrenderer.c @@ -535,17 +535,16 @@ transform_rect (GskGLRenderer *self, RenderOpBuilder *builder, const GskRoundedRect *rect) { - const float scale = ops_get_scale (builder); GskRoundedRect r; - int i; - ops_transform_bounds_modelview (builder, &rect->bounds, &r.bounds); + r.bounds.origin.x = builder->dx + rect->bounds.origin.x; + r.bounds.origin.y = builder->dy + rect->bounds.origin.y; + r.bounds.size = rect->bounds.size; - for (i = 0; i < 4; i ++) - { - r.corner[i].width = rect->corner[i].width * scale; - r.corner[i].height = rect->corner[i].height * scale; - } + r.corner[0] = rect->corner[0]; + r.corner[1] = rect->corner[1]; + r.corner[2] = rect->corner[2]; + r.corner[3] = rect->corner[3]; return r; } @@ -745,24 +744,22 @@ render_border_node (GskGLRenderer *self, GskRenderNode *node, RenderOpBuilder *builder) { - const float scale = ops_get_scale (builder); const float min_x = builder->dx + node->bounds.origin.x; const float min_y = builder->dy + node->bounds.origin.y; const float max_x = min_x + node->bounds.size.width; const float max_y = min_y + node->bounds.size.height; const GdkRGBA *colors = gsk_border_node_peek_colors (node); const GskRoundedRect *rounded_outline = gsk_border_node_peek_outline (node); - const float *og_widths = gsk_border_node_peek_widths (node); - float widths[4]; + const float *widths = gsk_border_node_peek_widths (node); int i; struct { float w; float h; } sizes[4]; - if (og_widths[0] == og_widths[1] && - og_widths[0] == og_widths[2] && - og_widths[0] == og_widths[3] && + if (widths[0] == widths[1] && + widths[0] == widths[2] && + widths[0] == widths[3] && gdk_rgba_equal (&colors[0], &colors[1]) && gdk_rgba_equal (&colors[0], &colors[2]) && gdk_rgba_equal (&colors[0], &colors[3])) @@ -773,7 +770,7 @@ render_border_node (GskGLRenderer *self, op = ops_begin (builder, OP_CHANGE_INSET_SHADOW); op->color = &colors[0]; op->outline = transform_rect (self, builder, rounded_outline); - op->spread = og_widths[0] * scale; + op->spread = widths[0]; op->offset[0] = 0; op->offset[1] = 0; @@ -781,9 +778,6 @@ render_border_node (GskGLRenderer *self, return; } - for (i = 0; i < 4; i ++) - widths[i] = og_widths[i]; - /* Top left */ if (widths[3] > 0) sizes[0].w = MAX (widths[3], rounded_outline->corner[0].width); @@ -829,9 +823,6 @@ render_border_node (GskGLRenderer *self, else sizes[3].h = 0; - for (i = 0; i < 4; i ++) - widths[i] *= scale; - { const GskQuadVertex side_data[4][6] = { /* Top */ @@ -1189,17 +1180,16 @@ render_rounded_clip_node (GskGLRenderer *self, RenderOpBuilder *builder) { const float scale = ops_get_scale (builder); - GskRoundedRect child_clip = *gsk_rounded_clip_node_peek_clip (node); - GskRoundedRect transformed_clip; + const GskRoundedRect *clip = gsk_rounded_clip_node_peek_clip (node); GskRenderNode *child = gsk_rounded_clip_node_get_child (node); + GskRoundedRect transformed_clip; gboolean need_offscreen; int i; if (node_is_invisible (child)) return; - transformed_clip = child_clip; - ops_transform_bounds_modelview (builder, &child_clip.bounds, &transformed_clip.bounds); + ops_transform_bounds_modelview (builder, &clip->bounds, &transformed_clip.bounds); if (!ops_has_clip (builder)) need_offscreen = FALSE; @@ -1215,8 +1205,8 @@ render_rounded_clip_node (GskGLRenderer *self, * the new clip and add the render ops */ for (i = 0; i < 4; i ++) { - transformed_clip.corner[i].width *= scale; - transformed_clip.corner[i].height *= scale; + transformed_clip.corner[i].width = clip->corner[i].width * scale; + transformed_clip.corner[i].height = clip->corner[i].height * scale; } ops_push_clip (builder, &transformed_clip); @@ -1225,7 +1215,7 @@ render_rounded_clip_node (GskGLRenderer *self, } else { - graphene_matrix_t scale_matrix; + GskRoundedRect scaled_clip; gboolean is_offscreen; TextureRegion region; /* NOTE: We are *not* transforming the clip by the current modelview here. @@ -1234,18 +1224,19 @@ render_rounded_clip_node (GskGLRenderer *self, * * We do, however, apply the scale factor to the child clip of course. */ - - graphene_matrix_init_scale (&scale_matrix, scale, scale, 1.0f); - graphene_matrix_transform_bounds (&scale_matrix, &child_clip.bounds, &child_clip.bounds); + scaled_clip.bounds.origin.x = clip->bounds.origin.x * scale; + scaled_clip.bounds.origin.y = clip->bounds.origin.y * scale; + scaled_clip.bounds.size.width = clip->bounds.size.width * scale; + scaled_clip.bounds.size.height = clip->bounds.size.height * scale; /* Increase corner radius size by scale factor */ for (i = 0; i < 4; i ++) { - child_clip.corner[i].width *= scale; - child_clip.corner[i].height *= scale; + scaled_clip.corner[i].width = clip->corner[i].width * scale; + scaled_clip.corner[i].height = clip->corner[i].height * scale; } - ops_push_clip (builder, &child_clip); + ops_push_clip (builder, &scaled_clip); if (!add_offscreen_ops (self, builder, &node->bounds, child, ®ion, &is_offscreen, @@ -1455,6 +1446,9 @@ render_blur_node (GskGLRenderer *self, GskRenderNode *child = gsk_blur_node_get_child (node); TextureRegion blurred_region; + if (node_is_invisible (child)) + return; + if (blur_radius <= 0) { gsk_gl_renderer_add_render_ops (self, child, builder); @@ -1481,7 +1475,6 @@ render_unblurred_inset_shadow_node (GskGLRenderer *self, GskRenderNode *node, RenderOpBuilder *builder) { - const float scale = ops_get_scale (builder); const float blur_radius = gsk_inset_shadow_node_get_blur_radius (node); const float dx = gsk_inset_shadow_node_get_dx (node); const float dy = gsk_inset_shadow_node_get_dy (node); @@ -1494,9 +1487,9 @@ render_unblurred_inset_shadow_node (GskGLRenderer *self, op = ops_begin (builder, OP_CHANGE_INSET_SHADOW); op->color = gsk_inset_shadow_node_peek_color (node); op->outline = transform_rect (self, builder, gsk_inset_shadow_node_peek_outline (node)); - op->spread = spread * scale; - op->offset[0] = dx * scale; - op->offset[1] = dy * scale; + op->spread = spread; + op->offset[0] = dx; + op->offset[1] = dy; load_vertex_data (ops_draw (builder, NULL), node, builder); } @@ -1647,7 +1640,6 @@ render_unblurred_outset_shadow_node (GskGLRenderer *self, GskRenderNode *node, RenderOpBuilder *builder) { - const float scale = ops_get_scale (builder); const GskRoundedRect *outline = gsk_outset_shadow_node_peek_outline (node); const float spread = gsk_outset_shadow_node_get_spread (node); const float dx = gsk_outset_shadow_node_get_dx (node); @@ -1658,9 +1650,9 @@ render_unblurred_outset_shadow_node (GskGLRenderer *self, op = ops_begin (builder, OP_CHANGE_UNBLURRED_OUTSET_SHADOW); op->color = gsk_outset_shadow_node_peek_color (node); op->outline = transform_rect (self, builder, outline); - op->spread = spread * scale; - op->offset[0] = dx * scale; - op->offset[1] = dy * scale; + op->spread = spread; + op->offset[0] = dx; + op->offset[1] = dy; load_vertex_data (ops_draw (builder, NULL), node, builder); } @@ -2163,14 +2155,24 @@ render_cross_fade_node (GskGLRenderer *self, start_node, &start_region, &is_offscreen1, FORCE_OFFSCREEN | RESET_CLIP | RESET_OPACITY)) - g_assert_not_reached (); + { + gsk_gl_renderer_add_render_ops (self, end_node, builder); + return; + } if (!add_offscreen_ops (self, builder, &node->bounds, end_node, &end_region, &is_offscreen2, FORCE_OFFSCREEN | RESET_CLIP | RESET_OPACITY)) - g_assert_not_reached (); + { + load_vertex_data_with_region (ops_draw (builder, NULL), + node, + builder, + &start_region, + TRUE); + return; + } ops_set_program (builder, &self->cross_fade_program); @@ -2576,6 +2578,7 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self, gboolean success = TRUE; gsk_gl_shader_builder_init (&shader_builder, + "/org/gtk/libgsk/glsl/preamble.glsl", "/org/gtk/libgsk/glsl/preamble.vs.glsl", "/org/gtk/libgsk/glsl/preamble.fs.glsl"); diff --git a/gsk/gl/gskglrenderops.c b/gsk/gl/gskglrenderops.c index 39916be36c..f113df5edf 100644 --- a/gsk/gl/gskglrenderops.c +++ b/gsk/gl/gskglrenderops.c @@ -180,13 +180,15 @@ ops_transform_bounds_modelview (const RenderOpBuilder *builder, const graphene_rect_t *src, graphene_rect_t *dst) { + graphene_rect_t r = *src; + g_assert (builder->mv_stack != NULL); g_assert (builder->mv_stack->len >= 1); - gsk_transform_transform_bounds (builder->current_modelview, src, dst); + r.origin.x += builder->dx; + r.origin.y += builder->dy; - dst->origin.x += builder->dx * builder->scale_x; - dst->origin.y += builder->dy * builder->scale_y; + gsk_transform_transform_bounds (builder->current_modelview, &r, dst); } void diff --git a/gsk/gl/gskglshaderbuilder.c b/gsk/gl/gskglshaderbuilder.c index f28bf127f7..a133527784 100644 --- a/gsk/gl/gskglshaderbuilder.c +++ b/gsk/gl/gskglshaderbuilder.c @@ -9,14 +9,17 @@ void gsk_gl_shader_builder_init (GskGLShaderBuilder *self, + const char *common_preamble_resource_path, const char *vs_preamble_resource_path, const char *fs_preamble_resource_path) { memset (self, 0, sizeof (*self)); + self->preamble = g_resources_lookup_data (common_preamble_resource_path, 0, NULL); self->vs_preamble = g_resources_lookup_data (vs_preamble_resource_path, 0, NULL); self->fs_preamble = g_resources_lookup_data (fs_preamble_resource_path, 0, NULL); + g_assert (self->preamble); g_assert (self->vs_preamble); g_assert (self->fs_preamble); } @@ -24,6 +27,7 @@ gsk_gl_shader_builder_init (GskGLShaderBuilder *self, void gsk_gl_shader_builder_finish (GskGLShaderBuilder *self) { + g_bytes_unref (self->preamble); g_bytes_unref (self->vs_preamble); g_bytes_unref (self->fs_preamble); } @@ -102,13 +106,14 @@ gsk_gl_shader_builder_create_program (GskGLShaderBuilder *self, "#version %d\n", self->version); vertex_id = glCreateShader (GL_VERTEX_SHADER); - glShaderSource (vertex_id, 7, + glShaderSource (vertex_id, 8, (const char *[]) { version_buffer, self->debugging ? "#define GSK_DEBUG 1\n" : "", self->legacy ? "#define GSK_LEGACY 1\n" : "", self->gl3 ? "#define GSK_GL3 1\n" : "", self->gles ? "#define GSK_GLES 1\n" : "", + g_bytes_get_data (self->preamble, NULL), g_bytes_get_data (self->vs_preamble, NULL), vertex_shader_start }, @@ -119,6 +124,7 @@ gsk_gl_shader_builder_create_program (GskGLShaderBuilder *self, -1, -1, -1, + -1, fragment_shader_start - vertex_shader_start }); glCompileShader (vertex_id); @@ -130,13 +136,14 @@ gsk_gl_shader_builder_create_program (GskGLShaderBuilder *self, } fragment_id = glCreateShader (GL_FRAGMENT_SHADER); - glShaderSource (fragment_id, 7, + glShaderSource (fragment_id, 8, (const char *[]) { version_buffer, self->debugging ? "#define GSK_DEBUG 1\n" : "", self->legacy ? "#define GSK_LEGACY 1\n" : "", self->gl3 ? "#define GSK_GL3 1\n" : "", self->gles ? "#define GSK_GLES 1\n" : "", + g_bytes_get_data (self->preamble, NULL), g_bytes_get_data (self->fs_preamble, NULL), fragment_shader_start }, @@ -148,6 +155,7 @@ gsk_gl_shader_builder_create_program (GskGLShaderBuilder *self, -1, -1, -1, + -1, }); glCompileShader (fragment_id); diff --git a/gsk/gl/gskglshaderbuilderprivate.h b/gsk/gl/gskglshaderbuilderprivate.h index 209fa5ff91..ec9cd66845 100644 --- a/gsk/gl/gskglshaderbuilderprivate.h +++ b/gsk/gl/gskglshaderbuilderprivate.h @@ -8,6 +8,7 @@ G_BEGIN_DECLS typedef struct { + GBytes *preamble; GBytes *vs_preamble; GBytes *fs_preamble; @@ -22,6 +23,7 @@ typedef struct void gsk_gl_shader_builder_init (GskGLShaderBuilder *self, + const char *common_preamble_resource_path, const char *vs_preamble_resource_path, const char *fs_preamble_resource_path); void gsk_gl_shader_builder_finish (GskGLShaderBuilder *self); diff --git a/gsk/gsktransform.c b/gsk/gsktransform.c index 388dad5b45..5d9d538d4c 100644 --- a/gsk/gsktransform.c +++ b/gsk/gsktransform.c @@ -1773,6 +1773,62 @@ gsk_transform_transform_bounds (GskTransform *self, } } +/** + * gsk_transform_transform_point: + * @self: a #GskTransform + * @point: a #graphene_point_t + * @out_point: (out caller-allocates): return location for + * the transformed point + * + * Transforms a #graphene_point_t using the given transform @self. + */ +void +gsk_transform_transform_point (GskTransform *self, + const graphene_point_t *point, + graphene_point_t *out_point) +{ + switch (gsk_transform_get_category (self)) + { + case GSK_TRANSFORM_CATEGORY_IDENTITY: + *out_point = *point; + break; + + case GSK_TRANSFORM_CATEGORY_2D_TRANSLATE: + { + float dx, dy; + + gsk_transform_to_translate (self, &dx, &dy); + out_point->x = point->x + dx; + out_point->y = point->y + dy; + } + break; + + case GSK_TRANSFORM_CATEGORY_2D_AFFINE: + { + float dx, dy, scale_x, scale_y; + + gsk_transform_to_affine (self, &scale_x, &scale_y, &dx, &dy); + + out_point->x = (point->x * scale_x) + dx; + out_point->y = (point->y * scale_y) + dy; + } + break; + + case GSK_TRANSFORM_CATEGORY_UNKNOWN: + case GSK_TRANSFORM_CATEGORY_ANY: + case GSK_TRANSFORM_CATEGORY_3D: + case GSK_TRANSFORM_CATEGORY_2D: + default: + { + graphene_matrix_t mat; + + gsk_transform_to_matrix (self, &mat); + graphene_matrix_transform_point (&mat, point, out_point); + } + break; + } +} + static guint gsk_transform_parse_float (GtkCssParser *parser, guint n, diff --git a/gsk/gsktransform.h b/gsk/gsktransform.h index 56cafcc430..f3676bca63 100644 --- a/gsk/gsktransform.h +++ b/gsk/gsktransform.h @@ -116,6 +116,11 @@ GDK_AVAILABLE_IN_ALL void gsk_transform_transform_bounds (GskTransform *self, const graphene_rect_t *rect, graphene_rect_t *out_rect); +GDK_AVAILABLE_IN_ALL +void gsk_transform_transform_point (GskTransform *self, + const graphene_point_t *point, + graphene_point_t *out_point); + G_END_DECLS diff --git a/gsk/meson.build b/gsk/meson.build index 6dd4925155..8aeae9e7e8 100644 --- a/gsk/meson.build +++ b/gsk/meson.build @@ -1,4 +1,5 @@ gsk_private_gl_shaders = [ + 'resources/glsl/preamble.glsl', 'resources/glsl/preamble.fs.glsl', 'resources/glsl/preamble.vs.glsl', 'resources/glsl/border.glsl', diff --git a/gsk/resources/glsl/border.glsl b/gsk/resources/glsl/border.glsl index a47fe7e393..812d365431 100644 --- a/gsk/resources/glsl/border.glsl +++ b/gsk/resources/glsl/border.glsl @@ -1,7 +1,11 @@ // VERTEX_SHADER: uniform vec4 u_color; +uniform vec4 u_widths; +uniform vec4[3] u_outline_rect; _OUT_ vec4 final_color; +_OUT_ _ROUNDED_RECT_UNIFORM_ transformed_outside_outline; +_OUT_ _ROUNDED_RECT_UNIFORM_ transformed_inside_outline; void main() { gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); @@ -9,25 +13,32 @@ void main() { final_color = u_color; final_color.rgb *= final_color.a; // pre-multiply final_color *= u_alpha; + + RoundedRect outside = create_rect(u_outline_rect); + RoundedRect inside = rounded_rect_shrink (outside, u_widths); + + rounded_rect_transform(outside, u_modelview); + rounded_rect_transform(inside, u_modelview); + + rounded_rect_encode(outside, transformed_outside_outline); + rounded_rect_encode(inside, transformed_inside_outline); } // FRAGMENT_SHADER: -uniform vec4 u_widths; uniform vec4[3] u_outline_rect; _IN_ vec4 final_color; +_IN_ _ROUNDED_RECT_UNIFORM_ transformed_outside_outline; +_IN_ _ROUNDED_RECT_UNIFORM_ transformed_inside_outline; void main() { vec4 f = gl_FragCoord; f.x += u_viewport.x; f.y = (u_viewport.y + u_viewport.w) - f.y; - RoundedRect outside = create_rect(u_outline_rect); - RoundedRect inside = rounded_rect_shrink (outside, u_widths); - - float alpha = clamp (rounded_rect_coverage (outside, f.xy) - - rounded_rect_coverage (inside, f.xy), - 0.0, 1.0); + float alpha = clamp(rounded_rect_coverage(decode_rect(transformed_outside_outline), f.xy) - + rounded_rect_coverage(decode_rect(transformed_inside_outline), f.xy), + 0.0, 1.0); setOutputColor(final_color * alpha); } diff --git a/gsk/resources/glsl/inset_shadow.glsl b/gsk/resources/glsl/inset_shadow.glsl index 425b140391..b3ba05a41f 100644 --- a/gsk/resources/glsl/inset_shadow.glsl +++ b/gsk/resources/glsl/inset_shadow.glsl @@ -1,7 +1,12 @@ // VERTEX_SHADER: uniform vec4 u_color; +uniform float u_spread; +uniform vec2 u_offset; +uniform vec4[3] u_outline_rect; _OUT_ vec4 final_color; +_OUT_ _ROUNDED_RECT_UNIFORM_ transformed_outside_outline; +_OUT_ _ROUNDED_RECT_UNIFORM_ transformed_inside_outline; void main() { gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); @@ -9,26 +14,33 @@ void main() { final_color = u_color; final_color.rgb *= final_color.a; final_color *= u_alpha; + + RoundedRect outside = create_rect(u_outline_rect); + RoundedRect inside = rounded_rect_shrink(outside, vec4(u_spread)); + + rounded_rect_offset(inside, u_offset); + + rounded_rect_transform(outside, u_modelview); + rounded_rect_transform(inside, u_modelview); + + rounded_rect_encode(outside, transformed_outside_outline); + rounded_rect_encode(inside, transformed_inside_outline); } // FRAGMENT_SHADER: -uniform float u_spread; -uniform vec2 u_offset; -uniform vec4[3] u_outline_rect; - _IN_ vec4 final_color; +_IN_ _ROUNDED_RECT_UNIFORM_ transformed_outside_outline; +_IN_ _ROUNDED_RECT_UNIFORM_ transformed_inside_outline; void main() { vec4 f = gl_FragCoord; - vec4 color; f.x += u_viewport.x; f.y = (u_viewport.y + u_viewport.w) - f.y; - RoundedRect outside = create_rect(u_outline_rect); - RoundedRect inside = rounded_rect_shrink(outside, vec4(u_spread)); - color = final_color * clamp (rounded_rect_coverage (outside, f.xy) - - rounded_rect_coverage (inside, f.xy - u_offset), - 0.0, 1.0); - setOutputColor(color); + float alpha = clamp (rounded_rect_coverage(decode_rect(transformed_outside_outline), f.xy) - + rounded_rect_coverage(decode_rect(transformed_inside_outline), f.xy), + 0.0, 1.0); + + setOutputColor(final_color * alpha); } diff --git a/gsk/resources/glsl/outset_shadow.glsl b/gsk/resources/glsl/outset_shadow.glsl index f0c5b3fede..4111ddcea8 100644 --- a/gsk/resources/glsl/outset_shadow.glsl +++ b/gsk/resources/glsl/outset_shadow.glsl @@ -1,7 +1,9 @@ // VERTEX_SHADER: uniform vec4 u_color; +uniform vec4[3] u_outline_rect; _OUT_ vec4 final_color; +_OUT_ _ROUNDED_RECT_UNIFORM_ transformed_outline; void main() { gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); @@ -12,12 +14,15 @@ void main() { // pre-multiply final_color.rgb *= final_color.a; final_color *= u_alpha; + + RoundedRect outline = create_rect(u_outline_rect); + rounded_rect_transform(outline, u_modelview); + rounded_rect_encode(outline, transformed_outline); } // FRAGMENT_SHADER: -uniform vec4[3] u_outline_rect; - _IN_ vec4 final_color; +_IN_ _ROUNDED_RECT_UNIFORM_ transformed_outline; void main() { vec4 f = gl_FragCoord; @@ -25,10 +30,8 @@ void main() { f.x += u_viewport.x; f.y = (u_viewport.y + u_viewport.w) - f.y; - RoundedRect outline = create_rect(u_outline_rect); - float alpha = Texture(u_source, vUv).a; - alpha *= (1.0 - clamp(rounded_rect_coverage(outline, f.xy), 0.0, 1.0)); + alpha *= (1.0 - clamp(rounded_rect_coverage(decode_rect(transformed_outline), f.xy), 0.0, 1.0)); vec4 color = final_color * alpha; diff --git a/gsk/resources/glsl/preamble.fs.glsl b/gsk/resources/glsl/preamble.fs.glsl index 00a8c2135e..5107470e00 100644 --- a/gsk/resources/glsl/preamble.fs.glsl +++ b/gsk/resources/glsl/preamble.fs.glsl @@ -1,12 +1,3 @@ -#ifdef GSK_GL3 -precision highp float; -#endif - -#ifdef GSK_GLES -precision highp float; -#endif - - uniform sampler2D u_source; uniform mat4 u_projection; uniform mat4 u_modelview; @@ -15,36 +6,23 @@ uniform vec4 u_viewport; uniform vec4[3] u_clip_rect; #if GSK_GLES -#define _OUT_ varying -#define _IN_ varying #elif GSK_LEGACY -#define _OUT_ varying -#define _IN_ varying _OUT_ vec4 outputColor; #else -#define _OUT_ out -#define _IN_ in _OUT_ vec4 outputColor; #endif + _IN_ vec2 vUv; -struct RoundedRect +RoundedRect decode_rect(_ROUNDED_RECT_UNIFORM_ r) { - vec4 bounds; - vec4 corner_widths; - vec4 corner_heights; -}; - -// Transform from a GskRoundedRect to a RoundedRect as we need it. -RoundedRect -create_rect(vec4 data[3]) -{ - vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); - vec4 widths = vec4(data[1].x, data[1].z, data[2].x, data[2].z); - vec4 heights = vec4(data[1].y, data[1].w, data[2].y, data[2].w); - return RoundedRect(bounds, widths, heights); +#if defined(GSK_GLES) || defined(GSK_LEGACY) + return RoundedRect(r[0], r[1], r[2]); +#else + return r; +#endif } float @@ -73,15 +51,15 @@ rounded_rect_coverage (RoundedRect r, vec2 p) p.x >= r.bounds.z || p.y >= r.bounds.w) return 0.0; - vec2 rad_tl = vec2(r.corner_widths.x, r.corner_heights.x); - vec2 rad_tr = vec2(r.corner_widths.y, r.corner_heights.y); - vec2 rad_br = vec2(r.corner_widths.z, r.corner_heights.z); - vec2 rad_bl = vec2(r.corner_widths.w, r.corner_heights.w); + vec2 rad_tl = r.corner_points1.xy - r.bounds.xy; + vec2 rad_tr = r.corner_points1.zw - r.bounds.zy; + vec2 rad_br = r.corner_points2.xy - r.bounds.zw; + vec2 rad_bl = r.corner_points2.zw - r.bounds.xw; - vec2 ref_tl = r.bounds.xy + vec2( r.corner_widths.x, r.corner_heights.x); - vec2 ref_tr = r.bounds.zy + vec2(-r.corner_widths.y, r.corner_heights.y); - vec2 ref_br = r.bounds.zw + vec2(-r.corner_widths.z, -r.corner_heights.z); - vec2 ref_bl = r.bounds.xw + vec2( r.corner_widths.w, -r.corner_heights.w); + vec2 ref_tl = r.corner_points1.xy; + vec2 ref_tr = r.corner_points1.zw; + vec2 ref_br = r.corner_points2.xy; + vec2 ref_bl = r.corner_points2.zw; float d_tl = ellipsis_coverage(p, ref_tl, rad_tl); float d_tr = ellipsis_coverage(p, ref_tr, rad_tr); @@ -98,37 +76,8 @@ rounded_rect_coverage (RoundedRect r, vec2 p) return 1.0 - dot(vec4(is_out), corner_coverages); } -// amount is: top, right, bottom, left -RoundedRect -rounded_rect_shrink (RoundedRect r, vec4 amount) -{ - vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; - vec4 new_widths = vec4(0); - vec4 new_heights = vec4(0); - - // Left top - if (r.corner_widths.x > 0.0) new_widths.x = r.corner_widths.x - amount.w; - if (r.corner_heights.x > 0.0) new_heights.x = r.corner_heights.x - amount.x; - - // Top right - if (r.corner_widths.y > 0.0) new_widths.y = r.corner_widths.y - amount.y; - if (r.corner_heights.y > 0.0) new_heights.y = r.corner_heights.y - amount.x; - - // Bottom right - if (r.corner_widths.z > 0.0) new_widths.z = r.corner_widths.z - amount.y; - if (r.corner_heights.z > 0.0) new_heights.z = r.corner_heights.z - amount.z; - - // Bottom left - if (r.corner_widths.w > 0.0) new_widths.w = r.corner_widths.w - amount.w; - if (r.corner_heights.w > 0.0) new_heights.w = r.corner_heights.w - amount.z; - - return RoundedRect (new_bounds, new_widths, new_heights); -} - vec4 Texture(sampler2D sampler, vec2 texCoords) { -#if GSK_GLES - return texture2D(sampler, texCoords); -#elif GSK_LEGACY +#if defined(GSK_GLES) || defined(GSK_LEGACY) return texture2D(sampler, texCoords); #else return texture(sampler, texCoords); @@ -141,9 +90,10 @@ void setOutputColor(vec4 color) { f.x += u_viewport.x; f.y = (u_viewport.y + u_viewport.w) - f.y; -#if GSK_GLES - gl_FragColor = color * rounded_rect_coverage(create_rect(u_clip_rect), f.xy); -#elif GSK_LEGACY + + // We do *NOT* transform the clip rect here since we already + // need to do that on the CPU. +#if defined(GSK_GLES) || defined(GSK_LEGACY) gl_FragColor = color * rounded_rect_coverage(create_rect(u_clip_rect), f.xy); #else outputColor = color * rounded_rect_coverage(create_rect(u_clip_rect), f.xy); diff --git a/gsk/resources/glsl/preamble.glsl b/gsk/resources/glsl/preamble.glsl new file mode 100644 index 0000000000..9dd711cbd2 --- /dev/null +++ b/gsk/resources/glsl/preamble.glsl @@ -0,0 +1,37 @@ +#ifndef GSK_LEGACY +precision highp float; +#endif + +#if defined(GSK_GLES) || defined(GSK_LEGACY) +#define _OUT_ varying +#define _IN_ varying +#define _ROUNDED_RECT_UNIFORM_ vec4[3] +#else +#define _OUT_ out +#define _IN_ in +#define _ROUNDED_RECT_UNIFORM_ RoundedRect +#endif + + +struct RoundedRect +{ + vec4 bounds; + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left +}; + +// Transform from a GskRoundedRect to a RoundedRect as we need it. +RoundedRect +create_rect(vec4[3] data) +{ + vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return RoundedRect(bounds, corner_points1, corner_points2); +} diff --git a/gsk/resources/glsl/preamble.vs.glsl b/gsk/resources/glsl/preamble.vs.glsl index 94c4f276a4..76de2d6561 100644 --- a/gsk/resources/glsl/preamble.vs.glsl +++ b/gsk/resources/glsl/preamble.vs.glsl @@ -2,26 +2,68 @@ uniform mat4 u_projection; uniform mat4 u_modelview; uniform float u_alpha; -#ifdef GSK_GLES -precision highp float; -#endif - -#if GSK_GLES -#define _OUT_ varying -#define _IN_ varying -attribute vec2 aPosition; -attribute vec2 aUv; -_OUT_ vec2 vUv; -#elif GSK_LEGACY -#define _OUT_ varying -#define _IN_ varying +#if defined(GSK_GLES) || defined(GSK_LEGACY) attribute vec2 aPosition; attribute vec2 aUv; _OUT_ vec2 vUv; #else -#define _OUT_ out -#define _IN_ in _IN_ vec2 aPosition; _IN_ vec2 aUv; _OUT_ vec2 vUv; #endif + +// amount is: top, right, bottom, left +RoundedRect +rounded_rect_shrink (RoundedRect r, vec4 amount) +{ + vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; + vec4 new_corner_points1 = r.corner_points1; + vec4 new_corner_points2 = r.corner_points2; + + if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; + if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; + if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; + if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; + + return RoundedRect (new_bounds, new_corner_points1, new_corner_points2); +} + +void +rounded_rect_offset(inout RoundedRect r, vec2 offset) +{ + r.bounds.xy += offset; + r.bounds.zw += offset; + r.corner_points1.xy += offset; + r.corner_points1.zw += offset; + r.corner_points2.xy += offset; + r.corner_points2.zw += offset; +} + +void rounded_rect_transform(inout RoundedRect r, mat4 mat) +{ + r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; + r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; + + r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; + r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; + + r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; + r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; +} + +#if defined(GSK_LEGACY) +// Can't have out or inout array parameters... +#define rounded_rect_encode(r, uni) uni[0] = r.bounds; uni[1] = r.corner_points1; uni[2] = r.corner_points2; +#else +void rounded_rect_encode(RoundedRect r, out _ROUNDED_RECT_UNIFORM_ out_r) +{ +#if defined(GSK_GLES) + out_r[0] = r.bounds; + out_r[1] = r.corner_points1; + out_r[2] = r.corner_points2; +#else + out_r = r; +#endif +} + +#endif diff --git a/gsk/resources/glsl/unblurred_outset_shadow.glsl b/gsk/resources/glsl/unblurred_outset_shadow.glsl index f48288d05c..77c02be8e1 100644 --- a/gsk/resources/glsl/unblurred_outset_shadow.glsl +++ b/gsk/resources/glsl/unblurred_outset_shadow.glsl @@ -1,7 +1,12 @@ // VERTEX_SHADER: uniform vec4 u_color; +uniform float u_spread; +uniform vec2 u_offset; +uniform vec4[3] u_outline_rect; _OUT_ vec4 final_color; +_OUT_ _ROUNDED_RECT_UNIFORM_ transformed_outside_outline; +_OUT_ _ROUNDED_RECT_UNIFORM_ transformed_inside_outline; void main() { gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0); @@ -9,26 +14,33 @@ void main() { final_color = u_color; final_color.rgb *= final_color.a; final_color *= u_alpha; + + RoundedRect inside = create_rect(u_outline_rect); + RoundedRect outside = rounded_rect_shrink(inside, vec4(- u_spread)); + + rounded_rect_offset(outside, u_offset); + + rounded_rect_transform(outside, u_modelview); + rounded_rect_transform(inside, u_modelview); + + rounded_rect_encode(outside, transformed_outside_outline); + rounded_rect_encode(inside, transformed_inside_outline); } // FRAGMENT_SHADER: -uniform float u_spread; -uniform vec2 u_offset; -uniform vec4[3] u_outline_rect; - _IN_ vec4 final_color; +_IN_ _ROUNDED_RECT_UNIFORM_ transformed_outside_outline; +_IN_ _ROUNDED_RECT_UNIFORM_ transformed_inside_outline; void main() { vec4 f = gl_FragCoord; - vec4 color; f.x += u_viewport.x; f.y = (u_viewport.y + u_viewport.w) - f.y; - RoundedRect inside = create_rect(u_outline_rect); - RoundedRect outside = rounded_rect_shrink(inside, vec4(- u_spread)); - color = final_color * clamp (rounded_rect_coverage (outside, f.xy - u_offset) - - rounded_rect_coverage (inside, f.xy), - 0.0, 1.0); - setOutputColor(color); + float alpha = clamp(rounded_rect_coverage(decode_rect(transformed_outside_outline), f.xy) - + rounded_rect_coverage(decode_rect(transformed_inside_outline), f.xy), + 0.0, 1.0); + + setOutputColor(final_color * alpha); } diff --git a/gtk/gtkcssimageicontheme.c b/gtk/gtkcssimageicontheme.c index c2a21c41b9..508c90d435 100644 --- a/gtk/gtkcssimageicontheme.c +++ b/gtk/gtkcssimageicontheme.c @@ -94,21 +94,22 @@ gtk_css_image_icon_theme_snapshot (GtkCssImage *image, if (symbolic) { + const GdkRGBA *fg = &icon_theme->color; + const GdkRGBA *sc = &icon_theme->success; + const GdkRGBA *wc = &icon_theme->warning; + const GdkRGBA *ec = &icon_theme->error; graphene_matrix_t matrix; graphene_vec4_t offset; - GdkRGBA fg = icon_theme->color; - GdkRGBA sc = icon_theme->success; - GdkRGBA wc = icon_theme->warning; - GdkRGBA ec = icon_theme->error; + graphene_matrix_init_from_float (&matrix, (float[16]) { - sc.red - fg.red, sc.green - fg.green, sc.blue - fg.blue, 0, - wc.red - fg.red, wc.green - fg.green, wc.blue - fg.blue, 0, - ec.red - fg.red, ec.green - fg.green, ec.blue - fg.blue, 0, - 0, 0, 0, fg.alpha + sc->red - fg->red, sc->green - fg->green, sc->blue - fg->blue, 0, + wc->red - fg->red, wc->green - fg->green, wc->blue - fg->blue, 0, + ec->red - fg->red, ec->green - fg->green, ec->blue - fg->blue, 0, + 0, 0, 0, fg->alpha }); - graphene_vec4_init (&offset, fg.red, fg.green, fg.blue, 0); + graphene_vec4_init (&offset, fg->red, fg->green, fg->blue, 0); gtk_snapshot_push_color_matrix (snapshot, &matrix, &offset); } diff --git a/gtk/gtkcssimagepaintable.c b/gtk/gtkcssimagepaintable.c index 327ca90862..d4056ab263 100644 --- a/gtk/gtkcssimagepaintable.c +++ b/gtk/gtkcssimagepaintable.c @@ -150,6 +150,14 @@ gtk_css_image_paintable_dispose (GObject *object) G_OBJECT_CLASS (gtk_css_image_paintable_parent_class)->dispose (object); } +static gboolean +gtk_css_image_paintable_is_computed (GtkCssImage *image) +{ + GtkCssImagePaintable *self = GTK_CSS_IMAGE_PAINTABLE (image); + + return (gdk_paintable_get_flags (self->paintable) & GDK_PAINTABLE_IMMUTABLE) == GDK_PAINTABLE_IMMUTABLE; +} + static void gtk_css_image_paintable_class_init (GtkCssImagePaintableClass *klass) { @@ -164,6 +172,7 @@ gtk_css_image_paintable_class_init (GtkCssImagePaintableClass *klass) image_class->compute = gtk_css_image_paintable_compute; image_class->equal = gtk_css_image_paintable_equal; image_class->is_dynamic = gtk_css_image_paintable_is_dynamic; + image_class->is_computed = gtk_css_image_paintable_is_computed; image_class->get_dynamic_image = gtk_css_image_paintable_get_dynamic_image; object_class->dispose = gtk_css_image_paintable_dispose; diff --git a/gtk/gtkcssimagerecolor.c b/gtk/gtkcssimagerecolor.c index 36cc7bd9c4..4094de8a78 100644 --- a/gtk/gtkcssimagerecolor.c +++ b/gtk/gtkcssimagerecolor.c @@ -308,6 +308,15 @@ gtk_css_image_recolor_get_height (GtkCssImage *image) return gdk_texture_get_height (recolor->texture); } +static gboolean +gtk_css_image_recolor_is_computed (GtkCssImage *image) +{ + GtkCssImageRecolor *recolor = GTK_CSS_IMAGE_RECOLOR (image); + + return recolor->texture && + (!recolor->palette || gtk_css_value_is_computed (recolor->palette)); +} + static void _gtk_css_image_recolor_class_init (GtkCssImageRecolorClass *klass) { @@ -320,6 +329,7 @@ _gtk_css_image_recolor_class_init (GtkCssImageRecolorClass *klass) image_class->snapshot = gtk_css_image_recolor_snapshot; image_class->parse = gtk_css_image_recolor_parse; image_class->print = gtk_css_image_recolor_print; + image_class->is_computed = gtk_css_image_recolor_is_computed; object_class->dispose = gtk_css_image_recolor_dispose; } diff --git a/gtk/gtkcssimagescaled.c b/gtk/gtkcssimagescaled.c index 5fce72949b..6dd3b05b4e 100644 --- a/gtk/gtkcssimagescaled.c +++ b/gtk/gtkcssimagescaled.c @@ -203,6 +203,15 @@ gtk_css_image_scaled_parse (GtkCssImage *image, return TRUE; } +static gboolean +gtk_css_image_scaled_is_computed (GtkCssImage *image) +{ + GtkCssImageScaled *self = GTK_CSS_IMAGE_SCALED (image); + + return self->n_images == 1 && + gtk_css_image_is_computed (self->images[0]); +} + static void _gtk_css_image_scaled_class_init (GtkCssImageScaledClass *klass) { @@ -216,6 +225,7 @@ _gtk_css_image_scaled_class_init (GtkCssImageScaledClass *klass) image_class->parse = gtk_css_image_scaled_parse; image_class->compute = gtk_css_image_scaled_compute; image_class->print = gtk_css_image_scaled_print; + image_class->is_computed = gtk_css_image_scaled_is_computed; object_class->dispose = gtk_css_image_scaled_dispose; } diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index f3224d2cb6..283c5163e3 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -10502,12 +10502,15 @@ gtk_widget_do_pick (GtkWidget *widget, { transform = NULL; } - if (gsk_transform_get_category (transform) >= GSK_TRANSFORM_CATEGORY_2D_TRANSLATE) + + if (gsk_transform_get_category (transform) >= GSK_TRANSFORM_CATEGORY_2D_AFFINE) { - float dx, dy; + graphene_point_t transformed_p; - gsk_transform_to_translate (transform, &dx, &dy); - graphene_point3d_init (&res, x + dx, y + dy, 0.); + gsk_transform_transform_point (transform, + &(graphene_point_t) { x, y }, + &transformed_p); + graphene_point3d_init (&res, transformed_p.x, transformed_p.y, 0.); } else { diff --git a/testsuite/gsk/compare/transform-in-transform-in-transform.node b/testsuite/gsk/compare/transform-in-transform-in-transform.node new file mode 100644 index 0000000000..6c8a2f11aa --- /dev/null +++ b/testsuite/gsk/compare/transform-in-transform-in-transform.node @@ -0,0 +1,14 @@ +transform { + child: transform { + child: transform { + child: color { + bounds: 0 0 20 20; + color: blue; + } + transform: translate(0, -20); + } + transform: rotate(90); + } + + transform: translate(300, 200); +} diff --git a/testsuite/gsk/compare/transform-in-transform-in-transform.png b/testsuite/gsk/compare/transform-in-transform-in-transform.png Binary files differnew file mode 100644 index 0000000000..8b8846daca --- /dev/null +++ b/testsuite/gsk/compare/transform-in-transform-in-transform.png diff --git a/testsuite/gsk/compare/transform-in-transform.node b/testsuite/gsk/compare/transform-in-transform.node new file mode 100644 index 0000000000..25689f479b --- /dev/null +++ b/testsuite/gsk/compare/transform-in-transform.node @@ -0,0 +1,10 @@ +transform { + child: transform { + child: color { + bounds: 0 0 20 20; + color: blue; + } + transform: translate(0, -20); + } + transform: scale(2) rotate(90); +} diff --git a/testsuite/gsk/compare/transform-in-transform.png b/testsuite/gsk/compare/transform-in-transform.png Binary files differnew file mode 100644 index 0000000000..90b7de6096 --- /dev/null +++ b/testsuite/gsk/compare/transform-in-transform.png diff --git a/testsuite/gsk/meson.build b/testsuite/gsk/meson.build index aadc40642b..bee40fd32e 100644 --- a/testsuite/gsk/meson.build +++ b/testsuite/gsk/meson.build @@ -64,6 +64,8 @@ compare_render_tests = [ 'inset-shadow-multiple', 'borders-rotated', 'blend-invisible-child', + 'transform-in-transform', + 'transform-in-transform-in-transform', ] # these are too sensitive to differences in the renderers |