vulkan: Implement crossfade

This is the first shader using two textures. It almost works.
This commit is contained in:
Matthias Clasen 2017-09-22 14:20:57 -04:00
parent 8ad0539cf7
commit a75d995bd4
17 changed files with 373 additions and 6 deletions

View File

@ -0,0 +1,146 @@
#include "config.h"
#include "gskvulkancrossfadepipelineprivate.h"
struct _GskVulkanCrossFadePipeline
{
GObject parent_instance;
};
typedef struct _GskVulkanCrossFadeInstance GskVulkanCrossFadeInstance;
struct _GskVulkanCrossFadeInstance
{
float rect[4];
float start_tex_rect[4];
float end_tex_rect[4];
float progress;
};
G_DEFINE_TYPE (GskVulkanCrossFadePipeline, gsk_vulkan_cross_fade_pipeline, GSK_TYPE_VULKAN_PIPELINE)
static const VkPipelineVertexInputStateCreateInfo *
gsk_vulkan_cross_fade_pipeline_get_input_state_create_info (GskVulkanPipeline *self)
{
static const VkVertexInputBindingDescription vertexBindingDescriptions[] = {
{
.binding = 0,
.stride = sizeof (GskVulkanCrossFadeInstance),
.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 (GskVulkanCrossFadeInstance, start_tex_rect),
},
{
.location = 2,
.binding = 0,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanCrossFadeInstance, end_tex_rect),
},
{
.location = 3,
.binding = 0,
.format = VK_FORMAT_R32_SFLOAT,
.offset = G_STRUCT_OFFSET (GskVulkanCrossFadeInstance, progress),
}
};
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_cross_fade_pipeline_finalize (GObject *gobject)
{
//GskVulkanCrossFadePipeline *self = GSK_VULKAN_BLUR_PIPELINE (gobject);
G_OBJECT_CLASS (gsk_vulkan_cross_fade_pipeline_parent_class)->finalize (gobject);
}
static void
gsk_vulkan_cross_fade_pipeline_class_init (GskVulkanCrossFadePipelineClass *klass)
{
GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass);
G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_cross_fade_pipeline_finalize;
pipeline_class->get_input_state_create_info = gsk_vulkan_cross_fade_pipeline_get_input_state_create_info;
}
static void
gsk_vulkan_cross_fade_pipeline_init (GskVulkanCrossFadePipeline *self)
{
}
GskVulkanPipeline *
gsk_vulkan_cross_fade_pipeline_new (GdkVulkanContext *context,
VkPipelineLayout layout,
const char *shader_name,
VkRenderPass render_pass)
{
return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_CROSS_FADE_PIPELINE, context, layout, shader_name, render_pass);
}
gsize
gsk_vulkan_cross_fade_pipeline_count_vertex_data (GskVulkanCrossFadePipeline *pipeline)
{
return sizeof (GskVulkanCrossFadeInstance);
}
void
gsk_vulkan_cross_fade_pipeline_collect_vertex_data (GskVulkanCrossFadePipeline *pipeline,
guchar *data,
const graphene_rect_t *bounds,
const graphene_rect_t *start_bounds,
const graphene_rect_t *end_bounds,
double progress)
{
GskVulkanCrossFadeInstance *instance = (GskVulkanCrossFadeInstance *) 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->start_tex_rect[0] = (bounds->origin.x - start_bounds->origin.x)/start_bounds->size.width;
instance->start_tex_rect[1] = (bounds->origin.y - start_bounds->origin.y)/start_bounds->size.height;
instance->start_tex_rect[2] = (bounds->size.width + bounds->origin.x - start_bounds->origin.x)/start_bounds->size.width;
instance->start_tex_rect[3] = (bounds->size.height + bounds->origin.y - start_bounds->origin.y)/start_bounds->size.height;
instance->end_tex_rect[0] = (bounds->origin.x - end_bounds->origin.x)/end_bounds->size.width;
instance->end_tex_rect[1] = (bounds->origin.y - end_bounds->origin.y)/end_bounds->size.height;
instance->end_tex_rect[2] = (bounds->size.width + bounds->origin.x - end_bounds->origin.x)/end_bounds->size.width;
instance->end_tex_rect[3] = (bounds->size.height + bounds->origin.y - end_bounds->origin.y)/end_bounds->size.height;
instance->progress = progress;
}
gsize
gsk_vulkan_cross_fade_pipeline_draw (GskVulkanCrossFadePipeline *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_CROSS_FADE_PIPELINE_PRIVATE_H__
#define __GSK_VULKAN_CROSS_FADE_PIPELINE_PRIVATE_H__
#include <graphene.h>
#include "gskvulkanpipelineprivate.h"
G_BEGIN_DECLS
typedef struct _GskVulkanCrossFadePipelineLayout GskVulkanCrossFadePipelineLayout;
#define GSK_TYPE_VULKAN_CROSS_FADE_PIPELINE (gsk_vulkan_cross_fade_pipeline_get_type ())
G_DECLARE_FINAL_TYPE (GskVulkanCrossFadePipeline, gsk_vulkan_cross_fade_pipeline, GSK, VULKAN_CROSS_FADE_PIPELINE, GskVulkanPipeline)
GskVulkanPipeline * gsk_vulkan_cross_fade_pipeline_new (GdkVulkanContext *context,
VkPipelineLayout layout,
const char *shader_name,
VkRenderPass render_pass);
gsize gsk_vulkan_cross_fade_pipeline_count_vertex_data (GskVulkanCrossFadePipeline *pipeline);
void gsk_vulkan_cross_fade_pipeline_collect_vertex_data (GskVulkanCrossFadePipeline *pipeline,
guchar *data,
const graphene_rect_t *bounds,
const graphene_rect_t *start_bounds,
const graphene_rect_t *end_bounds,
double progress);
gsize gsk_vulkan_cross_fade_pipeline_draw (GskVulkanCrossFadePipeline *pipeline,
VkCommandBuffer command_buffer,
gsize offset,
gsize n_commands);
G_END_DECLS
#endif /* __GSK_VULKAN_CROSS_FADE_PIPELINE_PRIVATE_H__ */

View File

@ -32,7 +32,6 @@ gsk_vulkan_handle_result (VkResult res,
#define GSK_VK_CHECK(func, ...) gsk_vulkan_handle_result (func (__VA_ARGS__), G_STRINGIFY (func))
GskVulkanPipeline * gsk_vulkan_pipeline_new (GType pipeline_type,
GdkVulkanContext *context,
VkPipelineLayout layout,

View File

@ -16,6 +16,7 @@
#include "gskvulkanboxshadowpipelineprivate.h"
#include "gskvulkancolorpipelineprivate.h"
#include "gskvulkancolortextpipelineprivate.h"
#include "gskvulkancrossfadepipelineprivate.h"
#include "gskvulkaneffectpipelineprivate.h"
#include "gskvulkanlineargradientpipelineprivate.h"
#include "gskvulkantextpipelineprivate.h"
@ -388,6 +389,9 @@ gsk_vulkan_render_get_pipeline (GskVulkanRender *self,
{ "blend", 1, gsk_vulkan_color_text_pipeline_new },
{ "blend-clip", 1, gsk_vulkan_color_text_pipeline_new },
{ "blend-clip-rounded", 1, gsk_vulkan_color_text_pipeline_new },
{ "crossfade", 2, gsk_vulkan_cross_fade_pipeline_new },
{ "crossfade-clip", 2, gsk_vulkan_cross_fade_pipeline_new },
{ "crossfade-clip-rounded", 2, gsk_vulkan_cross_fade_pipeline_new },
};
g_return_val_if_fail (type < GSK_VULKAN_N_PIPELINES, NULL);

View File

@ -13,6 +13,7 @@
#include "gskvulkanclipprivate.h"
#include "gskvulkancolorpipelineprivate.h"
#include "gskvulkancolortextpipelineprivate.h"
#include "gskvulkancrossfadepipelineprivate.h"
#include "gskvulkaneffectpipelineprivate.h"
#include "gskvulkanlineargradientpipelineprivate.h"
#include "gskvulkantextpipelineprivate.h"
@ -26,6 +27,7 @@
typedef union _GskVulkanOp GskVulkanOp;
typedef struct _GskVulkanOpRender GskVulkanOpRender;
typedef struct _GskVulkanOpText GskVulkanOpText;
typedef struct _GskVulkanOpCrossFade GskVulkanOpCrossFade;
typedef struct _GskVulkanOpPushConstants GskVulkanOpPushConstants;
typedef enum {
@ -35,8 +37,6 @@ typedef enum {
GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP,
GSK_VULKAN_OP_SURFACE,
GSK_VULKAN_OP_TEXTURE,
GSK_VULKAN_OP_TEXT,
GSK_VULKAN_OP_COLOR_TEXT,
GSK_VULKAN_OP_COLOR,
GSK_VULKAN_OP_LINEAR_GRADIENT,
GSK_VULKAN_OP_OPACITY,
@ -45,8 +45,13 @@ typedef enum {
GSK_VULKAN_OP_BORDER,
GSK_VULKAN_OP_INSET_SHADOW,
GSK_VULKAN_OP_OUTSET_SHADOW,
/* GskVulkanOpText */
GSK_VULKAN_OP_TEXT,
GSK_VULKAN_OP_COLOR_TEXT,
/* GskVulkanOpCrossFade */
GSK_VULKAN_OP_CROSS_FADE,
/* GskVulkanOpPushConstants */
GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS
GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS,
} GskVulkanOpType;
struct _GskVulkanOpRender
@ -76,6 +81,20 @@ struct _GskVulkanOpText
guint num_glyphs; /* number of *non-empty* glyphs (== instances) we render */
};
struct _GskVulkanOpCrossFade
{
GskVulkanOpType type;
GskRenderNode *node; /* node that's the source of this op */
GskVulkanPipeline *pipeline; /* pipeline to use */
GskRoundedRect clip; /* clip rect (or random memory if not relevant) */
GskVulkanImage *start; /* source images to render */
GskVulkanImage *end;
gsize vertex_offset; /* offset into vertex buffer */
gsize vertex_count; /* number of vertices */
gsize descriptor_set_start; /* indices into descriptor sets array */
gsize descriptor_set_end;
};
struct _GskVulkanOpPushConstants
{
GskVulkanOpType type;
@ -87,8 +106,9 @@ union _GskVulkanOp
{
GskVulkanOpType type;
GskVulkanOpRender render;
GskVulkanOpPushConstants constants;
GskVulkanOpText text;
GskVulkanOpCrossFade crossfade;
GskVulkanOpPushConstants constants;
};
struct _GskVulkanRenderPass
@ -161,10 +181,23 @@ gsk_vulkan_render_pass_add_node (GskVulkanRenderPass *self,
case GSK_REPEAT_NODE:
case GSK_SHADOW_NODE:
case GSK_BLEND_NODE:
case GSK_CROSS_FADE_NODE:
default:
FALLBACK ("Unsupported node '%s'\n", node->node_class->type_name);
case GSK_CROSS_FADE_NODE:
if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
pipeline_type = GSK_VULKAN_PIPELINE_CROSS_FADE;
else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
pipeline_type = GSK_VULKAN_PIPELINE_CROSS_FADE_CLIP;
else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
pipeline_type = GSK_VULKAN_PIPELINE_CROSS_FADE_CLIP_ROUNDED;
else
FALLBACK ("Cross fade nodes can't deal with clip type %u\n", constants->clip.type);
op.type = GSK_VULKAN_OP_CROSS_FADE;
op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
g_array_append_val (self->render_ops, op);
return;
case GSK_INSET_SHADOW_NODE:
if (gsk_inset_shadow_node_get_blur_radius (node) > 0)
FALLBACK ("Blur support not implemented for inset shadows\n");
@ -707,6 +740,24 @@ gsk_vulkan_render_pass_upload (GskVulkanRenderPass *self,
}
break;
case GSK_VULKAN_OP_CROSS_FADE:
{
GskRenderNode *start = gsk_cross_fade_node_get_start_child (op->crossfade.node);
GskRenderNode *end = gsk_cross_fade_node_get_end_child (op->crossfade.node);
op->crossfade.start = gsk_vulkan_render_pass_get_node_as_texture (self,
render,
uploader,
start,
&start->bounds);
op->crossfade.end = gsk_vulkan_render_pass_get_node_as_texture (self,
render,
uploader,
end,
&end->bounds);
}
break;
default:
g_assert_not_reached ();
case GSK_VULKAN_OP_COLOR:
@ -787,6 +838,11 @@ gsk_vulkan_render_pass_count_vertex_data (GskVulkanRenderPass *self)
n_bytes += op->render.vertex_count;
break;
case GSK_VULKAN_OP_CROSS_FADE:
op->crossfade.vertex_count = gsk_vulkan_cross_fade_pipeline_count_vertex_data (GSK_VULKAN_CROSS_FADE_PIPELINE (op->crossfade.pipeline));
n_bytes += op->crossfade.vertex_count;
break;
default:
g_assert_not_reached ();
case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS:
@ -977,6 +1033,22 @@ gsk_vulkan_render_pass_collect_vertex_data (GskVulkanRenderPass *self,
}
break;
case GSK_VULKAN_OP_CROSS_FADE:
{
GskRenderNode *start = gsk_cross_fade_node_get_start_child (op->crossfade.node);
GskRenderNode *end = gsk_cross_fade_node_get_end_child (op->crossfade.node);
op->crossfade.vertex_offset = offset + n_bytes;
gsk_vulkan_cross_fade_pipeline_collect_vertex_data (GSK_VULKAN_CROSS_FADE_PIPELINE (op->crossfade.pipeline),
data + n_bytes + offset,
&op->crossfade.node->bounds,
&start->bounds,
&end->bounds,
gsk_cross_fade_node_get_progress (op->crossfade.node));
n_bytes += op->crossfade.vertex_count;
}
break;
default:
g_assert_not_reached ();
case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS:
@ -1017,6 +1089,12 @@ gsk_vulkan_render_pass_reserve_descriptor_sets (GskVulkanRenderPass *self,
case GSK_VULKAN_OP_COLOR_TEXT:
op->text.descriptor_set_index = gsk_vulkan_render_reserve_descriptor_set (render, op->text.source);
break;
case GSK_VULKAN_OP_CROSS_FADE:
op->crossfade.descriptor_set_start = gsk_vulkan_render_reserve_descriptor_set (render, op->crossfade.start);
op->crossfade.descriptor_set_end = gsk_vulkan_render_reserve_descriptor_set (render, op->crossfade.end);
break;
default:
g_assert_not_reached ();
case GSK_VULKAN_OP_COLOR:
@ -1320,6 +1398,40 @@ gsk_vulkan_render_pass_draw (GskVulkanRenderPass *self,
pipeline_layout[i]);
break;
case GSK_VULKAN_OP_CROSS_FADE:
if (current_pipeline != op->crossfade.pipeline)
{
current_pipeline = op->crossfade.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->crossfade.vertex_offset });
current_draw_index = 0;
}
vkCmdBindDescriptorSets (command_buffer,
VK_PIPELINE_BIND_POINT_GRAPHICS,
gsk_vulkan_pipeline_get_pipeline_layout (current_pipeline),
0,
2,
(VkDescriptorSet[2]) {
gsk_vulkan_render_get_descriptor_set (render, op->crossfade.descriptor_set_start),
gsk_vulkan_render_get_descriptor_set (render, op->crossfade.descriptor_set_end)
},
0,
NULL);
current_draw_index += gsk_vulkan_cross_fade_pipeline_draw (GSK_VULKAN_CROSS_FADE_PIPELINE (current_pipeline),
command_buffer,
current_draw_index, 1);
break;
default:
g_assert_not_reached ();
break;

View File

@ -40,6 +40,9 @@ typedef enum {
GSK_VULKAN_PIPELINE_COLOR_TEXT,
GSK_VULKAN_PIPELINE_COLOR_TEXT_CLIP,
GSK_VULKAN_PIPELINE_COLOR_TEXT_CLIP_ROUNDED,
GSK_VULKAN_PIPELINE_CROSS_FADE,
GSK_VULKAN_PIPELINE_CROSS_FADE_CLIP,
GSK_VULKAN_PIPELINE_CROSS_FADE_CLIP_ROUNDED,
/* add more */
GSK_VULKAN_N_PIPELINES
} GskVulkanPipelineType;

View File

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

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,21 @@
#version 420 core
#include "clip.frag.glsl"
layout(location = 0) in vec2 inPos;
layout(location = 1) in vec2 inStartTexCoord;
layout(location = 2) in vec2 inEndTexCoord;
layout(location = 3) in float inProgress;
layout(set = 0, binding = 0) uniform sampler2D startTexture;
layout(set = 1, binding = 0) uniform sampler2D endTexture;
layout(location = 0) out vec4 color;
void main()
{
vec4 start = texture (startTexture, inStartTexCoord);
vec4 end = texture (endTexture, inEndTexCoord);
color = clip (inPos, mix (start, end, inProgress));
}

Binary file not shown.

View File

@ -0,0 +1,44 @@
#version 420 core
#include "clip.vert.glsl"
layout(location = 0) in vec4 inRect;
layout(location = 1) in vec4 inStartTexRect;
layout(location = 2) in vec4 inEndTexRect;
layout(location = 3) in float inProgress;
layout(location = 0) out vec2 outPos;
layout(location = 1) out vec2 outStartTexCoord;
layout(location = 2) out vec2 outEndTexCoord;
layout(location = 3) out float outProgress;
out gl_PerVertex {
vec4 gl_Position;
};
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 starttexrect = vec4(inStartTexRect.xy + inStartTexRect.zw * texrect.xy,
inStartTexRect.zw * texrect.zw);
vec4 endtexrect = vec4(inEndTexRect.xy + inEndTexRect.zw * texrect.xy,
inEndTexRect.zw * texrect.zw);
outStartTexCoord = starttexrect.xy + starttexrect.zw * offsets[gl_VertexIndex];
outEndTexCoord = endtexrect.xy + endtexrect.zw * offsets[gl_VertexIndex];
outProgress = inProgress;
}

Binary file not shown.

View File

@ -12,6 +12,7 @@ gsk_private_vulkan_fragment_shaders = [
'border.frag',
'color.frag',
'color-matrix.frag',
'crossfade.frag',
'inset-shadow.frag',
'linear.frag',
'mask.frag',
@ -24,6 +25,7 @@ gsk_private_vulkan_vertex_shaders = [
'border.vert',
'color.vert',
'color-matrix.vert',
'crossfade.vert',
'inset-shadow.vert',
'linear.vert',
'mask.vert',