From a90a0dcbed21e668d339af10161f2ae2650b07e1 Mon Sep 17 00:00:00 2001 From: Georges Basile Stavracas Neto Date: Wed, 19 Apr 2023 14:39:35 -0300 Subject: WIP --- gdk/gdksurface-vulkan.c | 60 +++++++++++ gsk/meson.build | 1 + gsk/vulkan/gskvulkanrenderpass.c | 88 +++++++++++++++- gsk/vulkan/gskvulkanshadowpipeline.c | 158 ++++++++++++++++++++++++++++ gsk/vulkan/gskvulkanshadowpipelineprivate.h | 30 ++++++ gsk/vulkan/resources/shadow.frag | 0 gsk/vulkan/resources/shadow.vert | 0 7 files changed, 336 insertions(+), 1 deletion(-) create mode 100644 gdk/gdksurface-vulkan.c create mode 100644 gsk/vulkan/gskvulkanshadowpipeline.c create mode 100644 gsk/vulkan/gskvulkanshadowpipelineprivate.h create mode 100644 gsk/vulkan/resources/shadow.frag create mode 100644 gsk/vulkan/resources/shadow.vert diff --git a/gdk/gdksurface-vulkan.c b/gdk/gdksurface-vulkan.c new file mode 100644 index 0000000000..8bfdec80cc --- /dev/null +++ b/gdk/gdksurface-vulkan.c @@ -0,0 +1,60 @@ +/* GDK - The GIMP Drawing Kit + * + * gdksurface-vk_c: Vulkan wrappers + * + * Copyright © 2023 Georges Basile Stavracas Neto + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library. If not, see . + */ + +#include "gdksurfaceprivate.h" + +#ifdef GDK_RENDERING_VULKAN + +#include "gdkdisplayprivate.h" +#include "gdkvulkancontextprivate.h" + +#include + +VkResult +gdk_surface_ensure_vk_surface (GdkSurface *surface, + GError **error) +{ + g_return_val_if_fail (GDK_IS_SURFACE (surface), VK_ERROR_UNKNOWN); + + if (surface->vk_surface != VK_NULL_HANDLE) + return VK_SUCCESS; + + return GDK_SURFACE_GET_CLASS (surface)->create_vk_surface (surface, + &surface->vk_surface, + error); +} + +void +gdk_surface_clear_vk_surface (GdkSurface *surface) +{ + g_return_if_fail (GDK_IS_SURFACE (surface)); + + if (surface->vk_surface != VK_NULL_HANDLE) + { + GdkDisplay *display = gdk_surface_get_display (surface); + + vkDestroySurfaceKHR (display->vk_instance, + surface->vk_surface, + NULL); + surface->vk_surface = VK_NULL_HANDLE; + } +} + +#endif diff --git a/gsk/meson.build b/gsk/meson.build index bd50524785..250dd28d12 100644 --- a/gsk/meson.build +++ b/gsk/meson.build @@ -129,6 +129,7 @@ if have_vulkan 'vulkan/gskvulkanrenderer.c', 'vulkan/gskvulkanrenderpass.c', 'vulkan/gskvulkanshader.c', + 'vulkan/gskvulkanshadowpipeline.c', ]) subdir('vulkan/resources') diff --git a/gsk/vulkan/gskvulkanrenderpass.c b/gsk/vulkan/gskvulkanrenderpass.c index 5bd4d234af..698e271a05 100644 --- a/gsk/vulkan/gskvulkanrenderpass.c +++ b/gsk/vulkan/gskvulkanrenderpass.c @@ -51,6 +51,7 @@ typedef enum { GSK_VULKAN_OP_REPEAT, GSK_VULKAN_OP_CROSS_FADE, GSK_VULKAN_OP_BLEND_MODE, + GSK_VULKAN_OP_SHADOW, /* GskVulkanOpText */ GSK_VULKAN_OP_TEXT, GSK_VULKAN_OP_COLOR_TEXT, @@ -710,6 +711,34 @@ gsk_vulkan_render_pass_add_rounded_clip_node (GskVulkanRenderPass *self return TRUE; } +static inline gboolean +gsk_vulkan_render_pass_add_shadow_node (GskVulkanRenderPass *self, + GskVulkanRender *render, + const GskVulkanPushConstants *constants, + GskRenderNode *node) +{ + GskVulkanPipelineType pipeline_type; + GskVulkanOp op = { + .render.node = node + }; + + if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds)) + pipeline_type = GSK_VULKAN_PIPELINE_SHADOW; + else if (constants->clip.type == GSK_VULKAN_CLIP_RECT) + pipeline_type = GSK_VULKAN_PIPELINE_SHADOW_CLIP; + else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR) + pipeline_type = GSK_VULKAN_PIPELINE_SHADOW_CLIP_ROUNDED; + else + FALLBACK ("Shadow nodes can't deal with clip type %u", constants->clip.type); + + + op.type = GSK_VULKAN_OP_SHADOW; + op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type); + g_array_append_val (self->render_ops, op); + + return TRUE; +} + static inline gboolean gsk_vulkan_render_pass_add_repeat_node (GskVulkanRenderPass *self, GskVulkanRender *render, @@ -957,7 +986,7 @@ static const GskVulkanRenderPassNodeFunc nodes_vtable[N_RENDER_NODES] = { [GSK_REPEAT_NODE] = gsk_vulkan_render_pass_add_repeat_node, [GSK_CLIP_NODE] = gsk_vulkan_render_pass_add_clip_node, [GSK_ROUNDED_CLIP_NODE] = gsk_vulkan_render_pass_add_rounded_clip_node, - [GSK_SHADOW_NODE] = NULL, + [GSK_SHADOW_NODE] = gsk_vulkan_render_pass_add_shadow_node, [GSK_BLEND_NODE] = gsk_vulkan_render_pass_add_blend_node, [GSK_CROSS_FADE_NODE] = gsk_vulkan_render_pass_add_cross_fade_node, [GSK_TEXT_NODE] = gsk_vulkan_render_pass_add_text_node, @@ -1727,6 +1756,21 @@ gsk_vulkan_render_pass_collect_vertex_data (GskVulkanRenderPass *self, } break; + case GSK_VULKAN_OP_SHADOW: + { + op->render.vertex_offset = offset + n_bytes; + gsk_vulkan_shadow_pipeline_collect_vertex_data (GSK_VULKAN_SHADOW_PIPELINE (op->render.pipeline), + data + n_bytes + offset, + gsk_shadow_pipeline_get (op->render.node), + gsk_outset_shadow_node_get_color (op->render.node), + gsk_outset_shadow_node_get_dx (op->render.node), + gsk_outset_shadow_node_get_dy (op->render.node), + gsk_outset_shadow_node_get_spread (op->render.node), + gsk_outset_shadow_node_get_blur_radius (op->render.node)); + n_bytes += op->render.vertex_count; + } + break; + case GSK_VULKAN_OP_CROSS_FADE: { op->render.vertex_offset = offset + n_bytes; @@ -1842,6 +1886,13 @@ gsk_vulkan_render_pass_reserve_descriptor_sets (GskVulkanRenderPass *self, op->render.descriptor_set_index2 = gsk_vulkan_render_reserve_descriptor_set (render, op->render.source2, FALSE); } break; + case GSK_VULKAN_OP_SHADOW: + if (op->render.source && op->render.source2) + { + op->render.descriptor_set_index = gsk_vulkan_render_reserve_descriptor_set (render, op->render.source, FALSE); + op->render.descriptor_set_index2 = gsk_vulkan_render_reserve_descriptor_set (render, op->render.source2, FALSE); + } + break; default: g_assert_not_reached (); @@ -2055,6 +2106,41 @@ gsk_vulkan_render_pass_draw_rect (GskVulkanRenderPass *self, current_draw_index, 1); break; + case GSK_VULKAN_OP_SHADOW: + if (!op->render.source) + continue; + 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; + } + + vkCmdBindDescriptorSets (command_buffer, + VK_PIPELINE_BIND_POINT_GRAPHICS, + gsk_vulkan_pipeline_get_pipeline_layout (current_pipeline), + 0, + 1, + (VkDescriptorSet[1]) { + gsk_vulkan_render_get_descriptor_set (render, op->render.descriptor_set_index) + }, + 0, + NULL); + + current_draw_index += gsk_vulkan_shadow_pipeline_draw (GSK_VULKAN_SHADOW_PIPELINE (current_pipeline), + command_buffer, + current_draw_index, 1); + break; + case GSK_VULKAN_OP_COLOR: if (current_pipeline != op->render.pipeline) { diff --git a/gsk/vulkan/gskvulkanshadowpipeline.c b/gsk/vulkan/gskvulkanshadowpipeline.c new file mode 100644 index 0000000000..35521d9667 --- /dev/null +++ b/gsk/vulkan/gskvulkanshadowpipeline.c @@ -0,0 +1,158 @@ +#include "config.h" + +#include "gskvulkanshadowpipelineprivate.h" + +struct _GskVulkanShadowPipeline +{ + GObject parent_instance; +}; + +typedef struct _GskVulkanShadowInstance GskVulkanShadowInstance; + +struct _GskVulkanShadowInstance +{ + float rect[4]; + float tex_rect[4]; + float color_matrix[16]; + float color_offset[4]; +}; + +G_DEFINE_TYPE (GskVulkanShadowPipeline, gsk_vulkan_shadow_pipeline, GSK_TYPE_VULKAN_PIPELINE) + +static const VkPipelineVertexInputStateCreateInfo * +gsk_vulkan_shadow_pipeline_get_input_state_create_info (GskVulkanPipeline *self) +{ + static const VkVertexInputBindingDescription vertexBindingDescriptions[] = { + { + .binding = 0, + .stride = sizeof (GskVulkanShadowInstance), + .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 (GskVulkanShadowInstance, tex_rect), + }, + { + .location = 2, + .binding = 0, + .format = VK_FORMAT_R32G32B32A32_SFLOAT, + .offset = G_STRUCT_OFFSET (GskVulkanShadowInstance, color_matrix), + }, + { + .location = 3, + .binding = 0, + .format = VK_FORMAT_R32G32B32A32_SFLOAT, + .offset = G_STRUCT_OFFSET (GskVulkanShadowInstance, color_matrix) + sizeof (float) * 4, + }, + { + .location = 4, + .binding = 0, + .format = VK_FORMAT_R32G32B32A32_SFLOAT, + .offset = G_STRUCT_OFFSET (GskVulkanShadowInstance, color_matrix) + sizeof (float) * 8, + }, + { + .location = 5, + .binding = 0, + .format = VK_FORMAT_R32G32B32A32_SFLOAT, + .offset = G_STRUCT_OFFSET (GskVulkanShadowInstance, color_matrix) + sizeof (float) * 12, + }, + { + .location = 6, + .binding = 0, + .format = VK_FORMAT_R32G32B32A32_SFLOAT, + .offset = G_STRUCT_OFFSET (GskVulkanShadowInstance, color_offset), + } + }; + 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_shadow_pipeline_finalize (GObject *gobject) +{ + //GskVulkanShadowPipeline *self = GSK_VULKAN_SHADOW_PIPELINE (gobject); + + G_OBJECT_CLASS (gsk_vulkan_shadow_pipeline_parent_class)->finalize (gobject); +} + +static void +gsk_vulkan_shadow_pipeline_class_init (GskVulkanShadowPipelineClass *klass) +{ + GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass); + + G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_shadow_pipeline_finalize; + + pipeline_class->get_input_state_create_info = gsk_vulkan_shadow_pipeline_get_input_state_create_info; +} + +static void +gsk_vulkan_shadow_pipeline_init (GskVulkanShadowPipeline *self) +{ +} + +GskVulkanPipeline * +gsk_vulkan_shadow_pipeline_new (GdkVulkanContext *context, + VkPipelineLayout layout, + const char *shader_name, + VkRenderPass render_pass) +{ + return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_SHADOW_PIPELINE, context, layout, shader_name, render_pass); +} + +gsize +gsk_vulkan_shadow_pipeline_count_vertex_data (GskVulkanShadowPipeline *pipeline) +{ + return sizeof (GskVulkanShadowInstance); +} + +void +gsk_vulkan_shadow_pipeline_collect_vertex_data (GskVulkanShadowPipeline *pipeline, + guchar *data, + const graphene_rect_t *rect, + const graphene_rect_t *tex_rect, + const graphene_matrix_t *color_matrix, + const graphene_vec4_t *color_offset) +{ + GskVulkanShadowInstance *instance = (GskVulkanShadowInstance *) 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->tex_rect[0] = tex_rect->origin.x; + instance->tex_rect[1] = tex_rect->origin.y; + instance->tex_rect[2] = tex_rect->size.width; + instance->tex_rect[3] = tex_rect->size.height; + graphene_matrix_to_float (color_matrix, instance->color_matrix); + graphene_vec4_to_float (color_offset, instance->color_offset); +} + +gsize +gsk_vulkan_shadow_pipeline_draw (GskVulkanShadowPipeline *pipeline, + VkCommandBuffer command_buffer, + gsize offset, + gsize n_commands) +{ + vkCmdDraw (command_buffer, + 6, n_commands, + 0, offset); + + return n_commands; +} diff --git a/gsk/vulkan/gskvulkanshadowpipelineprivate.h b/gsk/vulkan/gskvulkanshadowpipelineprivate.h new file mode 100644 index 0000000000..86d512afbb --- /dev/null +++ b/gsk/vulkan/gskvulkanshadowpipelineprivate.h @@ -0,0 +1,30 @@ +#pragma once + +#include + +#include "gskvulkanpipelineprivate.h" + +G_BEGIN_DECLS + +typedef struct _GskVulkanShadowPipelineLayout GskVulkanShadowPipelineLayout; + +#define GSK_TYPE_VULKAN_SHADOW_PIPELINE (gsk_vulkan_shadow_pipeline_get_type ()) + +G_DECLARE_FINAL_TYPE (GskVulkanShadowPipeline, gsk_vulkan_shadow_pipeline, GSK, VULKAN_SHADOW_PIPELINE, GskVulkanPipeline) + +GskVulkanPipeline * gsk_vulkan_shadow_pipeline_new (GdkVulkanContext *context, + VkPipelineLayout layout, + const char *shader_name, + VkRenderPass render_pass); + +gsize gsk_vulkan_shadow_pipeline_count_vertex_data (GskVulkanShadowPipeline *pipeline); +void gsk_vulkan_shadow_pipeline_collect_vertex_data (GskVulkanShadowPipeline *pipeline, + guchar *data, + const GskShadow *shadow); +gsize gsk_vulkan_shadow_pipeline_draw (GskVulkanShadowPipeline *pipeline, + VkCommandBuffer command_buffer, + gsize offset, + gsize n_commands); + +G_END_DECLS + diff --git a/gsk/vulkan/resources/shadow.frag b/gsk/vulkan/resources/shadow.frag new file mode 100644 index 0000000000..e69de29bb2 diff --git a/gsk/vulkan/resources/shadow.vert b/gsk/vulkan/resources/shadow.vert new file mode 100644 index 0000000000..e69de29bb2 -- cgit v1.2.1