|
|
@ -52,18 +52,37 @@ typedef struct AllocatedBufferStruct {
|
|
|
|
VkDeviceMemory memory;
|
|
|
|
VkDeviceMemory memory;
|
|
|
|
} AllocatedBuffer;
|
|
|
|
} AllocatedBuffer;
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct MaterialStruct {
|
|
|
|
|
|
|
|
VkPipelineLayout pipeline_layout;
|
|
|
|
|
|
|
|
VkPipeline pipeline;
|
|
|
|
|
|
|
|
} Material;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct MeshStruct {
|
|
|
|
typedef struct MeshStruct {
|
|
|
|
uint32_t vertex_count;
|
|
|
|
uint32_t vertex_count;
|
|
|
|
AllocatedBuffer vertex_buffer;
|
|
|
|
AllocatedBuffer vertex_buffer;
|
|
|
|
|
|
|
|
|
|
|
|
uint32_t index_count;
|
|
|
|
uint32_t index_count;
|
|
|
|
AllocatedBuffer index_buffer;
|
|
|
|
AllocatedBuffer index_buffer;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void* data;
|
|
|
|
} Mesh;
|
|
|
|
} Mesh;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
typedef void (*MaterialBindFunc)(VkCommandBuffer, void*);
|
|
|
|
|
|
|
|
typedef void (*MeshBindFunc)(Mesh, VkCommandBuffer, void*);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct MaterialStruct {
|
|
|
|
|
|
|
|
VkPipelineLayout pipeline_layout;
|
|
|
|
|
|
|
|
VkPipeline pipeline;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
MaterialBindFunc material_bind;
|
|
|
|
|
|
|
|
MeshBindFunc mesh_bind;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void* data;
|
|
|
|
|
|
|
|
} Material;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct TextureMaterialDataStruct {
|
|
|
|
|
|
|
|
// Store pool to allocate new texture descriptor sets
|
|
|
|
|
|
|
|
} TextureMaterialData;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct TextureMeshDataStruct {
|
|
|
|
|
|
|
|
// Store allocated texture descriptor set
|
|
|
|
|
|
|
|
} TextureMeshData;
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct VulkanContextStruct {
|
|
|
|
typedef struct VulkanContextStruct {
|
|
|
|
VkInstance instance;
|
|
|
|
VkInstance instance;
|
|
|
|
VkDebugUtilsMessengerEXT debug_messenger;
|
|
|
|
VkDebugUtilsMessengerEXT debug_messenger;
|
|
|
@ -190,7 +209,7 @@ GLFWwindow* init_window(int width, int height) {
|
|
|
|
glfwSetErrorCallback(glfw_error);
|
|
|
|
glfwSetErrorCallback(glfw_error);
|
|
|
|
|
|
|
|
|
|
|
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
|
|
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
|
|
|
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
|
|
|
|
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
|
|
|
|
GLFWwindow* window = glfwCreateWindow(width, height, "Vulkan window", 0, 0);
|
|
|
|
GLFWwindow* window = glfwCreateWindow(width, height, "Vulkan window", 0, 0);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -1188,18 +1207,84 @@ VkCommandPool create_command_pool(VkDevice device, uint32_t queue_family) {
|
|
|
|
void record_command_buffer_mesh(Mesh mesh, VkCommandBuffer command_buffer) {
|
|
|
|
void record_command_buffer_mesh(Mesh mesh, VkCommandBuffer command_buffer) {
|
|
|
|
VkBuffer vertex_buffers[] = {mesh.vertex_buffer.buffer};
|
|
|
|
VkBuffer vertex_buffers[] = {mesh.vertex_buffer.buffer};
|
|
|
|
VkDeviceSize offsets[] = {0};
|
|
|
|
VkDeviceSize offsets[] = {0};
|
|
|
|
|
|
|
|
|
|
|
|
vkCmdBindVertexBuffers(command_buffer, 0, 1, vertex_buffers, offsets);
|
|
|
|
vkCmdBindVertexBuffers(command_buffer, 0, 1, vertex_buffers, offsets);
|
|
|
|
vkCmdBindIndexBuffer(command_buffer, mesh.index_buffer.buffer, 0, VK_INDEX_TYPE_UINT16);
|
|
|
|
vkCmdBindIndexBuffer(command_buffer, mesh.index_buffer.buffer, 0, VK_INDEX_TYPE_UINT16);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vkCmdDrawIndexed(command_buffer, mesh.index_count, 1, 0, 0, 0);
|
|
|
|
vkCmdDrawIndexed(command_buffer, mesh.index_count, 1, 0, 0, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
VkResult recreate_swap_chain(VulkanContext* context, VkExtent2D new_extent) {
|
|
|
|
|
|
|
|
for(uint32_t i = 0; i < context->swapchain_image_count; i++) {
|
|
|
|
|
|
|
|
vkDestroyFramebuffer(context->device, context->swapchain_framebuffers[i], 0);
|
|
|
|
|
|
|
|
vkDestroyImageView(context->device, context->swapchain_image_views[i], 0);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vkDestroySwapchainKHR(context->device, context->swapchain, 0);
|
|
|
|
|
|
|
|
free(context->swapchain_images);
|
|
|
|
|
|
|
|
free(context->swapchain_image_views);
|
|
|
|
|
|
|
|
free(context->swapchain_framebuffers);
|
|
|
|
|
|
|
|
free(context->swapchain_details.formats);
|
|
|
|
|
|
|
|
free(context->swapchain_details.present_modes);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
context->swapchain_extent = new_extent;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SwapchainDetails swapchain_details = get_swapchain_details(context->physical_device, context->surface);
|
|
|
|
|
|
|
|
if(swapchain_details.formats == 0) {
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
context->swapchain_details = swapchain_details;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
context->swapchain_format = choose_swapchain_format(context->swapchain_details);
|
|
|
|
|
|
|
|
context->swapchain_present_mode = choose_present_mode(context->swapchain_details);
|
|
|
|
|
|
|
|
context->swapchain_extent = choose_swapchain_extent(context->swapchain_details);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
VkSwapchainKHR swapchain = create_swapchain(context->device, context->swapchain_format, context->swapchain_present_mode, context->swapchain_extent, context->surface, context->swapchain_details.capabilities, context->queue_indices, context->swapchain);
|
|
|
|
|
|
|
|
if(swapchain == VK_NULL_HANDLE) {
|
|
|
|
|
|
|
|
context->swapchain = VK_NULL_HANDLE;
|
|
|
|
|
|
|
|
return VK_ERROR_INITIALIZATION_FAILED;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
context->swapchain = swapchain;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SwapchainImages swapchain_images = get_swapchain_images(context->device, context->swapchain);
|
|
|
|
|
|
|
|
if(swapchain_images.count == 0) {
|
|
|
|
|
|
|
|
return VK_ERROR_INITIALIZATION_FAILED;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
context->swapchain_images = swapchain_images.images;
|
|
|
|
|
|
|
|
context->swapchain_image_count = swapchain_images.count;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
VkImageView* image_views = create_image_views(context->device, context->swapchain_image_count, context->swapchain_images, context->swapchain_format);
|
|
|
|
|
|
|
|
if(image_views == 0) {
|
|
|
|
|
|
|
|
return VK_ERROR_INITIALIZATION_FAILED;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
context->swapchain_image_views = image_views;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
VkFramebuffer* framebuffers = create_swapchain_framebuffers(context->device, context->swapchain_image_count, context->swapchain_image_views, context->render_pass, context->swapchain_extent);
|
|
|
|
|
|
|
|
if(framebuffers == 0) {
|
|
|
|
|
|
|
|
return VK_ERROR_INITIALIZATION_FAILED;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
context->swapchain_framebuffers = framebuffers;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return VK_SUCCESS;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void record_command_buffer_material(Material material, uint32_t mesh_count, Mesh* meshes, VkDescriptorSet scene_ubo_descriptor, VkCommandBuffer command_buffer) {
|
|
|
|
void record_command_buffer_material(Material material, uint32_t mesh_count, Mesh* meshes, VkDescriptorSet scene_ubo_descriptor, VkCommandBuffer command_buffer) {
|
|
|
|
vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, material.pipeline);
|
|
|
|
vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, material.pipeline);
|
|
|
|
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, material.pipeline_layout, 0, 1, &scene_ubo_descriptor, 0, 0);
|
|
|
|
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, material.pipeline_layout, 0, 1, &scene_ubo_descriptor, 0, 0);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(material.material_bind != 0) {
|
|
|
|
|
|
|
|
material.material_bind(command_buffer, material.data);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for(uint32_t i = 0; i < mesh_count; i++) {
|
|
|
|
for(uint32_t i = 0; i < mesh_count; i++) {
|
|
|
|
|
|
|
|
if(material.mesh_bind != 0) {
|
|
|
|
|
|
|
|
material.mesh_bind(meshes[i], command_buffer, material.data);
|
|
|
|
|
|
|
|
}
|
|
|
|
record_command_buffer_mesh(meshes[i], command_buffer);
|
|
|
|
record_command_buffer_mesh(meshes[i], command_buffer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -1341,7 +1426,21 @@ Mesh load_mesh(VkPhysicalDevice physical_device, VkDevice device, struct Vertex*
|
|
|
|
return mesh;
|
|
|
|
return mesh;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Material create_material(VkDevice device, VkExtent2D extent, VkRenderPass render_pass, uint32_t shader_stage_count, VkPipelineShaderStageCreateInfo* shader_stages, VkDescriptorSetLayout scene_ubo_layout, uint32_t set_count, VkDescriptorSetLayout* set_layouts, uint32_t pcr_count, VkPushConstantRange* pcrs) {
|
|
|
|
Material create_material(
|
|
|
|
|
|
|
|
VkDevice device,
|
|
|
|
|
|
|
|
VkExtent2D extent,
|
|
|
|
|
|
|
|
VkRenderPass render_pass,
|
|
|
|
|
|
|
|
uint32_t shader_stage_count,
|
|
|
|
|
|
|
|
VkPipelineShaderStageCreateInfo* shader_stages,
|
|
|
|
|
|
|
|
VkDescriptorSetLayout scene_ubo_layout,
|
|
|
|
|
|
|
|
uint32_t set_count,
|
|
|
|
|
|
|
|
VkDescriptorSetLayout* set_layouts,
|
|
|
|
|
|
|
|
uint32_t pcr_count,
|
|
|
|
|
|
|
|
VkPushConstantRange* pcrs,
|
|
|
|
|
|
|
|
MaterialBindFunc material_bind,
|
|
|
|
|
|
|
|
MeshBindFunc mesh_bind,
|
|
|
|
|
|
|
|
void* data
|
|
|
|
|
|
|
|
) {
|
|
|
|
Material zero_material = {
|
|
|
|
Material zero_material = {
|
|
|
|
.pipeline = VK_NULL_HANDLE,
|
|
|
|
.pipeline = VK_NULL_HANDLE,
|
|
|
|
};
|
|
|
|
};
|
|
|
@ -1372,8 +1471,6 @@ Material create_material(VkDevice device, VkExtent2D extent, VkRenderPass render
|
|
|
|
free(all_pcrs);
|
|
|
|
free(all_pcrs);
|
|
|
|
return zero_material;
|
|
|
|
return zero_material;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
free(all_layouts);
|
|
|
|
|
|
|
|
free(all_pcrs);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
VkPipeline pipeline = create_graphics_pipeline(device, extent, pipeline_layout, render_pass, shader_stage_count, shader_stages);
|
|
|
|
VkPipeline pipeline = create_graphics_pipeline(device, extent, pipeline_layout, render_pass, shader_stage_count, shader_stages);
|
|
|
|
if(pipeline == VK_NULL_HANDLE) {
|
|
|
|
if(pipeline == VK_NULL_HANDLE) {
|
|
|
@ -1383,6 +1480,9 @@ Material create_material(VkDevice device, VkExtent2D extent, VkRenderPass render
|
|
|
|
Material material = {
|
|
|
|
Material material = {
|
|
|
|
.pipeline_layout = pipeline_layout,
|
|
|
|
.pipeline_layout = pipeline_layout,
|
|
|
|
.pipeline = pipeline,
|
|
|
|
.pipeline = pipeline,
|
|
|
|
|
|
|
|
.material_bind = material_bind,
|
|
|
|
|
|
|
|
.mesh_bind = mesh_bind,
|
|
|
|
|
|
|
|
.data = data,
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
return material;
|
|
|
|
return material;
|
|
|
@ -1637,7 +1737,7 @@ VulkanContext* init_vulkan(GLFWwindow* window, uint32_t max_frames_in_flight) {
|
|
|
|
shader_stages[1].module = frag_shader;
|
|
|
|
shader_stages[1].module = frag_shader;
|
|
|
|
shader_stages[1].pName = "main";
|
|
|
|
shader_stages[1].pName = "main";
|
|
|
|
|
|
|
|
|
|
|
|
Material simple_mesh_material = create_material(context->device, context->swapchain_extent, context->render_pass, 2, shader_stages, context->scene_ubo_layout, 0, 0, 0, 0);
|
|
|
|
Material simple_mesh_material = create_material(context->device, context->swapchain_extent, context->render_pass, 2, shader_stages, context->scene_ubo_layout, 0, 0, 0, 0, 0, 0, 0);
|
|
|
|
if(simple_mesh_material.pipeline == VK_NULL_HANDLE) {
|
|
|
|
if(simple_mesh_material.pipeline == VK_NULL_HANDLE) {
|
|
|
|
fprintf(stderr, "failed to create simple mesh material\n");
|
|
|
|
fprintf(stderr, "failed to create simple mesh material\n");
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
@ -1666,11 +1766,18 @@ struct {
|
|
|
|
bool down: 1;
|
|
|
|
bool down: 1;
|
|
|
|
bool turn_left: 1;
|
|
|
|
bool turn_left: 1;
|
|
|
|
bool turn_right: 1;
|
|
|
|
bool turn_right: 1;
|
|
|
|
|
|
|
|
bool turn_up: 1;
|
|
|
|
|
|
|
|
bool turn_down: 1;
|
|
|
|
} key_flags = {
|
|
|
|
} key_flags = {
|
|
|
|
.forward = false,
|
|
|
|
.forward = false,
|
|
|
|
.backward = false,
|
|
|
|
.backward = false,
|
|
|
|
.left = false,
|
|
|
|
.left = false,
|
|
|
|
.right = false,
|
|
|
|
.right = false,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.turn_left = false,
|
|
|
|
|
|
|
|
.turn_right = false,
|
|
|
|
|
|
|
|
.turn_up = false,
|
|
|
|
|
|
|
|
.turn_down = false,
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) {
|
|
|
|
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) {
|
|
|
@ -1742,6 +1849,22 @@ void key_callback(GLFWwindow* window, int key, int scancode, int action, int mod
|
|
|
|
key_flags.turn_left = false;
|
|
|
|
key_flags.turn_left = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case GLFW_KEY_UP:
|
|
|
|
|
|
|
|
if(action == GLFW_PRESS) {
|
|
|
|
|
|
|
|
key_flags.turn_up = true;
|
|
|
|
|
|
|
|
} else if(action == GLFW_RELEASE) {
|
|
|
|
|
|
|
|
key_flags.turn_up = false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case GLFW_KEY_DOWN:
|
|
|
|
|
|
|
|
if(action == GLFW_PRESS) {
|
|
|
|
|
|
|
|
key_flags.turn_down = true;
|
|
|
|
|
|
|
|
} else if(action == GLFW_RELEASE) {
|
|
|
|
|
|
|
|
key_flags.turn_down = false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -1801,7 +1924,7 @@ VkResult update_scene_ubo(void** buffers, uint32_t frame_index, vec3 world_posit
|
|
|
|
return VK_SUCCESS;
|
|
|
|
return VK_SUCCESS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VkResult draw_frame(VulkanContext* context) {
|
|
|
|
VkResult draw_frame(GLFWwindow* window, VulkanContext* context) {
|
|
|
|
update_scene_ubo(context->scene_ubo_ptrs, context->current_frame, world_position, &rotation, (float)context->swapchain_extent.width/(float)context->swapchain_extent.height, 0.01);
|
|
|
|
update_scene_ubo(context->scene_ubo_ptrs, context->current_frame, world_position, &rotation, (float)context->swapchain_extent.width/(float)context->swapchain_extent.height, 0.01);
|
|
|
|
|
|
|
|
|
|
|
|
VkResult result;
|
|
|
|
VkResult result;
|
|
|
@ -1810,13 +1933,19 @@ VkResult draw_frame(VulkanContext* context) {
|
|
|
|
return result;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
result = vkResetFences(context->device, 1, &context->in_flight_fences[context->current_frame]);
|
|
|
|
uint32_t image_index;
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
result = vkAcquireNextImageKHR(context->device, context->swapchain, UINT64_MAX, context->image_available_semaphores[context->current_frame], VK_NULL_HANDLE, &image_index);
|
|
|
|
|
|
|
|
if(result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) {
|
|
|
|
|
|
|
|
int width, height;
|
|
|
|
|
|
|
|
glfwGetWindowSize(window, &width, &height);
|
|
|
|
|
|
|
|
VkExtent2D window_extent = {width, height};
|
|
|
|
|
|
|
|
recreate_swap_chain(context, window_extent);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
} else if(result != VK_SUCCESS) {
|
|
|
|
return result;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint32_t image_index;
|
|
|
|
result = vkResetFences(context->device, 1, &context->in_flight_fences[context->current_frame]);
|
|
|
|
result = vkAcquireNextImageKHR(context->device, context->swapchain, UINT64_MAX, context->image_available_semaphores[context->current_frame], VK_NULL_HANDLE, &image_index);
|
|
|
|
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
return result;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -1866,7 +1995,7 @@ void main_loop(GLFWwindow* window, VulkanContext* context) {
|
|
|
|
while(!glfwWindowShouldClose(window)) {
|
|
|
|
while(!glfwWindowShouldClose(window)) {
|
|
|
|
glfwPollEvents();
|
|
|
|
glfwPollEvents();
|
|
|
|
|
|
|
|
|
|
|
|
draw_frame(context);
|
|
|
|
draw_frame(window, context);
|
|
|
|
context->current_frame += 1;
|
|
|
|
context->current_frame += 1;
|
|
|
|
if(context->current_frame >= context->max_frames_in_flight) {
|
|
|
|
if(context->current_frame >= context->max_frames_in_flight) {
|
|
|
|
context->current_frame = 0;
|
|
|
|
context->current_frame = 0;
|
|
|
|