[gtk+/wip/matthiasc/shadertoy: 1/3] wip: support custom shaders in vulkan
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/wip/matthiasc/shadertoy: 1/3] wip: support custom shaders in vulkan
- Date: Sun, 24 Sep 2017 04:44:15 +0000 (UTC)
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]