Updated gitignore, got basic polygon UI pipeline rendering shapes with offsets/colors

main
noah metz 2024-10-09 20:00:56 -06:00
parent 1fa7b38624
commit e9d3a71a1d
11 changed files with 468 additions and 167 deletions

4
.gitignore vendored

@ -30,3 +30,7 @@ roleplay
.cache
*.o
*.spv
.DS_Store

@ -6,7 +6,7 @@ CPP = /opt/homebrew/opt/llvm/bin/clang++
DSYM = /opt/homebrew/opt/llvm/bin/dsymutil
GDB = /opt/homebrew/opt/llvm/bin/lldb
SOURCES = src/main.c src/render.c src/vma.cpp src/pipeline.c
SOURCES = src/main.c src/render.c src/vma.cpp src/pipeline.c src/command.c
OBJECTS = $(addsuffix .o, $(basename $(SOURCES)))
VERT_SPV = $(addsuffix .vert.spv, $(basename $(wildcard shader_src/*.vert)))
FRAG_SPV = $(addsuffix .frag.spv, $(basename $(wildcard shader_src/*.frag)))
@ -38,13 +38,13 @@ clean_compdb:
rm -rf .compdb
rm compile_commands.json
run: roleplay
run: roleplay $(VERT_SPV) $(FRAG_SPV)
./roleplay
roleplay.dSYM: roleplay
$(DSYM) roleplay
debug: roleplay roleplay.dSYM
debug: roleplay roleplay.dSYM $(VERT_SPV) $(FRAG_SPV)
$(GDB) roleplay

@ -0,0 +1,21 @@
#ifndef COMMAND_H
#define COMMAND_H
#include "vulkan/vulkan_core.h"
typedef struct QueueStruct {
VkQueue handle;
uint32_t family;
uint32_t index;
} Queue;
VkCommandBuffer command_begin_single(VkDevice device, VkCommandPool transfer_pool);
VkResult command_end_single(VkDevice device, VkCommandBuffer command_buffer, VkCommandPool transfer_pool, Queue transfer_queue);
VkResult command_transition_image_layout(VkDevice device, VkCommandPool transfer_pool, Queue transfer_queue, VkImageLayout old_layout, VkImageLayout new_layout, VkImage image, VkAccessFlags src_mask, VkAccessFlags dst_mask, VkPipelineStageFlags source, VkPipelineStageFlags dest, uint32_t source_family, uint32_t dest_family, VkImageAspectFlags aspect_flags);
VkResult command_transition_image_layout(VkDevice device, VkCommandPool transfer_pool, Queue transfer_queue, VkImageLayout old_layout, VkImageLayout new_layout, VkImage image, VkAccessFlags src_mask, VkAccessFlags dst_mask, VkPipelineStageFlags source, VkPipelineStageFlags dest, uint32_t source_family, uint32_t dest_family, VkImageAspectFlags aspect_flags);
#endif

@ -3,18 +3,24 @@
#include "vulkan/vulkan_core.h"
#include "cglm/types.h"
#include "vk_mem_alloc.h"
#include "command.h"
typedef struct GraphicsPipelineStruct {
VkDescriptorPool descriptor_pool;
VkDescriptorSet* descriptors;
VkPipelineLayout layout;
VkPipeline pipeline;
} GraphicsPipeline;
struct Vertex2 {
vec2 pos;
vec3 color;
struct UIElement {
vec3 pos;
vec2 size;
vec4 color;
};
struct UIUniform {
vec2 size;
};
VkResult create_ui_polygon_pipeline(VkDevice device, VkRenderPass render_pass, VkDescriptorSetLayout descriptor_layout, VmaAllocator allocator, VkCommandPool transfer_pool, Queue transfer_queue, VmaAllocation* polygon_buffer_memory, VkBuffer* polygon_buffer, GraphicsPipeline* pipeline);
#endif

@ -3,7 +3,6 @@
#define VK_USE_PLATFORM_MACOS_MVK
#include "vulkan/vulkan_core.h"
#include "vulkan/vk_enum_string_helper.h"
#include "vk_mem_alloc.h"
@ -20,17 +19,11 @@
#include <cglm/affine.h>
#include <cglm/quat.h>
#include <cglm/cam.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
extern const uint32_t MAX_FRAMES_IN_FLIGHT;
#include "pipeline.h"
#include "command.h"
typedef struct QueueStruct {
VkQueue handle;
uint32_t family;
uint32_t index;
} Queue;
extern const uint32_t MAX_FRAMES_IN_FLIGHT;
typedef struct SwapchainDetailsStruct {
VkSurfaceCapabilitiesKHR capabilities;
@ -83,14 +76,22 @@ typedef struct RenderContextStruct {
VkFence* in_flight_fences;
VkPipeline ui_pipeline_rect;
VkPipeline ui_pipeline_text;
GraphicsPipeline ui_pipeline_polygon;
VkBuffer ui_polygon_buffer;
VmaAllocation ui_polygon_buffer_memory;
VkBuffer ui_descriptor_buffer;
VmaAllocation ui_descriptor_memory;
VkDescriptorSetLayout ui_descriptor_layout;
VkDescriptorPool ui_descriptor_pool;
VkDescriptorSet ui_descriptor_set;
GraphicsPipeline ui_pipeline_text;
uint32_t current_frame;
} RenderContext;
GLFWwindow* init_window();
VkResult init_vulkan(GLFWwindow* window, RenderContext* context);
VkResult draw_frame(RenderContext* context);
VkResult draw_frame(RenderContext* context, VkBuffer ui_polygons, uint32_t polygon_count);
#endif

@ -0,0 +1,10 @@
#version 450
layout(location = 0) in vec4 fragColor;
layout(location = 0) out vec4 outColor;
void main() {
outColor = fragColor;
}

@ -0,0 +1,19 @@
#version 450
#extension GL_EXT_buffer_reference : require
layout(set = 0, binding = 0) uniform UIUniform {
vec2 screen;
} scene;
layout(location = 0) in vec2 inVertexPosition;
layout(location = 1) in vec3 inPolygonPosition;
layout(location = 2) in vec2 inPolygonSize;
layout(location = 3) in vec4 inColor;
layout(location = 0) out vec4 fragColor;
void main() {
gl_Position = vec4(vec3(inVertexPosition * inPolygonSize, 0.0) + inPolygonPosition, 1.0);
fragColor = inColor;
}

@ -0,0 +1,104 @@
#include "command.h"
VkCommandBuffer command_begin_single(VkDevice device, VkCommandPool transfer_pool) {
VkCommandBufferAllocateInfo command_info = {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
.commandPool = transfer_pool,
.commandBufferCount = 1,
};
VkCommandBuffer command_buffer;
VkResult result = vkAllocateCommandBuffers(device, &command_info, &command_buffer);
if(result != VK_SUCCESS) {
return VK_NULL_HANDLE;
}
VkCommandBufferBeginInfo begin_info = {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
};
result = vkBeginCommandBuffer(command_buffer, &begin_info);
if(result != VK_SUCCESS) {
vkFreeCommandBuffers(device, transfer_pool, 1, &command_buffer);
return VK_NULL_HANDLE;
}
return command_buffer;
}
VkResult command_end_single(VkDevice device, VkCommandBuffer command_buffer, VkCommandPool transfer_pool, Queue transfer_queue) {
VkResult result = vkEndCommandBuffer(command_buffer);
if(result != VK_SUCCESS) {
vkFreeCommandBuffers(device, transfer_pool, 1, &command_buffer);
return result;
}
VkSubmitInfo submit_info = {
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
.commandBufferCount = 1,
.pCommandBuffers = &command_buffer,
};
result = vkQueueSubmit(transfer_queue.handle, 1, &submit_info, 0);
if(result != VK_SUCCESS) {
vkFreeCommandBuffers(device, transfer_pool, 1, &command_buffer);
return result;
}
result = vkQueueWaitIdle(transfer_queue.handle);
vkFreeCommandBuffers(device, transfer_pool, 1, &command_buffer);
return result;
}
VkResult command_transition_image_layout(VkDevice device, VkCommandPool transfer_pool, Queue transfer_queue, VkImageLayout old_layout, VkImageLayout new_layout, VkImage image, VkAccessFlags src_mask, VkAccessFlags dst_mask, VkPipelineStageFlags source, VkPipelineStageFlags dest, uint32_t source_family, uint32_t dest_family, VkImageAspectFlags aspect_flags) {
VkCommandBuffer command_buffer = command_begin_single(device, transfer_pool);
VkImageMemoryBarrier barrier = {
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.oldLayout = old_layout,
.newLayout = new_layout,
.srcQueueFamilyIndex = source_family,
.dstQueueFamilyIndex = dest_family,
.image = image,
.subresourceRange = {
.aspectMask = aspect_flags,
.levelCount = 1,
.layerCount = 1,
.baseMipLevel = 0,
.baseArrayLayer = 0,
},
.srcAccessMask = src_mask,
.dstAccessMask = dst_mask,
};
vkCmdPipelineBarrier(command_buffer, source, dest, 0, 0, 0, 0, 0, 1, &barrier);
return command_end_single(device, command_buffer, transfer_pool, transfer_queue);
}
VkResult command_copy_buffer_to_image(VkDevice device, VkCommandPool transfer_pool, Queue transfer_queue, VkExtent3D image_size, VkBuffer source, VkImage dest) {
VkCommandBuffer command_buffer = command_begin_single(device, transfer_pool);
VkBufferImageCopy region = {
.bufferOffset = 0,
.bufferRowLength = 0,
.bufferImageHeight = 0,
.imageSubresource = {
.baseArrayLayer = 0,
.layerCount = 1,
.mipLevel = 0,
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
},
.imageOffset = {
.x = 0,
.y = 0,
.z = 0,
},
.imageExtent = image_size,
};
vkCmdCopyBufferToImage(command_buffer, source, dest, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
return command_end_single(device, command_buffer, transfer_pool, transfer_queue);
}

@ -2,10 +2,68 @@
#include "vulkan/vk_enum_string_helper.h"
VkResult render_thread(GLFWwindow* window, RenderContext* render_context) {
VkBuffer test_ui_buffer;
VmaAllocation test_ui_memory;
VkBufferCreateInfo test_ui_buffer_info = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
.size = 3*sizeof(struct UIElement),
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
};
VmaAllocationCreateInfo test_ui_memory_info = {
.usage = VMA_MEMORY_USAGE_CPU_TO_GPU,
};
VkResult result = vmaCreateBuffer(render_context->allocator, &test_ui_buffer_info, &test_ui_memory_info, &test_ui_buffer, &test_ui_memory, NULL);
if(result != VK_SUCCESS) {
return result;
}
struct UIElement* mapped;
result = vmaMapMemory(render_context->allocator, test_ui_memory, (void**)&mapped);
if(result != VK_SUCCESS) {
return result;
}
mapped[0].size[0] = 0.5;
mapped[0].size[1] = 0.5;
mapped[0].color[0] = 1.0;
mapped[0].color[1] = 0.0;
mapped[0].color[2] = 0.0;
mapped[0].color[3] = 1.0;
mapped[0].pos[0] = 0.0;
mapped[0].pos[1] = 0.0;
mapped[0].pos[2] = 0.5;
mapped[1].size[0] = 0.5;
mapped[1].size[1] = 0.5;
mapped[1].color[0] = 0.0;
mapped[1].color[1] = 1.0;
mapped[1].color[2] = 0.0;
mapped[1].color[3] = 1.0;
mapped[1].pos[0] = 0.5;
mapped[1].pos[1] = 0.0;
mapped[1].pos[2] = 0.5;
mapped[2].size[0] = 0.5;
mapped[2].size[1] = 0.5;
mapped[2].color[0] = 0.0;
mapped[2].color[1] = 0.0;
mapped[2].color[2] = 1.0;
mapped[2].color[3] = 1.0;
mapped[2].pos[0] = 0.0;
mapped[2].pos[1] = 0.5;
mapped[2].pos[2] = 0.5;
vmaUnmapMemory(render_context->allocator, test_ui_memory);
while(glfwWindowShouldClose(window) == 0) {
glfwPollEvents();
VkResult result = draw_frame(render_context);
result = draw_frame(render_context, test_ui_buffer, 3);
if(result != VK_SUCCESS) {
fprintf(stderr, "draw_frame error: %s\n", string_VkResult(result));
return result;

@ -1,6 +1,7 @@
#include "pipeline.h"
#include "stdio.h"
#include "stdlib.h"
#include "vulkan/vulkan_core.h"
VkShaderModule load_shader_file(const char* path, VkDevice device) {
FILE* file;
@ -44,14 +45,10 @@ VkShaderModule load_shader_file(const char* path, VkDevice device) {
return shader;
}
VkResult create_ui_rect_pipeline(VkDevice device, VkRenderPass render_pass, GraphicsPipeline* out) {
if(out == NULL) {
return VK_ERROR_VALIDATION_FAILED_EXT;
}
VkShaderModule vert_shader = load_shader_file("shader_src/ui_rect.vert.spv", device);
VkShaderModule frag_shader = load_shader_file("shader_src/ui_rect.frag.spv", device);
VkPipelineShaderStageCreateInfo shader_stages[2] = {
VkResult create_ui_polygon_pipeline(VkDevice device, VkRenderPass render_pass, VkDescriptorSetLayout descriptor_layout, VmaAllocator allocator, VkCommandPool transfer_pool, Queue transfer_queue, VmaAllocation* polygon_buffer_memory, VkBuffer* polygon_buffer, GraphicsPipeline* pipeline) {
VkShaderModule vert_shader = load_shader_file("shader_src/ui_polygon.vert.spv", device);
VkShaderModule frag_shader = load_shader_file("shader_src/ui_polygon.frag.spv", device);
VkPipelineShaderStageCreateInfo shader_stages[] = {
{
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
.stage = VK_SHADER_STAGE_VERTEX_BIT,
@ -66,29 +63,47 @@ VkResult create_ui_rect_pipeline(VkDevice device, VkRenderPass render_pass, Grap
},
};
VkVertexInputBindingDescription bindings[1] = {
VkVertexInputBindingDescription bindings[] = {
{
.binding = 0,
.stride = sizeof(vec2),
.inputRate = VK_VERTEX_INPUT_RATE_VERTEX,
},
{
.binding = 0, // Which buffer 'binding' to use
.stride = sizeof(struct Vertex2), // How many bytes to increase the index between instance
.inputRate = VK_VERTEX_INPUT_RATE_VERTEX, // Whether an instance is a vertex or an index
.binding = 1,
.stride = sizeof(struct UIElement),
.inputRate = VK_VERTEX_INPUT_RATE_INSTANCE,
},
};
VkVertexInputAttributeDescription attributes[3] = {
VkVertexInputAttributeDescription attributes[] = {
{
.binding = 0, // Which buffer 'binding' to use
.location = 0, // Which 'location' to export as to shader
.format = VK_FORMAT_R32G32_SFLOAT, // What format to interpret as for shader
.offset = offsetof(struct Vertex2, pos), // What offset from instance start
.binding = 0,
.location = 0,
.format = VK_FORMAT_R32G32_SFLOAT,
.offset = 0,
},
{
.binding = 0,
.binding = 1,
.location = 1,
.format = VK_FORMAT_R32G32B32_SFLOAT,
.offset = offsetof(struct Vertex2, color),
.offset = offsetof(struct UIElement, pos),
},
{
.binding = 1,
.location = 2,
.format = VK_FORMAT_R32G32_SFLOAT,
.offset = offsetof(struct UIElement, size),
},
{
.binding = 1,
.location = 3,
.format = VK_FORMAT_R32G32B32A32_SFLOAT,
.offset = offsetof(struct UIElement, color),
},
};
VkPipelineVertexInputStateCreateInfo input_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
.pVertexBindingDescriptions = bindings,
@ -97,19 +112,13 @@ VkResult create_ui_rect_pipeline(VkDevice device, VkRenderPass render_pass, Grap
.vertexAttributeDescriptionCount = sizeof(attributes)/sizeof(VkVertexInputAttributeDescription),
};
VkPushConstantRange pcr = {
.stageFlags = VK_SHADER_STAGE_ALL,
.offset = 0,
.size = sizeof(VkDeviceAddress),
};
VkPipelineLayoutCreateInfo layout_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
.pushConstantRangeCount = 1,
.pPushConstantRanges = &pcr,
.setLayoutCount = 1,
.pSetLayouts = &descriptor_layout,
};
VkResult result = vkCreatePipelineLayout(device, &layout_info, 0, &out->layout);
VkResult result = vkCreatePipelineLayout(device, &layout_info, 0, &pipeline->layout);
if(result != VK_SUCCESS) {
return result;
}
@ -223,7 +232,7 @@ VkResult create_ui_rect_pipeline(VkDevice device, VkRenderPass render_pass, Grap
VkGraphicsPipelineCreateInfo draw_pipeline_info = {
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
.stageCount = 2,
.stageCount = sizeof(shader_stages)/sizeof(VkPipelineShaderStageCreateInfo),
.pStages = shader_stages,
.pVertexInputState = &input_info,
.pInputAssemblyState = &input_assembly_info,
@ -233,17 +242,83 @@ VkResult create_ui_rect_pipeline(VkDevice device, VkRenderPass render_pass, Grap
.pDynamicState = &dynamic_info,
.pDepthStencilState = &depth_info,
.pMultisampleState = &multisample_info,
.layout = out->layout,
.layout = pipeline->layout,
.renderPass = render_pass,
.subpass = 0,
.basePipelineHandle = VK_NULL_HANDLE,
.basePipelineIndex = -1,
};
result = vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &draw_pipeline_info, 0, &out->pipeline);
result = vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &draw_pipeline_info, 0, &pipeline->pipeline);
if(result != VK_SUCCESS) {
return result;
}
// Create and populate polygon buffer
uint32_t polygon_buffer_size = 3 * sizeof(vec2);
VkBufferCreateInfo temp_buffer_info = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.size = polygon_buffer_size
};
VmaAllocationCreateInfo temp_allocation_info = {
.usage = VMA_MEMORY_USAGE_CPU_TO_GPU,
};
VkBuffer temp_buffer;
VmaAllocation temp_buffer_memory;
result = vmaCreateBuffer(allocator, &temp_buffer_info, &temp_allocation_info, &temp_buffer, &temp_buffer_memory, NULL);
if(result != VK_SUCCESS) {
return result;
}
VkBufferCreateInfo buffer_info = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.size = polygon_buffer_size,
};
VmaAllocationCreateInfo allocation_info = {
.usage = VMA_MEMORY_USAGE_GPU_ONLY,
};
result = vmaCreateBuffer(allocator, &buffer_info, &allocation_info, polygon_buffer, polygon_buffer_memory, NULL);
if(result != VK_SUCCESS) {
return result;
}
vec2* mapped;
result = vmaMapMemory(allocator, temp_buffer_memory, (void**)&mapped);
if(result != VK_SUCCESS) {
return result;
}
mapped[0][0] = 0.0f;
mapped[0][1] = 0.0f;
mapped[1][0] = 1.0f;
mapped[1][1] = 0.0f;
mapped[2][0] = 0.0f;
mapped[2][1] = 1.0f;
vmaUnmapMemory(allocator, temp_buffer_memory);
VkCommandBuffer copy_buffer = command_begin_single(device, transfer_pool);
VkBufferCopy copy_region = {
.size = polygon_buffer_size,
.dstOffset = 0,
.srcOffset = 0,
};
vkCmdCopyBuffer(copy_buffer, temp_buffer, *polygon_buffer, 1, &copy_region);
result = command_end_single(device, copy_buffer, transfer_pool, transfer_queue);
if(result != VK_SUCCESS) {
return result;
}
vmaDestroyBuffer(allocator, temp_buffer, temp_buffer_memory);
return VK_SUCCESS;
}

@ -1,4 +1,6 @@
#include "render.h"
#include "pipeline.h"
#include "vk_mem_alloc.h"
#include "vulkan/vulkan_core.h"
const uint32_t MAX_FRAMES_IN_FLIGHT = 2;
@ -81,7 +83,6 @@ bool check_validation_layers(const char ** layers, uint32_t num_layers) {
VkResult create_instance(VkInstance* instance) {
if(check_validation_layers(validation_layers, validation_layer_count) == false) {
fprintf(stderr, "requested validation layers not supported\n");
return VK_ERROR_VALIDATION_FAILED_EXT;
}
@ -122,7 +123,6 @@ VkResult create_instance(VkInstance* instance) {
VkResult result = vkCreateInstance(&instance_info, 0, instance);
if(result != VK_SUCCESS) {
fprintf(stderr, "vkCreateInstance: %s\n", string_VkResult(result));
return result;
}
@ -159,7 +159,6 @@ VkResult create_debug_messenger(VkInstance instance, VkDebugUtilsMessengerEXT* d
VkResult result;
result = func(instance, &messenger_info, 0, debug_messenger);
if(result != VK_SUCCESS) {
fprintf(stderr, "failed to create debug messenger\n");
return result;
}
@ -646,109 +645,6 @@ VkResult create_render_pass(VkDevice device, VkSurfaceFormatKHR format, VkFormat
return VK_SUCCESS;
}
VkCommandBuffer command_begin_single(VkDevice device, VkCommandPool transfer_pool) {
VkCommandBufferAllocateInfo command_info = {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
.commandPool = transfer_pool,
.commandBufferCount = 1,
};
VkCommandBuffer command_buffer;
VkResult result = vkAllocateCommandBuffers(device, &command_info, &command_buffer);
if(result != VK_SUCCESS) {
return VK_NULL_HANDLE;
}
VkCommandBufferBeginInfo begin_info = {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
};
result = vkBeginCommandBuffer(command_buffer, &begin_info);
if(result != VK_SUCCESS) {
vkFreeCommandBuffers(device, transfer_pool, 1, &command_buffer);
return VK_NULL_HANDLE;
}
return command_buffer;
}
VkResult command_end_single(VkDevice device, VkCommandBuffer command_buffer, VkCommandPool transfer_pool, Queue transfer_queue) {
VkResult result = vkEndCommandBuffer(command_buffer);
if(result != VK_SUCCESS) {
vkFreeCommandBuffers(device, transfer_pool, 1, &command_buffer);
return result;
}
VkSubmitInfo submit_info = {
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
.commandBufferCount = 1,
.pCommandBuffers = &command_buffer,
};
result = vkQueueSubmit(transfer_queue.handle, 1, &submit_info, 0);
if(result != VK_SUCCESS) {
vkFreeCommandBuffers(device, transfer_pool, 1, &command_buffer);
return result;
}
result = vkQueueWaitIdle(transfer_queue.handle);
vkFreeCommandBuffers(device, transfer_pool, 1, &command_buffer);
return result;
}
VkResult command_transition_image_layout(VkDevice device, VkCommandPool transfer_pool, Queue transfer_queue, VkImageLayout old_layout, VkImageLayout new_layout, VkImage image, VkAccessFlags src_mask, VkAccessFlags dst_mask, VkPipelineStageFlags source, VkPipelineStageFlags dest, uint32_t source_family, uint32_t dest_family, VkImageAspectFlags aspect_flags) {
VkCommandBuffer command_buffer = command_begin_single(device, transfer_pool);
VkImageMemoryBarrier barrier = {
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.oldLayout = old_layout,
.newLayout = new_layout,
.srcQueueFamilyIndex = source_family,
.dstQueueFamilyIndex = dest_family,
.image = image,
.subresourceRange = {
.aspectMask = aspect_flags,
.levelCount = 1,
.layerCount = 1,
.baseMipLevel = 0,
.baseArrayLayer = 0,
},
.srcAccessMask = src_mask,
.dstAccessMask = dst_mask,
};
vkCmdPipelineBarrier(command_buffer, source, dest, 0, 0, 0, 0, 0, 1, &barrier);
return command_end_single(device, command_buffer, transfer_pool, transfer_queue);
}
VkResult command_copy_buffer_to_image(VkDevice device, VkCommandPool transfer_pool, Queue transfer_queue, VkExtent3D image_size, VkBuffer source, VkImage dest) {
VkCommandBuffer command_buffer = command_begin_single(device, transfer_pool);
VkBufferImageCopy region = {
.bufferOffset = 0,
.bufferRowLength = 0,
.bufferImageHeight = 0,
.imageSubresource = {
.baseArrayLayer = 0,
.layerCount = 1,
.mipLevel = 0,
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
},
.imageOffset = {
.x = 0,
.y = 0,
.z = 0,
},
.imageExtent = image_size,
};
vkCmdCopyBufferToImage(command_buffer, source, dest, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
return command_end_single(device, command_buffer, transfer_pool, transfer_queue);
}
VkResult create_swapchain_framebuffers(VkDevice device, uint32_t image_count, VkImageView* image_views, VkImageView depth_image_view, VkRenderPass render_pass, VkExtent2D extent, VkFramebuffer** framebuffers) {
*framebuffers = malloc(sizeof(VkFramebuffer)*image_count);
if(*framebuffers == 0) {
@ -1043,12 +939,110 @@ VkResult init_vulkan(GLFWwindow* window, RenderContext* context) {
return result;
}
context->current_frame = 0;
VkDescriptorSetLayoutBinding ui_descriptor_bindings[] = {
{
.binding = 0,
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
}
};
VkDescriptorSetLayoutCreateInfo ui_descriptor_info = {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
.pBindings = ui_descriptor_bindings,
.bindingCount = sizeof(ui_descriptor_bindings)/sizeof(VkDescriptorSetLayoutBinding),
};
result = vkCreateDescriptorSetLayout(context->device, &ui_descriptor_info, NULL, &context->ui_descriptor_layout);
if(result != VK_SUCCESS) {
return result;
}
VkDescriptorPoolSize pool_size = {
.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
.descriptorCount = 1,
};
VkDescriptorPoolCreateInfo ui_pool_info = {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
.pPoolSizes = &pool_size,
.poolSizeCount = 1,
.maxSets = 1,
};
result = vkCreateDescriptorPool(context->device, &ui_pool_info, NULL, &context->ui_descriptor_pool);
if(result != VK_SUCCESS) {
return result;
}
VkDescriptorSetAllocateInfo ui_descriptor_allocate_info = {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
.pSetLayouts = &context->ui_descriptor_layout,
.descriptorSetCount = 1,
.descriptorPool = context->ui_descriptor_pool,
};
result = vkAllocateDescriptorSets(context->device, &ui_descriptor_allocate_info, &context->ui_descriptor_set);
if(result != VK_SUCCESS) {
return result;
}
VkBufferCreateInfo ui_uniform_buffer_info = {
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
.size = sizeof(struct UIUniform),
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
};
VmaAllocationCreateInfo ui_uniform_memory_info = {
.usage = VMA_MEMORY_USAGE_CPU_TO_GPU,
};
result = vmaCreateBuffer(context->allocator, &ui_uniform_buffer_info, &ui_uniform_memory_info, &context->ui_descriptor_buffer, &context->ui_descriptor_memory, NULL);
if(result != VK_SUCCESS) {
return result;
}
void * mapped;
result = vmaMapMemory(context->allocator, context->ui_descriptor_memory, &mapped);
if(result != VK_SUCCESS) {
return result;
}
struct UIUniform ui_uniform = {
.size = {context->swapchain_extent.width, context->swapchain_extent.height}
};
memcpy(mapped, &ui_uniform, sizeof(ui_uniform));
vmaUnmapMemory(context->allocator, context->ui_descriptor_memory);
VkDescriptorBufferInfo ui_uniform_info = {
.offset = 0,
.range = sizeof(ui_uniform),
.buffer = context->ui_descriptor_buffer,
};
VkWriteDescriptorSet ui_uniform_write = {
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = context->ui_descriptor_set,
.dstBinding = 0,
.dstArrayElement = 0,
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
.descriptorCount = 1,
.pBufferInfo = &ui_uniform_info,
};
vkUpdateDescriptorSets(context->device, 1, &ui_uniform_write, 0, NULL);
result = create_ui_polygon_pipeline(context->device, context->render_pass, context->ui_descriptor_layout, context->allocator, context->transfer_pool, context->transfer_queue, &context->ui_polygon_buffer_memory, &context->ui_polygon_buffer, &context->ui_pipeline_polygon);
if(result != VK_SUCCESS) {
return result;
}
context->current_frame = 0;
return VK_SUCCESS;
}
VkResult draw_frame(RenderContext* context) {
VkResult draw_frame(RenderContext* context, VkBuffer ui_polygons, uint32_t ui_polygon_count) {
VkResult result;
result = vkWaitForFences(context->device, 1, &context->in_flight_fences[context->current_frame], VK_TRUE, UINT64_MAX);
@ -1081,7 +1075,7 @@ VkResult draw_frame(RenderContext* context) {
return result;
}
VkClearValue clear_color = {{{0.0f, 0.0f, 0.0f, 1.0f}}};
VkClearValue clear_values[2] = {{.color={{0.0f, 0.0f, 0.0f, 1.0f}}}, {.depthStencil={1.0f, 0.0f}}};
VkRenderPassBeginInfo render_pass_begin = {
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
@ -1089,10 +1083,19 @@ VkResult draw_frame(RenderContext* context) {
.framebuffer = context->swapchain_framebuffers[image_index],
.renderArea.offset = {0, 0},
.renderArea.extent = context->swapchain_extent,
.clearValueCount = 1,
.pClearValues = &clear_color,
.clearValueCount = 2,
.pClearValues = clear_values,
};
vkCmdBeginRenderPass(context->swapchain_command_buffers[context->current_frame], &render_pass_begin, VK_SUBPASS_CONTENTS_INLINE);
// Draw UI polygons
vkCmdBindPipeline(context->swapchain_command_buffers[context->current_frame], VK_PIPELINE_BIND_POINT_GRAPHICS, context->ui_pipeline_polygon.pipeline);
VkDeviceSize offset = 0;
vkCmdBindVertexBuffers(context->swapchain_command_buffers[context->current_frame], 0, 1, &context->ui_polygon_buffer, &offset);
VkDeviceSize offset2 = 0;
vkCmdBindVertexBuffers(context->swapchain_command_buffers[context->current_frame], 1, 1, &ui_polygons, &offset2);
vkCmdDraw(context->swapchain_command_buffers[context->current_frame], 3, ui_polygon_count, 0, 0);
vkCmdEndRenderPass(context->swapchain_command_buffers[context->current_frame]);
result = vkEndCommandBuffer(context->swapchain_command_buffers[context->current_frame]);