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:
Matthias Clasen
2017-09-23 20:38:12 -04:00
parent f4ffd261db
commit 2905e9dbcc
19 changed files with 671 additions and 8 deletions

View File

@@ -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;
/**

View File

@@ -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,

View File

@@ -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 *

View File

@@ -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__ */

View 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;
}

View 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__ */

View File

@@ -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,

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;

View File

@@ -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,

View File

@@ -11,7 +11,7 @@ struct _GskVulkanShader
VkShaderModule vk_shader;
};
static GskVulkanShader *
GskVulkanShader *
gsk_vulkan_shader_new_from_bytes (GdkVulkanContext *context,
GskVulkanShaderType type,
GBytes *bytes,

View File

@@ -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,

View File

@@ -63,6 +63,7 @@ if have_vulkan
'gskvulkancolorpipeline.c',
'gskvulkancolortextpipeline.c',
'gskvulkancrossfadepipeline.c',
'gskvulkancustompipeline.c',
'gskvulkancommandpool.c',
'gskvulkaneffectpipeline.c',
'gskvulkanglyphcache.c',

Binary file not shown.

Binary file not shown.

View 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;
}

Binary file not shown.

View File

@@ -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