From: Matthias Clasen Date: Wed, 8 Feb 2023 03:52:06 +0000 (-0500) Subject: gsk: Introduce GskTextureScaleNode X-Git-Tag: archive/raspbian/4.12.3+ds-1+rpi1~1^2^2^2~22^2~7^2~20^2~8 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=b937c19dd4970b8c516505bfa43bdcc0260ca3e9;p=gtk4.git gsk: Introduce GskTextureScaleNode --- diff --git a/gsk/broadway/gskbroadwayrenderer.c b/gsk/broadway/gskbroadwayrenderer.c index bfd7270f56..6fee960edf 100644 --- a/gsk/broadway/gskbroadwayrenderer.c +++ b/gsk/broadway/gskbroadwayrenderer.c @@ -250,6 +250,7 @@ collect_reused_child_nodes (GskRenderer *renderer, /* Leaf nodes */ case GSK_TEXTURE_NODE: + case GSK_TEXTURE_SCALE_NODE: case GSK_CAIRO_NODE: case GSK_COLOR_NODE: case GSK_BORDER_NODE: @@ -845,6 +846,7 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer, } break; /* Fallback */ + case GSK_TEXTURE_SCALE_NODE: case GSK_TEXT_NODE: case GSK_RADIAL_GRADIENT_NODE: case GSK_REPEATING_LINEAR_GRADIENT_NODE: diff --git a/gsk/gl/gskglrenderjob.c b/gsk/gl/gskglrenderjob.c index e30a1e1341..103f40c029 100644 --- a/gsk/gl/gskglrenderjob.c +++ b/gsk/gl/gskglrenderjob.c @@ -3762,6 +3762,10 @@ gsk_gl_render_job_visit_node (GskGLRenderJob *job, gsk_gl_render_job_visit_texture_node (job, node); break; + case GSK_TEXTURE_SCALE_NODE: + gsk_gl_render_job_visit_as_fallback (job, node); + break; + case GSK_TRANSFORM_NODE: gsk_gl_render_job_visit_transform_node (job, node); break; diff --git a/gsk/gskenums.h b/gsk/gskenums.h index 0dfeb0a0ea..0c92555cfd 100644 --- a/gsk/gskenums.h +++ b/gsk/gskenums.h @@ -35,6 +35,7 @@ * @GSK_CONIC_GRADIENT_NODE: A node drawing a conic gradient * @GSK_BORDER_NODE: A node stroking a border around an area * @GSK_TEXTURE_NODE: A node drawing a `GdkTexture` + * @GSK_TEXTURE_SCALE_NODE: A node drawing a `GdkTexture` scaled and filtered * @GSK_INSET_SHADOW_NODE: A node drawing an inset shadow * @GSK_OUTSET_SHADOW_NODE: A node drawing an outset shadow * @GSK_TRANSFORM_NODE: A node that renders its child after applying a matrix transform @@ -65,6 +66,7 @@ typedef enum { GSK_CONIC_GRADIENT_NODE, GSK_BORDER_NODE, GSK_TEXTURE_NODE, + GSK_TEXTURE_SCALE_NODE, GSK_INSET_SHADOW_NODE, GSK_OUTSET_SHADOW_NODE, GSK_TRANSFORM_NODE, diff --git a/gsk/gskrendernode.h b/gsk/gskrendernode.h index 3fa1d057c2..fb6e1f51f6 100644 --- a/gsk/gskrendernode.h +++ b/gsk/gskrendernode.h @@ -142,6 +142,7 @@ GskRenderNode * gsk_render_node_deserialize (GBytes #define GSK_TYPE_DEBUG_NODE (gsk_debug_node_get_type()) #define GSK_TYPE_COLOR_NODE (gsk_color_node_get_type()) #define GSK_TYPE_TEXTURE_NODE (gsk_texture_node_get_type()) +#define GSK_TYPE_TEXTURE_SCALE_NODE (gsk_texture_scale_node_get_type()) #define GSK_TYPE_LINEAR_GRADIENT_NODE (gsk_linear_gradient_node_get_type()) #define GSK_TYPE_REPEATING_LINEAR_GRADIENT_NODE (gsk_repeating_linear_gradient_node_get_type()) #define GSK_TYPE_RADIAL_GRADIENT_NODE (gsk_radial_gradient_node_get_type()) @@ -168,6 +169,7 @@ GskRenderNode * gsk_render_node_deserialize (GBytes typedef struct _GskDebugNode GskDebugNode; typedef struct _GskColorNode GskColorNode; typedef struct _GskTextureNode GskTextureNode; +typedef struct _GskTextureScaleNode GskTextureScaleNode; typedef struct _GskLinearGradientNode GskLinearGradientNode; typedef struct _GskRepeatingLinearGradientNode GskRepeatingLinearGradientNode; typedef struct _GskRadialGradientNode GskRadialGradientNode; @@ -217,6 +219,17 @@ GskRenderNode * gsk_texture_node_new (GdkTexture GDK_AVAILABLE_IN_ALL GdkTexture * gsk_texture_node_get_texture (const GskRenderNode *node) G_GNUC_PURE; +GDK_AVAILABLE_IN_4_10 +GType gsk_texture_scale_node_get_type (void) G_GNUC_CONST; +GDK_AVAILABLE_IN_4_10 +GskRenderNode * gsk_texture_scale_node_new (GdkTexture *texture, + const graphene_rect_t *bounds, + GskScalingFilter filter); +GDK_AVAILABLE_IN_4_10 +GdkTexture * gsk_texture_scale_node_get_texture (const GskRenderNode *node) G_GNUC_PURE; +GDK_AVAILABLE_IN_4_10 +GskScalingFilter gsk_texture_scale_node_get_filter (const GskRenderNode *node) G_GNUC_PURE; + GDK_AVAILABLE_IN_ALL GType gsk_linear_gradient_node_get_type (void) G_GNUC_CONST; GDK_AVAILABLE_IN_ALL diff --git a/gsk/gskrendernodeimpl.c b/gsk/gskrendernodeimpl.c index cb747802ba..376d32cb4e 100644 --- a/gsk/gskrendernodeimpl.c +++ b/gsk/gskrendernodeimpl.c @@ -1581,6 +1581,191 @@ gsk_texture_node_new (GdkTexture *texture, return node; } +/* }}} */ +/* {{{ GSK_TEXTURE_SCALE_NODE */ + +/** + * GskTextureScaleNode: + * + * A render node for a `GdkTexture`. + */ +struct _GskTextureScaleNode +{ + GskRenderNode render_node; + + GdkTexture *texture; + GskScalingFilter filter; +}; + +static void +gsk_texture_scale_node_finalize (GskRenderNode *node) +{ + GskTextureScaleNode *self = (GskTextureScaleNode *) node; + GskRenderNodeClass *parent_class = g_type_class_peek (g_type_parent (GSK_TYPE_TEXTURE_SCALE_NODE)); + + g_clear_object (&self->texture); + + parent_class->finalize (node); +} + +static void +gsk_texture_scale_node_draw (GskRenderNode *node, + cairo_t *cr) +{ + GskTextureScaleNode *self = (GskTextureScaleNode *) node; + cairo_surface_t *surface; + cairo_pattern_t *pattern; + cairo_matrix_t matrix; + cairo_filter_t filters[] = { + CAIRO_FILTER_BILINEAR, + CAIRO_FILTER_NEAREST, + CAIRO_FILTER_GOOD, + }; + cairo_t *cr2; + cairo_surface_t *surface2; + + surface2 = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + (int) ceilf (node->bounds.size.width), + (int) ceilf (node->bounds.size.height)); + cr2 = cairo_create (surface2); + + cairo_set_source_rgba (cr2, 0, 0, 0, 0); + cairo_paint (cr2); + + surface = gdk_texture_download_surface (self->texture); + pattern = cairo_pattern_create_for_surface (surface); + cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD); + + cairo_matrix_init_scale (&matrix, + gdk_texture_get_width (self->texture) / node->bounds.size.width, + gdk_texture_get_height (self->texture) / node->bounds.size.height); + cairo_pattern_set_matrix (pattern, &matrix); + cairo_pattern_set_filter (pattern, filters[self->filter]); + + cairo_set_source (cr2, pattern); + cairo_pattern_destroy (pattern); + cairo_surface_destroy (surface); + + cairo_rectangle (cr2, 0, 0, node->bounds.size.width, node->bounds.size.height); + cairo_fill (cr2); + + cairo_destroy (cr2); + + cairo_save (cr); + + pattern = cairo_pattern_create_for_surface (surface2); + cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD); + + cairo_matrix_init_identity (&matrix); + cairo_matrix_translate (&matrix, + -node->bounds.origin.x, + -node->bounds.origin.y); + cairo_pattern_set_matrix (pattern, &matrix); + cairo_set_source (cr, pattern); + cairo_pattern_destroy (pattern); + cairo_surface_destroy (surface2); + + gsk_cairo_rectangle (cr, &node->bounds); + cairo_fill (cr); + + cairo_restore (cr); +} + +static void +gsk_texture_scale_node_diff (GskRenderNode *node1, + GskRenderNode *node2, + cairo_region_t *region) +{ + GskTextureScaleNode *self1 = (GskTextureScaleNode *) node1; + GskTextureScaleNode *self2 = (GskTextureScaleNode *) node2; + + if (graphene_rect_equal (&node1->bounds, &node2->bounds) && + self1->texture == self2->texture && + self1->filter == self2->filter) + return; + + gsk_render_node_diff_impossible (node1, node2, region); +} + +/** + * gsk_texture_scale_node_get_texture: + * @node: (type GskTextureNode): a `GskRenderNode` of type %GSK_TEXTURE_SCALE_NODE + * + * Retrieves the `GdkTexture` used when creating this `GskRenderNode`. + * + * Returns: (transfer none): the `GdkTexture` + * + * Since: 4.10 + */ +GdkTexture * +gsk_texture_scale_node_get_texture (const GskRenderNode *node) +{ + const GskTextureScaleNode *self = (const GskTextureScaleNode *) node; + + return self->texture; +} + +/** + * gsk_texture_scale_node_get_filter: + * @node: (type GskTextureNode): a `GskRenderNode` of type %GSK_TEXTURE_SCALE_NODE + * + * Retrieves the `GskScalingFilter` used when creating this `GskRenderNode`. + * + * Returns: (transfer none): the `GskScalingFilter` + * + * Since: 4.10 + */ +GskScalingFilter +gsk_texture_scale_node_get_filter (const GskRenderNode *node) +{ + const GskTextureScaleNode *self = (const GskTextureScaleNode *) node; + + return self->filter; +} + +/** + * gsk_texture_scale_node_new: + * @texture: the texture to scale + * @bounds: the size of the texture to scale to + * @filter: how to scale the texture + * + * Creates a node that scales the texture to the size given by the + * bounds and the filter and then places it at the bounds' position. + * + * This node is intended for tight control over scaling applied + * to a texture, such as in image editors and requires the + * application to be aware of the whole render tree as further + * transforms may be applied that conflict with the desired effect + * of this node. + * + * Returns: (transfer full) (type GskTextureScaleNode): A new `GskRenderNode` + * + * Since: 4.10 + */ +GskRenderNode * +gsk_texture_scale_node_new (GdkTexture *texture, + const graphene_rect_t *bounds, + GskScalingFilter filter) +{ + GskTextureScaleNode *self; + GskRenderNode *node; + + g_return_val_if_fail (GDK_IS_TEXTURE (texture), NULL); + g_return_val_if_fail (bounds != NULL, NULL); + + self = gsk_render_node_alloc (GSK_TEXTURE_SCALE_NODE); + node = (GskRenderNode *) self; + node->offscreen_for_opacity = FALSE; + + self->texture = g_object_ref (texture); + graphene_rect_init_from_rect (&node->bounds, bounds); + self->filter = filter; + + node->prefers_high_depth = gdk_memory_format_prefers_high_depth (gdk_texture_get_format (texture)); + + return node; +} + /* }}} */ /* {{{ GSK_INSET_SHADOW_NODE */ @@ -5357,6 +5542,7 @@ GSK_DEFINE_RENDER_NODE_TYPE (gsk_repeating_radial_gradient_node, GSK_REPEATING_R GSK_DEFINE_RENDER_NODE_TYPE (gsk_conic_gradient_node, GSK_CONIC_GRADIENT_NODE) GSK_DEFINE_RENDER_NODE_TYPE (gsk_border_node, GSK_BORDER_NODE) GSK_DEFINE_RENDER_NODE_TYPE (gsk_texture_node, GSK_TEXTURE_NODE) +GSK_DEFINE_RENDER_NODE_TYPE (gsk_texture_scale_node, GSK_TEXTURE_SCALE_NODE) GSK_DEFINE_RENDER_NODE_TYPE (gsk_inset_shadow_node, GSK_INSET_SHADOW_NODE) GSK_DEFINE_RENDER_NODE_TYPE (gsk_outset_shadow_node, GSK_OUTSET_SHADOW_NODE) GSK_DEFINE_RENDER_NODE_TYPE (gsk_transform_node, GSK_TRANSFORM_NODE) @@ -5536,6 +5722,22 @@ gsk_render_node_init_types_once (void) gsk_render_node_types[GSK_TEXTURE_NODE] = node_type; } + { + const GskRenderNodeTypeInfo node_info = + { + GSK_TEXTURE_SCALE_NODE, + sizeof (GskTextureScaleNode), + NULL, + gsk_texture_scale_node_finalize, + gsk_texture_scale_node_draw, + NULL, + gsk_texture_scale_node_diff, + }; + + GType node_type = gsk_render_node_type_register_static (I_("GskTextureScaleNode"), &node_info); + gsk_render_node_types[GSK_TEXTURE_SCALE_NODE] = node_type; + } + { const GskRenderNodeTypeInfo node_info = { diff --git a/gsk/vulkan/gskvulkanrenderpass.c b/gsk/vulkan/gskvulkanrenderpass.c index 48127e20b9..3008c42154 100644 --- a/gsk/vulkan/gskvulkanrenderpass.c +++ b/gsk/vulkan/gskvulkanrenderpass.c @@ -440,6 +440,9 @@ gsk_vulkan_render_pass_add_node (GskVulkanRenderPass *self, g_array_append_val (self->render_ops, op); return; + case GSK_TEXTURE_SCALE_NODE: + goto fallback; + case GSK_COLOR_NODE: if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds)) pipeline_type = GSK_VULKAN_PIPELINE_COLOR; diff --git a/gtk/inspector/recorder.c b/gtk/inspector/recorder.c index e33d058b05..53528a26cb 100644 --- a/gtk/inspector/recorder.c +++ b/gtk/inspector/recorder.c @@ -264,6 +264,7 @@ create_list_model_for_render_node (GskRenderNode *node) case GSK_CAIRO_NODE: case GSK_TEXT_NODE: case GSK_TEXTURE_NODE: + case GSK_TEXTURE_SCALE_NODE: case GSK_COLOR_NODE: case GSK_LINEAR_GRADIENT_NODE: case GSK_REPEATING_LINEAR_GRADIENT_NODE: @@ -402,6 +403,8 @@ node_type_name (GskRenderNodeType type) return "Border"; case GSK_TEXTURE_NODE: return "Texture"; + case GSK_TEXTURE_SCALE_NODE: + return "Scaled Texture"; case GSK_INSET_SHADOW_NODE: return "Inset Shadow"; case GSK_OUTSET_SHADOW_NODE: @@ -476,6 +479,11 @@ node_name (GskRenderNode *node) GdkTexture *texture = gsk_texture_node_get_texture (node); return g_strdup_printf ("%dx%d Texture", gdk_texture_get_width (texture), gdk_texture_get_height (texture)); } + case GSK_TEXTURE_SCALE_NODE: + { + GdkTexture *texture = gsk_texture_node_get_texture (node); + return g_strdup_printf ("%dx%d Texture, Filter %d", gdk_texture_get_width (texture), gdk_texture_get_height (texture), gsk_texture_scale_node_get_filter (node)); + } } } @@ -933,6 +941,18 @@ populate_render_node_properties (GListStore *store, } break; + case GSK_TEXTURE_SCALE_NODE: + { + GdkTexture *texture = g_object_ref (gsk_texture_scale_node_get_texture (node)); + GskScalingFilter filter = gsk_texture_scale_node_get_filter (node); + g_list_store_append (store, object_property_new ("Texture", "", texture)); + + tmp = g_enum_to_string (GSK_TYPE_SCALING_FILTER, filter); + add_text_row (store, "Filter", tmp); + g_free (tmp); + } + break; + case GSK_COLOR_NODE: add_color_row (store, "Color", gsk_color_node_get_color (node)); break;