[gtk+/wip/matthiasc/shadertoy: 1/3] wip: support custom shaders in vulkan



commit 5e887ee1cabe245b962d86268029b8b3198a2202
Author: Matthias Clasen <mclasen redhat com>
Date:   Sat Sep 23 20:38:12 2017 -0400

    wip: support custom shaders in vulkan
    
    Initial work for letting widgets and eventually applications
    provide their own shaders. Unsolved problems involve involve:
    textures - can we determine automatically how many children
    each node has and add them as texture inputs to the shader?
    Other input needs to be described in the pipeline setup code.
    
    For now, we don't have any textures, and provide only a fixed
    set of inputs: the rectangle, and a time parameter.

 gsk/gskenums.h                       |    4 +-
 gsk/gskrendernode.h                  |    6 ++
 gsk/gskrendernodeimpl.c              |  148 +++++++++++++++++++++++++++++++
 gsk/gskrendernodeprivate.h           |    4 +
 gsk/gskvulkancustompipeline.c        |  159 ++++++++++++++++++++++++++++++++++
 gsk/gskvulkancustompipelineprivate.h |   34 +++++++
 gsk/gskvulkanpipeline.c              |   39 ++++++++-
 gsk/gskvulkanpipelineprivate.h       |    9 ++
 gsk/gskvulkanrender.c                |   23 +++++
 gsk/gskvulkanrenderpass.c            |   52 +++++++++++-
 gsk/gskvulkanrenderprivate.h         |    3 +
 gsk/gskvulkanshader.c                |    2 +-
 gsk/gskvulkanshaderprivate.h         |    4 +
 gsk/meson.build                      |    1 +
 14 files changed, 481 insertions(+), 7 deletions(-)
---
diff --git a/gsk/gskenums.h b/gsk/gskenums.h
index ca9d5a8..b4d20be 100644
--- a/gsk/gskenums.h
+++ b/gsk/gskenums.h
@@ -45,6 +45,7 @@
  * @GSK_CROSS_FADE_NODE: A node that cross-fades between two children
  * @GSK_TEXT_NODE: A node containing a glyph string
  * @GSK_BLUR_NODE: A node that applies a blur
+ * @GSK_PIXEL_SHADER_NODE: A node that applies a custom shader
  *
  * The type of a node determines what the node is rendering.
  *
@@ -71,7 +72,8 @@ typedef enum {
   GSK_BLEND_NODE,
   GSK_CROSS_FADE_NODE,
   GSK_TEXT_NODE,
-  GSK_BLUR_NODE
+  GSK_BLUR_NODE,
+  GSK_PIXEL_SHADER_NODE
 } GskRenderNodeType;
 
 /**
diff --git a/gsk/gskrendernode.h b/gsk/gskrendernode.h
index 3816e1c..dbcaa9f 100644
--- a/gsk/gskrendernode.h
+++ b/gsk/gskrendernode.h
@@ -185,6 +185,12 @@ GDK_AVAILABLE_IN_3_92
 GskRenderNode *         gsk_blur_node_new                       (GskRenderNode *child,
                                                                  double         radius);
 
+GDK_AVAILABLE_IN_3_92
+GskRenderNode *         gsk_pixel_shader_node_new               (const graphene_rect_t *bounds,
+                                                                 GBytes                *vertex_bytes,
+                                                                 GBytes                *fragement_bytes,
+                                                                 float                  time);
+
 GDK_AVAILABLE_IN_3_90
 void                    gsk_render_node_set_scaling_filters     (GskRenderNode *node,
                                                                  GskScalingFilter min_filter,
diff --git a/gsk/gskrendernodeimpl.c b/gsk/gskrendernodeimpl.c
index c5d26b2..d7e3307 100644
--- a/gsk/gskrendernodeimpl.c
+++ b/gsk/gskrendernodeimpl.c
@@ -4360,6 +4360,154 @@ gsk_blur_node_get_radius (GskRenderNode *node)
   return self->radius;
 }
 
+/*** GSK_PIXEL_SHADER_NODE ***/
+
+typedef struct _GskPixelShaderNode GskPixelShaderNode;
+
+struct _GskPixelShaderNode
+{
+  GskRenderNode render_node;
+
+  GBytes *vertex_bytes;
+  GBytes *fragment_bytes;
+
+  float time;
+};
+
+static void
+gsk_pixel_shader_node_finalize (GskRenderNode *node)
+{
+  GskPixelShaderNode *self = (GskPixelShaderNode *) node;
+
+  g_bytes_unref (self->vertex_bytes);
+  g_bytes_unref (self->fragment_bytes);
+}
+
+static void
+gsk_pixel_shader_node_draw (GskRenderNode *node,
+                            cairo_t       *cr)
+{
+  cairo_save (cr);
+  cairo_set_source_rgb (cr, 1, 0, 0);
+  cairo_paint (cr);
+  cairo_restore (cr);
+}
+
+#define GSK_PIXEL_SHADER_NODE_VARIANT_TYPE "(ddddayayd)"
+
+static GVariant *
+gsk_pixel_shader_node_serialize (GskRenderNode *node)
+{
+  GskPixelShaderNode *self = (GskPixelShaderNode *) node;
+
+  return g_variant_new ("(dddd@ay@ayd)",
+                        (double) node->bounds.origin.x, (double) node->bounds.origin.y,
+                        (double) node->bounds.size.width, (double) node->bounds.size.height,
+                         g_variant_new_fixed_array (G_VARIANT_TYPE ("y"),
+                                                    g_bytes_get_data (self->vertex_bytes, NULL),
+                                                    g_bytes_get_size (self->vertex_bytes), 1),
+                         g_variant_new_fixed_array (G_VARIANT_TYPE ("y"),
+                                                    g_bytes_get_data (self->fragment_bytes, NULL),
+                                                    g_bytes_get_size (self->fragment_bytes), 1),
+                         self->time);
+}
+
+static GskRenderNode *
+gsk_pixel_shader_node_deserialize (GVariant  *variant,
+                                   GError   **error)
+{
+  GVariant *vertex_variant;
+  GVariant *fragment_variant;
+  char *data;
+  double bounds[4];
+  double time;
+  gsize length;
+  GBytes *vertex_bytes;
+  GBytes *fragment_bytes;
+  GskRenderNode *node;
+
+  g_variant_get (variant, "(dddd@ay@ay)",
+                 &bounds[0], &bounds[1], &bounds[2], &bounds[3],
+                 &vertex_variant, &fragment_variant, &time);
+
+  /* XXX: Make this work without copying the data */
+  data = g_variant_get_fixed_array (vertex_variant, &length, 1);
+  vertex_bytes = g_bytes_new (data, length);
+
+  data = g_variant_get_fixed_array (fragment_variant, &length, 1);
+  fragment_bytes = g_bytes_new (data, length);
+
+  node = gsk_pixel_shader_node_new (&GRAPHENE_RECT_INIT(bounds[0], bounds[1], bounds[2], bounds[3]),
+                                    vertex_bytes, fragment_bytes, time);
+
+  g_bytes_unref (vertex_bytes);
+  g_bytes_unref (fragment_bytes);
+  g_variant_unref (vertex_variant);
+  g_variant_unref (fragment_variant);
+
+  return node;
+}
+
+static const GskRenderNodeClass GSK_PIXEL_SHADER_NODE_CLASS = {
+  GSK_PIXEL_SHADER_NODE,
+  sizeof (GskPixelShaderNode),
+  "GskPixelShaderNode",
+  gsk_pixel_shader_node_finalize,
+  gsk_pixel_shader_node_draw,
+  gsk_pixel_shader_node_serialize,
+  gsk_pixel_shader_node_deserialize
+};
+
+GskRenderNode *
+gsk_pixel_shader_node_new (const graphene_rect_t *bounds,
+                           GBytes                *vertex_bytes,
+                           GBytes                *fragment_bytes,
+                           float                  time)
+{
+  GskPixelShaderNode *self;
+
+  self = (GskPixelShaderNode *) gsk_render_node_new (&GSK_PIXEL_SHADER_NODE_CLASS, 0);
+
+  graphene_rect_init_from_rect (&self->render_node.bounds, bounds);
+  self->vertex_bytes = g_bytes_ref (vertex_bytes);
+  self->fragment_bytes = g_bytes_ref (fragment_bytes);
+  self->time = time;
+
+  return &self->render_node;
+}
+
+GBytes *
+gsk_pixel_shader_node_get_vertex_bytes (GskRenderNode *node)
+{
+  GskPixelShaderNode *self = (GskPixelShaderNode *) node;
+
+  g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_PIXEL_SHADER_NODE), NULL);
+
+  return self->vertex_bytes;
+}
+
+GBytes *
+gsk_pixel_shader_node_get_fragment_bytes (GskRenderNode *node)
+{
+  GskPixelShaderNode *self = (GskPixelShaderNode *) node;
+
+  g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_PIXEL_SHADER_NODE), NULL);
+
+  return self->fragment_bytes;
+}
+
+float
+gsk_pixel_shader_node_get_time (GskRenderNode *node)
+{
+  GskPixelShaderNode *self = (GskPixelShaderNode *) node;
+
+  g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_PIXEL_SHADER_NODE), 0);
+
+  return self->time;
+}
+
+/*** ***/
+
 static const GskRenderNodeClass *klasses[] = {
   [GSK_CONTAINER_NODE] = &GSK_CONTAINER_NODE_CLASS,
   [GSK_CAIRO_NODE] = &GSK_CAIRO_NODE_CLASS,
diff --git a/gsk/gskrendernodeprivate.h b/gsk/gskrendernodeprivate.h
index 4934ea3..7b29e94 100644
--- a/gsk/gskrendernodeprivate.h
+++ b/gsk/gskrendernodeprivate.h
@@ -110,6 +110,10 @@ double gsk_cross_fade_node_get_progress (GskRenderNode *node);
 GskRenderNode * gsk_blur_node_get_child (GskRenderNode *node);
 double gsk_blur_node_get_radius (GskRenderNode *node);
 
+GBytes * gsk_pixel_shader_node_get_vertex_bytes (GskRenderNode *node);
+GBytes * gsk_pixel_shader_node_get_fragment_bytes (GskRenderNode *node);
+float    gsk_pixel_shader_node_get_time (GskRenderNode *node);
+
 G_END_DECLS
 
 #endif /* __GSK_RENDER_NODE_PRIVATE_H__ */
diff --git a/gsk/gskvulkancustompipeline.c b/gsk/gskvulkancustompipeline.c
new file mode 100644
index 0000000..4b69f6f
--- /dev/null
+++ b/gsk/gskvulkancustompipeline.c
@@ -0,0 +1,159 @@
+#include "config.h"
+
+#include "gskvulkancustompipelineprivate.h"
+
+struct _GskVulkanCustomPipeline
+{
+  GObject parent_instance;
+};
+
+typedef struct _GskVulkanCustomInstance GskVulkanCustomInstance;
+
+struct _GskVulkanCustomInstance
+{
+  float rect[4];
+  float time;
+};
+
+G_DEFINE_TYPE (GskVulkanCustomPipeline, gsk_vulkan_custom_pipeline, GSK_TYPE_VULKAN_PIPELINE)
+
+static const VkPipelineVertexInputStateCreateInfo *
+gsk_vulkan_custom_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
+{
+  static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
+      {
+          .binding = 0,
+          .stride = sizeof (GskVulkanCustomInstance),
+          .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE
+      }
+  };
+  static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = {
+      {
+          .location = 0,
+          .binding = 0,
+          .format = VK_FORMAT_R32G32B32A32_SFLOAT,
+          .offset = 0,
+      },
+      {
+          .location = 1,
+          .binding = 0,
+          .format = VK_FORMAT_R32_SFLOAT,
+          .offset = G_STRUCT_OFFSET (GskVulkanCustomInstance, time),
+      },
+  };
+  static const VkPipelineVertexInputStateCreateInfo info = {
+      .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
+      .vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions),
+      .pVertexBindingDescriptions = vertexBindingDescriptions,
+      .vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription),
+      .pVertexAttributeDescriptions = vertexInputAttributeDescription
+  };
+
+  return &info;
+}
+
+static void
+gsk_vulkan_custom_pipeline_finalize (GObject *gobject)
+{
+  //GskVulkanCustomPipeline *self = GSK_VULKAN_BLUR_PIPELINE (gobject);
+
+  G_OBJECT_CLASS (gsk_vulkan_custom_pipeline_parent_class)->finalize (gobject);
+}
+
+static void
+gsk_vulkan_custom_pipeline_class_init (GskVulkanCustomPipelineClass *klass)
+{
+  GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass);
+
+  G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_custom_pipeline_finalize;
+
+  pipeline_class->get_input_state_create_info = gsk_vulkan_custom_pipeline_get_input_state_create_info;
+}
+
+static void
+gsk_vulkan_custom_pipeline_init (GskVulkanCustomPipeline *self)
+{
+}
+
+GskVulkanPipeline *
+gsk_vulkan_custom_pipeline_new (GdkVulkanContext      *context,
+                                VkPipelineLayout       layout,
+                                GBytes                *vertex_bytes,
+                                GBytes                *fragment_bytes,
+                                VkRenderPass           render_pass)
+{
+  GskVulkanShader *vertex_shader;
+  GskVulkanShader *fragment_shader;
+  GError *error = NULL;
+
+  if (vertex_bytes != NULL)
+    vertex_shader = gsk_vulkan_shader_new_from_bytes (context,
+                                                      GSK_VULKAN_SHADER_VERTEX,
+                                                      vertex_bytes,
+                                                      &error);
+  else
+    vertex_shader = gsk_vulkan_shader_new_from_resource (context,
+                                                         GSK_VULKAN_SHADER_VERTEX,
+                                                         "color", // FIXME
+                                                         &error);
+  if (vertex_shader == NULL)
+    {
+      g_error ("%s", error->message);
+      g_error_free (error);
+      return NULL;
+    }
+
+  fragment_shader = gsk_vulkan_shader_new_from_bytes (context,
+                                                      GSK_VULKAN_SHADER_FRAGMENT,
+                                                      fragment_bytes,
+                                                      &error);
+  if (fragment_shader == NULL)
+    {
+      g_error ("%s", error->message);
+      g_error_free (error);
+      return NULL;
+    }
+
+  return gsk_vulkan_pipeline_new_with_shaders (GSK_TYPE_VULKAN_CUSTOM_PIPELINE,
+                                               context, layout,
+                                               vertex_shader,
+                                               fragment_shader,
+                                               render_pass,
+                                               VK_BLEND_FACTOR_ONE,
+                                               VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA);
+}
+
+gsize
+gsk_vulkan_custom_pipeline_count_vertex_data (GskVulkanCustomPipeline *pipeline)
+{
+  return sizeof (GskVulkanCustomInstance);
+}
+
+void
+gsk_vulkan_custom_pipeline_collect_vertex_data (GskVulkanCustomPipeline *pipeline,
+                                                guchar                  *data,
+                                                const graphene_rect_t   *rect,
+                                                float                    time)
+{
+  GskVulkanCustomInstance *instance = (GskVulkanCustomInstance *) data;
+
+  instance->rect[0] = rect->origin.x;
+  instance->rect[1] = rect->origin.y;
+  instance->rect[2] = rect->size.width;
+  instance->rect[3] = rect->size.height;
+
+  instance->time = time;
+}
+
+gsize
+gsk_vulkan_custom_pipeline_draw (GskVulkanCustomPipeline *pipeline,
+                                 VkCommandBuffer          command_buffer,
+                                 gsize                    offset,
+                                 gsize                    n_commands)
+{
+  vkCmdDraw (command_buffer,
+             6, n_commands,
+             0, offset);
+
+  return n_commands;
+}
diff --git a/gsk/gskvulkancustompipelineprivate.h b/gsk/gskvulkancustompipelineprivate.h
new file mode 100644
index 0000000..f430bc3
--- /dev/null
+++ b/gsk/gskvulkancustompipelineprivate.h
@@ -0,0 +1,34 @@
+#ifndef __GSK_VULKAN_CUSTOM_PIPELINE_PRIVATE_H__
+#define __GSK_VULKAN_CUSTOM_PIPELINE_PRIVATE_H__
+
+#include <graphene.h>
+
+#include "gskvulkanpipelineprivate.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GskVulkanCustomPipelineLayout GskVulkanCustomPipelineLayout;
+
+#define GSK_TYPE_VULKAN_CUSTOM_PIPELINE (gsk_vulkan_custom_pipeline_get_type ())
+
+G_DECLARE_FINAL_TYPE (GskVulkanCustomPipeline, gsk_vulkan_custom_pipeline, GSK, VULKAN_CUSTOM_PIPELINE, 
GskVulkanPipeline)
+
+GskVulkanPipeline *     gsk_vulkan_custom_pipeline_new                   (GdkVulkanContext        *context,
+                                                                          VkPipelineLayout         layout,
+                                                                          GBytes                  
*vertex_shader,
+                                                                          GBytes                  
*fragment_shader,
+                                                                          VkRenderPass             
render_pass);
+
+gsize                   gsk_vulkan_custom_pipeline_count_vertex_data     (GskVulkanCustomPipeline   
*pipeline);
+void                    gsk_vulkan_custom_pipeline_collect_vertex_data   (GskVulkanCustomPipeline   
*pipeline,
+                                                                          guchar                  *data,
+                                                                          const graphene_rect_t   *rect,
+                                                                          float                    time);
+gsize                   gsk_vulkan_custom_pipeline_draw                  (GskVulkanCustomPipeline   
*pipeline,
+                                                                          VkCommandBuffer          
command_buffer,
+                                                                          gsize                    offset,
+                                                                          gsize                    
n_commands);
+
+G_END_DECLS
+
+#endif /* __GSK_VULKAN_CUSTOM_PIPELINE_PRIVATE_H__ */
diff --git a/gsk/gskvulkanpipeline.c b/gsk/gskvulkanpipeline.c
index 38d5a57..341c683 100644
--- a/gsk/gskvulkanpipeline.c
+++ b/gsk/gskvulkanpipeline.c
@@ -60,7 +60,9 @@ gsk_vulkan_pipeline_new (GType                    pipeline_type,
                          const char              *shader_name,
                          VkRenderPass             render_pass)
 {
-  return gsk_vulkan_pipeline_new_full (pipeline_type, context, layout, shader_name, render_pass,
+  return gsk_vulkan_pipeline_new_full (pipeline_type, context, layout,
+                                       shader_name,
+                                       render_pass,
                                        VK_BLEND_FACTOR_ONE,
                                        VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA);
 }
@@ -74,13 +76,42 @@ gsk_vulkan_pipeline_new_full (GType                    pipeline_type,
                               VkBlendFactor            srcBlendFactor,
                               VkBlendFactor            dstBlendFactor)
 {
+  GskVulkanShader *vertex_shader;
+  GskVulkanShader *fragment_shader;
+
+  vertex_shader = gsk_vulkan_shader_new_from_resource (context,
+                                                       GSK_VULKAN_SHADER_VERTEX,
+                                                       shader_name,
+                                                       NULL);
+  fragment_shader = gsk_vulkan_shader_new_from_resource (context,
+                                                         GSK_VULKAN_SHADER_FRAGMENT,
+                                                         shader_name,
+                                                         NULL);
+
+  return gsk_vulkan_pipeline_new_with_shaders (pipeline_type, context, layout,
+                                               vertex_shader, fragment_shader,
+                                               render_pass,
+                                               srcBlendFactor, dstBlendFactor);
+}
+
+GskVulkanPipeline *
+gsk_vulkan_pipeline_new_with_shaders (GType                    pipeline_type,
+                                      GdkVulkanContext        *context,
+                                      VkPipelineLayout         layout,
+                                      GskVulkanShader         *vertex_shader,
+                                      GskVulkanShader         *fragment_shader,
+                                      VkRenderPass             render_pass,
+                                      VkBlendFactor            srcBlendFactor,
+                                      VkBlendFactor            dstBlendFactor)
+{
   GskVulkanPipelinePrivate *priv;
   GskVulkanPipeline *self;
   VkDevice device;
 
   g_return_val_if_fail (g_type_is_a (pipeline_type, GSK_TYPE_VULKAN_PIPELINE), NULL);
   g_return_val_if_fail (layout != VK_NULL_HANDLE, NULL);
-  g_return_val_if_fail (shader_name != NULL, NULL);
+  g_return_val_if_fail (vertex_shader != NULL, NULL);
+  g_return_val_if_fail (fragment_shader != NULL, NULL);
   g_return_val_if_fail (render_pass != VK_NULL_HANDLE, NULL);
 
   self = g_object_new (pipeline_type, NULL);
@@ -92,8 +123,8 @@ gsk_vulkan_pipeline_new_full (GType                    pipeline_type,
   priv->context = context;
   priv->layout = layout;
 
-  priv->vertex_shader = gsk_vulkan_shader_new_from_resource (context, GSK_VULKAN_SHADER_VERTEX, shader_name, 
NULL);
-  priv->fragment_shader = gsk_vulkan_shader_new_from_resource (context, GSK_VULKAN_SHADER_FRAGMENT, 
shader_name, NULL);
+  priv->vertex_shader = vertex_shader;
+  priv->fragment_shader = fragment_shader;
 
   GSK_VK_CHECK (vkCreateGraphicsPipelines, device,
                                            VK_NULL_HANDLE,
diff --git a/gsk/gskvulkanpipelineprivate.h b/gsk/gskvulkanpipelineprivate.h
index cd41f82..6d03b54 100644
--- a/gsk/gskvulkanpipelineprivate.h
+++ b/gsk/gskvulkanpipelineprivate.h
@@ -4,6 +4,7 @@
 #include <gdk/gdk.h>
 
 #include "gskdebugprivate.h"
+#include "gskvulkanshaderprivate.h"
 
 G_BEGIN_DECLS
 
@@ -44,6 +45,14 @@ GskVulkanPipeline *     gsk_vulkan_pipeline_new_full                    (GType
                                                                          VkRenderPass                    
render_pass,
                                                                          VkBlendFactor                   
srcBlendFactor,
                                                                          VkBlendFactor                   
dstBlendFactor);
+GskVulkanPipeline *     gsk_vulkan_pipeline_new_with_shaders            (GType                           
pipeline_type,
+                                                                         GdkVulkanContext               
*context,
+                                                                         VkPipelineLayout                
layout,
+                                                                         GskVulkanShader                
*vertex_shader,
+                                                                         GskVulkanShader                
*fragment_shader,
+                                                                         VkRenderPass                    
render_pass,
+                                                                         VkBlendFactor                   
srcBlendFactor,
+                                                                         VkBlendFactor                   
dstBlendFactor);
 
 VkPipeline              gsk_vulkan_pipeline_get_pipeline                (GskVulkanPipeline              
*self);
 VkPipelineLayout        gsk_vulkan_pipeline_get_pipeline_layout         (GskVulkanPipeline              
*self);
diff --git a/gsk/gskvulkanrender.c b/gsk/gskvulkanrender.c
index f87f4cc..f5ef788 100644
--- a/gsk/gskvulkanrender.c
+++ b/gsk/gskvulkanrender.c
@@ -18,6 +18,7 @@
 #include "gskvulkancolorpipelineprivate.h"
 #include "gskvulkancolortextpipelineprivate.h"
 #include "gskvulkancrossfadepipelineprivate.h"
+#include "gskvulkancustompipelineprivate.h"
 #include "gskvulkaneffectpipelineprivate.h"
 #include "gskvulkanlineargradientpipelineprivate.h"
 #include "gskvulkantextpipelineprivate.h"
@@ -59,6 +60,7 @@ struct _GskVulkanRender
 
   GSList *render_passes;
   GSList *cleanup_images;
+  GSList *cleanup_pipelines;
 };
 
 static void
@@ -409,6 +411,25 @@ gsk_vulkan_render_get_pipeline (GskVulkanRender       *self,
   return self->pipelines[type];
 }
 
+GskVulkanPipeline *
+gsk_vulkan_render_get_custom_pipeline (GskVulkanRender *self,
+                                       GBytes          *vertex_bytes,
+                                       GBytes          *fragment_bytes)
+{
+  GskVulkanPipeline *pipeline;
+
+
+  pipeline = gsk_vulkan_custom_pipeline_new (self->vulkan,
+                                             self->pipeline_layout[0],
+                                             vertex_bytes,
+                                             fragment_bytes,
+                                             self->render_pass);
+
+  self->cleanup_pipelines = g_slist_prepend (self->cleanup_pipelines, pipeline);
+
+  return pipeline;
+}
+
 VkDescriptorSet
 gsk_vulkan_render_get_descriptor_set (GskVulkanRender *self,
                                       gsize            id)
@@ -645,6 +666,8 @@ gsk_vulkan_render_cleanup (GskVulkanRender *self)
   self->render_passes = NULL;
   g_slist_free_full (self->cleanup_images, g_object_unref);
   self->cleanup_images = NULL;
+  g_slist_free_full (self->cleanup_pipelines, g_object_unref);
+  self->cleanup_pipelines = NULL;
 
   g_clear_pointer (&self->clip, cairo_region_destroy);
   g_clear_object (&self->target);
diff --git a/gsk/gskvulkanrenderpass.c b/gsk/gskvulkanrenderpass.c
index efdef6d..f158616 100644
--- a/gsk/gskvulkanrenderpass.c
+++ b/gsk/gskvulkanrenderpass.c
@@ -15,6 +15,7 @@
 #include "gskvulkancolorpipelineprivate.h"
 #include "gskvulkancolortextpipelineprivate.h"
 #include "gskvulkancrossfadepipelineprivate.h"
+#include "gskvulkancustompipelineprivate.h"
 #include "gskvulkaneffectpipelineprivate.h"
 #include "gskvulkanlineargradientpipelineprivate.h"
 #include "gskvulkantextpipelineprivate.h"
@@ -47,6 +48,7 @@ typedef enum {
   GSK_VULKAN_OP_OUTSET_SHADOW,
   GSK_VULKAN_OP_CROSS_FADE,
   GSK_VULKAN_OP_BLEND_MODE,
+  GSK_VULKAN_OP_PIXEL_SHADER,
   /* GskVulkanOpText */
   GSK_VULKAN_OP_TEXT,
   GSK_VULKAN_OP_COLOR_TEXT,
@@ -171,6 +173,14 @@ gsk_vulkan_render_pass_add_node (GskVulkanRenderPass           *self,
     default:
       FALLBACK ("Unsupported node '%s'\n", node->node_class->type_name);
 
+    case GSK_PIXEL_SHADER_NODE:
+      op.type = GSK_VULKAN_OP_PIXEL_SHADER;
+      op.render.pipeline = gsk_vulkan_render_get_custom_pipeline (render,
+                                                                  gsk_pixel_shader_node_get_vertex_bytes 
(node),
+                                                                  gsk_pixel_shader_node_get_fragment_bytes 
(node));
+      g_array_append_val (self->render_ops, op);
+      return;
+
     case GSK_BLEND_NODE:
       if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
         pipeline_type = GSK_VULKAN_PIPELINE_BLEND_MODE;
@@ -183,7 +193,7 @@ gsk_vulkan_render_pass_add_node (GskVulkanRenderPass           *self,
       op.type = GSK_VULKAN_OP_BLEND_MODE;
       op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
       g_array_append_val (self->render_ops, op);
-       return;
+      return;
 
     case GSK_CROSS_FADE_NODE:
       if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
@@ -785,6 +795,7 @@ gsk_vulkan_render_pass_upload (GskVulkanRenderPass  *self,
         case GSK_VULKAN_OP_BORDER:
         case GSK_VULKAN_OP_INSET_SHADOW:
         case GSK_VULKAN_OP_OUTSET_SHADOW:
+        case GSK_VULKAN_OP_PIXEL_SHADER:
           break;
         }
     }
@@ -867,6 +878,11 @@ gsk_vulkan_render_pass_count_vertex_data (GskVulkanRenderPass *self)
           n_bytes += op->render.vertex_count;
           break;
 
+        case GSK_VULKAN_OP_PIXEL_SHADER:
+          op->render.vertex_count = gsk_vulkan_custom_pipeline_count_vertex_data (GSK_VULKAN_CUSTOM_PIPELINE 
(op->render.pipeline));
+          n_bytes += op->render.vertex_count;
+          break;
+
         default:
           g_assert_not_reached ();
         case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS:
@@ -1089,6 +1105,17 @@ gsk_vulkan_render_pass_collect_vertex_data (GskVulkanRenderPass *self,
           }
           break;
 
+        case GSK_VULKAN_OP_PIXEL_SHADER:
+          {
+            op->render.vertex_offset = offset + n_bytes;
+            gsk_vulkan_custom_pipeline_collect_vertex_data (GSK_VULKAN_CUSTOM_PIPELINE (op->render.pipeline),
+                                                            data + n_bytes + offset,
+                                                            &op->render.node->bounds,
+                                                            gsk_pixel_shader_node_get_time 
(op->render.node));
+            n_bytes += op->render.vertex_count;
+          }
+          break;
+
         default:
           g_assert_not_reached ();
         case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS:
@@ -1144,6 +1171,7 @@ gsk_vulkan_render_pass_reserve_descriptor_sets (GskVulkanRenderPass *self,
         case GSK_VULKAN_OP_BORDER:
         case GSK_VULKAN_OP_INSET_SHADOW:
         case GSK_VULKAN_OP_OUTSET_SHADOW:
+        case GSK_VULKAN_OP_PIXEL_SHADER:
           break;
         }
     }
@@ -1507,6 +1535,28 @@ gsk_vulkan_render_pass_draw (GskVulkanRenderPass     *self,
                                                                      current_draw_index, 1);
           break;
 
+        case GSK_VULKAN_OP_PIXEL_SHADER:
+          if (current_pipeline != op->render.pipeline)
+            {
+              current_pipeline = op->render.pipeline;
+              vkCmdBindPipeline (command_buffer,
+                                 VK_PIPELINE_BIND_POINT_GRAPHICS,
+                                 gsk_vulkan_pipeline_get_pipeline (current_pipeline));
+              vkCmdBindVertexBuffers (command_buffer,
+                                      0,
+                                      1,
+                                      (VkBuffer[1]) {
+                                          gsk_vulkan_buffer_get_buffer (vertex_buffer)
+                                      },
+                                      (VkDeviceSize[1]) { op->render.vertex_offset });
+              current_draw_index = 0;
+            }
+
+          current_draw_index += gsk_vulkan_custom_pipeline_draw (GSK_VULKAN_CUSTOM_PIPELINE 
(current_pipeline),
+                                                                 command_buffer,
+                                                                 current_draw_index, 1);
+          break;
+
         default:
           g_assert_not_reached ();
           break;
diff --git a/gsk/gskvulkanrenderprivate.h b/gsk/gskvulkanrenderprivate.h
index ed35019..d8a126a 100644
--- a/gsk/gskvulkanrenderprivate.h
+++ b/gsk/gskvulkanrenderprivate.h
@@ -73,6 +73,9 @@ void                    gsk_vulkan_render_upload                        (GskVulk
 
 GskVulkanPipeline *     gsk_vulkan_render_get_pipeline                  (GskVulkanRender        *self,
                                                                          GskVulkanPipelineType   
pipeline_type);
+GskVulkanPipeline *     gsk_vulkan_render_get_custom_pipeline           (GskVulkanRender        *self,
+                                                                         GBytes                 
*vertex_bytes,
+                                                                         GBytes                 
*fragment_bytes);
 VkDescriptorSet         gsk_vulkan_render_get_descriptor_set            (GskVulkanRender        *self,
                                                                          gsize                   id);
 gsize                   gsk_vulkan_render_reserve_descriptor_set        (GskVulkanRender        *self,
diff --git a/gsk/gskvulkanshader.c b/gsk/gskvulkanshader.c
index 1010b21..7b9d2be 100644
--- a/gsk/gskvulkanshader.c
+++ b/gsk/gskvulkanshader.c
@@ -11,7 +11,7 @@ struct _GskVulkanShader
   VkShaderModule vk_shader;
 };
 
-static GskVulkanShader *
+GskVulkanShader *
 gsk_vulkan_shader_new_from_bytes (GdkVulkanContext     *context,
                                   GskVulkanShaderType   type,
                                   GBytes               *bytes,
diff --git a/gsk/gskvulkanshaderprivate.h b/gsk/gskvulkanshaderprivate.h
index e94424f..11841af 100644
--- a/gsk/gskvulkanshaderprivate.h
+++ b/gsk/gskvulkanshaderprivate.h
@@ -20,6 +20,10 @@ typedef struct _GskVulkanShader GskVulkanShader;
   .pName = "main", \
 }
 
+GskVulkanShader *       gsk_vulkan_shader_new_from_bytes                (GdkVulkanContext       *context,
+                                                                         GskVulkanShaderType     type,
+                                                                         GBytes                 *bytes,
+                                                                         GError                **error);
 GskVulkanShader *       gsk_vulkan_shader_new_from_resource             (GdkVulkanContext       *context,
                                                                          GskVulkanShaderType     type,
                                                                          const char             
*resource_name,
diff --git a/gsk/meson.build b/gsk/meson.build
index e91985a..9f5b756 100644
--- a/gsk/meson.build
+++ b/gsk/meson.build
@@ -64,6 +64,7 @@ if have_vulkan
     'gskvulkancolorpipeline.c',
     'gskvulkancolortextpipeline.c',
     'gskvulkancrossfadepipeline.c',
+    'gskvulkancustompipeline.c',
     'gskvulkancommandpool.c',
     'gskvulkaneffectpipeline.c',
     'gskvulkanglyphcache.c',


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