summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Otte <otte@redhat.com>2016-12-21 20:23:46 +0100
committerBenjamin Otte <otte@redhat.com>2016-12-22 04:17:57 +0100
commit67d0fd06b871bd57bfb0f1c5c559148a8cc662fb (patch)
tree291e409cb3058f2d5fd0b949e946ed4558d2c776
parent9d89e4981bfdeceeffc00876b4b8730db3cfa82f (diff)
downloadgtk+-67d0fd06b871bd57bfb0f1c5c559148a8cc662fb.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.
-rw-r--r--docs/reference/gsk/gsk4-sections.txt1
-rw-r--r--gsk/gskcairorenderer.c70
-rw-r--r--gsk/gskrenderer.c80
-rw-r--r--gsk/gskrenderer.h5
-rw-r--r--gsk/gskrendererprivate.h3
5 files changed, 141 insertions, 18 deletions
diff --git a/docs/reference/gsk/gsk4-sections.txt b/docs/reference/gsk/gsk4-sections.txt
index 45b48699dd..a67ccc19db 100644
--- a/docs/reference/gsk/gsk4-sections.txt
+++ b/docs/reference/gsk/gsk4-sections.txt
@@ -12,6 +12,7 @@ gsk_renderer_unrealize
gsk_renderer_begin_draw_frame
gsk_renderer_end_draw_frame
gsk_renderer_render
+gsk_renderer_render_texture
<SUBSECTION Standard>
GSK_IS_RENDERER
GSK_RENDERER
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,