[gtk/glshader-paintable: 1/3] Add a shader paintable




commit 892a4d579357ec50f6844f29c9bbdb9baf6ba5d9
Author: Matthias Clasen <mclasen redhat com>
Date:   Thu Sep 24 21:16:53 2020 -0400

    Add a shader paintable
    
    This is a GdkPaintable implementation wrapped
    around a GskGLShader. It can optionally be hooked
    up to a frame clock to update a time uniform.

 gtk/gtk.h                |   1 +
 gtk/gtkshaderpaintable.c | 310 +++++++++++++++++++++++++++++++++++++++++++++++
 gtk/gtkshaderpaintable.h |  55 +++++++++
 gtk/meson.build          |   1 +
 4 files changed, 367 insertions(+)
---
diff --git a/gtk/gtk.h b/gtk/gtk.h
index be942b218b..2e5ff47c42 100644
--- a/gtk/gtk.h
+++ b/gtk/gtk.h
@@ -217,6 +217,7 @@
 #include <gtk/gtkselectionmodel.h>
 #include <gtk/gtkseparator.h>
 #include <gtk/gtksettings.h>
+#include <gtk/gtkshaderpaintable.h>
 #include <gtk/gtkshortcut.h>
 #include <gtk/gtkshortcutaction.h>
 #include <gtk/gtkshortcutcontroller.h>
diff --git a/gtk/gtkshaderpaintable.c b/gtk/gtkshaderpaintable.c
new file mode 100644
index 0000000000..bdd9df2cd9
--- /dev/null
+++ b/gtk/gtkshaderpaintable.c
@@ -0,0 +1,310 @@
+/*
+ * Copyright © 2020 Red Hat, Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Matthias Clasen <mclasen redhat com>
+ */
+
+#include "config.h"
+
+#include "gtkshaderpaintable.h"
+
+#include "gtkintl.h"
+#include "gtksnapshot.h"
+#include "gtkrendernodepaintableprivate.h"
+
+struct _GtkShaderPaintable
+{
+  GObject parent_instance;
+
+  GskGLShader *shader;
+  GBytes *uniform_data;
+
+  GdkFrameClock *frame_clock;
+  guint clock_tick_id;
+  int time_idx;
+  gint64 first_frame_time;
+  gint64 frame_time;
+};
+
+struct _GtkShaderPaintableClass
+{
+  GObjectClass parent_class;
+};
+
+enum {
+  PROP_0,
+  PROP_SHADER,
+  PROP_UNIFORM_DATA,
+
+  N_PROPS,
+};
+
+static GParamSpec *properties[N_PROPS] = { NULL, };
+
+static void
+gtk_shader_paintable_paintable_snapshot (GdkPaintable *paintable,
+                                         GdkSnapshot  *snapshot,
+                                         double        width,
+                                         double        height)
+{
+  GtkShaderPaintable *self = GTK_SHADER_PAINTABLE (paintable);
+  graphene_rect_t bounds;
+  GBytes *uniform_data;
+  gsize size;
+
+  size = gsk_gl_shader_get_uniforms_size (self->shader);
+
+  if (self->time_idx > -1)
+    {
+      int offset = gsk_gl_shader_get_uniform_offset (self->shader, self->time_idx);
+      guchar *data;
+
+      data = g_new0 (guchar, size);
+      memcpy (data, g_bytes_get_data (self->uniform_data, NULL), size);
+
+      *(float*)(data + offset) = (self->frame_time - self->first_frame_time) / (float)G_TIME_SPAN_SECOND;
+
+      uniform_data = g_bytes_new_take (data, size);
+    }
+  else
+    uniform_data = g_bytes_ref (self->uniform_data);
+
+  graphene_rect_init (&bounds, 0, 0, width, height);
+
+  gtk_snapshot_push_gl_shader (snapshot, self->shader, &GRAPHENE_RECT_INIT(0, 0, width, height), 
uniform_data, 0);
+  gtk_snapshot_append_color (snapshot, &(GdkRGBA){1.0, 0.5, 0.6, 1.0}, &GRAPHENE_RECT_INIT(0, 0, width, 
height));
+  gtk_snapshot_pop (snapshot);
+
+  g_bytes_unref (uniform_data);
+}
+
+static void
+gtk_shader_paintable_paintable_init (GdkPaintableInterface *iface)
+{
+  iface->snapshot = gtk_shader_paintable_paintable_snapshot;
+}
+
+G_DEFINE_TYPE_EXTENDED (GtkShaderPaintable, gtk_shader_paintable, G_TYPE_OBJECT, 0,
+                        G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE,
+                                               gtk_shader_paintable_paintable_init))
+
+static void
+gtk_shader_paintable_set_property (GObject      *object,
+                                   guint         prop_id,
+                                   const GValue *value,
+                                   GParamSpec   *pspec)
+
+{
+  GtkShaderPaintable *self = GTK_SHADER_PAINTABLE (object);
+
+  switch (prop_id)
+    {
+    case PROP_SHADER:
+      gtk_shader_paintable_set_shader (self, g_value_get_object (value));
+      break;
+
+    case PROP_UNIFORM_DATA:
+      gtk_shader_paintable_set_uniform_data (self, g_value_get_boxed (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+gtk_shader_paintable_get_property (GObject    *object,
+                                   guint       prop_id,
+                                   GValue     *value,
+                                   GParamSpec *pspec)
+{
+  GtkShaderPaintable *self = GTK_SHADER_PAINTABLE (object);
+
+  switch (prop_id)
+    {
+    case PROP_SHADER:
+      g_value_set_object (value, self->shader);
+      break;
+
+    case PROP_UNIFORM_DATA:
+      g_value_set_boxed (value, self->uniform_data);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+gtk_shader_paintable_finalize (GObject *object)
+{
+  GtkShaderPaintable *self = GTK_SHADER_PAINTABLE (object);
+
+  if (self->clock_tick_id)
+    {
+      g_signal_handler_disconnect (self->frame_clock, self->clock_tick_id);
+      gdk_frame_clock_end_updating (self->frame_clock);
+      g_object_unref (self->frame_clock);
+    }
+
+  g_clear_pointer (&self->uniform_data, g_bytes_unref);
+  g_clear_object (&self->shader);
+
+  G_OBJECT_CLASS (gtk_shader_paintable_parent_class)->finalize (object);
+}
+
+static void
+gtk_shader_paintable_class_init (GtkShaderPaintableClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->get_property = gtk_shader_paintable_get_property;
+  gobject_class->set_property = gtk_shader_paintable_set_property;
+  gobject_class->finalize = gtk_shader_paintable_finalize;
+
+  properties[PROP_SHADER] =
+    g_param_spec_object ("shader",
+                         P_("Shader"),
+                         P_("The shader"),
+                         GSK_TYPE_GLSHADER,
+                         G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
+  properties[PROP_UNIFORM_DATA] =
+    g_param_spec_boxed ("uniform-data",
+                        P_("Uniform data"),
+                        P_("The uniform data"),
+                        G_TYPE_BYTES,
+                        G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
+  g_object_class_install_properties (gobject_class, N_PROPS, properties);
+}
+
+static void
+gtk_shader_paintable_init (GtkShaderPaintable *self)
+{
+  self->time_idx = -1;
+}
+
+GdkPaintable *
+gtk_shader_paintable_new (GskGLShader *shader,
+                          GBytes      *data)
+{
+  GdkPaintable *ret;
+
+  g_return_val_if_fail (shader == NULL || GSK_IS_GL_SHADER (shader), NULL);
+
+  ret = g_object_new (GTK_TYPE_SHADER_PAINTABLE,
+                      "shader", shader,
+                      "uniform-data", data,
+                      NULL);
+
+  g_clear_object (&shader);
+  g_clear_pointer (&data, g_bytes_unref);
+
+  return ret;
+}
+
+void
+gtk_shader_paintable_set_shader (GtkShaderPaintable *self,
+                                 GskGLShader        *shader)
+{
+  g_return_if_fail (GTK_IS_SHADER_PAINTABLE (self));
+  g_return_if_fail (shader == NULL || GSK_IS_GL_SHADER (shader));
+
+  if (!g_set_object (&self->shader, shader))
+    return;
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SHADER]);
+  gdk_paintable_invalidate_size (GDK_PAINTABLE (self));
+  gdk_paintable_invalidate_contents (GDK_PAINTABLE (self));
+
+  g_clear_pointer (&self->uniform_data, g_bytes_unref);
+}
+
+GskGLShader *
+gtk_shader_paintable_get_shader (GtkShaderPaintable *self)
+{
+  g_return_val_if_fail (GTK_IS_SHADER_PAINTABLE (self), NULL);
+
+  return self->shader;
+}
+
+void
+gtk_shader_paintable_set_uniform_data (GtkShaderPaintable *self,
+                                       GBytes             *data)
+{
+  g_return_if_fail (GTK_IS_SHADER_PAINTABLE (self));
+
+  g_clear_pointer (&self->uniform_data, g_bytes_unref);
+  if (data)
+    self->uniform_data = g_bytes_ref (data);
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_UNIFORM_DATA]);
+  gdk_paintable_invalidate_size (GDK_PAINTABLE (self));
+  gdk_paintable_invalidate_contents (GDK_PAINTABLE (self));
+}
+
+GBytes *
+gtk_shader_paintable_get_uniform_data (GtkShaderPaintable *self)
+{
+  g_return_val_if_fail (GTK_IS_SHADER_PAINTABLE (self), NULL);
+
+  return self->uniform_data;
+}
+
+static void
+on_frame_clock_update (GdkFrameClock      *frame_clock,
+                       GtkShaderPaintable *self)
+{
+  gint64 frame_time;
+
+  frame_time = gdk_frame_clock_get_frame_time (frame_clock);
+
+  if (self->first_frame_time == 0)
+    self->first_frame_time = frame_time;
+
+  self->frame_time = frame_time;
+
+  gdk_paintable_invalidate_size (GDK_PAINTABLE (self));
+  gdk_paintable_invalidate_contents (GDK_PAINTABLE (self));
+}
+
+void
+gtk_shader_paintable_set_frame_clock (GtkShaderPaintable *self,
+                                      GdkFrameClock      *frame_clock,
+                                      int                 uniform_idx)
+{
+  self->time_idx = uniform_idx;
+  self->first_frame_time = 0;
+
+  if (self->clock_tick_id)
+    {
+      g_signal_handler_disconnect (self->frame_clock, self->clock_tick_id);
+      self->clock_tick_id = 0;
+      gdk_frame_clock_end_updating (self->frame_clock);
+    }
+
+  g_set_object (&self->frame_clock, frame_clock);
+
+  if (frame_clock)
+    {
+      self->clock_tick_id = g_signal_connect (frame_clock, "update",
+                                              G_CALLBACK (on_frame_clock_update), self);
+      gdk_frame_clock_begin_updating (frame_clock);
+    }
+}
diff --git a/gtk/gtkshaderpaintable.h b/gtk/gtkshaderpaintable.h
new file mode 100644
index 0000000000..9672e0a948
--- /dev/null
+++ b/gtk/gtkshaderpaintable.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright © 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Matthias Clasen <mclasen redhat com>
+ */
+
+#ifndef __GTK_SHADER_PAINTABLE_H__
+#define __GTK_SHADER_PAINTABLE_H__
+
+#include <gdk/gdk.h>
+#include <gsk/gskglshader.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_SHADER_PAINTABLE (gtk_shader_paintable_get_type ())
+
+GDK_AVAILABLE_IN_ALL
+G_DECLARE_FINAL_TYPE (GtkShaderPaintable, gtk_shader_paintable, GTK, SHADER_PAINTABLE, GObject)
+
+GDK_AVAILABLE_IN_ALL
+GdkPaintable *   gtk_shader_paintable_new              (GskGLShader        *shader,
+                                                        GBytes             *data);
+
+GDK_AVAILABLE_IN_ALL
+GskGLShader *    gtk_shader_paintable_get_shader       (GtkShaderPaintable *self);
+GDK_AVAILABLE_IN_ALL
+void             gtk_shader_paintable_set_shader       (GtkShaderPaintable *self,
+                                                        GskGLShader        *shader);
+GDK_AVAILABLE_IN_ALL
+GBytes *         gtk_shader_paintable_get_uniform_data (GtkShaderPaintable *self);
+GDK_AVAILABLE_IN_ALL
+void             gtk_shader_paintable_set_uniform_data (GtkShaderPaintable *self,
+                                                        GBytes             *data);
+
+GDK_AVAILABLE_IN_ALL
+void             gtk_shader_paintable_set_frame_clock  (GtkShaderPaintable *self,
+                                                        GdkFrameClock      *frame_clock,
+                                                        int                 uniform_idx);
+
+G_END_DECLS
+
+#endif /* __GTK_SHADER_PAINTABLE_H__ */
diff --git a/gtk/meson.build b/gtk/meson.build
index 3554c1b2f1..25f256db8f 100644
--- a/gtk/meson.build
+++ b/gtk/meson.build
@@ -356,6 +356,7 @@ gtk_public_sources = files([
   'gtkselectionmodel.c',
   'gtkseparator.c',
   'gtksettings.c',
+  'gtkshaderpaintable.c',
   'gtkshortcut.c',
   'gtkshortcutaction.c',
   'gtkshortcutcontroller.c',


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]