diff --git a/gsk/Makefile.am b/gsk/Makefile.am index 77bfc0e5a1..84ae987602 100644 --- a/gsk/Makefile.am +++ b/gsk/Makefile.am @@ -24,9 +24,17 @@ noinst_LTLIBRARIES = if HAVE_VULKAN gsk_private_vulan_source_h = \ - gskvulkanrendererprivate.h + gskvulkanbufferprivate.h \ + gskvulkanmemoryprivate.h \ + gskvulkanpipelineprivate.h \ + gskvulkanrendererprivate.h \ + gskvulkanshaderprivate.h gsk_private_vulkan_source_c = \ - gskvulkanrenderer.c + gskvulkanbuffer.c \ + gskvulkanmemory.c \ + gskvulkanpipeline.c \ + gskvulkanrenderer.c \ + gskvulkanshader.c endif gsk_public_source_h = \ @@ -48,7 +56,6 @@ gsk_private_source_h = \ gskrendererprivate.h \ gskrendernodeprivate.h \ gskshaderbuilderprivate.h \ - gskvulkanrendererprivate.h \ gsktextureprivate.h gsk_public_source_c = \ gskrenderer.c \ @@ -95,6 +102,14 @@ DISTCLEANFILES += gskenumtypes.h gskenumtypes.c resource_files = $(shell $(GLIB_COMPILE_RESOURCES) --sourcedir=$(srcdir) --generate-dependencies $(builddir)/gsk.resources.xml) +resources/vulkan/%.frag.spv: resources/vulkan/%.frag.glsl + @if test -z "$(GLSLC)"; then echo "Missing glslc. See https://github.com/google/shaderc"; exit 1; fi + $(AM_V_GEN) $(GLSLC) -fshader-stage=fragment -o $@.tmp $< && mv $@.tmp $@ + +resources/vulkan/%.vert.spv: resources/vulkan/%.vert.glsl + @if test -z "$(GLSLC)"; then echo "Missing glslc. See https://github.com/google/shaderc"; exit 1; fi + $(AM_V_GEN) $(GLSLC) -fshader-stage=vertex -o $@.tmp $< && mv $@.tmp $@ + gsk.resources.xml: Makefile.am $(AM_V_GEN) echo "" > $@; \ echo "" >> $@; \ @@ -103,6 +118,14 @@ gsk.resources.xml: Makefile.am n=`basename $$f`; \ echo " resources/glsl/$$n" >> $@; \ done; \ + for f in $(top_srcdir)/gsk/resources/vulkan/*.spv; do \ + n=`basename $$f`; \ + echo " resources/vulkan/$$n" >> $@; \ + done; \ + for f in $(top_srcdir)/gsk/resources/vulkan/*.glsl; do \ + n=`basename $$f`; \ + echo " resources/vulkan/$$n" >> $@; \ + done; \ echo " " >> $@; \ echo "" >> $@ diff --git a/gsk/gskvulkanbuffer.c b/gsk/gskvulkanbuffer.c new file mode 100644 index 0000000000..6694131bd7 --- /dev/null +++ b/gsk/gskvulkanbuffer.c @@ -0,0 +1,88 @@ +#include "config.h" + +#include "gskvulkanbufferprivate.h" +#include "gskvulkanmemoryprivate.h" +#include "gskvulkanpipelineprivate.h" + +struct _GskVulkanBuffer +{ + GdkVulkanContext *vulkan; + + gsize size; + + VkBuffer vk_buffer; + + GskVulkanMemory *memory; +}; + +GskVulkanBuffer * +gsk_vulkan_buffer_new (GdkVulkanContext *context, + gsize size) +{ + VkMemoryRequirements requirements; + GskVulkanBuffer *self; + + self = g_slice_new0 (GskVulkanBuffer); + + self->vulkan = g_object_ref (context); + self->size = size; + + GSK_VK_CHECK (vkCreateBuffer, gdk_vulkan_context_get_device (context), + &(VkBufferCreateInfo) { + .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + .size = size, + .flags = 0, + .usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT + | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE + }, + NULL, + &self->vk_buffer); + + vkGetBufferMemoryRequirements (gdk_vulkan_context_get_device (context), + self->vk_buffer, + &requirements); + + self->memory = gsk_vulkan_memory_new (context, + requirements.memoryTypeBits, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + size); + + GSK_VK_CHECK (vkBindBufferMemory, gdk_vulkan_context_get_device (context), + self->vk_buffer, + gsk_vulkan_memory_get_device_memory (self->memory), + 0); + return self; +} + +void +gsk_vulkan_buffer_free (GskVulkanBuffer *self) +{ + gsk_vulkan_memory_free (self->memory); + + vkDestroyBuffer (gdk_vulkan_context_get_device (self->vulkan), + self->vk_buffer, + NULL); + + g_object_unref (self->vulkan); + + g_slice_free (GskVulkanBuffer, self); +} + +VkBuffer +gsk_vulkan_buffer_get_buffer (GskVulkanBuffer *self) +{ + return self->vk_buffer; +} + +guchar * +gsk_vulkan_buffer_map (GskVulkanBuffer *self) +{ + return gsk_vulkan_memory_map (self->memory); +} + +void +gsk_vulkan_buffer_unmap (GskVulkanBuffer *self) +{ + gsk_vulkan_memory_unmap (self->memory); +} diff --git a/gsk/gskvulkanbufferprivate.h b/gsk/gskvulkanbufferprivate.h new file mode 100644 index 0000000000..e49719272e --- /dev/null +++ b/gsk/gskvulkanbufferprivate.h @@ -0,0 +1,21 @@ +#ifndef __GSK_VULKAN_BUFFER_PRIVATE_H__ +#define __GSK_VULKAN_BUFFER_PRIVATE_H__ + +#include + +G_BEGIN_DECLS + +typedef struct _GskVulkanBuffer GskVulkanBuffer; + +GskVulkanBuffer * gsk_vulkan_buffer_new (GdkVulkanContext *context, + gsize size); +void gsk_vulkan_buffer_free (GskVulkanBuffer *buffer); + +VkBuffer gsk_vulkan_buffer_get_buffer (GskVulkanBuffer *self); + +guchar * gsk_vulkan_buffer_map (GskVulkanBuffer *self); +void gsk_vulkan_buffer_unmap (GskVulkanBuffer *self); + +G_END_DECLS + +#endif /* __GSK_VULKAN_BUFFER_PRIVATE_H__ */ diff --git a/gsk/gskvulkanmemory.c b/gsk/gskvulkanmemory.c new file mode 100644 index 0000000000..1ff46757d4 --- /dev/null +++ b/gsk/gskvulkanmemory.c @@ -0,0 +1,95 @@ +#include "config.h" + +#include "gskvulkanpipelineprivate.h" +#include "gskvulkanmemoryprivate.h" + +struct _GskVulkanMemory +{ + GdkVulkanContext *vulkan; + + gsize size; + + VkDeviceMemory vk_memory; +}; + +GskVulkanMemory * +gsk_vulkan_memory_new (GdkVulkanContext *context, + uint32_t allowed_types, + VkMemoryPropertyFlags flags, + gsize size) +{ + VkPhysicalDeviceMemoryProperties properties; + GskVulkanMemory *self; + uint32_t i; + + self = g_slice_new0 (GskVulkanMemory); + + self->vulkan = g_object_ref (context); + self->size = size; + + vkGetPhysicalDeviceMemoryProperties (gdk_vulkan_context_get_physical_device (context), + &properties); + + for (i = 0; i < properties.memoryTypeCount; i++) + { + if (!(allowed_types & (1 << i))) + continue; + + if ((properties.memoryTypes[i].propertyFlags & flags) == flags) + break; + } + + g_assert (i < properties.memoryTypeCount); + + GSK_VK_CHECK (vkAllocateMemory, gdk_vulkan_context_get_device (context), + &(VkMemoryAllocateInfo) { + .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + .allocationSize = size, + .memoryTypeIndex = i + }, + NULL, + &self->vk_memory); + + return self; +} + +void +gsk_vulkan_memory_free (GskVulkanMemory *self) +{ + vkFreeMemory (gdk_vulkan_context_get_device (self->vulkan), + self->vk_memory, + NULL); + + g_object_unref (self->vulkan); + + g_slice_free (GskVulkanMemory, self); +} + +VkDeviceMemory +gsk_vulkan_memory_get_device_memory (GskVulkanMemory *self) +{ + return self->vk_memory; +} + +guchar * +gsk_vulkan_memory_map (GskVulkanMemory *self) +{ + void *data; + + GSK_VK_CHECK (vkMapMemory, gdk_vulkan_context_get_device (self->vulkan), + self->vk_memory, + 0, + self->size, + 0, + &data); + + return data; +} + +void +gsk_vulkan_memory_unmap (GskVulkanMemory *self) +{ + vkUnmapMemory (gdk_vulkan_context_get_device (self->vulkan), + self->vk_memory); +} + diff --git a/gsk/gskvulkanmemoryprivate.h b/gsk/gskvulkanmemoryprivate.h new file mode 100644 index 0000000000..010c133018 --- /dev/null +++ b/gsk/gskvulkanmemoryprivate.h @@ -0,0 +1,23 @@ +#ifndef __GSK_VULKAN_MEMORY_PRIVATE_H__ +#define __GSK_VULKAN_MEMORY_PRIVATE_H__ + +#include + +G_BEGIN_DECLS + +typedef struct _GskVulkanMemory GskVulkanMemory; + +GskVulkanMemory * gsk_vulkan_memory_new (GdkVulkanContext *context, + uint32_t allowed_types, + VkMemoryPropertyFlags properties, + gsize size); +void gsk_vulkan_memory_free (GskVulkanMemory *memory); + +VkDeviceMemory gsk_vulkan_memory_get_device_memory (GskVulkanMemory *self); + +guchar * gsk_vulkan_memory_map (GskVulkanMemory *self); +void gsk_vulkan_memory_unmap (GskVulkanMemory *self); + +G_END_DECLS + +#endif /* __GSK_VULKAN_MEMORY_PRIVATE_H__ */ diff --git a/gsk/gskvulkanpipeline.c b/gsk/gskvulkanpipeline.c new file mode 100644 index 0000000000..8da3f27b44 --- /dev/null +++ b/gsk/gskvulkanpipeline.c @@ -0,0 +1,176 @@ +#include "config.h" + +#include "gskvulkanpipelineprivate.h" + +#include "gskvulkanshaderprivate.h" + +struct _GskVulkanPipeline +{ + GObject parent_instance; + + GdkVulkanContext *vulkan; + + VkPipeline pipeline; + VkPipelineLayout pipeline_layout; + + GskVulkanShader *vertex_shader; + GskVulkanShader *fragment_shader; +}; + +G_DEFINE_TYPE (GskVulkanPipeline, gsk_vulkan_pipeline, G_TYPE_OBJECT) + +static void +gsk_vulkan_pipeline_finalize (GObject *gobject) +{ + GskVulkanPipeline *self = GSK_VULKAN_PIPELINE (gobject); + VkDevice device = gdk_vulkan_context_get_device (self->vulkan); + + vkDestroyPipeline (device, + self->pipeline, + NULL); + + g_clear_pointer (&self->fragment_shader, gsk_vulkan_shader_free); + g_clear_pointer (&self->vertex_shader, gsk_vulkan_shader_free); + + vkDestroyPipelineLayout (device, + self->pipeline_layout, + NULL); + + g_clear_object (&self->vulkan); + + G_OBJECT_CLASS (gsk_vulkan_pipeline_parent_class)->finalize (gobject); +} + +static void +gsk_vulkan_pipeline_class_init (GskVulkanPipelineClass *klass) +{ + G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_pipeline_finalize; +} + +static void +gsk_vulkan_pipeline_init (GskVulkanPipeline *self) +{ +} + +GskVulkanPipeline * +gsk_vulkan_pipeline_new (GdkVulkanContext *context, + VkRenderPass render_pass) +{ + GskVulkanPipeline *self; + VkDevice device; + + g_return_val_if_fail (GDK_IS_VULKAN_CONTEXT (context), NULL); + g_return_val_if_fail (render_pass != VK_NULL_HANDLE, NULL); + + device = gdk_vulkan_context_get_device (context); + + self = g_object_new (GSK_TYPE_VULKAN_PIPELINE, NULL); + + self->vulkan = g_object_ref (context); + + GSK_VK_CHECK (vkCreatePipelineLayout, device, + &(VkPipelineLayoutCreateInfo) { + .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, + .setLayoutCount = 0, + }, + NULL, + &self->pipeline_layout); + + self->vertex_shader = gsk_vulkan_shader_new_from_resource (context, GSK_VULKAN_SHADER_VERTEX, "blit", NULL); + self->fragment_shader = gsk_vulkan_shader_new_from_resource (context, GSK_VULKAN_SHADER_FRAGMENT, "blit", NULL); + + GSK_VK_CHECK (vkCreateGraphicsPipelines, device, + VK_NULL_HANDLE, + 1, + &(VkGraphicsPipelineCreateInfo) { + .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, + .stageCount = 2, + .pStages = (VkPipelineShaderStageCreateInfo[2]) { + GST_VULKAN_SHADER_STAGE_CREATE_INFO (self->vertex_shader), + GST_VULKAN_SHADER_STAGE_CREATE_INFO (self->fragment_shader) + }, + .pVertexInputState = &(VkPipelineVertexInputStateCreateInfo) { + .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, + .vertexBindingDescriptionCount = 1, + .pVertexBindingDescriptions = (VkVertexInputBindingDescription[]) { + { + .binding = 0, + .stride = 2 * sizeof(float), + .inputRate = VK_VERTEX_INPUT_RATE_VERTEX + } + }, + .vertexAttributeDescriptionCount = 1, + .pVertexAttributeDescriptions = (VkVertexInputAttributeDescription[]) { + { + .location = 0, + .binding = 0, + .format = VK_FORMAT_R32G32_SFLOAT, + .offset = 0, + } + } + }, + .pInputAssemblyState = &(VkPipelineInputAssemblyStateCreateInfo) { + .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, + .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, + .primitiveRestartEnable = VK_FALSE, + }, + .pTessellationState = NULL, + .pViewportState = &(VkPipelineViewportStateCreateInfo) { + .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, + .viewportCount = 1, + .scissorCount = 1 + }, + .pRasterizationState = &(VkPipelineRasterizationStateCreateInfo) { + .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, + .depthClampEnable = VK_FALSE, + .rasterizerDiscardEnable = VK_FALSE, + .polygonMode = VK_POLYGON_MODE_FILL, + .cullMode = VK_CULL_MODE_BACK_BIT, + .frontFace = VK_FRONT_FACE_CLOCKWISE, + .lineWidth = 1.0f, + }, + .pMultisampleState = &(VkPipelineMultisampleStateCreateInfo) { + .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, + .rasterizationSamples = 1, + }, + .pDepthStencilState = &(VkPipelineDepthStencilStateCreateInfo) { + .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO + }, + .pColorBlendState = &(VkPipelineColorBlendStateCreateInfo) { + .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, + .attachmentCount = 1, + .pAttachments = (VkPipelineColorBlendAttachmentState []) { + { .colorWriteMask = VK_COLOR_COMPONENT_A_BIT | + VK_COLOR_COMPONENT_R_BIT | + VK_COLOR_COMPONENT_G_BIT | + VK_COLOR_COMPONENT_B_BIT }, + } + }, + .pDynamicState = &(VkPipelineDynamicStateCreateInfo) { + .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, + .dynamicStateCount = 2, + .pDynamicStates = (VkDynamicState[2]) { + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR + }, + }, + .layout = self->pipeline_layout, + .renderPass = render_pass, + .subpass = 0, + .basePipelineHandle = VK_NULL_HANDLE, + .basePipelineIndex = -1, + }, + NULL, + &self->pipeline); + + + return self; +} + +VkPipeline +gsk_vulkan_pipeline_get_pipeline (GskVulkanPipeline *self) +{ + return self->pipeline; +} + + diff --git a/gsk/gskvulkanpipelineprivate.h b/gsk/gskvulkanpipelineprivate.h new file mode 100644 index 0000000000..b4e9e285ba --- /dev/null +++ b/gsk/gskvulkanpipelineprivate.h @@ -0,0 +1,34 @@ +#ifndef __GSK_VULKAN_PIPELINE_PRIVATE_H__ +#define __GSK_VULKAN_PIPELINE_PRIVATE_H__ + +#include + +#include "gskdebugprivate.h" + +G_BEGIN_DECLS + +#define GSK_TYPE_VULKAN_PIPELINE (gsk_vulkan_pipeline_get_type ()) + +G_DECLARE_FINAL_TYPE (GskVulkanPipeline, gsk_vulkan_pipeline, GSK, VULKAN_PIPELINE, GObject) + +static inline VkResult +gsk_vulkan_handle_result (VkResult res, + const char *called_function) +{ + if (res != VK_SUCCESS) + { + GSK_NOTE (VULKAN,g_printerr ("%s(): %s (%d)\n", called_function, gdk_vulkan_strerror (res), res)); + } + return res; +} + +#define GSK_VK_CHECK(func, ...) gsk_vulkan_handle_result (func (__VA_ARGS__), G_STRINGIFY (func)) + +GskVulkanPipeline * gsk_vulkan_pipeline_new (GdkVulkanContext *context, + VkRenderPass render_pass); + +VkPipeline gsk_vulkan_pipeline_get_pipeline (GskVulkanPipeline *self); + +G_END_DECLS + +#endif /* __GSK_VULKAN_PIPELINE_PRIVATE_H__ */ diff --git a/gsk/gskvulkanrenderer.c b/gsk/gskvulkanrenderer.c index ccae2de02e..dddcc5a7ff 100644 --- a/gsk/gskvulkanrenderer.c +++ b/gsk/gskvulkanrenderer.c @@ -3,10 +3,13 @@ #include "gskvulkanrendererprivate.h" #include "gskdebugprivate.h" +#include "gskprivate.h" #include "gskrendererprivate.h" #include "gskrendernodeiter.h" #include "gskrendernodeprivate.h" #include "gsktextureprivate.h" +#include "gskvulkanbufferprivate.h" +#include "gskvulkanpipelineprivate.h" typedef struct _GskVulkanTarget GskVulkanTarget; @@ -28,6 +31,9 @@ struct _GskVulkanRenderer VkRenderPass render_pass; VkCommandPool command_pool; + VkFence command_pool_fence; + + GskVulkanPipeline *pipeline; #ifdef G_ENABLE_DEBUG ProfileTimers profile_timers; @@ -47,19 +53,6 @@ struct _GskVulkanTarget { VkFramebuffer framebuffer; }; -static inline VkResult -gsk_vulkan_handle_result (VkResult res, - const char *called_function) -{ - if (res != VK_SUCCESS) - { - GSK_NOTE (VULKAN,g_printerr ("%s(): %s (%d)\n", called_function, gdk_vulkan_strerror (res), res)); - } - return res; -} - -#define GSK_VK_CHECK(func, ...) gsk_vulkan_handle_result (func (__VA_ARGS__), G_STRINGIFY (func)) - static GskVulkanTarget * gsk_vulkan_target_new_for_image (GskVulkanRenderer *self, VkImage image) @@ -218,14 +211,25 @@ gsk_vulkan_renderer_realize (GskRenderer *renderer, }, NULL, &self->render_pass); - GSK_VK_CHECK (vkCreateCommandPool, device, - &(const VkCommandPoolCreateInfo) { - .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, - .queueFamilyIndex = gdk_vulkan_context_get_queue_family_index (self->vulkan), - .flags = 0 - }, - NULL, - &self->command_pool); + GSK_VK_CHECK (vkCreateCommandPool, device, + &(const VkCommandPoolCreateInfo) { + .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, + .queueFamilyIndex = gdk_vulkan_context_get_queue_family_index (self->vulkan), + .flags = 0 + }, + NULL, + &self->command_pool); + + GSK_VK_CHECK (vkCreateFence, device, + &(VkFenceCreateInfo) { + .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, + .flags = 0 + }, + NULL, + &self->command_pool_fence); + + + self->pipeline = gsk_vulkan_pipeline_new (self->vulkan, self->render_pass); g_signal_connect (self->vulkan, "images-updated", @@ -249,6 +253,11 @@ gsk_vulkan_renderer_unrealize (GskRenderer *renderer) gsk_vulkan_renderer_update_images_cb, self); + vkDestroyFence (device, + self->command_pool_fence, + NULL); + self->command_pool_fence = VK_NULL_HANDLE; + vkDestroyCommandPool (device, self->command_pool, NULL); @@ -262,11 +271,106 @@ gsk_vulkan_renderer_unrealize (GskRenderer *renderer) g_clear_object (&self->vulkan); } +static void +gsk_vulkan_renderer_do_render_commands (GskVulkanRenderer *self, + VkCommandBuffer command_buffer) +{ + GskVulkanBuffer *buffer; + float pts[] = { + -1.0, -1.0, + 1.0, -1.0, + -1.0, 1.0, + + -1.0, 1.0, + 1.0, -1.0, + 1.0, 1.0 + }; + guchar *data; + + buffer = gsk_vulkan_buffer_new (self->vulkan, sizeof (pts)); + + data = gsk_vulkan_buffer_map (buffer); + memcpy (data, pts, sizeof (pts)); + gsk_vulkan_buffer_unmap (buffer); + + vkCmdBindPipeline (command_buffer, + VK_PIPELINE_BIND_POINT_GRAPHICS, + gsk_vulkan_pipeline_get_pipeline (self->pipeline)); + + vkCmdBindVertexBuffers (command_buffer, + 0, + 1, + (VkBuffer[1]) { + gsk_vulkan_buffer_get_buffer (buffer) + }, + (VkDeviceSize[1]) { 0 }); + + vkCmdDraw (command_buffer, + 6, 1, + 0, 0); + + gsk_vulkan_buffer_free (buffer); +} + +static void +gsk_vulkan_renderer_do_render_pass (GskVulkanRenderer *self, + VkCommandBuffer command_buffer, + GskRenderNode *root) +{ + GdkRectangle extents; + GdkWindow *window; + + window = gsk_renderer_get_window (GSK_RENDERER (self)); + cairo_region_get_extents (gdk_drawing_context_get_clip (gsk_renderer_get_drawing_context (GSK_RENDERER (self))), + &extents); + + vkCmdBeginRenderPass (command_buffer, + &(VkRenderPassBeginInfo) { + .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, + .renderPass = self->render_pass, + .framebuffer = self->targets[gdk_vulkan_context_get_draw_index (self->vulkan)]->framebuffer, + .renderArea = { + { 0, 0 }, + { gdk_window_get_width (window), gdk_window_get_height (window) } + }, + .clearValueCount = 1, + .pClearValues = (VkClearValue [1]) { + { .color = { .float32 = { 0.f, 0.f, 0.f, 0.f } } } + } + }, + VK_SUBPASS_CONTENTS_INLINE); + + vkCmdSetViewport (command_buffer, + 0, + 1, + &(VkViewport) { + .x = 0, + .y = 0, + .width = gdk_window_get_width (window), + .height = gdk_window_get_height (window), + .minDepth = 0, + .maxDepth = 1 + }); + + vkCmdSetScissor (command_buffer, + 0, + 1, + &(VkRect2D) { + { extents.x, extents.y }, + { extents.width, extents.height } + }); + + gsk_vulkan_renderer_do_render_commands (self, command_buffer); + + vkCmdEndRenderPass (command_buffer); +} + static void gsk_vulkan_renderer_render (GskRenderer *renderer, GskRenderNode *root) { GskVulkanRenderer *self = GSK_VULKAN_RENDERER (renderer); + VkCommandBuffer command_buffer; #ifdef G_ENABLE_DEBUG GskProfiler *profiler; gint64 cpu_time; @@ -277,6 +381,54 @@ gsk_vulkan_renderer_render (GskRenderer *renderer, gsk_profiler_timer_begin (profiler, self->profile_timers.cpu_time); #endif + GSK_VK_CHECK (vkAllocateCommandBuffers, gdk_vulkan_context_get_device (self->vulkan), + &(VkCommandBufferAllocateInfo) { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, + .commandPool = self->command_pool, + .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, + .commandBufferCount = 1, + }, + &command_buffer); + + GSK_VK_CHECK (vkBeginCommandBuffer, command_buffer, + &(VkCommandBufferBeginInfo) { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, + .flags = 0 + }); + + gsk_vulkan_renderer_do_render_pass (self, command_buffer, root); + + GSK_VK_CHECK (vkEndCommandBuffer, command_buffer); + + GSK_VK_CHECK (vkQueueSubmit, gdk_vulkan_context_get_queue (self->vulkan), + 1, + &(VkSubmitInfo) { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, + .waitSemaphoreCount = 1, + .pWaitSemaphores = (VkSemaphore[1]) { + gdk_vulkan_context_get_draw_semaphore (self->vulkan), + }, + .pWaitDstStageMask = (VkPipelineStageFlags []) { + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + }, + .commandBufferCount = 1, + .pCommandBuffers = &command_buffer, + }, + self->command_pool_fence); + + GSK_VK_CHECK (vkWaitForFences, gdk_vulkan_context_get_device (self->vulkan), + 1, + &self->command_pool_fence, + true, + INT64_MAX); + GSK_VK_CHECK (vkResetFences, gdk_vulkan_context_get_device (self->vulkan), + 1, + &self->command_pool_fence); + + GSK_VK_CHECK (vkResetCommandPool, gdk_vulkan_context_get_device (self->vulkan), + self->command_pool, + 0); + #ifdef G_ENABLE_DEBUG cpu_time = gsk_profiler_timer_end (profiler, self->profile_timers.cpu_time); gsk_profiler_timer_set (profiler, self->profile_timers.cpu_time, cpu_time); @@ -304,7 +456,7 @@ gsk_vulkan_renderer_begin_draw_frame (GskRenderer *renderer, result = gdk_window_begin_draw_frame (window, GDK_DRAW_CONTEXT (self->vulkan), - region); + whole_window); cairo_region_destroy (whole_window); @@ -327,7 +479,11 @@ gsk_vulkan_renderer_init (GskVulkanRenderer *self) { #ifdef G_ENABLE_DEBUG GskProfiler *profiler = gsk_renderer_get_profiler (GSK_RENDERER (self)); +#endif + gsk_ensure_resources (); + +#ifdef G_ENABLE_DEBUG self->profile_timers.cpu_time = gsk_profiler_add_timer (profiler, "cpu-time", "CPU time", FALSE, TRUE); #endif } diff --git a/gsk/gskvulkanshader.c b/gsk/gskvulkanshader.c new file mode 100644 index 0000000000..1010b21304 --- /dev/null +++ b/gsk/gskvulkanshader.c @@ -0,0 +1,102 @@ +#include "config.h" + +#include "gskvulkanshaderprivate.h" +#include "gskvulkanpipelineprivate.h" + +struct _GskVulkanShader +{ + GdkVulkanContext *vulkan; + + GskVulkanShaderType type; + VkShaderModule vk_shader; +}; + +static GskVulkanShader * +gsk_vulkan_shader_new_from_bytes (GdkVulkanContext *context, + GskVulkanShaderType type, + GBytes *bytes, + GError **error) +{ + GskVulkanShader *self; + VkShaderModule shader; + VkResult res; + + res = GSK_VK_CHECK (vkCreateShaderModule, gdk_vulkan_context_get_device (context), + &(VkShaderModuleCreateInfo) { + .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, + .codeSize = g_bytes_get_size (bytes), + .pCode = (uint32_t *) g_bytes_get_data (bytes, NULL), + }, + NULL, + &shader); + if (res != VK_SUCCESS) + { + /* Someone invent better error categories plz */ + g_set_error (error, GDK_VULKAN_ERROR, GDK_VULKAN_ERROR_UNSUPPORTED, + "Could not create shader: %s", gdk_vulkan_strerror (res)); + return NULL; + } + + self = g_slice_new0 (GskVulkanShader); + + self->vulkan = g_object_ref (context); + self->type = type; + self->vk_shader = shader; + + return self; +} + +GskVulkanShader * +gsk_vulkan_shader_new_from_resource (GdkVulkanContext *context, + GskVulkanShaderType type, + const char *resource_name, + GError **error) +{ + GskVulkanShader *self; + GBytes *bytes; + GError *local_error = NULL; + char *path; + + path = g_strconcat ("/org/gtk/libgsk/vulkan/", + resource_name, + type == GSK_VULKAN_SHADER_VERTEX ? ".vert.spv" : ".frag.spv", + NULL); + bytes = g_resources_lookup_data (path, 0, &local_error); + g_free (path); + if (bytes == NULL) + { + GSK_NOTE (VULKAN, g_printerr ("Error loading shader data: %s\n", local_error->message)); + g_propagate_error (error, local_error); + return NULL; + } + + self = gsk_vulkan_shader_new_from_bytes (context, type, bytes, error); + g_bytes_unref (bytes); + + return self; +} + +void +gsk_vulkan_shader_free (GskVulkanShader *self) +{ + vkDestroyShaderModule (gdk_vulkan_context_get_device (self->vulkan), + self->vk_shader, + NULL); + + g_object_unref (self->vulkan); + + g_slice_free (GskVulkanShader, self); +} + +GskVulkanShaderType +gsk_vulkan_shader_get_type (GskVulkanShader *shader) +{ + return shader->type; +} + +VkShaderModule +gsk_vulkan_shader_get_module (GskVulkanShader *shader) +{ + return shader->vk_shader; +} + diff --git a/gsk/gskvulkanshaderprivate.h b/gsk/gskvulkanshaderprivate.h new file mode 100644 index 0000000000..e94424f30a --- /dev/null +++ b/gsk/gskvulkanshaderprivate.h @@ -0,0 +1,34 @@ +#ifndef __GSK_VULKAN_SHADER_PRIVATE_H__ +#define __GSK_VULKAN_SHADER_PRIVATE_H__ + +#include + +G_BEGIN_DECLS + +typedef enum { + GSK_VULKAN_SHADER_VERTEX, + GSK_VULKAN_SHADER_FRAGMENT +} GskVulkanShaderType; + +typedef struct _GskVulkanShader GskVulkanShader; + +#define GST_VULKAN_SHADER_STAGE_CREATE_INFO(shader) \ + (VkPipelineShaderStageCreateInfo) { \ + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, \ + .stage = gsk_vulkan_shader_get_type (shader) == GSK_VULKAN_SHADER_VERTEX ? VK_SHADER_STAGE_VERTEX_BIT : VK_SHADER_STAGE_FRAGMENT_BIT, \ + .module = gsk_vulkan_shader_get_module (shader), \ + .pName = "main", \ +} + +GskVulkanShader * gsk_vulkan_shader_new_from_resource (GdkVulkanContext *context, + GskVulkanShaderType type, + const char *resource_name, + GError **error); +void gsk_vulkan_shader_free (GskVulkanShader *shader); + +GskVulkanShaderType gsk_vulkan_shader_get_type (GskVulkanShader *shader); +VkShaderModule gsk_vulkan_shader_get_module (GskVulkanShader *shader); + +G_END_DECLS + +#endif /* __GSK_VULKAN_SHADER_PRIVATE_H__ */ diff --git a/gsk/resources/vulkan/blit.frag.glsl b/gsk/resources/vulkan/blit.frag.glsl new file mode 100644 index 0000000000..94f76e4f16 --- /dev/null +++ b/gsk/resources/vulkan/blit.frag.glsl @@ -0,0 +1,8 @@ +#version 420 core + +layout(location = 0) out vec4 color; + +void main() +{ + color = vec4(1.0, 1.0, 0.0, 1.0); +} diff --git a/gsk/resources/vulkan/blit.frag.spv b/gsk/resources/vulkan/blit.frag.spv new file mode 100644 index 0000000000..76adb08511 Binary files /dev/null and b/gsk/resources/vulkan/blit.frag.spv differ diff --git a/gsk/resources/vulkan/blit.vert.glsl b/gsk/resources/vulkan/blit.vert.glsl new file mode 100644 index 0000000000..ae450004d2 --- /dev/null +++ b/gsk/resources/vulkan/blit.vert.glsl @@ -0,0 +1,11 @@ +#version 420 core + +layout(location = 0) in vec2 inPosition; + +out gl_PerVertex { + vec4 gl_Position; +}; + +void main() { + gl_Position = vec4(inPosition, 0.0, 1.0); +} diff --git a/gsk/resources/vulkan/blit.vert.spv b/gsk/resources/vulkan/blit.vert.spv new file mode 100644 index 0000000000..41ea691e5b Binary files /dev/null and b/gsk/resources/vulkan/blit.vert.spv differ