|  |  | @ -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; | 
			
		
	
		
		
			
				
					
					|  |  |  |   } |  |  |  |   } | 
			
		
	
	
		
		
			
				
					|  |  | 
 |