[gtk/matthiasc/gltransition-demo: 6/10] GtkSnapshot: Add gtk_snapshot_push_glshader()




commit d21e794d252fea80579a783c46430e5356e3a07d
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 | 148 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gtk/gtksnapshot.h |  12 +++++
 2 files changed, 160 insertions(+)
---
diff --git a/gtk/gtksnapshot.c b/gtk/gtksnapshot.c
index 3b7c5173a8..1e44502caa 100644
--- a/gtk/gtksnapshot.c
+++ b/gtk/gtksnapshot.c
@@ -91,6 +91,14 @@ struct _GtkSnapshotState {
     struct {
       graphene_rect_t bounds;
     } clip;
+    struct {
+      GskGLShader *shader;
+      guchar *args;
+      graphene_rect_t bounds;
+      int n_children;
+      int node_idx;
+      GskRenderNode **nodes;
+    } glshader;
     struct {
       GskRoundedRect bounds;
     } rounded_clip;
@@ -812,6 +820,146 @@ 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.bounds,
+                                           state->data.glshader.args,
+                                           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_va:
+ * @snapshot: a #GtkSnapshot
+ * @shader: The code to run
+ * @bounds: the rectangle to render into
+ * @n_children: The number of extra nodes given as argument to the shader as textures.
+ * @uniforms: The uniforms, ending with NULL
+ *
+ * Renders a rectangle 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_va (GtkSnapshot           *snapshot,
+                               GskGLShader           *shader,
+                               const graphene_rect_t *bounds,
+                               int                    n_children,
+                               va_list                uniforms)
+{
+  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);
+  state->data.glshader.args = gsk_glshader_format_uniform_data_va (shader, uniforms);
+  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;
+    }
+}
+
+/**
+ * gtk_snapshot_push_glshader:
+ * @snapshot: a #GtkSnapshot
+ * @shader: The code to run
+ * @bounds: the rectangle to render into
+ * @n_children: The number of extra nodes given as argument to the shader as textures.
+ *
+ * Renders a rectangle 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_rect_t *bounds,
+                            int                    n_children,
+                            ...)
+{
+  va_list args;
+
+  va_start (args, n_children);
+  gtk_snapshot_push_glshader_va (snapshot, shader, bounds, n_children, args);
+  va_end (args);
+}
+
 static GskRenderNode *
 gtk_snapshot_collect_rounded_clip (GtkSnapshot      *snapshot,
                                    GtkSnapshotState *state,
diff --git a/gtk/gtksnapshot.h b/gtk/gtksnapshot.h
index e3c0e17e65..0786d5e2ae 100644
--- a/gtk/gtksnapshot.h
+++ b/gtk/gtksnapshot.h
@@ -99,6 +99,18 @@ 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_rect_t  *bounds,
+                                                         int                     n_children,
+                                                         ...);
+GDK_AVAILABLE_IN_ALL
+void            gtk_snapshot_push_glshader_va           (GtkSnapshot            *snapshot,
+                                                         GskGLShader            *shader,
+                                                         const graphene_rect_t  *bounds,
+                                                         int                     n_children,
+                                                         va_list                 uniforms);
+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]