[gtk+/wip/otte/vulkan: 59/59] gsk: Loads of work on Vulkan backend



commit bfb9378dffb0b9c509882743768f66e70efbb210
Author: Benjamin Otte <otte redhat com>
Date:   Mon Dec 5 02:50:06 2016 +0100

    gsk: Loads of work on Vulkan backend
    
    We can now upload vertices.
    
    And we use this to draw a yellow background. Which is clearly superior
    to not drawing anything.
    
    Also, we have shaders now. If you modify them, you need glslc installed
    so they can be recompiled into Spir-V bytecode.

 gsk/Makefile.am                     |   29 +++++-
 gsk/gskvulkanbuffer.c               |   88 +++++++++++++++
 gsk/gskvulkanbufferprivate.h        |   21 ++++
 gsk/gskvulkanmemory.c               |   95 +++++++++++++++++
 gsk/gskvulkanmemoryprivate.h        |   23 ++++
 gsk/gskvulkanpipeline.c             |  176 ++++++++++++++++++++++++++++++
 gsk/gskvulkanpipelineprivate.h      |   34 ++++++
 gsk/gskvulkanrenderer.c             |  200 +++++++++++++++++++++++++++++++----
 gsk/gskvulkanshader.c               |  102 ++++++++++++++++++
 gsk/gskvulkanshaderprivate.h        |   34 ++++++
 gsk/resources/vulkan/blit.frag.glsl |    8 ++
 gsk/resources/vulkan/blit.frag.spv  |  Bin 0 -> 420 bytes
 gsk/resources/vulkan/blit.vert.glsl |   11 ++
 gsk/resources/vulkan/blit.vert.spv  |  Bin 0 -> 692 bytes
 14 files changed, 796 insertions(+), 25 deletions(-)
---
diff --git a/gsk/Makefile.am b/gsk/Makefile.am
index 77bfc0e..84ae987 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 "<?xml version='1.0' encoding='UTF-8'?>" > $@; \
        echo "<gresources>" >> $@; \
@@ -103,6 +118,14 @@ gsk.resources.xml: Makefile.am
          n=`basename $$f`; \
          echo "    <file alias='glsl/$$n'>resources/glsl/$$n</file>" >> $@; \
        done; \
+       for f in $(top_srcdir)/gsk/resources/vulkan/*.spv; do \
+         n=`basename $$f`; \
+         echo "    <file alias='vulkan/$$n'>resources/vulkan/$$n</file>" >> $@; \
+       done; \
+       for f in $(top_srcdir)/gsk/resources/vulkan/*.glsl; do \
+         n=`basename $$f`; \
+         echo "    <file alias='vulkan/$$n'>resources/vulkan/$$n</file>" >> $@; \
+       done; \
        echo "  </gresource>" >> $@; \
        echo "</gresources>" >> $@
 
diff --git a/gsk/gskvulkanbuffer.c b/gsk/gskvulkanbuffer.c
new file mode 100644
index 0000000..6694131
--- /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 0000000..e497192
--- /dev/null
+++ b/gsk/gskvulkanbufferprivate.h
@@ -0,0 +1,21 @@
+#ifndef __GSK_VULKAN_BUFFER_PRIVATE_H__
+#define __GSK_VULKAN_BUFFER_PRIVATE_H__
+
+#include <gdk/gdk.h>
+
+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 0000000..1ff4675
--- /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 0000000..010c133
--- /dev/null
+++ b/gsk/gskvulkanmemoryprivate.h
@@ -0,0 +1,23 @@
+#ifndef __GSK_VULKAN_MEMORY_PRIVATE_H__
+#define __GSK_VULKAN_MEMORY_PRIVATE_H__
+
+#include <gdk/gdk.h>
+
+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 0000000..8da3f27
--- /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 0000000..b4e9e28
--- /dev/null
+++ b/gsk/gskvulkanpipelineprivate.h
@@ -0,0 +1,34 @@
+#ifndef __GSK_VULKAN_PIPELINE_PRIVATE_H__
+#define __GSK_VULKAN_PIPELINE_PRIVATE_H__
+
+#include <gdk/gdk.h>
+
+#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 ccae2de..927197f 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);
@@ -263,10 +272,105 @@ gsk_vulkan_renderer_unrealize (GskRenderer *renderer)
 }
 
 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 0000000..1010b21
--- /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 0000000..e94424f
--- /dev/null
+++ b/gsk/gskvulkanshaderprivate.h
@@ -0,0 +1,34 @@
+#ifndef __GSK_VULKAN_SHADER_PRIVATE_H__
+#define __GSK_VULKAN_SHADER_PRIVATE_H__
+
+#include <gdk/gdk.h>
+
+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 0000000..94f76e4
--- /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 0000000..76adb08
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 0000000..ae45000
--- /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 0000000..41ea691
Binary files /dev/null and b/gsk/resources/vulkan/blit.vert.spv differ



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]