[gtk/matthiasc/glshader-demo: 5/9] GtkSnapshot: Add gtk_snapshot_push_glshader()
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/matthiasc/glshader-demo: 5/9] GtkSnapshot: Add gtk_snapshot_push_glshader()
- Date: Tue, 22 Sep 2020 02:17:57 +0000 (UTC)
commit f7978c784f295e0fd10ab6499567e16479062dfc
Author: Alexander Larsson <alexl redhat com>
Date: Fri Sep 18 17:56:02 2020 +0200
GtkSnapshot: Add gtk_snapshot_push_glshader()
This is a helper to create GskGLShader nodes
gtk/gtksnapshot.c | 124 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
gtk/gtksnapshot.h | 6 +++
2 files changed, 130 insertions(+)
---
diff --git a/gtk/gtksnapshot.c b/gtk/gtksnapshot.c
index 3b7c5173a8..d1f1375ad9 100644
--- a/gtk/gtksnapshot.c
+++ b/gtk/gtksnapshot.c
@@ -91,6 +91,14 @@ struct _GtkSnapshotState {
struct {
graphene_rect_t bounds;
} clip;
+ struct {
+ GskGLShader *shader;
+ graphene_vec4_t args;
+ graphene_rect_t bounds;
+ int n_children;
+ int node_idx;
+ GskRenderNode **nodes;
+ } glshader;
struct {
GskRoundedRect bounds;
} rounded_clip;
@@ -812,6 +820,122 @@ gtk_snapshot_push_clip (GtkSnapshot *snapshot,
gtk_graphene_rect_scale_affine (bounds, scale_x, scale_y, dx, dy, &state->data.clip.bounds);
}
+static GskRenderNode *
+maybe_clip (GskRenderNode *node,
+ const graphene_rect_t *bounds)
+{
+ if (node &&
+ !graphene_rect_contains_rect (bounds, &node->bounds))
+ {
+ return gsk_clip_node_new (node, bounds);
+ }
+
+ return gsk_render_node_ref (node);
+}
+
+static GskRenderNode *
+gtk_snapshot_collect_glshader (GtkSnapshot *snapshot,
+ GtkSnapshotState *state,
+ GskRenderNode **nodes,
+ guint n_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;
+
+ if (state->data.glshader.node_idx != state->data.glshader.n_children)
+ return NULL; /* Not last */
+
+ /* This is the last pop */
+
+ shader_node = NULL;
+
+ if (state->data.glshader.bounds.size.width != 0 &&
+ state->data.glshader.bounds.size.height != 0)
+ {
+ GskRenderNode *fallback_node = maybe_clip (state->data.glshader.nodes[0],
+ &state->data.glshader.bounds);
+ shader_node = gsk_glshader_node_new (state->data.glshader.shader,
+ &state->data.glshader.args,
+ &state->data.glshader.bounds,
+ fallback_node,
+ &state->data.glshader.nodes[1],
+ state->data.glshader.n_children);
+ gsk_render_node_unref (fallback_node);
+ }
+
+ g_object_unref (state->data.glshader.shader);
+ for (guint i = 0; i < state->data.glshader.n_children + 1; i++)
+ gsk_render_node_unref (state->data.glshader.nodes[i]);
+ g_free (state->data.glshader.nodes);
+
+ return shader_node;
+}
+
+/**
+ * gtk_snapshot_push_glshader:
+ * @snapshot: a #GtkSnapshot
+ * @shader: The code to run
+ * @args: A vec4 argument given to the shader
+ * @bounds: the rectangle to render into
+ * @n_children: The number of extra nodes given as argument to the shader as textures.
+ *
+ * Renders a rectagle with output from a GLSL shader. If shaders are not supported
+ * the fallback will be used instead. The fallback is pushed to the snapshot
+ * until the first call to gtk_snapshot_pop(). After that the extra nodes
+ * pushed, and @n_children mode gtk_snapshot_pop() calls are expected for
+ * these.
+ */
+void
+gtk_snapshot_push_glshader (GtkSnapshot *snapshot,
+ GskGLShader *shader,
+ const graphene_vec4_t *args,
+ const graphene_rect_t *bounds,
+ int n_children)
+{
+ GtkSnapshotState *state;
+ float scale_x, scale_y, dx, dy;
+ GskRenderNode **nodes;
+ int node_idx;
+ graphene_rect_t transformed_bounds;
+
+ gtk_snapshot_ensure_affine (snapshot, &scale_x, &scale_y, &dx, &dy);
+
+ state = gtk_snapshot_push_state (snapshot,
+ gtk_snapshot_get_current_state (snapshot)->transform,
+ gtk_snapshot_collect_glshader);
+ gtk_graphene_rect_scale_affine (bounds, scale_x, scale_y, dx, dy, &transformed_bounds);
+ state->data.glshader.bounds = transformed_bounds;
+ state->data.glshader.shader = g_object_ref (shader);
+ if (args)
+ state->data.glshader.args = *args;
+ else
+ graphene_vec4_init (&state->data.glshader.args, 0, 0, 0, 0);
+ state->data.glshader.n_children = n_children;
+ nodes = g_new0 (GskRenderNode *, n_children + 1);
+ node_idx = n_children; /* We pop in reverse order */
+
+ state->data.glshader.node_idx = node_idx--;
+ state->data.glshader.nodes = nodes;
+
+ for (int i = 0; i < n_children; i++)
+ {
+ state = gtk_snapshot_push_state (snapshot,
+ gtk_snapshot_get_current_state (snapshot)->transform,
+ gtk_snapshot_collect_glshader);
+ 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;
+ }
+}
+
static GskRenderNode *
gtk_snapshot_collect_rounded_clip (GtkSnapshot *snapshot,
GtkSnapshotState *state,
diff --git a/gtk/gtksnapshot.h b/gtk/gtksnapshot.h
index e3c0e17e65..89833c9d61 100644
--- a/gtk/gtksnapshot.h
+++ b/gtk/gtksnapshot.h
@@ -99,6 +99,12 @@ GDK_AVAILABLE_IN_ALL
void gtk_snapshot_push_cross_fade (GtkSnapshot *snapshot,
double progress);
GDK_AVAILABLE_IN_ALL
+void gtk_snapshot_push_glshader (GtkSnapshot *snapshot,
+ GskGLShader *shader,
+ const graphene_vec4_t *args,
+ const graphene_rect_t *bounds,
+ int n_children);
+GDK_AVAILABLE_IN_ALL
void gtk_snapshot_pop (GtkSnapshot *snapshot);
GDK_AVAILABLE_IN_ALL
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]