[gtk/matthiasc/glshader-node: 11/18] snapshot: Drop n_children from push_gl_shader and use custom pop
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/matthiasc/glshader-node: 11/18] snapshot: Drop n_children from push_gl_shader and use custom pop
- Date: Mon, 28 Sep 2020 16:52:32 +0000 (UTC)
commit 48cb5ca3db0a86fada9ac200786c583a65da20a0
Author: Alexander Larsson <alexl redhat com>
Date: Mon Sep 28 12:59:27 2020 +0200
snapshot: Drop n_children from push_gl_shader and use custom pop
We now always assume you pass the right amount of children for the
shader, and each such child is followed by
gtk_snapshot_gl_shader_pop_texture() and then a final
gtk_snapshot_pop().
This means we handle the 0 child case ok, and that we can validate
that the number of pops of various types are correct.
demos/gtk-demo/gskshaderpaintable.c | 7 +-
demos/gtk-demo/gtkshaderbin.c | 4 +-
demos/gtk-demo/gtkshaderstack.c | 8 +-
gtk/gtksnapshot.c | 174 ++++++++++++++++++++++++++----------
gtk/gtksnapshot.h | 6 +-
5 files changed, 136 insertions(+), 63 deletions(-)
---
diff --git a/demos/gtk-demo/gskshaderpaintable.c b/demos/gtk-demo/gskshaderpaintable.c
index c441714113..a6a6832365 100644
--- a/demos/gtk-demo/gskshaderpaintable.c
+++ b/demos/gtk-demo/gskshaderpaintable.c
@@ -76,12 +76,7 @@ gsk_shader_paintable_paintable_snapshot (GdkPaintable *paintable,
{
GskShaderPaintable *self = GSK_SHADER_PAINTABLE (paintable);
- /* FIXME: We have to add a pointless extra child here to
- * keep GtkSnapshot from blowing up. We really want n_children = 0,
- * but then we would pop() 0 times, and... no pop, no node.
- */
- gtk_snapshot_push_gl_shader (snapshot, self->shader, &GRAPHENE_RECT_INIT(0, 0, width, height), g_bytes_ref
(self->uniform_data), 1);
- gtk_snapshot_append_color (snapshot, &(GdkRGBA){1.0, 0.5, 0.6, 1.0}, &GRAPHENE_RECT_INIT(0, 0, width,
height));
+ gtk_snapshot_push_gl_shader (snapshot, self->shader, &GRAPHENE_RECT_INIT(0, 0, width, height), g_bytes_ref
(self->uniform_data));
gtk_snapshot_pop (snapshot);
}
diff --git a/demos/gtk-demo/gtkshaderbin.c b/demos/gtk-demo/gtkshaderbin.c
index c728458090..14f5651ac6 100644
--- a/demos/gtk-demo/gtkshaderbin.c
+++ b/demos/gtk-demo/gtkshaderbin.c
@@ -202,9 +202,9 @@ gtk_shader_bin_snapshot (GtkWidget *widget,
&GRAPHENE_RECT_INIT(0, 0, width, height),
gsk_gl_shader_format_args (self->active_shader->shader,
"u_time", &self->time,
- NULL),
- 1);
+ NULL));
gtk_widget_snapshot_child (widget, self->child, snapshot);
+ gtk_snapshot_gl_shader_pop_texture (snapshot);
gtk_snapshot_pop (snapshot);
return;
diff --git a/demos/gtk-demo/gtkshaderstack.c b/demos/gtk-demo/gtkshaderstack.c
index 32dbc1e658..c84aa232f0 100644
--- a/demos/gtk-demo/gtkshaderstack.c
+++ b/demos/gtk-demo/gtkshaderstack.c
@@ -246,13 +246,13 @@ gtk_shader_stack_snapshot (GtkWidget *widget,
&GRAPHENE_RECT_INIT(0, 0, width, height),
gsk_gl_shader_format_args (self->shader,
"progress", &progress,
- NULL),
- 2);
+ NULL));
gtk_widget_snapshot_child (widget, current, snapshot);
- gtk_snapshot_pop (snapshot); /* current child */
+ gtk_snapshot_gl_shader_pop_texture (snapshot); /* current child */
gtk_widget_snapshot_child (widget, next, snapshot);
- gtk_snapshot_pop (snapshot); /* next child */
+ gtk_snapshot_gl_shader_pop_texture (snapshot); /* next child */
+ gtk_snapshot_pop (snapshot);
}
else
{
diff --git a/gtk/gtksnapshot.c b/gtk/gtksnapshot.c
index 1f5af89655..685af380b9 100644
--- a/gtk/gtksnapshot.c
+++ b/gtk/gtksnapshot.c
@@ -95,10 +95,14 @@ struct _GtkSnapshotState {
GskGLShader *shader;
GBytes *args;
graphene_rect_t bounds;
- int n_children;
- int node_idx;
GskRenderNode **nodes;
+ GskRenderNode *internal_nodes[4];
} glshader;
+ struct {
+ graphene_rect_t bounds;
+ int node_idx;
+ int n_children;
+ } glshader_texture;
struct {
GskRoundedRect bounds;
} rounded_clip;
@@ -238,6 +242,18 @@ gtk_snapshot_get_previous_state (const GtkSnapshot *snapshot)
return gtk_snapshot_states_get (&snapshot->state_stack, size - 2);
}
+/* n == 0 => current, n == 1, previous, etc */
+static GtkSnapshotState *
+gtk_snapshot_get_nth_previous_state (const GtkSnapshot *snapshot,
+ int n)
+{
+ gsize size = gtk_snapshot_states_get_size (&snapshot->state_stack);
+
+ g_assert (size > n);
+
+ return gtk_snapshot_states_get (&snapshot->state_stack, size - (1 + n));
+}
+
static void
gtk_snapshot_state_clear (GtkSnapshotState *state)
{
@@ -823,59 +839,88 @@ gtk_snapshot_push_clip (GtkSnapshot *snapshot,
static GskRenderNode *
gtk_snapshot_collect_gl_shader (GtkSnapshot *snapshot,
GtkSnapshotState *state,
- GskRenderNode **nodes,
- guint n_nodes)
+ GskRenderNode **collected_nodes,
+ guint n_collected_nodes)
{
- GskRenderNode *shader_node = NULL, *child_node;
- GdkRGBA transparent = { 0, 0, 0, 0 };
-
- child_node = gtk_snapshot_collect_default (snapshot, state, nodes, n_nodes);
-
- if (child_node == NULL)
- child_node = gsk_color_node_new (&transparent, &state->data.glshader.bounds);
-
- state->data.glshader.nodes[state->data.glshader.node_idx] = child_node;
+ GskRenderNode *shader_node = NULL;
+ GskRenderNode **nodes;
+ int n_children;
- if (state->data.glshader.node_idx != state->data.glshader.n_children - 1)
- return NULL; /* Not last */
+ n_children = gsk_gl_shader_get_n_required_textures (state->data.glshader.shader);
+ shader_node = NULL;
- /* This is the last pop */
+ if (n_collected_nodes != 0)
+ g_warning ("Unexpected children when poping gl shader.");
- shader_node = NULL;
+ if (state->data.glshader.nodes)
+ nodes = state->data.glshader.nodes;
+ else
+ nodes = &state->data.glshader.internal_nodes[0];
if (state->data.glshader.bounds.size.width != 0 &&
state->data.glshader.bounds.size.height != 0)
- {
- shader_node = gsk_gl_shader_node_new (state->data.glshader.shader,
- &state->data.glshader.bounds,
- state->data.glshader.args,
- &state->data.glshader.nodes[0],
- state->data.glshader.n_children);
- }
+ shader_node = gsk_gl_shader_node_new (state->data.glshader.shader,
+ &state->data.glshader.bounds,
+ state->data.glshader.args,
+ nodes, n_children);
g_object_unref (state->data.glshader.shader);
g_bytes_unref (state->data.glshader.args);
- for (guint i = 0; i < state->data.glshader.n_children; i++)
- gsk_render_node_unref (state->data.glshader.nodes[i]);
+
+ for (guint i = 0; i < n_children; i++)
+ gsk_render_node_unref (nodes[i]);
+
g_free (state->data.glshader.nodes);
return shader_node;
}
+static GskRenderNode *
+gtk_snapshot_collect_gl_shader_texture (GtkSnapshot *snapshot,
+ GtkSnapshotState *state,
+ GskRenderNode **nodes,
+ guint n_nodes)
+{
+ GskRenderNode *child_node;
+ GdkRGBA transparent = { 0, 0, 0, 0 };
+ int n_children, node_idx;
+ GtkSnapshotState *glshader_state;
+ GskRenderNode **out_nodes;
+
+ child_node = gtk_snapshot_collect_default (snapshot, state, nodes, n_nodes);
+
+ if (child_node == NULL)
+ child_node = gsk_color_node_new (&transparent, &state->data.glshader_texture.bounds);
+
+ n_children = state->data.glshader_texture.n_children;
+ node_idx = state->data.glshader_texture.node_idx;
+
+ glshader_state = gtk_snapshot_get_nth_previous_state (snapshot, n_children - node_idx);
+ g_assert (glshader_state->collect_func == gtk_snapshot_collect_gl_shader);
+
+ if (glshader_state->data.glshader.nodes)
+ out_nodes = glshader_state->data.glshader.nodes;
+ else
+ out_nodes = &glshader_state->data.glshader.internal_nodes[0];
+
+ out_nodes[node_idx] = child_node;
+
+ return NULL;
+}
+
/**
* gtk_snapshot_push_gl_shader:
* @snapshot: a #GtkSnapshot
* @shader: The code to run
* @bounds: the rectangle to render into
* @take_args: (transfer full): Data block with arguments for the shader.
- * @n_children: The number of extra nodes given as argument to the shader as textures.
*
* Push a #GskGLShaderNode with a specific #GskGLShader and a set of uniform values
* to use while rendering. Additionally this takes a list of @n_children other nodes
* which will be passed to the #GskGLShaderNode.
*
* The @take_args argument is a block of data to use for uniform
- * input, as per types and offsets defined by the @shader. Normally this is
+ * arguments, as per types and offsets defined by the @shader. Normally this is
* generated by gsk_gl_shader_format_args() or #GskGLShaderArgBuilder.
* The snapshotter takes ownership of @take_args, so the caller should not free it
* after this.
@@ -885,10 +930,16 @@ gtk_snapshot_collect_gl_shader (GtkSnapshot *snapshot,
* gsk_gl_shader_try_compile_for() to ensure the @shader will work for the renderer
* before using it.
*
- * If @n_children > 0, then it is expected that you (after the fallback call
- * gtk_snapshot_pop() @n_children times. Each of these will generate a node that
- * is added as a child to the gl shader node, which in turn will render these to
- * textures and pass as arguments to the shader.
+ * If the shader requires textures (see gsk_gl_shader_get_n_required_textures()), then it is
+ * expected that you call gtk_snapshot_gl_shader_pop_texture() the number of times that are
+ * required. Each of these calls will generate a node that is added as a child to the gl shader
+ * node, which in turn will render these offscreen and pass as a texture to the shader.
+ *
+ * Once all textures (if any) are pop:ed, you must call the regular gtk_snapshot_pop().
+ *
+ * If you want to use pre-existing textures as input to the shader rather than
+ * rendering new ones, use gtk_snapshot_append_texture() to push a texture node. These
+ * will be used directly rather than being re-rendered.
*
* For details on how to write shaders, see #GskGLShader.
*/
@@ -896,14 +947,12 @@ void
gtk_snapshot_push_gl_shader (GtkSnapshot *snapshot,
GskGLShader *shader,
const graphene_rect_t *bounds,
- GBytes *take_args,
- int n_children)
+ GBytes *take_args)
{
GtkSnapshotState *state;
float scale_x, scale_y, dx, dy;
- GskRenderNode **nodes;
- int node_idx;
graphene_rect_t transformed_bounds;
+ int n_children = gsk_gl_shader_get_n_required_textures (shader);
gtk_snapshot_ensure_affine (snapshot, &scale_x, &scale_y, &dx, &dy);
@@ -914,22 +963,19 @@ gtk_snapshot_push_gl_shader (GtkSnapshot *snapshot,
state->data.glshader.bounds = transformed_bounds;
state->data.glshader.shader = g_object_ref (shader);
state->data.glshader.args = take_args; /* Takes ownership */
- state->data.glshader.n_children = n_children;
- nodes = g_new0 (GskRenderNode *, n_children);
- node_idx = n_children-1; /* We pop in reverse order */
-
- state->data.glshader.node_idx = node_idx--;
- state->data.glshader.nodes = nodes;
+ if (n_children <= G_N_ELEMENTS (state->data.glshader.internal_nodes))
+ state->data.glshader.nodes = NULL;
+ else
+ state->data.glshader.nodes = g_new (GskRenderNode *, n_children);
- for (int i = 0; i < n_children-1; i++)
+ for (int i = 0; i < n_children; i++)
{
state = gtk_snapshot_push_state (snapshot,
gtk_snapshot_get_current_state (snapshot)->transform,
- gtk_snapshot_collect_gl_shader);
- state->data.glshader.node_idx = node_idx--;
- state->data.glshader.n_children = n_children;
- state->data.glshader.nodes = nodes;
- state->data.glshader.bounds = transformed_bounds;
+ gtk_snapshot_collect_gl_shader_texture);
+ state->data.glshader_texture.bounds = transformed_bounds;
+ state->data.glshader_texture.node_idx = n_children - 1 - i;/* We pop in reverse order */
+ state->data.glshader_texture.n_children = n_children;
}
}
@@ -1433,14 +1479,46 @@ gtk_snapshot_to_paintable (GtkSnapshot *snapshot,
void
gtk_snapshot_pop (GtkSnapshot *snapshot)
{
+ GtkSnapshotState *state = gtk_snapshot_get_current_state (snapshot);
GskRenderNode *node;
+ if (state->collect_func == gtk_snapshot_collect_gl_shader_texture)
+ g_warning ("Not enough calls to gtk_snapshot_gl_shader_pop_texture().");
+
node = gtk_snapshot_pop_internal (snapshot);
if (node)
gtk_snapshot_append_node_internal (snapshot, node);
}
+/**
+ * gtk_snapshot_gl_shader_pop_texture:
+ * @snapshot: a #GtkSnapshot
+ *
+ * Removes the top element from the stack of render nodes and
+ * adds it to the nearest GskGLShaderNode below it. This must be called the
+ * same number of times as the number of textures is needed for the
+ * shader in gtk_snapshot_push_gl_shader().
+ */
+void
+gtk_snapshot_gl_shader_pop_texture (GtkSnapshot *snapshot)
+{
+ GtkSnapshotState *state = gtk_snapshot_get_current_state (snapshot);
+ GskRenderNode *node;
+
+ if (state->collect_func != gtk_snapshot_collect_gl_shader_texture)
+ {
+ g_warning ("Too many calls to gtk_snapshot_gl_shader_pop_texture().");
+ return;
+ }
+
+ g_assert (state->collect_func == gtk_snapshot_collect_gl_shader_texture);
+
+ node = gtk_snapshot_pop_internal (snapshot);
+ g_assert (node == NULL);
+}
+
+
/**
* gtk_snapshot_save:
* @snapshot: a #GtkSnapshot
diff --git a/gtk/gtksnapshot.h b/gtk/gtksnapshot.h
index de8f554159..19e0045b17 100644
--- a/gtk/gtksnapshot.h
+++ b/gtk/gtksnapshot.h
@@ -102,11 +102,11 @@ GDK_AVAILABLE_IN_ALL
void gtk_snapshot_push_gl_shader (GtkSnapshot *snapshot,
GskGLShader *shader,
const graphene_rect_t *bounds,
- GBytes *take_args,
- int n_children);
+ GBytes *take_args);
+GDK_AVAILABLE_IN_ALL
+void gtk_snapshot_gl_shader_pop_texture (GtkSnapshot *snapshot);
GDK_AVAILABLE_IN_ALL
void gtk_snapshot_pop (GtkSnapshot *snapshot);
-
GDK_AVAILABLE_IN_ALL
void gtk_snapshot_save (GtkSnapshot *snapshot);
GDK_AVAILABLE_IN_ALL
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]