Browse Source

Add UBOs.

master
Amber 2 years ago
parent
commit
ea5e4c9e6f
  1. 153
      src/main.c
  2. 8
      src/vertex_simple.vert

153
src/main.c

@ -7,6 +7,10 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdbool.h> #include <stdbool.h>
#include <cglm/cglm.h> #include <cglm/cglm.h>
#include <cglm/affine.h>
#include <cglm/cam.h>
#include <time.h>
#include <cglm/util.h>
#define WIDTH 2560 #define WIDTH 2560
#define HEIGHT 1440 #define HEIGHT 1440
@ -56,6 +60,8 @@ typedef struct ApplicationState {
//describes how to access an image and allows access to it //describes how to access an image and allows access to it
VkImageView* swapchain_image_views; VkImageView* swapchain_image_views;
VkRenderPass render_pass; VkRenderPass render_pass;
VkDescriptorSetLayout descriptor_set_layout;
VkPipelineLayout pipeline_layout; VkPipelineLayout pipeline_layout;
VkPipeline graphics_pipeline; VkPipeline graphics_pipeline;
@ -76,6 +82,12 @@ typedef struct ApplicationState {
VkBuffer index_buffer; VkBuffer index_buffer;
VkDeviceMemory index_buffer_memory; 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; } ApplicationState;
typedef struct QueueFamilyIndices { typedef struct QueueFamilyIndices {
@ -101,6 +113,12 @@ const uint16_t indices[] = {
0, 1, 2, 2, 3, 0 0, 1, 2, 2, 3, 0
}; };
typedef struct UBO {
mat4 model;
mat4 view;
mat4 proj;
} UBO;
void create_window(ApplicationState* state) { void create_window(ApplicationState* state) {
glfwInit(); glfwInit();
@ -656,13 +674,33 @@ void create_render_pass(ApplicationState* state) {
render_pass_info.pDependencies = &dependency; render_pass_info.pDependencies = &dependency;
if (vkCreateRenderPass(state->device, &render_pass_info, NULL, &state->render_pass) != VK_SUCCESS) { 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); exit(1);
} }
printf("created render pass\n"); 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 //now we need to setup a graphics pipeline
//the usual stages of a pipeline are: //the usual stages of a pipeline are:
// //
@ -815,8 +853,8 @@ void create_graphics_pipeline(ApplicationState* state) {
//used for things such as uniforms //used for things such as uniforms
VkPipelineLayoutCreateInfo pipeline_layout_create_info = {0}; VkPipelineLayoutCreateInfo pipeline_layout_create_info = {0};
pipeline_layout_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pipeline_layout_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipeline_layout_create_info.setLayoutCount = 0; pipeline_layout_create_info.setLayoutCount = 1;
pipeline_layout_create_info.pSetLayouts = NULL; pipeline_layout_create_info.pSetLayouts = &state->descriptor_set_layout;
pipeline_layout_create_info.pushConstantRangeCount = 0; pipeline_layout_create_info.pushConstantRangeCount = 0;
pipeline_layout_create_info.pPushConstantRanges = NULL; pipeline_layout_create_info.pPushConstantRanges = NULL;
@ -1030,6 +1068,72 @@ void create_index_buffer(ApplicationState* state) {
vkFreeMemory(state->device, staging_buffer_memory, NULL); 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) { void create_command_buffer(ApplicationState* state) {
VkCommandBufferAllocateInfo command_buf_allocate_info = {0}; VkCommandBufferAllocateInfo command_buf_allocate_info = {0};
command_buf_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; 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"); 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}; VkCommandBufferBeginInfo begin_info = {0};
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;
@ -1100,6 +1204,8 @@ void record_command_buffer(ApplicationState* state, VkCommandBuffer command_buff
scissor.extent = state->swapchain_extent; scissor.extent = state->swapchain_extent;
vkCmdSetScissor(command_buffer, 0, 1, &scissor); 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 //vertex count, instance count, first vertex and first instance
vkCmdDrawIndexed(command_buffer, ARRSIZE(indices), 1, 0, 0, 0); vkCmdDrawIndexed(command_buffer, ARRSIZE(indices), 1, 0, 0, 0);
@ -1140,15 +1246,45 @@ void init_vulkan(ApplicationState* state) {
create_swap_chain(state); create_swap_chain(state);
create_image_views(state); create_image_views(state);
create_render_pass(state); create_render_pass(state);
create_descriptor_set_layout(state);
create_graphics_pipeline(state); create_graphics_pipeline(state);
create_framebuffers(state); create_framebuffers(state);
create_command_pool(state); create_command_pool(state);
create_vertex_buffer(state); create_vertex_buffer(state);
create_index_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_command_buffer(state);
create_sync_objects(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) { void draw_frame(ApplicationState* state, uint32_t current_frame) {
//wait for the previous frame to be rendered //wait for the previous frame to be rendered
vkWaitForFences(state->device, 1, &state->in_flight_frames[current_frame], VK_TRUE, UINT64_MAX); 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 //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); 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 //reset and setup the commands we want to run
vkResetCommandBuffer(state->command_buffer[current_frame], 0); 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 //specify what to wait for before execution can begin
VkSubmitInfo submit_info = {0}; VkSubmitInfo submit_info = {0};
@ -1214,6 +1352,9 @@ void terminate(ApplicationState* state) {
vkDestroyFence(state->device, state->in_flight_frames[i], NULL); vkDestroyFence(state->device, state->in_flight_frames[i], NULL);
vkDestroySemaphore(state->device, state->image_available_semaph[i], NULL); vkDestroySemaphore(state->device, state->image_available_semaph[i], NULL);
vkDestroySemaphore(state->device, state->render_finished_sempah[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); vkDestroyCommandPool(state->device, state->commandPool, NULL);
for (int i = 0; i < state->swapchain_image_count; i++) { 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); vkDestroyPipeline(state->device, state->graphics_pipeline, NULL);
vkDestroyRenderPass(state->device, state->render_pass, NULL); vkDestroyRenderPass(state->device, state->render_pass, NULL);
vkDestroyPipelineLayout(state->device, state->pipeline_layout, 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++) { for (int i = 0; i < state->swapchain_image_count; i++) {
vkDestroyImageView(state->device, state->swapchain_image_views[i], NULL); vkDestroyImageView(state->device, state->swapchain_image_views[i], NULL);
} }

8
src/vertex_simple.vert

@ -1,11 +1,17 @@
#version 450 #version 450
layout(binding = 0) uniform UBO {
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;
} }

Loading…
Cancel
Save