Added UBO for shader matrices

main
noah metz 2024-01-08 12:42:59 -07:00
parent 960f0b94ea
commit c74daec6bd
2 changed files with 199 additions and 8 deletions

@ -1,11 +1,17 @@
#version 450 #version 450
layout(binding = 0) uniform UniformBufferObject {
mat4 model;
mat4 view;
mat4 proj;
} ubo;
layout(location = 0) in vec2 inPosition; layout(location = 0) in vec2 inPosition;
layout(location = 1) in vec3 inColor; layout(location = 1) in vec3 inColor;
layout(location = 0) out vec3 fragColor; layout(location = 0) out vec3 fragColor;
void main() { void main() {
gl_Position = vec4(inPosition, 0.0, 1.0); gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition, 0.0, 1.0);
fragColor = inColor; fragColor = inColor;
} }

@ -7,8 +7,8 @@
#define GLM_FORCE_RADIANS #define GLM_FORCE_RADIANS
#define GLM_FORCE_DEPTH_ZERO_TO_ONE #define GLM_FORCE_DEPTH_ZERO_TO_ONE
#include <cglm/vec3.h> #include <cglm/types.h>
#include <cglm/vec2.h> #include <cglm/mat4.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
@ -80,11 +80,17 @@ typedef struct VulkanContextStruct {
VkSemaphore* render_finished_semaphores; VkSemaphore* render_finished_semaphores;
VkFence* in_flight_fences; VkFence* in_flight_fences;
AllocatedBuffer* uniform_buffers;
void** uniform_buffer_ptrs;
VkDescriptorPool descriptor_pool;
VkDescriptorSet* descriptor_sets;
VkRenderPass render_pass; VkRenderPass render_pass;
VkCommandPool graphics_command_pool; VkCommandPool graphics_command_pool;
VkCommandPool transfer_command_pool; VkCommandPool transfer_command_pool;
VkDescriptorSetLayout triangle_descriptor_set;
VkPipelineLayout triangle_pipeline_layout; VkPipelineLayout triangle_pipeline_layout;
VkPipeline triangle_pipeline; VkPipeline triangle_pipeline;
AllocatedBuffer triangle_vertex_buffer; AllocatedBuffer triangle_vertex_buffer;
@ -98,6 +104,12 @@ struct Vertex{
vec3 color; vec3 color;
}; };
struct ShaderUBO {
mat4 model;
mat4 view;
mat4 proj;
};
const struct Vertex vertices[] = { const struct Vertex vertices[] = {
{.pos = {-0.5f, -0.5f}, .color = {1.0f, 0.0f, 0.0f}}, {.pos = {-0.5f, -0.5f}, .color = {1.0f, 0.0f, 0.0f}},
{.pos = { 0.5f, -0.5f}, .color = {0.0f, 1.0f, 0.0f}}, {.pos = { 0.5f, -0.5f}, .color = {0.0f, 1.0f, 0.0f}},
@ -199,7 +211,7 @@ bool check_validation_layers(const char ** layers, uint32_t num_layers) {
free(available_layers); free(available_layers);
return true; return true;
}; }
static VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback( static VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback(
VkDebugUtilsMessageSeverityFlagBitsEXT severity, VkDebugUtilsMessageSeverityFlagBitsEXT severity,
@ -214,7 +226,81 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback(
fprintf(stderr, "Validation layer: %s\n", callback_data->pMessage); fprintf(stderr, "Validation layer: %s\n", callback_data->pMessage);
return VK_FALSE; return VK_FALSE;
}; }
VkDescriptorSet* create_descriptor_sets(VkDevice device, VkDescriptorSetLayout layout, VkDescriptorPool pool, AllocatedBuffer* uniform_buffers, uint32_t count) {
VkDescriptorSetLayout* layouts = malloc(sizeof(VkDescriptorSetLayout)*count);
if(layouts == 0) {
return 0;
}
VkDescriptorSet* sets = malloc(sizeof(VkDescriptorSet)*count);
if(sets == 0) {
free(layouts);
return 0;
}
for(uint32_t i = 0; i < count; i++) {
layouts[i] = layout;
}
VkDescriptorSetAllocateInfo alloc_info = {};
alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
alloc_info.descriptorPool = pool;
alloc_info.descriptorSetCount = count;
alloc_info.pSetLayouts = layouts;
VkResult result = vkAllocateDescriptorSets(device, &alloc_info, sets);
free(layouts);
if(result != VK_SUCCESS) {
free(sets);
return 0;
}
for(uint32_t i = 0; i < count; i++) {
VkDescriptorBufferInfo buffer_info = {};
buffer_info.buffer = uniform_buffers[i].buffer;
buffer_info.offset = 0;
buffer_info.range = sizeof(struct ShaderUBO);
VkWriteDescriptorSet descriptor_write = {};
descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptor_write.dstSet = sets[i];
descriptor_write.dstBinding = 0;
descriptor_write.dstArrayElement = 0;
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
descriptor_write.descriptorCount = 1;
descriptor_write.pBufferInfo = &buffer_info;
descriptor_write.pImageInfo = 0;
descriptor_write.pTexelBufferView = 0;
vkUpdateDescriptorSets(device, 1, &descriptor_write, 0, 0);
}
return sets;
}
VkDescriptorSetLayout create_descriptor_set_layout(VkDevice device) {
VkDescriptorSetLayoutBinding layout_binding = {};
layout_binding.binding = 0;
layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
layout_binding.descriptorCount = 1;
layout_binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
layout_binding.pImmutableSamplers = 0;
VkDescriptorSetLayoutCreateInfo layout_info = {};
layout_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
layout_info.bindingCount = 1;
layout_info.pBindings = &layout_binding;
VkDescriptorSetLayout layout;
VkResult result = vkCreateDescriptorSetLayout(device, &layout_info, 0, &layout);
if(result != VK_SUCCESS) {
return VK_NULL_HANDLE;
}
return layout;
}
VkSurfaceKHR create_surface_khr(VkInstance instance, GLFWwindow* window) { VkSurfaceKHR create_surface_khr(VkInstance instance, GLFWwindow* window) {
VkSurfaceKHR surface; VkSurfaceKHR surface;
@ -364,6 +450,26 @@ VkDebugUtilsMessengerEXT create_debug_messenger(VkInstance instance) {
return debug_messenger; return debug_messenger;
} }
VkDescriptorPool create_descriptor_pool(VkDevice device, uint32_t size) {
VkDescriptorPoolSize pool_size = {};
pool_size.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
pool_size.descriptorCount = size;
VkDescriptorPoolCreateInfo pool_info = {};
pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
pool_info.poolSizeCount = 1;
pool_info.pPoolSizes = &pool_size;
pool_info.maxSets = size;
VkDescriptorPool pool;
VkResult result = vkCreateDescriptorPool(device, &pool_info, 0, &pool);
if(result != VK_SUCCESS) {
return VK_NULL_HANDLE;
}
return pool;
}
VkInstance create_instance() { VkInstance create_instance() {
VkInstance instance; VkInstance instance;
@ -849,6 +955,27 @@ void deallocate_buffer(VkDevice device, AllocatedBuffer buffer) {
vkFreeMemory(device, buffer.memory, 0); vkFreeMemory(device, buffer.memory, 0);
}; };
AllocatedBuffer* allocate_buffers(VkPhysicalDevice physical_device, VkDevice device, VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, uint32_t count) {
AllocatedBuffer* buffers = malloc(sizeof(AllocatedBuffer)*count);
if(buffers == 0) {
return 0;
}
for(uint32_t i = 0; i < count; i++) {
buffers[i] = allocate_buffer(physical_device, device, size, usage, properties);
if(buffers[i].memory == VK_NULL_HANDLE) {
for(uint32_t j = 0; j < i; j++) {
deallocate_buffer(device, buffers[i]);
}
free(buffers);
return 0;
}
}
return buffers;
}
VkResult command_copy_buffers(VkDevice device, VkCommandPool transfer_pool, VkQueue transfer_queue, VkBuffer source, VkBuffer dest, VkDeviceSize size) { VkResult command_copy_buffers(VkDevice device, VkCommandPool transfer_pool, VkQueue transfer_queue, VkBuffer source, VkBuffer dest, VkDeviceSize size) {
VkCommandBufferAllocateInfo command_info = {}; VkCommandBufferAllocateInfo command_info = {};
command_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; command_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
@ -1087,7 +1214,7 @@ VkCommandPool create_command_pool(VkDevice device, uint32_t queue_family) {
return command_pool; return command_pool;
} }
VkResult record_command_buffer_triangle(VkCommandBuffer command_buffer, uint32_t image_index, VkRenderPass render_pass, VkFramebuffer* framebuffers, VkExtent2D extent, VkPipeline graphics_pipeline, VkBuffer vertex_buffer, VkBuffer index_buffer, uint32_t num_vertices) { VkResult record_command_buffer_triangle(VkCommandBuffer command_buffer, uint32_t image_index, VkRenderPass render_pass, VkFramebuffer* framebuffers, VkExtent2D extent, VkPipeline graphics_pipeline, VkPipelineLayout pipeline_layout, VkDescriptorSet descriptor_set, VkBuffer vertex_buffer, VkBuffer index_buffer, uint32_t num_vertices) {
VkCommandBufferBeginInfo begin_info = {}; VkCommandBufferBeginInfo begin_info = {};
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
begin_info.flags = 0; begin_info.flags = 0;
@ -1132,6 +1259,7 @@ VkResult record_command_buffer_triangle(VkCommandBuffer command_buffer, uint32_t
scissor.extent = extent; scissor.extent = extent;
vkCmdSetScissor(command_buffer, 0, 1, &scissor); vkCmdSetScissor(command_buffer, 0, 1, &scissor);
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &descriptor_set, 0, 0);
vkCmdDrawIndexed(command_buffer, num_vertices, 1, 0, 0, 0); vkCmdDrawIndexed(command_buffer, num_vertices, 1, 0, 0, 0);
vkCmdEndRenderPass(command_buffer); vkCmdEndRenderPass(command_buffer);
@ -1355,7 +1483,51 @@ VulkanContext* init_vulkan(GLFWwindow* window, uint32_t max_frames_in_flight) {
context->in_flight_fences = if_fences; context->in_flight_fences = if_fences;
} }
VkPipelineLayout triangle_pipeline_layout = create_pipeline_layout(device, 0, 0, 0, 0); AllocatedBuffer* uniform_buffers = allocate_buffers(context->physical_device, context->device, sizeof(struct ShaderUBO), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, max_frames_in_flight);
if(uniform_buffers == 0) {
fprintf(stderr, "failed to create vulkan uniform buffers\n");
return 0;
} else {
context->uniform_buffers = uniform_buffers;
context->uniform_buffer_ptrs = malloc(sizeof(void*)*max_frames_in_flight);
if(context->uniform_buffer_ptrs == 0) {
fprintf(stderr, "failed to allocate cpu pointers for uniform buffers\n");
return 0;
}
for(uint32_t i = 0; i < max_frames_in_flight; i++) {
VkResult result = vkMapMemory(context->device, context->uniform_buffers[i].memory, 0, sizeof(struct ShaderUBO), 0, &context->uniform_buffer_ptrs[i]);
if(result != VK_SUCCESS) {
fprintf(stderr, "failed to map cpu pointer for uniform buffer\n");
return 0;
}
}
}
VkDescriptorPool descriptor_pool = create_descriptor_pool(context->device, max_frames_in_flight);
if(descriptor_pool == VK_NULL_HANDLE) {
fprintf(stderr, "failed to create vulkan descriptor pool\n");
return 0;
} else {
context->descriptor_pool = descriptor_pool;
}
VkDescriptorSetLayout triangle_descriptor_set = create_descriptor_set_layout(device);
if(triangle_descriptor_set == VK_NULL_HANDLE) {
fprintf(stderr, "failed to create vulkan descriptor set layout\n");
return 0;
} else {
context->triangle_descriptor_set = triangle_descriptor_set;
}
VkDescriptorSet* descriptor_sets = create_descriptor_sets(context->device, context->triangle_descriptor_set, context->descriptor_pool, context->uniform_buffers, max_frames_in_flight);
if(descriptor_sets == 0) {
fprintf(stderr, "failed to create vulkan descriptor sets\n");
return 0;
} else {
context->descriptor_sets = descriptor_sets;
}
VkPipelineLayout triangle_pipeline_layout = create_pipeline_layout(device, 1, &context->triangle_descriptor_set, 0, 0);
if(triangle_pipeline_layout == VK_NULL_HANDLE) { if(triangle_pipeline_layout == VK_NULL_HANDLE) {
fprintf(stderr, "failed to create vulkan pipeline layout\n"); fprintf(stderr, "failed to create vulkan pipeline layout\n");
return 0; return 0;
@ -1388,7 +1560,20 @@ VulkanContext* init_vulkan(GLFWwindow* window, uint32_t max_frames_in_flight) {
return context; return context;
} }
VkResult update_ubo(void** buffers, uint32_t frame_index) {
struct ShaderUBO ubo = {};
glm_mat4_identity(ubo.proj);
glm_mat4_identity(ubo.view);
glm_mat4_identity(ubo.model);
memcpy(buffers[frame_index], (void*)&ubo, sizeof(ubo));
return VK_SUCCESS;
}
VkResult draw_frame(VulkanContext* context) { VkResult draw_frame(VulkanContext* context) {
update_ubo(context->uniform_buffer_ptrs, context->current_frame);
VkResult result; VkResult result;
result = vkWaitForFences(context->device, 1, &context->in_flight_fences[context->current_frame], VK_TRUE, UINT64_MAX); result = vkWaitForFences(context->device, 1, &context->in_flight_fences[context->current_frame], VK_TRUE, UINT64_MAX);
if(result != VK_SUCCESS) { if(result != VK_SUCCESS) {
@ -1411,7 +1596,7 @@ VkResult draw_frame(VulkanContext* context) {
return result; return result;
} }
result = record_command_buffer_triangle(context->swapchain_command_buffers[context->current_frame], image_index, context->render_pass, context->swapchain_framebuffers, context->swapchain_extent, context->triangle_pipeline, context->triangle_vertex_buffer.buffer, context->triangle_index_buffer.buffer, 6); result = record_command_buffer_triangle(context->swapchain_command_buffers[context->current_frame], image_index, context->render_pass, context->swapchain_framebuffers, context->swapchain_extent, context->triangle_pipeline, context->triangle_pipeline_layout, context->descriptor_sets[context->current_frame], context->triangle_vertex_buffer.buffer, context->triangle_index_buffer.buffer, 6);
if(result != VK_SUCCESS) { if(result != VK_SUCCESS) {
return result; return result;
} }