Support custom shaders in vulkan
Initial work for letting widgets and eventually applications provide their own shaders. For now, we only have a limited set of inputs: the rectangle, a time parameter and up to two children which are passed as textures to the shader.
This commit is contained in:
@@ -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;
|
||||
|
||||
/**
|
||||
|
||||
@@ -182,6 +182,18 @@ 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,
|
||||
GskRenderNode *child1,
|
||||
GskRenderNode *child2,
|
||||
GBytes *fragement_bytes,
|
||||
float time);
|
||||
GDK_AVAILABLE_IN_3_92
|
||||
GskRenderNode *gsk_pixel_shader_node_get_child1 (GskRenderNode *node);
|
||||
GDK_AVAILABLE_IN_3_92
|
||||
GskRenderNode *gsk_pixel_shader_node_get_child2 (GskRenderNode *node);
|
||||
|
||||
|
||||
GDK_AVAILABLE_IN_3_90
|
||||
void gsk_render_node_set_scaling_filters (GskRenderNode *node,
|
||||
GskScalingFilter min_filter,
|
||||
|
||||
@@ -4414,6 +4414,223 @@ gsk_blur_node_get_radius (GskRenderNode *node)
|
||||
return self->radius;
|
||||
}
|
||||
|
||||
/*** GSK_PIXEL_SHADER_NODE ***/
|
||||
|
||||
typedef struct _GskPixelShaderNode GskPixelShaderNode;
|
||||
|
||||
struct _GskPixelShaderNode
|
||||
{
|
||||
GskRenderNode render_node;
|
||||
|
||||
GBytes *fragment_bytes;
|
||||
|
||||
float time;
|
||||
|
||||
GskRenderNode *child1;
|
||||
GskRenderNode *child2;
|
||||
};
|
||||
|
||||
static void
|
||||
gsk_pixel_shader_node_finalize (GskRenderNode *node)
|
||||
{
|
||||
GskPixelShaderNode *self = (GskPixelShaderNode *) node;
|
||||
|
||||
g_bytes_unref (self->fragment_bytes);
|
||||
|
||||
if (self->child1)
|
||||
gsk_render_node_unref (self->child1);
|
||||
if (self->child2)
|
||||
gsk_render_node_unref (self->child2);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_pixel_shader_node_draw (GskRenderNode *node,
|
||||
cairo_t *cr)
|
||||
{
|
||||
GskPixelShaderNode *self = (GskPixelShaderNode *) node;
|
||||
|
||||
cairo_save (cr);
|
||||
cairo_set_source_rgb (cr, 1, 0, 0);
|
||||
cairo_paint (cr);
|
||||
cairo_restore (cr);
|
||||
|
||||
if (self->child1)
|
||||
gsk_render_node_draw (self->child1, cr);
|
||||
if (self->child2)
|
||||
gsk_render_node_draw (self->child2, cr);
|
||||
}
|
||||
|
||||
#define GSK_PIXEL_SHADER_NODE_VARIANT_TYPE "(dddda(uv)ayd)"
|
||||
|
||||
static GVariant *
|
||||
gsk_pixel_shader_node_serialize (GskRenderNode *node)
|
||||
{
|
||||
GskPixelShaderNode *self = (GskPixelShaderNode *) node;
|
||||
GVariantBuilder builder;
|
||||
|
||||
g_variant_builder_init (&builder, G_VARIANT_TYPE (GSK_CONTAINER_NODE_VARIANT_TYPE));
|
||||
|
||||
if (self->child1)
|
||||
g_variant_builder_add (&builder, "(uv)",
|
||||
(guint32) gsk_render_node_get_node_type (self->child1),
|
||||
gsk_render_node_serialize_node (self->child1));
|
||||
if (self->child2)
|
||||
g_variant_builder_add (&builder, "(uv)",
|
||||
(guint32) gsk_render_node_get_node_type (self->child2),
|
||||
gsk_render_node_serialize_node (self->child2));
|
||||
|
||||
return g_variant_new ("(dddd@ayda(uv))",
|
||||
(double) node->bounds.origin.x, (double) node->bounds.origin.y,
|
||||
(double) node->bounds.size.width, (double) node->bounds.size.height,
|
||||
&builder,
|
||||
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 *fragment_variant;
|
||||
char *data;
|
||||
double bounds[4];
|
||||
double time;
|
||||
gsize length;
|
||||
GBytes *fragment_bytes;
|
||||
GskRenderNode *node;
|
||||
GVariantIter *iter;
|
||||
gsize i, n_children;
|
||||
guint32 child_type;
|
||||
GVariant *child_variant;
|
||||
GskRenderNode *children[2] = { NULL, NULL };
|
||||
|
||||
if (!check_variant_type (variant, GSK_PIXEL_SHADER_NODE_VARIANT_TYPE, error))
|
||||
return NULL;
|
||||
|
||||
g_variant_get (variant, "(dddda(uv)@ayd)",
|
||||
&bounds[0], &bounds[1], &bounds[2], &bounds[3],
|
||||
&iter, &fragment_variant, &time);
|
||||
|
||||
n_children = g_variant_iter_init (iter, variant);
|
||||
if (n_children > 2)
|
||||
return NULL;
|
||||
|
||||
i = 0;
|
||||
while (g_variant_iter_loop (iter, "(uv)", &child_type, &child_variant))
|
||||
{
|
||||
children[i] = gsk_render_node_deserialize_node (child_type, child_variant, error);
|
||||
if (children[i] == NULL)
|
||||
{
|
||||
guint j;
|
||||
for (j = 0; j < i; j++)
|
||||
gsk_render_node_unref (children[j]);
|
||||
g_variant_unref (child_variant);
|
||||
return NULL;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
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]),
|
||||
children[0], children[1],
|
||||
fragment_bytes, time);
|
||||
|
||||
if (children[0])
|
||||
gsk_render_node_unref (children[0]);
|
||||
if (children[1])
|
||||
gsk_render_node_unref (children[1]);
|
||||
|
||||
g_bytes_unref (fragment_bytes);
|
||||
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,
|
||||
GskRenderNode *child1,
|
||||
GskRenderNode *child2,
|
||||
GBytes *fragment_bytes,
|
||||
float time)
|
||||
{
|
||||
GskPixelShaderNode *self;
|
||||
|
||||
self = (GskPixelShaderNode *) gsk_render_node_new (&GSK_PIXEL_SHADER_NODE_CLASS, 0);
|
||||
|
||||
if (child1)
|
||||
self->child1 = gsk_render_node_ref (child1);
|
||||
else
|
||||
self->child1 = NULL;
|
||||
|
||||
if (child2)
|
||||
self->child2 = gsk_render_node_ref (child2);
|
||||
else
|
||||
self->child2 = NULL;
|
||||
|
||||
graphene_rect_init_from_rect (&self->render_node.bounds, bounds);
|
||||
|
||||
self->fragment_bytes = g_bytes_ref (fragment_bytes);
|
||||
self->time = time;
|
||||
|
||||
return &self->render_node;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
GskRenderNode *
|
||||
gsk_pixel_shader_node_get_child1 (GskRenderNode *node)
|
||||
{
|
||||
GskPixelShaderNode *self = (GskPixelShaderNode *) node;
|
||||
|
||||
g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_PIXEL_SHADER_NODE), 0);
|
||||
|
||||
return self->child1;
|
||||
}
|
||||
|
||||
GskRenderNode *
|
||||
gsk_pixel_shader_node_get_child2 (GskRenderNode *node)
|
||||
{
|
||||
GskPixelShaderNode *self = (GskPixelShaderNode *) node;
|
||||
|
||||
g_return_val_if_fail (GSK_IS_RENDER_NODE_TYPE (node, GSK_PIXEL_SHADER_NODE), 0);
|
||||
|
||||
return self->child2;
|
||||
}
|
||||
|
||||
/*** ***/
|
||||
|
||||
static const GskRenderNodeClass *klasses[] = {
|
||||
[GSK_CONTAINER_NODE] = &GSK_CONTAINER_NODE_CLASS,
|
||||
[GSK_CAIRO_NODE] = &GSK_CAIRO_NODE_CLASS,
|
||||
@@ -4434,7 +4651,8 @@ static const GskRenderNodeClass *klasses[] = {
|
||||
[GSK_BLEND_NODE] = &GSK_BLEND_NODE_CLASS,
|
||||
[GSK_CROSS_FADE_NODE] = &GSK_CROSS_FADE_NODE_CLASS,
|
||||
[GSK_TEXT_NODE] = &GSK_TEXT_NODE_CLASS,
|
||||
[GSK_BLUR_NODE] = &GSK_BLUR_NODE_CLASS
|
||||
[GSK_BLUR_NODE] = &GSK_BLUR_NODE_CLASS,
|
||||
[GSK_PIXEL_SHADER_NODE] = &GSK_PIXEL_SHADER_NODE_CLASS,
|
||||
};
|
||||
|
||||
GskRenderNode *
|
||||
|
||||
@@ -110,6 +110,9 @@ 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_fragment_bytes (GskRenderNode *node);
|
||||
float gsk_pixel_shader_node_get_time (GskRenderNode *node);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GSK_RENDER_NODE_PRIVATE_H__ */
|
||||
|
||||
171
gsk/gskvulkancustompipeline.c
Normal file
171
gsk/gskvulkancustompipeline.c
Normal file
@@ -0,0 +1,171 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "gskvulkancustompipelineprivate.h"
|
||||
|
||||
struct _GskVulkanCustomPipeline
|
||||
{
|
||||
GObject parent_instance;
|
||||
};
|
||||
|
||||
typedef struct _GskVulkanCustomInstance GskVulkanCustomInstance;
|
||||
|
||||
struct _GskVulkanCustomInstance
|
||||
{
|
||||
float rect[4];
|
||||
float tex_rect1[4];
|
||||
float tex_rect2[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_R32G32B32A32_SFLOAT,
|
||||
.offset = G_STRUCT_OFFSET (GskVulkanCustomInstance, tex_rect1),
|
||||
},
|
||||
{
|
||||
.location = 2,
|
||||
.binding = 0,
|
||||
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
|
||||
.offset = G_STRUCT_OFFSET (GskVulkanCustomInstance, tex_rect2),
|
||||
},
|
||||
{
|
||||
.location = 3,
|
||||
.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 *fragment_bytes,
|
||||
VkRenderPass render_pass)
|
||||
{
|
||||
GskVulkanShader *vertex_shader;
|
||||
GskVulkanShader *fragment_shader;
|
||||
GError *error = NULL;
|
||||
|
||||
vertex_shader = gsk_vulkan_shader_new_from_resource (context,
|
||||
GSK_VULKAN_SHADER_VERTEX,
|
||||
"custom",
|
||||
&error);
|
||||
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 *bounds,
|
||||
const graphene_rect_t *tex_rect1,
|
||||
const graphene_rect_t *tex_rect2,
|
||||
float time)
|
||||
{
|
||||
GskVulkanCustomInstance *instance = (GskVulkanCustomInstance *) data;
|
||||
|
||||
instance->rect[0] = bounds->origin.x;
|
||||
instance->rect[1] = bounds->origin.y;
|
||||
instance->rect[2] = bounds->size.width;
|
||||
instance->rect[3] = bounds->size.height;
|
||||
|
||||
instance->tex_rect1[0] = tex_rect1->origin.x;
|
||||
instance->tex_rect1[1] = tex_rect1->origin.y;
|
||||
instance->tex_rect1[2] = tex_rect1->size.width;
|
||||
instance->tex_rect1[3] = tex_rect1->size.height;
|
||||
|
||||
instance->tex_rect2[0] = tex_rect2->origin.x;
|
||||
instance->tex_rect2[1] = tex_rect2->origin.y;
|
||||
instance->tex_rect2[2] = tex_rect2->size.width;
|
||||
instance->tex_rect2[3] = tex_rect2->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;
|
||||
}
|
||||
35
gsk/gskvulkancustompipelineprivate.h
Normal file
35
gsk/gskvulkancustompipelineprivate.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#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 *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,
|
||||
const graphene_rect_t *child1_bounds,
|
||||
const graphene_rect_t *child2_bounds,
|
||||
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__ */
|
||||
@@ -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);
|
||||
}
|
||||
@@ -73,6 +75,34 @@ gsk_vulkan_pipeline_new_full (GType pipeline_type,
|
||||
VkRenderPass render_pass,
|
||||
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;
|
||||
@@ -80,7 +110,8 @@ gsk_vulkan_pipeline_new_full (GType pipeline_type,
|
||||
|
||||
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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "gskvulkancolorpipelineprivate.h"
|
||||
#include "gskvulkancolortextpipelineprivate.h"
|
||||
#include "gskvulkancrossfadepipelineprivate.h"
|
||||
#include "gskvulkancustompipelineprivate.h"
|
||||
#include "gskvulkaneffectpipelineprivate.h"
|
||||
#include "gskvulkanlineargradientpipelineprivate.h"
|
||||
#include "gskvulkantextpipelineprivate.h"
|
||||
@@ -57,6 +58,7 @@ struct _GskVulkanRender
|
||||
|
||||
GList *render_passes;
|
||||
GSList *cleanup_images;
|
||||
GSList *cleanup_pipelines;
|
||||
|
||||
GQuark render_pass_counter;
|
||||
GQuark gpu_time_timer;
|
||||
@@ -419,6 +421,22 @@ gsk_vulkan_render_get_pipeline (GskVulkanRender *self,
|
||||
return self->pipelines[type];
|
||||
}
|
||||
|
||||
GskVulkanPipeline *
|
||||
gsk_vulkan_render_get_custom_pipeline (GskVulkanRender *self,
|
||||
GBytes *fragment_bytes)
|
||||
{
|
||||
GskVulkanPipeline *pipeline;
|
||||
|
||||
pipeline = gsk_vulkan_custom_pipeline_new (self->vulkan,
|
||||
self->pipeline_layout[2],
|
||||
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)
|
||||
@@ -666,6 +684,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);
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "gskvulkancolorpipelineprivate.h"
|
||||
#include "gskvulkancolortextpipelineprivate.h"
|
||||
#include "gskvulkancrossfadepipelineprivate.h"
|
||||
#include "gskvulkancustompipelineprivate.h"
|
||||
#include "gskvulkaneffectpipelineprivate.h"
|
||||
#include "gskvulkanlineargradientpipelineprivate.h"
|
||||
#include "gskvulkantextpipelineprivate.h"
|
||||
@@ -53,6 +54,7 @@ typedef enum {
|
||||
GSK_VULKAN_OP_REPEAT,
|
||||
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,
|
||||
@@ -278,6 +280,13 @@ 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_fragment_bytes (node));
|
||||
g_array_append_val (self->render_ops, op);
|
||||
return;
|
||||
|
||||
case GSK_REPEAT_NODE:
|
||||
if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
|
||||
pipeline_type = GSK_VULKAN_PIPELINE_TEXTURE;
|
||||
@@ -304,7 +313,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))
|
||||
@@ -1040,6 +1049,34 @@ gsk_vulkan_render_pass_upload (GskVulkanRenderPass *self,
|
||||
}
|
||||
break;
|
||||
|
||||
case GSK_VULKAN_OP_PIXEL_SHADER:
|
||||
{
|
||||
GskRenderNode *child1 = gsk_pixel_shader_node_get_child1 (op->render.node);
|
||||
GskRenderNode *child2 = gsk_pixel_shader_node_get_child2 (op->render.node);
|
||||
|
||||
if (child1)
|
||||
op->render.source = gsk_vulkan_render_pass_get_node_as_texture (self,
|
||||
render,
|
||||
uploader,
|
||||
child1,
|
||||
&child1->bounds,
|
||||
clip,
|
||||
&op->render.source_rect);
|
||||
else
|
||||
op->render.source = NULL;
|
||||
if (child2)
|
||||
op->render.source2 = gsk_vulkan_render_pass_get_node_as_texture (self,
|
||||
render,
|
||||
uploader,
|
||||
child2,
|
||||
&child2->bounds,
|
||||
clip,
|
||||
&op->render.source_rect);
|
||||
else
|
||||
op->render.source2 = NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS:
|
||||
clip = &op->constants.constants.clip;
|
||||
break;
|
||||
@@ -1134,6 +1171,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 ();
|
||||
|
||||
@@ -1368,6 +1410,19 @@ 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,
|
||||
&op->render.source ? &op->render.source_rect : &GRAPHENE_RECT_INIT(0,0,1,1),
|
||||
&op->render.source2 ? &op->render.source2_rect : &GRAPHENE_RECT_INIT(0,0,1,1),
|
||||
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:
|
||||
@@ -1445,6 +1500,13 @@ gsk_vulkan_render_pass_reserve_descriptor_sets (GskVulkanRenderPass *self,
|
||||
op->render.descriptor_set_index = gsk_vulkan_render_reserve_descriptor_set (render, op->render.source, TRUE);
|
||||
break;
|
||||
|
||||
case GSK_VULKAN_OP_PIXEL_SHADER:
|
||||
if (op->render.source)
|
||||
op->render.descriptor_set_index = gsk_vulkan_render_reserve_descriptor_set (render, op->render.source, FALSE);
|
||||
if (op->render.source2)
|
||||
op->render.descriptor_set_index2 = gsk_vulkan_render_reserve_descriptor_set (render, op->render.source2, FALSE);
|
||||
break;
|
||||
|
||||
case GSK_VULKAN_OP_TEXT:
|
||||
case GSK_VULKAN_OP_COLOR_TEXT:
|
||||
op->text.descriptor_set_index = gsk_vulkan_render_reserve_descriptor_set (render, op->text.source, FALSE);
|
||||
@@ -1844,6 +1906,45 @@ gsk_vulkan_render_pass_draw_rect (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;
|
||||
}
|
||||
|
||||
{
|
||||
VkDescriptorSet ds[2];
|
||||
gsize size = 0;
|
||||
if (op->render.source != NULL)
|
||||
ds[size++] = gsk_vulkan_render_get_descriptor_set (render, op->render.descriptor_set_index);
|
||||
if (op->render.source2 != NULL)
|
||||
ds[size++] = gsk_vulkan_render_get_descriptor_set (render, op->render.descriptor_set_index2);
|
||||
vkCmdBindDescriptorSets (command_buffer,
|
||||
VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
gsk_vulkan_pipeline_get_pipeline_layout (current_pipeline),
|
||||
0,
|
||||
size,
|
||||
ds,
|
||||
0,
|
||||
NULL);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@@ -76,6 +76,8 @@ 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 *fragment_bytes);
|
||||
VkDescriptorSet gsk_vulkan_render_get_descriptor_set (GskVulkanRender *self,
|
||||
gsize id);
|
||||
gsize gsk_vulkan_render_reserve_descriptor_set (GskVulkanRender *self,
|
||||
|
||||
@@ -11,7 +11,7 @@ struct _GskVulkanShader
|
||||
VkShaderModule vk_shader;
|
||||
};
|
||||
|
||||
static GskVulkanShader *
|
||||
GskVulkanShader *
|
||||
gsk_vulkan_shader_new_from_bytes (GdkVulkanContext *context,
|
||||
GskVulkanShaderType type,
|
||||
GBytes *bytes,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -63,6 +63,7 @@ if have_vulkan
|
||||
'gskvulkancolorpipeline.c',
|
||||
'gskvulkancolortextpipeline.c',
|
||||
'gskvulkancrossfadepipeline.c',
|
||||
'gskvulkancustompipeline.c',
|
||||
'gskvulkancommandpool.c',
|
||||
'gskvulkaneffectpipeline.c',
|
||||
'gskvulkanglyphcache.c',
|
||||
|
||||
BIN
gsk/resources/vulkan/custom-clip-rounded.vert.spv
Normal file
BIN
gsk/resources/vulkan/custom-clip-rounded.vert.spv
Normal file
Binary file not shown.
BIN
gsk/resources/vulkan/custom-clip.vert.spv
Normal file
BIN
gsk/resources/vulkan/custom-clip.vert.spv
Normal file
Binary file not shown.
53
gsk/resources/vulkan/custom.vert
Normal file
53
gsk/resources/vulkan/custom.vert
Normal file
@@ -0,0 +1,53 @@
|
||||
#version 420 core
|
||||
|
||||
layout(push_constant) uniform PushConstants {
|
||||
mat4 mvp;
|
||||
vec4 clip_bounds;
|
||||
vec4 clip_widths;
|
||||
vec4 clip_heights;
|
||||
} push;
|
||||
|
||||
layout(location = 0) in vec4 inRect;
|
||||
layout(location = 1) in vec4 inTexRect1;
|
||||
layout(location = 2) in vec4 inTexRect2;
|
||||
layout(location = 3) in float inTime;
|
||||
|
||||
layout(location = 0) out vec2 outPos;
|
||||
layout(location = 1) out vec2 outTexCoord1;
|
||||
layout(location = 2) out vec2 outTexCoord2;
|
||||
layout(location = 3) out float outTime;
|
||||
layout(location = 4) out vec2 outResolution;
|
||||
|
||||
out gl_PerVertex {
|
||||
vec4 gl_Position;
|
||||
};
|
||||
|
||||
vec4 clip(vec4 rect) { return rect; }
|
||||
|
||||
vec2 offsets[6] = { vec2(0.0, 0.0),
|
||||
vec2(1.0, 0.0),
|
||||
vec2(0.0, 1.0),
|
||||
vec2(0.0, 1.0),
|
||||
vec2(1.0, 0.0),
|
||||
vec2(1.0, 1.0) };
|
||||
|
||||
void main() {
|
||||
vec4 rect = clip (inRect);
|
||||
vec2 pos = rect.xy + rect.zw * offsets[gl_VertexIndex];
|
||||
gl_Position = push.mvp * vec4 (pos, 0.0, 1.0);
|
||||
|
||||
outPos = pos;
|
||||
|
||||
vec4 texrect = vec4((rect.xy - inRect.xy) / inRect.zw,
|
||||
rect.zw / inRect.zw);
|
||||
vec4 texrect1 = vec4(inTexRect1.xy + inTexRect1.zw * texrect.xy,
|
||||
inTexRect1.zw * texrect.zw);
|
||||
outTexCoord1 = texrect1.xy + texrect1.zw * offsets[gl_VertexIndex];
|
||||
|
||||
vec4 texrect2 = vec4(inTexRect2.xy + inTexRect2.zw * texrect.xy,
|
||||
inTexRect2.zw * texrect.zw);
|
||||
outTexCoord2 = texrect2.xy + texrect2.zw * offsets[gl_VertexIndex];
|
||||
|
||||
outTime = inTime;
|
||||
outResolution = inRect.zw;
|
||||
}
|
||||
BIN
gsk/resources/vulkan/custom.vert.spv
Normal file
BIN
gsk/resources/vulkan/custom.vert.spv
Normal file
Binary file not shown.
@@ -32,6 +32,7 @@ gsk_private_vulkan_vertex_shaders = [
|
||||
'mask.vert',
|
||||
'outset-shadow.vert',
|
||||
'texture.vert',
|
||||
'custom.vert'
|
||||
]
|
||||
|
||||
gsk_private_vulkan_shaders += gsk_private_vulkan_fragment_shaders
|
||||
|
||||
Reference in New Issue
Block a user