diff options
author | Benjamin Otte <otte@redhat.com> | 2016-12-21 20:23:46 +0100 |
---|---|---|
committer | Benjamin Otte <otte@redhat.com> | 2016-12-23 08:11:01 +0100 |
commit | 373e08d6d4ea35dbc937a012ef864fd36bb6e42d (patch) | |
tree | 9bca39da5924d122a3bac7fa50a1c754ce5fecd5 /gsk | |
parent | 98086014d85ea60862c3cb0598e7b6c8cf7fb072 (diff) | |
download | gtk+-373e08d6d4ea35dbc937a012ef864fd36bb6e42d.tar.gz |
gsk: Add gsk_renderer_render_texture()
... and implement it for the Cairo renderer.
It's an API that instructs a renderer to render to a texture.
So far this is mostly meant to be used for testing, but I could imagine
it being useful for rendering DND icons.
Diffstat (limited to 'gsk')
-rw-r--r-- | gsk/gskcairorenderer.c | 70 | ||||
-rw-r--r-- | gsk/gskrenderer.c | 80 | ||||
-rw-r--r-- | gsk/gskrenderer.h | 5 | ||||
-rw-r--r-- | gsk/gskrendererprivate.h | 3 |
4 files changed, 140 insertions, 18 deletions
diff --git a/gsk/gskcairorenderer.c b/gsk/gskcairorenderer.c index d112e4fca0..af23d610f6 100644 --- a/gsk/gskcairorenderer.c +++ b/gsk/gskcairorenderer.c @@ -45,17 +45,62 @@ gsk_cairo_renderer_unrealize (GskRenderer *renderer) } static void -gsk_cairo_renderer_render (GskRenderer *renderer, - GskRenderNode *root) +gsk_cairo_renderer_do_render (GskRenderer *renderer, + cairo_t *cr, + GskRenderNode *root) { - GskCairoRenderer *self = GSK_CAIRO_RENDERER (renderer); - GdkDrawingContext *context = gsk_renderer_get_drawing_context (renderer); - graphene_rect_t viewport; #ifdef G_ENABLE_DEBUG + GskCairoRenderer *self = GSK_CAIRO_RENDERER (renderer); GskProfiler *profiler; gint64 cpu_time; #endif +#ifdef G_ENABLE_DEBUG + profiler = gsk_renderer_get_profiler (renderer); + gsk_profiler_timer_begin (profiler, self->profile_timers.cpu_time); +#endif + + gsk_render_node_draw (root, cr); + +#ifdef G_ENABLE_DEBUG + cpu_time = gsk_profiler_timer_end (profiler, self->profile_timers.cpu_time); + gsk_profiler_timer_set (profiler, self->profile_timers.cpu_time, cpu_time); + + gsk_profiler_push_samples (profiler); +#endif +} + +static GskTexture * +gsk_cairo_renderer_render_texture (GskRenderer *renderer, + GskRenderNode *root, + const graphene_rect_t *viewport) +{ + GskTexture *texture; + cairo_surface_t *surface; + cairo_t *cr; + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, ceil (viewport->size.width), ceil (viewport->size.height)); + cr = cairo_create (surface); + + cairo_translate (cr, - viewport->origin.x, - viewport->origin.y); + + gsk_cairo_renderer_do_render (renderer, cr, root); + + cairo_destroy (cr); + + texture = gsk_texture_new_for_surface (surface); + cairo_surface_destroy (surface); + + return texture; +} + +static void +gsk_cairo_renderer_render (GskRenderer *renderer, + GskRenderNode *root) +{ + GdkDrawingContext *context = gsk_renderer_get_drawing_context (renderer); + graphene_rect_t viewport; + cairo_t *cr; cr = gdk_drawing_context_get_cairo_context (context); @@ -78,19 +123,7 @@ gsk_cairo_renderer_render (GskRenderer *renderer, cairo_restore (cr); } -#ifdef G_ENABLE_DEBUG - profiler = gsk_renderer_get_profiler (renderer); - gsk_profiler_timer_begin (profiler, self->profile_timers.cpu_time); -#endif - - gsk_render_node_draw (root, cr); - -#ifdef G_ENABLE_DEBUG - cpu_time = gsk_profiler_timer_end (profiler, self->profile_timers.cpu_time); - gsk_profiler_timer_set (profiler, self->profile_timers.cpu_time, cpu_time); - - gsk_profiler_push_samples (profiler); -#endif + gsk_cairo_renderer_do_render (renderer, cr, root); } static void @@ -101,6 +134,7 @@ gsk_cairo_renderer_class_init (GskCairoRendererClass *klass) renderer_class->realize = gsk_cairo_renderer_realize; renderer_class->unrealize = gsk_cairo_renderer_unrealize; renderer_class->render = gsk_cairo_renderer_render; + renderer_class->render_texture = gsk_cairo_renderer_render_texture; } static void diff --git a/gsk/gskrenderer.c b/gsk/gskrenderer.c index b50ebd7f56..87a4074735 100644 --- a/gsk/gskrenderer.c +++ b/gsk/gskrenderer.c @@ -113,6 +113,15 @@ gsk_renderer_real_unrealize (GskRenderer *self) GSK_RENDERER_WARN_NOT_IMPLEMENTED_METHOD (self, unrealize); } +static GskTexture * +gsk_renderer_real_render_texture (GskRenderer *self, + GskRenderNode *root, + const graphene_rect_t *viewport) +{ + GSK_RENDERER_WARN_NOT_IMPLEMENTED_METHOD (self, render_texture); + return NULL; +} + static GdkDrawingContext * gsk_renderer_real_begin_draw_frame (GskRenderer *self, const cairo_region_t *region) @@ -259,6 +268,7 @@ gsk_renderer_class_init (GskRendererClass *klass) klass->begin_draw_frame = gsk_renderer_real_begin_draw_frame; klass->end_draw_frame = gsk_renderer_real_end_draw_frame; klass->render = gsk_renderer_real_render; + klass->render_texture = gsk_renderer_real_render_texture; klass->create_cairo_surface = gsk_renderer_real_create_cairo_surface; gobject_class->constructed = gsk_renderer_constructed; @@ -607,6 +617,76 @@ gsk_renderer_unrealize (GskRenderer *renderer) } /** + * gsk_renderer_render_texture: + * @renderer: a realized #GdkRenderer + * @root: a #GskRenderNode + * @viewport: (allow-none): the section to draw or %NULL to use @root's bounds + * + * Renders the scene graph, described by a tree of #GskRenderNode instances, + * to a #GskTexture. + * + * The @renderer will acquire a reference on the #GskRenderNode tree while + * the rendering is in progress, and will make the tree immutable. + * + * If you want to apply any transformations to @root, you should put it into a + * transform node and pass that node instead. + * + * Returns: (transfer full): a #GskTexture with the rendered contents of @root. + * + * Since: 3.90 + */ +GskTexture * +gsk_renderer_render_texture (GskRenderer *renderer, + GskRenderNode *root, + const graphene_rect_t *viewport) +{ + GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer); + graphene_rect_t real_viewport; + GskTexture *texture; + + g_return_val_if_fail (GSK_IS_RENDERER (renderer), NULL); + g_return_val_if_fail (priv->is_realized, NULL); + g_return_val_if_fail (GSK_IS_RENDER_NODE (root), NULL); + g_return_val_if_fail (priv->root_node == NULL, NULL); + + priv->root_node = gsk_render_node_ref (root); + gsk_render_node_make_immutable (priv->root_node); + + if (viewport == NULL) + { + gsk_render_node_get_bounds (root, &real_viewport); + viewport = &real_viewport; + } + +#ifdef G_ENABLE_DEBUG + gsk_profiler_reset (priv->profiler); +#endif + + texture = GSK_RENDERER_GET_CLASS (renderer)->render_texture (renderer, root, viewport); + +#ifdef G_ENABLE_DEBUG + if (GSK_DEBUG_CHECK (RENDERER)) + { + GString *buf = g_string_new ("*** Texture stats ***\n\n"); + + gsk_profiler_append_counters (priv->profiler, buf); + g_string_append_c (buf, '\n'); + + gsk_profiler_append_timers (priv->profiler, buf); + g_string_append_c (buf, '\n'); + + g_print ("%s\n***\n\n", buf->str); + + g_string_free (buf, TRUE); + } +#endif + + g_clear_pointer (&priv->root_node, gsk_render_node_unref); + + return texture; +} + +/** * gsk_renderer_render: * @renderer: a #GskRenderer * @root: a #GskRenderNode diff --git a/gsk/gskrenderer.h b/gsk/gskrenderer.h index 7e62c39b71..0873cf76fa 100644 --- a/gsk/gskrenderer.h +++ b/gsk/gskrenderer.h @@ -66,6 +66,11 @@ GDK_AVAILABLE_IN_3_90 void gsk_renderer_unrealize (GskRenderer *renderer); GDK_AVAILABLE_IN_3_90 +GskTexture * gsk_renderer_render_texture (GskRenderer *renderer, + GskRenderNode *root, + const graphene_rect_t *viewport); + +GDK_AVAILABLE_IN_3_90 GdkDrawingContext * gsk_renderer_begin_draw_frame (GskRenderer *renderer, const cairo_region_t *region); GDK_AVAILABLE_IN_3_90 diff --git a/gsk/gskrendererprivate.h b/gsk/gskrendererprivate.h index cad512782f..d9dbe9eca0 100644 --- a/gsk/gskrendererprivate.h +++ b/gsk/gskrendererprivate.h @@ -42,6 +42,9 @@ struct _GskRendererClass GError **error); void (* unrealize) (GskRenderer *renderer); + GskTexture * (* render_texture) (GskRenderer *renderer, + GskRenderNode *root, + const graphene_rect_t *viewport); GdkDrawingContext * (* begin_draw_frame) (GskRenderer *renderer, const cairo_region_t *region); void (* end_draw_frame) (GskRenderer *renderer, |