[gtk/glshader-paintable: 1/8] GskGLShader: Drop fallback node and add try_compile function to replace it




commit e93a51b1cc585762043e2b945898d457b655beb9
Author: Alexander Larsson <alexl redhat com>
Date:   Fri Sep 25 14:05:21 2020 +0200

    GskGLShader: Drop fallback node and add try_compile function to replace it
    
    This removes the fallback node from GskGLShaderNode and adds
    a new function gsk_gl_shader_try_compile_for() which tries to compile a
    shader against a renderer. Then you can use the return value of this
    both as a way to implement the fallback, and as a way to get at
    the error report in a saner way.

 demos/gtk-demo/gtkshaderbin.c      |  53 +++++++---
 demos/gtk-demo/gtkshaderstack.c    |  33 +++---
 gsk/broadway/gskbroadwayrenderer.c |  12 +--
 gsk/gl/gskglrenderer.c             | 207 ++++++++++++++++++++++---------------
 gsk/gl/gskglrendererprivate.h      |  14 +++
 gsk/gl/gskglrenderopsprivate.h     |   3 +-
 gsk/gskglshader.c                  |  35 +++++++
 gsk/gskglshader.h                  |   4 +
 gsk/gskrendernode.h                |   3 -
 gsk/gskrendernodeimpl.c            |  37 ++-----
 gsk/gskrendernodeparser.c          |   5 +-
 gsk/vulkan/gskvulkanrenderpass.c   |   5 +-
 gtk/gtksnapshot.c                  |  41 +++-----
 gtk/inspector/recorder.c           |   2 +-
 14 files changed, 262 insertions(+), 192 deletions(-)
---
diff --git a/demos/gtk-demo/gtkshaderbin.c b/demos/gtk-demo/gtkshaderbin.c
index bf18b735f9..c617984b7e 100644
--- a/demos/gtk-demo/gtkshaderbin.c
+++ b/demos/gtk-demo/gtkshaderbin.c
@@ -4,13 +4,15 @@ typedef struct {
   GskGLShader *shader;
   GtkStateFlags state;
   GtkStateFlags state_mask;
+  gboolean compiled;
+  gboolean compiled_ok;
 } ShaderInfo;
 
 struct _GtkShaderBin
 {
   GtkWidget parent_instance;
   GtkWidget *child;
-  GskGLShader *active_shader;
+  ShaderInfo *active_shader;
   GPtrArray *shaders;
   guint tick_id;
   float time;
@@ -79,7 +81,7 @@ void
 gtk_shader_bin_update_active_shader (GtkShaderBin *self)
 {
   GtkStateFlags new_state = gtk_widget_get_state_flags (GTK_WIDGET (self));
-  GskGLShader *new_shader = NULL;
+  ShaderInfo *new_shader = NULL;
 
   for (int i = 0; i < self->shaders->len; i++)
     {
@@ -87,7 +89,7 @@ gtk_shader_bin_update_active_shader (GtkShaderBin *self)
 
       if ((info->state_mask & new_state) == info->state)
         {
-          new_shader = info->shader;
+          new_shader = info;
           break;
         }
     }
@@ -177,20 +179,39 @@ gtk_shader_bin_snapshot (GtkWidget   *widget,
 
   if (self->active_shader)
     {
-      gtk_snapshot_push_gl_shader_v (snapshot, self->active_shader,
-                                     &GRAPHENE_RECT_INIT(0, 0, width, height),
-                                     1,
-                                     "u_time", &self->time,
-                                     NULL);
-      gtk_widget_snapshot_child (widget, self->child, snapshot);
-      gtk_snapshot_pop (snapshot); /* Fallback */
-      gtk_widget_snapshot_child (widget, self->child, snapshot);
-      gtk_snapshot_pop (snapshot); /* Shader node child 1 */
-    }
-  else
-    {
-      gtk_widget_snapshot_child (widget, self->child, snapshot);
+      if (!self->active_shader->compiled)
+        {
+          GtkNative *native = gtk_widget_get_native (widget);
+          GskRenderer *renderer = gtk_native_get_renderer (native);
+          GError *error = NULL;
+
+          self->active_shader->compiled = TRUE;
+          self->active_shader->compiled_ok =
+            gsk_gl_shader_try_compile_for (self->active_shader->shader,
+                                           renderer, &error);
+          if (!self->active_shader->compiled_ok)
+            {
+              g_warning ("GtkShaderBin failed to compile shader: %s", error->message);
+              g_error_free (error);
+            }
+        }
+
+      if (self->active_shader->compiled_ok)
+        {
+          gtk_snapshot_push_gl_shader_v (snapshot, self->active_shader->shader,
+                                         &GRAPHENE_RECT_INIT(0, 0, width, height),
+                                         1,
+                                         "u_time", &self->time,
+                                         NULL);
+          gtk_widget_snapshot_child (widget, self->child, snapshot);
+          gtk_snapshot_pop (snapshot);
+
+          return;
+        }
     }
+
+  /* Non-shader fallback */
+  gtk_widget_snapshot_child (widget, self->child, snapshot);
 }
 
 static void
diff --git a/demos/gtk-demo/gtkshaderstack.c b/demos/gtk-demo/gtkshaderstack.c
index 8b3b336cf6..d83e115764 100644
--- a/demos/gtk-demo/gtkshaderstack.c
+++ b/demos/gtk-demo/gtkshaderstack.c
@@ -222,6 +222,8 @@ gtk_shader_stack_snapshot (GtkWidget   *widget,
     }
   else
     {
+      GtkNative *native = gtk_widget_get_native (widget);
+      GskRenderer *renderer = gtk_native_get_renderer (native);
       float progress;
 
       next = g_ptr_array_index (self->children, self->next);
@@ -236,18 +238,25 @@ gtk_shader_stack_snapshot (GtkWidget   *widget,
           progress = 1. - progress;
         }
 
-      gtk_snapshot_push_gl_shader_v (snapshot,
-                                     self->shader,
-                                     &GRAPHENE_RECT_INIT(0, 0, width, height),
-                                     2,
-                                     "progress", &progress,
-                                     NULL);
-      gtk_widget_snapshot_child (widget, next, snapshot);
-      gtk_snapshot_pop (snapshot); /* Fallback */
-      gtk_widget_snapshot_child (widget, current, snapshot);
-      gtk_snapshot_pop (snapshot); /* current child */
-      gtk_widget_snapshot_child (widget, next, snapshot);
-      gtk_snapshot_pop (snapshot); /* next child */
+      if (gsk_gl_shader_try_compile_for (self->shader,
+                                         renderer, NULL))
+        {
+          gtk_snapshot_push_gl_shader_v (snapshot,
+                                         self->shader,
+                                         &GRAPHENE_RECT_INIT(0, 0, width, height),
+                                         2,
+                                         "progress", &progress,
+                                         NULL);
+          gtk_widget_snapshot_child (widget, current, snapshot);
+          gtk_snapshot_pop (snapshot); /* current child */
+          gtk_widget_snapshot_child (widget, next, snapshot);
+          gtk_snapshot_pop (snapshot); /* next child */
+        }
+      else
+        {
+          /* Non-shader fallback */
+          gtk_widget_snapshot_child (widget, current, snapshot);
+        }
     }
 }
 
diff --git a/gsk/broadway/gskbroadwayrenderer.c b/gsk/broadway/gskbroadwayrenderer.c
index 1dd8e8164d..bb6de84846 100644
--- a/gsk/broadway/gskbroadwayrenderer.c
+++ b/gsk/broadway/gskbroadwayrenderer.c
@@ -258,6 +258,7 @@ collect_reused_child_nodes (GskRenderer *renderer,
     case GSK_LINEAR_GRADIENT_NODE:
 
       /* Fallbacks (=> leaf for now */
+    case GSK_GL_SHADER_NODE:
     case GSK_COLOR_MATRIX_NODE:
     case GSK_TEXT_NODE:
     case GSK_REPEATING_LINEAR_GRADIENT_NODE:
@@ -272,11 +273,6 @@ collect_reused_child_nodes (GskRenderer *renderer,
 
       /* Bin nodes */
 
-    case GSK_GL_SHADER_NODE:
-      collect_reused_node (renderer,
-                           gsk_gl_shader_node_get_fallback_child (node));
-      break;
-
     case GSK_SHADOW_NODE:
       collect_reused_node (renderer,
                            gsk_shadow_node_get_child (node));
@@ -797,11 +793,6 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer,
         }
       return;
 
-    case GSK_GL_SHADER_NODE:
-      gsk_broadway_renderer_add_node (renderer,
-                                      gsk_gl_shader_node_get_fallback_child (node), offset_x, offset_y, 
clip_bounds);
-      return;
-
       /* Generic nodes */
 
     case GSK_CONTAINER_NODE:
@@ -857,6 +848,7 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer,
     case GSK_BLEND_NODE:
     case GSK_CROSS_FADE_NODE:
     case GSK_BLUR_NODE:
+    case GSK_GL_SHADER_NODE:
     default:
       break; /* Fallback */
     }
diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c
index b31d7c3cea..cb7fe8aaeb 100644
--- a/gsk/gl/gskglrenderer.c
+++ b/gsk/gl/gskglrenderer.c
@@ -1,6 +1,6 @@
 #include "config.h"
 
-#include "gskglrenderer.h"
+#include "gskglrendererprivate.h"
 
 #include "gskdebugprivate.h"
 #include "gskenums.h"
@@ -138,7 +138,6 @@ print_render_node_tree (GskRenderNode *root, int level)
 
       case GSK_GL_SHADER_NODE:
         g_print ("%*s GL Shader\n", level * INDENT, " ");
-        print_render_node_tree (gsk_gl_shader_node_get_fallback_child (root), level + 1);
         for (i = 0; i < gsk_gl_shader_node_get_n_children (root); i++)
           print_render_node_tree (gsk_gl_shader_node_get_child (root, i), level + 1);
         break;
@@ -1053,93 +1052,136 @@ render_texture_node (GskGLRenderer       *self,
     }
 }
 
-static inline void
-render_gl_shader_node (GskGLRenderer       *self,
-                      GskRenderNode       *node,
-                      RenderOpBuilder     *builder)
+static Program *
+compile_glshader (GskGLRenderer  *self,
+                  GskGLShader    *shader,
+                  GError        **error)
 {
-  GskGLShader *shader = gsk_gl_shader_node_get_shader (node);
-  Program *program = gsk_gl_renderer_lookup_custom_program (self, shader);
-  GskRenderNode *fallback = gsk_gl_shader_node_get_fallback_child (node);
-  int n_children = gsk_gl_shader_node_get_n_children (node);
+  GskGLShaderBuilder shader_builder;
+  const char *shader_source;
+  gsize shader_source_len;
+  int n_uniforms;
+  const GskGLUniform *uniforms;
+  GBytes *bytes;
+  int n_required_textures = gsk_gl_shader_get_n_required_textures (shader);
+  int program_id;
+  Program *program;
 
-  if (program == NULL)
+  bytes = gsk_gl_shader_get_bytes (shader);
+  shader_source = g_bytes_get_data (bytes, &shader_source_len);
+  uniforms = gsk_gl_shader_get_uniforms (shader, &n_uniforms);
+
+  if (n_uniforms > G_N_ELEMENTS (program->glshader.args_locations))
     {
-      GskGLShaderBuilder shader_builder;
-      const char *shader_source;
-      gsize shader_source_len;
-      GError *error = NULL;
-      int n_uniforms;
-      const GskGLUniform *uniforms;
-      GBytes *bytes;
-      int n_required_textures = gsk_gl_shader_get_n_required_textures (shader);
+      g_set_error (error, GDK_GL_ERROR, GDK_GL_ERROR_UNSUPPORTED_FORMAT,
+                   "GLShaderNode supports max %d custom uniforms", (int)G_N_ELEMENTS 
(program->glshader.args_locations));
+      return NULL;
+    }
 
-      /* We always create the program, so that any compiler warnings or other is only reported once */
-      program = gsk_gl_renderer_create_custom_program (self, shader);
+  if (n_required_textures > G_N_ELEMENTS (program->glshader.texture_locations))
+    {
+      g_set_error (error, GDK_GL_ERROR, GDK_GL_ERROR_UNSUPPORTED_FORMAT,
+                   "GLShaderNode supports max %d texture sources", (int)(G_N_ELEMENTS 
(program->glshader.texture_locations)));
+      return NULL;
+    }
 
-      bytes = gsk_gl_shader_get_bytes (shader);
-      shader_source = g_bytes_get_data (bytes, &shader_source_len);
-      uniforms = gsk_gl_shader_get_uniforms (shader, &n_uniforms);
+  gsk_gl_shader_builder_init (&shader_builder,
+                              "/org/gtk/libgsk/glsl/preamble.glsl",
+                              "/org/gtk/libgsk/glsl/preamble.vs.glsl",
+                              "/org/gtk/libgsk/glsl/preamble.fs.glsl");
 
-      if (n_uniforms > G_N_ELEMENTS (program->glshader.args_locations))
-        {
-          g_set_error (&error, GDK_GL_ERROR, GDK_GL_ERROR_UNSUPPORTED_FORMAT,
-                       "GLShaderNode supports max %d custom uniforms", (int)G_N_ELEMENTS 
(program->glshader.args_locations));
-        }
-      else if (n_required_textures > G_N_ELEMENTS (program->glshader.texture_locations))
+  init_shader_builder (self, &shader_builder);
+  program_id = gsk_gl_shader_builder_create_program (&shader_builder,
+                                                     "/org/gtk/libgsk/glsl/custom.glsl",
+                                                     shader_source, shader_source_len,
+                                                     error);
+  gsk_gl_shader_builder_finish (&shader_builder);
+
+  if (program_id  < 0)
+    return NULL;
+
+  program = gsk_gl_renderer_create_custom_program (self, shader);
+
+  program->id = program_id;
+  INIT_COMMON_UNIFORM_LOCATION (program, alpha);
+  INIT_COMMON_UNIFORM_LOCATION (program, clip_rect);
+  INIT_COMMON_UNIFORM_LOCATION (program, viewport);
+  INIT_COMMON_UNIFORM_LOCATION (program, projection);
+  INIT_COMMON_UNIFORM_LOCATION (program, modelview);
+  program->glshader.size_location = glGetUniformLocation(program->id, "u_size");
+  program->glshader.texture_locations[0] = glGetUniformLocation(program->id, "u_texture1");
+  program->glshader.texture_locations[1] = glGetUniformLocation(program->id, "u_texture2");
+  program->glshader.texture_locations[2] = glGetUniformLocation(program->id, "u_texture3");
+  program->glshader.texture_locations[3] = glGetUniformLocation(program->id, "u_texture4");
+
+  /* We use u_textue1 for the texture 0 in the glshaders, so alias it here so we can use the regular setters 
*/
+  program->source_location = program->glshader.texture_locations[0];
+
+  for (int i = 0; i < G_N_ELEMENTS (program->glshader.args_locations); i++)
+    {
+      if (i < n_uniforms)
         {
-          g_set_error (&error, GDK_GL_ERROR, GDK_GL_ERROR_UNSUPPORTED_FORMAT,
-                       "GLShaderNode supports max %d texture sources", (int)(G_N_ELEMENTS 
(program->glshader.texture_locations)));
+          program->glshader.args_locations[i] = glGetUniformLocation(program->id, uniforms[i].name);
+          /* This isn't necessary a hard error, you might declare uniforms that are not actually
+             always used, for instance if you have an "API" in uniforms for multiple shaders. */
+          if (program->glshader.args_locations[i] == -1)
+            g_debug ("Declared uniform `%s` not found in GskGLShader", uniforms[i].name);
         }
       else
-        {
-          gsk_gl_shader_builder_init (&shader_builder,
-                                      "/org/gtk/libgsk/glsl/preamble.glsl",
-                                      "/org/gtk/libgsk/glsl/preamble.vs.glsl",
-                                      "/org/gtk/libgsk/glsl/preamble.fs.glsl");
+        program->glshader.args_locations[i] = -1;
+    }
+
+  return program;
+}
 
-          init_shader_builder (self, &shader_builder);
+gboolean
+gsk_gl_render_try_compile_gl_shader (GskGLRenderer    *self,
+                                     GskGLShader      *shader,
+                                     GError          **error)
+{
+  Program *program;
 
-          program->id = gsk_gl_shader_builder_create_program (&shader_builder,
-                                                              "/org/gtk/libgsk/glsl/custom.glsl",
-                                                              shader_source, shader_source_len,
-                                                              &error);
-          gsk_gl_shader_builder_finish (&shader_builder);
+  gdk_gl_context_make_current (self->gl_context);
 
-          if (program->id >= 0)
-            {
-              INIT_COMMON_UNIFORM_LOCATION (program, alpha);
-              INIT_COMMON_UNIFORM_LOCATION (program, clip_rect);
-              INIT_COMMON_UNIFORM_LOCATION (program, viewport);
-              INIT_COMMON_UNIFORM_LOCATION (program, projection);
-              INIT_COMMON_UNIFORM_LOCATION (program, modelview);
-              program->glshader.size_location = glGetUniformLocation(program->id, "u_size");
-              program->glshader.texture_locations[0] = glGetUniformLocation(program->id, "u_texture1");
-              program->glshader.texture_locations[1] = glGetUniformLocation(program->id, "u_texture2");
-              program->glshader.texture_locations[2] = glGetUniformLocation(program->id, "u_texture3");
-              program->glshader.texture_locations[3] = glGetUniformLocation(program->id, "u_texture4");
-
-              /* We use u_textue1 for the texture 0 in the glshaders, so alias it here so we can use the 
regular setters */
-              program->source_location = program->glshader.texture_locations[0];
-
-              for (int i = 0; i < G_N_ELEMENTS (program->glshader.args_locations); i++)
-                {
-                  if (i < n_uniforms)
-                    {
-                      program->glshader.args_locations[i] = glGetUniformLocation(program->id, 
uniforms[i].name);
-                      if (program->glshader.args_locations[i] == -1)
-                        g_warning ("Expected uniform `%s` not found in shader", uniforms[i].name);
-                    }
-                  else
-                    program->glshader.args_locations[i] = -1;
-                }
-            }
+  /* Maybe we tried to compile it already? */
+  program = gsk_gl_renderer_lookup_custom_program (self, shader);
+  if (program != NULL)
+    {
+      if (program->id > 0)
+        return TRUE;
+      else
+        {
+          g_propagate_error (error, g_error_copy (program->glshader.compile_error));
+          return FALSE;
         }
+    }
+
+  program = compile_glshader (self, shader, error);
+  return program != NULL;
+}
 
-      if (program->id <= 0)
+static inline void
+render_gl_shader_node (GskGLRenderer       *self,
+                       GskRenderNode       *node,
+                       RenderOpBuilder     *builder)
+{
+  GskGLShader *shader = gsk_gl_shader_node_get_shader (node);
+  Program *program = gsk_gl_renderer_lookup_custom_program (self, shader);
+  int n_children = gsk_gl_shader_node_get_n_children (node);
+
+  if (program == NULL)
+    {
+      GError *error = NULL;
+
+      program = compile_glshader (self, shader, &error);
+      if (program == NULL)
         {
-          g_warning ("Failed to compile gl shader: %s\n", error->message);
-          g_error_free (error);
+          /* We create the program anyway (in a failed state), so that any compiler warnings or other are 
only reported once */
+          program = gsk_gl_renderer_create_custom_program (self, shader);
+          program->id = -1;
+          program->glshader.compile_error = error;
+
+          g_warning ("Failed to compile gl shader: %s", error->message);
         }
     }
 
@@ -1148,7 +1190,6 @@ render_gl_shader_node (GskGLRenderer       *self,
       GBytes *uniform_data;
       TextureRegion regions[4];
       gboolean is_offscreen[4];
-
       for (guint i = 0; i < n_children; i++)
         {
           GskRenderNode *child = gsk_gl_shader_node_get_child (node, i);
@@ -1157,11 +1198,7 @@ render_gl_shader_node (GskGLRenderer       *self,
                                   child,
                                   &regions[i], &is_offscreen[i],
                                   FORCE_OFFSCREEN | RESET_CLIP | RESET_OPACITY))
-            {
-              if (fallback)
-                gsk_gl_renderer_add_render_ops (self, fallback, builder);
-              return;
-            }
+            return;
         }
 
       uniform_data = gsk_gl_shader_node_get_uniform_data (node);
@@ -1180,8 +1217,10 @@ render_gl_shader_node (GskGLRenderer       *self,
     }
   else
     {
-      if (fallback)
-        gsk_gl_renderer_add_render_ops (self, fallback, builder);
+      static GdkRGBA pink = { 255 / 255., 105 / 255., 180 / 255., 1.0 };
+      ops_set_program (builder, &self->programs->color_program);
+      ops_set_color (builder, &pink);
+      load_vertex_data (ops_draw (builder, NULL), node, builder);
     }
 }
 
@@ -3133,6 +3172,10 @@ program_finalize (Program *program)
 {
   if (program->id > 0)
     glDeleteProgram (program->id);
+  if (program->index == -1 &&
+      program->glshader.compile_error != NULL)
+    g_error_free (program->glshader.compile_error);
+
   gsk_transform_unref (program->state.modelview);
 }
 
diff --git a/gsk/gl/gskglrendererprivate.h b/gsk/gl/gskglrendererprivate.h
new file mode 100644
index 0000000000..917aecb2e8
--- /dev/null
+++ b/gsk/gl/gskglrendererprivate.h
@@ -0,0 +1,14 @@
+#ifndef __GSK_GL_RENDERER_PRIVATE_H__
+#define __GSK_GL_RENDERER_PRIVATE_H__
+
+#include "gskglrenderer.h"
+
+G_BEGIN_DECLS
+
+gboolean gsk_gl_render_try_compile_gl_shader (GskGLRenderer    *self,
+                                              GskGLShader      *shader,
+                                              GError          **error);
+
+G_END_DECLS
+
+#endif /* __GSK_GL_RENDERER_PRIVATE_H__ */
diff --git a/gsk/gl/gskglrenderopsprivate.h b/gsk/gl/gskglrenderopsprivate.h
index 2f87117110..1d642bc3ac 100644
--- a/gsk/gl/gskglrenderopsprivate.h
+++ b/gsk/gl/gskglrenderopsprivate.h
@@ -84,7 +84,7 @@ typedef struct
 
 struct _Program
 {
-  int index;        /* Into the renderer's program array */
+  int index;        /* Into the renderer's program array -1 for custom */
 
   int id;
   /* Common locations (gl_common)*/
@@ -163,6 +163,7 @@ struct _Program
       int size_location;
       int args_locations[8];
       int texture_locations[4];
+      GError *compile_error;
     } glshader;
   };
 
diff --git a/gsk/gskglshader.c b/gsk/gskglshader.c
index 281e3b67b8..c1a336c214 100644
--- a/gsk/gskglshader.c
+++ b/gsk/gskglshader.c
@@ -112,6 +112,7 @@
 #include "gskglshader.h"
 #include "gskglshaderprivate.h"
 #include "gskdebugprivate.h"
+#include "gl/gskglrendererprivate.h"
 
 static GskGLUniformType
 uniform_type_from_glsl (const char *str)
@@ -483,6 +484,40 @@ gsk_gl_shader_new_from_resource (const char      *resource_path)
                        NULL);
 }
 
+/**
+ * gsk_gl_shader_try_compile_for:
+ * @shader: A #GskGLShader
+ * @renderer: A #GskRenderer
+ * @error: Location to store error int
+ *
+ * Tries to compile the @shader for the given @renderer, and reports
+ * %FALSE with an error if there is a problem. You should use this
+ * before relying on the shader for rendering and use a fallback with
+ * a simpler shader or without shaders if it fails.
+ *
+ * Note that this will modify the rendering state (for example
+ * change the current GL context) and requires the renderer to be
+ * set up. This means that the widget has to be realized. Commonly you
+ * want to call this from the realize signal of a widget, or during
+ * widget snapshot.
+ *
+ * Returns: %TRUE on success, %FALSE if an error occurred
+ */
+gboolean
+gsk_gl_shader_try_compile_for (GskGLShader      *shader,
+                               GskRenderer      *renderer,
+                               GError          **error)
+{
+  if (GSK_IS_GL_RENDERER (renderer))
+    return gsk_gl_render_try_compile_gl_shader (GSK_GL_RENDERER (renderer),
+                                                shader, error);
+
+  g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+               "The renderer does not support gl shaders");
+  return FALSE;
+}
+
+
 /**
  * gsk_gl_shader_get_sourcecode:
  * @shader: A #GskGLShader
diff --git a/gsk/gskglshader.h b/gsk/gskglshader.h
index 26f21ee694..b27544780c 100644
--- a/gsk/gskglshader.h
+++ b/gsk/gskglshader.h
@@ -40,6 +40,10 @@ GskGLShader *    gsk_gl_shader_new_from_bytes          (GBytes           *source
 GDK_AVAILABLE_IN_ALL
 GskGLShader *    gsk_gl_shader_new_from_resource       (const char       *resource_path);
 GDK_AVAILABLE_IN_ALL
+gboolean         gsk_gl_shader_try_compile_for         (GskGLShader      *shader,
+                                                        GskRenderer      *renderer,
+                                                        GError          **error);
+GDK_AVAILABLE_IN_ALL
 GBytes *         gsk_gl_shader_get_bytes               (GskGLShader      *shader);
 GDK_AVAILABLE_IN_ALL
 int              gsk_gl_shader_get_n_required_textures (GskGLShader      *shader);
diff --git a/gsk/gskrendernode.h b/gsk/gskrendernode.h
index f554ef56a5..9585449f82 100644
--- a/gsk/gskrendernode.h
+++ b/gsk/gskrendernode.h
@@ -460,12 +460,9 @@ GDK_AVAILABLE_IN_ALL
 GskRenderNode *         gsk_gl_shader_node_new                  (GskGLShader              *shader,
                                                                  const graphene_rect_t    *bounds,
                                                                  GBytes                   *uniform_data,
-                                                                 GskRenderNode            *fallback,
                                                                  GskRenderNode           **children,
                                                                  int                       n_children);
 GDK_AVAILABLE_IN_ALL
-GskRenderNode *         gsk_gl_shader_node_get_fallback_child   (GskRenderNode            *node);
-GDK_AVAILABLE_IN_ALL
 guint                   gsk_gl_shader_node_get_n_children       (GskRenderNode            *node);
 GDK_AVAILABLE_IN_ALL
 GskRenderNode *         gsk_gl_shader_node_get_child            (GskRenderNode            *node,
diff --git a/gsk/gskrendernodeimpl.c b/gsk/gskrendernodeimpl.c
index f59c93cbc5..8f47e0234d 100644
--- a/gsk/gskrendernodeimpl.c
+++ b/gsk/gskrendernodeimpl.c
@@ -4478,7 +4478,6 @@ struct _GskGLShaderNode
 
   GskGLShader *shader;
   GBytes *uniform_data;
-  GskRenderNode *fallback;
   GskRenderNode **children;
   guint n_children;
 };
@@ -4493,7 +4492,6 @@ gsk_gl_shader_node_finalize (GskRenderNode *node)
     gsk_render_node_unref (self->children[i]);
   g_free (self->children);
 
-  gsk_render_node_unref (self->fallback);
   g_bytes_unref (self->uniform_data);
 
   g_object_unref (self->shader);
@@ -4505,9 +4503,9 @@ static void
 gsk_gl_shader_node_draw (GskRenderNode *node,
                          cairo_t       *cr)
 {
-  GskGLShaderNode *self = (GskGLShaderNode *) node;
-
-  gsk_render_node_draw (self->fallback, cr);
+  cairo_set_source_rgb (cr, 255 / 255., 105 / 255., 180 / 255.);
+  gsk_cairo_rectangle (cr, &node->bounds);
+  cairo_fill (cr);
 }
 
 static void
@@ -4523,8 +4521,6 @@ gsk_gl_shader_node_diff (GskRenderNode  *node1,
       g_bytes_compare (self1->uniform_data, self2->uniform_data) == 0 &&
       self1->n_children == self2->n_children)
     {
-      gsk_render_node_diff (self1->fallback, self2->fallback, region);
-
       for (guint i = 0; i < self1->n_children; i++)
         {
           if (self1->children[i] != self2->children[i])
@@ -4545,7 +4541,6 @@ gsk_gl_shader_node_diff (GskRenderNode  *node1,
  * @shader: the #GskGLShader
  * @bounds: the rectangle to render the shader into
  * @uniform_data: Data for the uniforms
- * @fallback: Render node to use if OpenGL is not supported
  * @children: List of child nodes, these will be rendered to textures and used as input.
  * @n_children: Length of @children (currenly the GL backend only supports max 4 children)
  *
@@ -4560,8 +4555,10 @@ gsk_gl_shader_node_diff (GskRenderNode  *node1,
  * #GskTextureNodes, which will be used directly). These textures will be
  * sent as input to the shader.
  *
- * If the backend doesn't support GL shaders, or if there is any problem when
- * compiling the shader, then the fallback shader node will be used instead.
+ * If the renderer doesn't support GL shaders, or if there is any problem when
+ * compiling the shader, then the node will draw pink. You should use
+ * gsk_gl_shader_try_compile_for() to ensure the @shader will work for the renderer
+ * before using it.
  *
  * Returns: (transfer full) (type GskGLShaderNode): A new #GskRenderNode
  */
@@ -4569,7 +4566,6 @@ GskRenderNode *
 gsk_gl_shader_node_new (GskGLShader           *shader,
                         const graphene_rect_t *bounds,
                         GBytes                *uniform_data,
-                        GskRenderNode         *fallback,
                         GskRenderNode        **children,
                         int                    n_children)
 {
@@ -4589,7 +4585,6 @@ gsk_gl_shader_node_new (GskGLShader           *shader,
   g_assert (g_bytes_get_size (uniform_data) == uniforms_size);
 
   self->uniform_data = g_bytes_ref (uniform_data);
-  self->fallback = gsk_render_node_ref (fallback);
 
   self->n_children = n_children;
   if (n_children > 0)
@@ -4602,24 +4597,6 @@ gsk_gl_shader_node_new (GskGLShader           *shader,
   return node;
 }
 
-/**
- * gsk_gl_shader_node_get_fallback_child:
- * @node: (type GskGLShaderNode): a #GskRenderNode for a gl shader
- *
- * Gets the fallback child node
- *
- * Returns: (transfer none): The fallback node
- */
-GskRenderNode *
-gsk_gl_shader_node_get_fallback_child (GskRenderNode *node)
-{
-  GskGLShaderNode *self = (GskGLShaderNode *) node;
-
-  g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_GL_SHADER_NODE), NULL);
-
-  return self->fallback;
-}
-
 /**
  * gsk_gl_shader_node_get_n_children:
  * @node: (type GskGLShaderNode): a #GskRenderNode for a gl shader
diff --git a/gsk/gskrendernodeparser.c b/gsk/gskrendernodeparser.c
index ca447e4a8d..28ecebbdea 100644
--- a/gsk/gskrendernodeparser.c
+++ b/gsk/gskrendernodeparser.c
@@ -1213,7 +1213,6 @@ static GskRenderNode *
 parse_glshader_node (GtkCssParser *parser)
 {
   graphene_rect_t bounds = GRAPHENE_RECT_INIT (0, 0, 50, 50);
-  GskRenderNode *fallback = NULL;
   GskRenderNode *child[4] = { NULL, };
   ShaderInfo shader_info = {
     NULL,
@@ -1223,7 +1222,6 @@ parse_glshader_node (GtkCssParser *parser)
     { "bounds", parse_rect, NULL, &bounds },
     { "sourcecode", parse_shader, NULL, &shader_info },
     { "uniform-data", parse_uniform_data, clear_shader_info, &shader_info },
-    { "fallback", parse_node, clear_node, &fallback },
     { "child1", parse_node, clear_node, &child[0] },
     { "child2", parse_node, clear_node, &child[1] },
     { "child3", parse_node, clear_node, &child[2] },
@@ -1303,7 +1301,7 @@ parse_glshader_node (GtkCssParser *parser)
   gsk_uniform_data_builder_free (builder);
 
   node = gsk_gl_shader_node_new (shader, &bounds, uniform_data,
-                                fallback, child, len);
+                                 child, len);
 
   g_array_unref (shader_info.uniform_values);
   g_bytes_unref (uniform_data);
@@ -2832,7 +2830,6 @@ render_node_print (Printer       *p,
             g_string_free (data, TRUE);
           }
 
-        append_node_param (p, "fallback", gsk_gl_shader_node_get_fallback_child (node));
         for (guint i = 0; i < gsk_gl_shader_node_get_n_children (node); i ++)
           {
             GskRenderNode *child = gsk_gl_shader_node_get_child (node, i);
diff --git a/gsk/vulkan/gskvulkanrenderpass.c b/gsk/vulkan/gskvulkanrenderpass.c
index ad729958ca..be8dd2795a 100644
--- a/gsk/vulkan/gskvulkanrenderpass.c
+++ b/gsk/vulkan/gskvulkanrenderpass.c
@@ -256,6 +256,7 @@ gsk_vulkan_render_pass_add_node (GskVulkanRenderPass           *self,
     case GSK_NOT_A_RENDER_NODE:
       g_assert_not_reached ();
       return;
+    case GSK_GL_SHADER_NODE:
     case GSK_SHADOW_NODE:
     case GSK_RADIAL_GRADIENT_NODE:
     case GSK_REPEATING_RADIAL_GRADIENT_NODE:
@@ -539,10 +540,6 @@ gsk_vulkan_render_pass_add_node (GskVulkanRenderPass           *self,
       }
       return;
 
-    case GSK_GL_SHADER_NODE:
-     gsk_vulkan_render_pass_add_node (self, render, constants, gsk_gl_shader_node_get_fallback_child (node));
-      return;
-
     case GSK_DEBUG_NODE:
       gsk_vulkan_render_pass_add_node (self, render, constants, gsk_debug_node_get_child (node));
       return;
diff --git a/gtk/gtksnapshot.c b/gtk/gtksnapshot.c
index 310a271feb..74cf37d960 100644
--- a/gtk/gtksnapshot.c
+++ b/gtk/gtksnapshot.c
@@ -820,19 +820,6 @@ 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_gl_shader (GtkSnapshot      *snapshot,
                                 GtkSnapshotState *state,
@@ -849,7 +836,7 @@ gtk_snapshot_collect_gl_shader (GtkSnapshot      *snapshot,
 
   state->data.glshader.nodes[state->data.glshader.node_idx] = child_node;
 
-  if (state->data.glshader.node_idx != state->data.glshader.n_children)
+  if (state->data.glshader.node_idx != state->data.glshader.n_children - 1)
     return NULL; /* Not last */
 
   /* This is the last pop */
@@ -859,20 +846,16 @@ gtk_snapshot_collect_gl_shader (GtkSnapshot      *snapshot,
   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_gl_shader_node_new (state->data.glshader.shader,
                                             &state->data.glshader.bounds,
                                             state->data.glshader.uniform_data,
-                                            fallback_node,
-                                            &state->data.glshader.nodes[1],
+                                            &state->data.glshader.nodes[0],
                                             state->data.glshader.n_children);
-      gsk_render_node_unref (fallback_node);
     }
 
   g_object_unref (state->data.glshader.shader);
   g_bytes_unref (state->data.glshader.uniform_data);
-  for (guint i = 0; i  < state->data.glshader.n_children + 1; i++)
+  for (guint i = 0; i  < state->data.glshader.n_children; i++)
     gsk_render_node_unref (state->data.glshader.nodes[i]);
   g_free (state->data.glshader.nodes);
 
@@ -888,13 +871,13 @@ gtk_snapshot_collect_gl_shader (GtkSnapshot      *snapshot,
  * @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 fallback node and a list of
- * @n_children other nodes which will be passed to the #GskGLShaderNode.
+ * to use while rendering. Additionally this takes a list of @n_children other nodes
+ * which will be passed to the #GskGLShaderNode.
  *
- * The fallback node is used if GLSL shaders are not supported by the backend, or if
- * there is any problem compiling the shader. The fallback node needs to be pushed
- * directly after the gtk_snapshot_push_gl_shader() call up until the first  call
- * to gtk_snapshot_pop().
+ * If the renderer doesn't support GL shaders, or if there is any problem when
+ * compiling the shader, then the node will draw pink. You should use
+ * 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
@@ -926,13 +909,13 @@ gtk_snapshot_push_gl_shader (GtkSnapshot           *snapshot,
   state->data.glshader.shader = g_object_ref (shader);
   state->data.glshader.uniform_data = g_bytes_ref (uniform_data);
   state->data.glshader.n_children = n_children;
-  nodes = g_new0 (GskRenderNode *, n_children + 1);
-  node_idx = n_children; /* We pop in reverse order */
+  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;
 
-  for (int i = 0; i  < n_children; i++)
+  for (int i = 0; i  < n_children-1; i++)
     {
       state = gtk_snapshot_push_state (snapshot,
                                        gtk_snapshot_get_current_state (snapshot)->transform,
diff --git a/gtk/inspector/recorder.c b/gtk/inspector/recorder.c
index 59747d625a..c14d4412a4 100644
--- a/gtk/inspector/recorder.c
+++ b/gtk/inspector/recorder.c
@@ -173,7 +173,7 @@ create_list_model_for_render_node (GskRenderNode *node)
 
     case GSK_GL_SHADER_NODE:
       {
-        GListStore *store = G_LIST_STORE (create_render_node_list_model ((GskRenderNode *[1]) { 
gsk_gl_shader_node_get_fallback_child (node) }, 1));
+        GListStore *store = g_list_store_new (GDK_TYPE_PAINTABLE);
 
         for (guint i = 0; i < gsk_gl_shader_node_get_n_children (node); i++)
           {


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