forked from AuroraMiddleware/gtk
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.
This commit is contained in:
parent
3f7cc013cc
commit
2a0e7f8829
@ -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>" >> $@
|
||||
|
||||
|
88
gsk/gskvulkanbuffer.c
Normal file
88
gsk/gskvulkanbuffer.c
Normal file
@ -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);
|
||||
}
|
21
gsk/gskvulkanbufferprivate.h
Normal file
21
gsk/gskvulkanbufferprivate.h
Normal file
@ -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__ */
|
95
gsk/gskvulkanmemory.c
Normal file
95
gsk/gskvulkanmemory.c
Normal file
@ -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);
|
||||
}
|
||||
|
23
gsk/gskvulkanmemoryprivate.h
Normal file
23
gsk/gskvulkanmemoryprivate.h
Normal file
@ -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__ */
|
176
gsk/gskvulkanpipeline.c
Normal file
176
gsk/gskvulkanpipeline.c
Normal file
@ -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;
|
||||
}
|
||||
|
||||
|
34
gsk/gskvulkanpipelineprivate.h
Normal file
34
gsk/gskvulkanpipelineprivate.h
Normal file
@ -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__ */
|
@ -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
|
||||
}
|
||||
|
102
gsk/gskvulkanshader.c
Normal file
102
gsk/gskvulkanshader.c
Normal file
@ -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;
|
||||
}
|
||||
|
34
gsk/gskvulkanshaderprivate.h
Normal file
34
gsk/gskvulkanshaderprivate.h
Normal file
@ -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__ */
|
8
gsk/resources/vulkan/blit.frag.glsl
Normal file
8
gsk/resources/vulkan/blit.frag.glsl
Normal file
@ -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);
|
||||
}
|
BIN
gsk/resources/vulkan/blit.frag.spv
Normal file
BIN
gsk/resources/vulkan/blit.frag.spv
Normal file
Binary file not shown.
11
gsk/resources/vulkan/blit.vert.glsl
Normal file
11
gsk/resources/vulkan/blit.vert.glsl
Normal file
@ -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);
|
||||
}
|
BIN
gsk/resources/vulkan/blit.vert.spv
Normal file
BIN
gsk/resources/vulkan/blit.vert.spv
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user