diff --git a/src/main.c b/src/main.c index d46cea0..2c7ebaa 100644 --- a/src/main.c +++ b/src/main.c @@ -7,6 +7,10 @@ #include #include #include +#include +#include +#include +#include #define WIDTH 2560 #define HEIGHT 1440 @@ -56,6 +60,8 @@ typedef struct ApplicationState { //describes how to access an image and allows access to it VkImageView* swapchain_image_views; VkRenderPass render_pass; + + VkDescriptorSetLayout descriptor_set_layout; VkPipelineLayout pipeline_layout; VkPipeline graphics_pipeline; @@ -76,6 +82,12 @@ typedef struct ApplicationState { VkBuffer index_buffer; VkDeviceMemory index_buffer_memory; + + VkBuffer uniform_buffers[MAX_FRAMES_IN_FLIGHT]; + VkDeviceMemory uniform_buffer_memory[MAX_FRAMES_IN_FLIGHT]; + + VkDescriptorPool descriptor_pool; + VkDescriptorSet descriptor_sets[2]; } ApplicationState; typedef struct QueueFamilyIndices { @@ -101,6 +113,12 @@ const uint16_t indices[] = { 0, 1, 2, 2, 3, 0 }; +typedef struct UBO { + mat4 model; + mat4 view; + mat4 proj; +} UBO; + void create_window(ApplicationState* state) { glfwInit(); @@ -656,13 +674,33 @@ void create_render_pass(ApplicationState* state) { render_pass_info.pDependencies = &dependency; if (vkCreateRenderPass(state->device, &render_pass_info, NULL, &state->render_pass) != VK_SUCCESS) { - printf("failed to create render pass"); + printf("failed to create render pass\n"); exit(1); } printf("created render pass\n"); } +//Descriptor set layouts specify the types of resources that are going to be accessed by the pipeline +void create_descriptor_set_layout(ApplicationState* state) { + VkDescriptorSetLayoutBinding ubo_layout_binding = {0}; + ubo_layout_binding.binding = 0; + ubo_layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + ubo_layout_binding.descriptorCount = 1; + ubo_layout_binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + + VkDescriptorSetLayoutCreateInfo layout_info = {0}; + layout_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + layout_info.bindingCount = 1; + layout_info.pBindings = &ubo_layout_binding; + + if (vkCreateDescriptorSetLayout(state->device, &layout_info, NULL, &state->descriptor_set_layout)) { + printf("could not create descriptor set layout\n"); + exit(1); + } + printf("created descriptor set layout\n"); +} + //now we need to setup a graphics pipeline //the usual stages of a pipeline are: // @@ -815,8 +853,8 @@ void create_graphics_pipeline(ApplicationState* state) { //used for things such as uniforms VkPipelineLayoutCreateInfo pipeline_layout_create_info = {0}; pipeline_layout_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - pipeline_layout_create_info.setLayoutCount = 0; - pipeline_layout_create_info.pSetLayouts = NULL; + pipeline_layout_create_info.setLayoutCount = 1; + pipeline_layout_create_info.pSetLayouts = &state->descriptor_set_layout; pipeline_layout_create_info.pushConstantRangeCount = 0; pipeline_layout_create_info.pPushConstantRanges = NULL; @@ -1030,6 +1068,72 @@ void create_index_buffer(ApplicationState* state) { vkFreeMemory(state->device, staging_buffer_memory, NULL); } +void create_uniform_buffers(ApplicationState* state) { + VkDeviceSize buffer_size = sizeof(UBO); + + for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + create_buffer(state, buffer_size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + &state->uniform_buffers[i], &state->uniform_buffer_memory[i]); + } +} + +void create_descriptor_pool(ApplicationState* state) { + VkDescriptorPoolSize pool_size = {0}; + pool_size.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + pool_size.descriptorCount = MAX_FRAMES_IN_FLIGHT; + + VkDescriptorPoolCreateInfo pool_info = {0}; + pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + pool_info.poolSizeCount = 1; + pool_info.pPoolSizes = &pool_size; + pool_info.maxSets = MAX_FRAMES_IN_FLIGHT; + + if (vkCreateDescriptorPool(state->device, &pool_info, NULL, &state->descriptor_pool) != VK_SUCCESS) { + printf("failed to create descriptor pool\n"); + exit(1); + } + + printf("created descriptor pool\n"); +} + +void create_descriptor_sets(ApplicationState* state) { + VkDescriptorSetLayout layouts[2] = {state->descriptor_set_layout, state->descriptor_set_layout}; + VkDescriptorSetAllocateInfo alloc_info = {0}; + alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + alloc_info.descriptorPool = state->descriptor_pool; + alloc_info.descriptorSetCount = MAX_FRAMES_IN_FLIGHT; + alloc_info.pSetLayouts = layouts; + + if (vkAllocateDescriptorSets(state->device, &alloc_info, state->descriptor_sets) != VK_SUCCESS) { + printf("failed to allocate descriptor sets\n"); + exit(1); + } + + printf("allocated descriptor sets\n"); + + for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { + VkDescriptorBufferInfo buffer_info = {0}; + buffer_info.buffer = state->uniform_buffers[i]; + buffer_info.offset = 0; + buffer_info.range = sizeof(UBO); + + VkWriteDescriptorSet descriptor_write = {0}; + descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptor_write.dstSet = state->descriptor_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 = NULL; + descriptor_write.pTexelBufferView = NULL; + + vkUpdateDescriptorSets(state->device, 1, &descriptor_write, 0, NULL); + } + + printf("created descriptor sets\n"); +} + void create_command_buffer(ApplicationState* state) { VkCommandBufferAllocateInfo command_buf_allocate_info = {0}; command_buf_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; @@ -1046,7 +1150,7 @@ void create_command_buffer(ApplicationState* state) { printf("created command buffer\n"); } -void record_command_buffer(ApplicationState* state, VkCommandBuffer command_buffer, uint32_t image_index) { +void record_command_buffer(ApplicationState* state, VkCommandBuffer command_buffer, uint32_t image_index, uint32_t current_frame) { VkCommandBufferBeginInfo begin_info = {0}; begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; begin_info.flags = 0; @@ -1100,6 +1204,8 @@ void record_command_buffer(ApplicationState* state, VkCommandBuffer command_buff scissor.extent = state->swapchain_extent; vkCmdSetScissor(command_buffer, 0, 1, &scissor); + vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, state->pipeline_layout, 0, 1, &state->descriptor_sets[current_frame], 0, NULL); + //vertex count, instance count, first vertex and first instance vkCmdDrawIndexed(command_buffer, ARRSIZE(indices), 1, 0, 0, 0); @@ -1140,15 +1246,45 @@ void init_vulkan(ApplicationState* state) { create_swap_chain(state); create_image_views(state); create_render_pass(state); + create_descriptor_set_layout(state); create_graphics_pipeline(state); create_framebuffers(state); create_command_pool(state); create_vertex_buffer(state); create_index_buffer(state); + create_uniform_buffers(state); + create_descriptor_pool(state); + printf("creating descriptor sets\n"); + create_descriptor_sets(state); create_command_buffer(state); create_sync_objects(state); } +void update_uniform_buffer(ApplicationState* state, uint32_t current_frame) { + uint64_t time = clock() / (CLOCKS_PER_SEC / 1000); + + UBO ubo = {0}; + glm_mat4_identity(ubo.model); + glm_mat4_identity(ubo.view); + glm_mat4_identity(ubo.proj); + + glm_mat4_identity(ubo.model); + vec3 axis = {0.0f, 1.0f, 1.0f}; + glm_rotate(ubo.model, time * glm_rad(90.0f), axis); + + vec3 eye = {2.0f, 2.0f, 2.0f}; + vec3 center = {0.0f, 0.0f, 0.0f}; + vec3 up = {0.0f, 0.0f, 1.0f}; + glm_lookat(eye, center, up, ubo.view); + + glm_perspective(glm_rad(45.0f), state->swapchain_extent.width / (float)state->swapchain_extent.height, 0.1f, 10.f, ubo.proj); + + void* data; + vkMapMemory(state->device, state->uniform_buffer_memory[current_frame], 0, sizeof(UBO), 0, &data); + memcpy(data, &ubo, sizeof(UBO)); + vkUnmapMemory(state->device, state->uniform_buffer_memory[current_frame]); +} + void draw_frame(ApplicationState* state, uint32_t current_frame) { //wait for the previous frame to be rendered vkWaitForFences(state->device, 1, &state->in_flight_frames[current_frame], VK_TRUE, UINT64_MAX); @@ -1158,9 +1294,11 @@ void draw_frame(ApplicationState* state, uint32_t current_frame) { //get images from the swapchain and signal when the image is ready vkAcquireNextImageKHR(state->device, state->swapchain, UINT64_MAX, state->image_available_semaph[current_frame], VK_NULL_HANDLE, &image_index); + update_uniform_buffer(state, current_frame); + //reset and setup the commands we want to run vkResetCommandBuffer(state->command_buffer[current_frame], 0); - record_command_buffer(state, state->command_buffer[current_frame], image_index); + record_command_buffer(state, state->command_buffer[current_frame], image_index, current_frame); //specify what to wait for before execution can begin VkSubmitInfo submit_info = {0}; @@ -1214,6 +1352,9 @@ void terminate(ApplicationState* state) { vkDestroyFence(state->device, state->in_flight_frames[i], NULL); vkDestroySemaphore(state->device, state->image_available_semaph[i], NULL); vkDestroySemaphore(state->device, state->render_finished_sempah[i], NULL); + + vkDestroyBuffer(state->device, state->uniform_buffers[i], NULL); + vkFreeMemory(state->device, state->uniform_buffer_memory[i], NULL); } vkDestroyCommandPool(state->device, state->commandPool, NULL); for (int i = 0; i < state->swapchain_image_count; i++) { @@ -1222,6 +1363,8 @@ void terminate(ApplicationState* state) { vkDestroyPipeline(state->device, state->graphics_pipeline, NULL); vkDestroyRenderPass(state->device, state->render_pass, NULL); vkDestroyPipelineLayout(state->device, state->pipeline_layout, NULL); + vkDestroyDescriptorPool(state->device, state->descriptor_pool, NULL); + vkDestroyDescriptorSetLayout(state->device, state->descriptor_set_layout, NULL); for (int i = 0; i < state->swapchain_image_count; i++) { vkDestroyImageView(state->device, state->swapchain_image_views[i], NULL); } diff --git a/src/vertex_simple.vert b/src/vertex_simple.vert index 2f02ab1..4aa8ad1 100644 --- a/src/vertex_simple.vert +++ b/src/vertex_simple.vert @@ -1,11 +1,17 @@ #version 450 -layout (location = 0) in vec2 inPosition; -layout (location = 1) in vec3 inColor; +layout(binding = 0) uniform UBO { + mat4 model; + mat4 view; + mat4 proj; +} ubo; + +layout(location = 0) in vec2 inPosition; +layout(location = 1) in vec3 inColor; layout(location = 0) out vec3 fragColor; 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; }