|  |  |  | @ -316,6 +316,26 @@ void object_update_mappings(Material material, Object object, uint32_t frame_num | 
		
	
		
			
				|  |  |  |  |   map_iterator_free(mapping_iterator); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | VkSemaphore* create_semaphores(VkDevice device, VkSemaphoreCreateFlags flags, uint32_t count) { | 
		
	
		
			
				|  |  |  |  |   VkSemaphore* semaphores = malloc(sizeof(VkSemaphore)*count); | 
		
	
		
			
				|  |  |  |  |   if(semaphores == 0) { | 
		
	
		
			
				|  |  |  |  |     return 0; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkSemaphoreCreateInfo semaphore_info = {}; | 
		
	
		
			
				|  |  |  |  |   semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; | 
		
	
		
			
				|  |  |  |  |   semaphore_info.flags = flags; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   for(uint32_t i = 0; i < count; i++) { | 
		
	
		
			
				|  |  |  |  |     VkResult result = vkCreateSemaphore(device, &semaphore_info, 0, &semaphores[i]); | 
		
	
		
			
				|  |  |  |  |     if(result != VK_SUCCESS) { | 
		
	
		
			
				|  |  |  |  |       free(semaphores); | 
		
	
		
			
				|  |  |  |  |       return 0; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  |   return semaphores; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | VkFormat find_depth_format(VkPhysicalDevice physical_device, uint32_t num_requested, VkFormat* requested, VkImageTiling tiling, VkFormatFeatureFlags features) { | 
		
	
		
			
				|  |  |  |  |   for(uint32_t i = 0; i < num_requested; i++) { | 
		
	
		
			
				|  |  |  |  |     VkFormatProperties properties; | 
		
	
	
		
			
				
					|  |  |  | @ -763,7 +783,6 @@ VkSwapchainKHR create_swapchain(VkDevice device, VkSurfaceFormatKHR format, VkPr | 
		
	
		
			
				|  |  |  |  |   swapchain_info.compositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR; | 
		
	
		
			
				|  |  |  |  |   swapchain_info.presentMode = present_mode; | 
		
	
		
			
				|  |  |  |  |   swapchain_info.clipped = VK_TRUE; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   swapchain_info.oldSwapchain = old_swapchain; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkSwapchainKHR swapchain; | 
		
	
	
		
			
				
					|  |  |  | @ -1167,7 +1186,7 @@ VkResult command_copy_buffers(VkDevice device, VkCommandPool transfer_pool, VkQu | 
		
	
		
			
				|  |  |  |  |   return command_end_single(device, command_buffer, transfer_pool, transfer_queue); | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | VkResult command_transition_image_layout(VkDevice device, VkCommandPool transfer_pool, VkQueue transfer_queue, VkImageLayout old_layout, VkImageLayout new_layout, VkImage image, VkAccessFlags src_mask, VkAccessFlags dst_mask, VkPipelineStageFlags source, VkPipelineStageFlags dest, uint32_t source_family, uint32_t dest_family) { | 
		
	
		
			
				|  |  |  |  | VkResult command_transition_image_layout(VkDevice device, VkCommandPool transfer_pool, VkQueue transfer_queue, VkImageLayout old_layout, VkImageLayout new_layout, VkImage image, VkAccessFlags src_mask, VkAccessFlags dst_mask, VkPipelineStageFlags source, VkPipelineStageFlags dest, uint32_t source_family, uint32_t dest_family, VkImageAspectFlags aspect_flags) { | 
		
	
		
			
				|  |  |  |  |   VkCommandBuffer command_buffer = command_begin_single(device, transfer_pool); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkImageMemoryBarrier barrier = { | 
		
	
	
		
			
				
					|  |  |  | @ -1178,7 +1197,7 @@ VkResult command_transition_image_layout(VkDevice device, VkCommandPool transfer | 
		
	
		
			
				|  |  |  |  |     .dstQueueFamilyIndex = dest_family, | 
		
	
		
			
				|  |  |  |  |     .image = image, | 
		
	
		
			
				|  |  |  |  |     .subresourceRange = { | 
		
	
		
			
				|  |  |  |  |       .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, | 
		
	
		
			
				|  |  |  |  |       .aspectMask = aspect_flags, | 
		
	
		
			
				|  |  |  |  |       .levelCount = 1, | 
		
	
		
			
				|  |  |  |  |       .layerCount = 1, | 
		
	
		
			
				|  |  |  |  |       .baseMipLevel = 0, | 
		
	
	
		
			
				
					|  |  |  | @ -1292,7 +1311,7 @@ Texture load_texture(VkPhysicalDeviceMemoryProperties memories, VkDevice device, | 
		
	
		
			
				|  |  |  |  |     return ret; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   result = command_transition_image_layout(device, transfer_pool, transfer_queue, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, image.image, 0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, transfer_family, transfer_family); | 
		
	
		
			
				|  |  |  |  |   result = command_transition_image_layout(device, transfer_pool, transfer_queue, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, image.image, 0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, transfer_family, transfer_family, VK_IMAGE_ASPECT_COLOR_BIT); | 
		
	
		
			
				|  |  |  |  |   if(result != VK_SUCCESS) { | 
		
	
		
			
				|  |  |  |  |     deallocate_buffer(device, staging); | 
		
	
		
			
				|  |  |  |  |     deallocate_image(device, image); | 
		
	
	
		
			
				
					|  |  |  | @ -1306,14 +1325,14 @@ Texture load_texture(VkPhysicalDeviceMemoryProperties memories, VkDevice device, | 
		
	
		
			
				|  |  |  |  |     return ret; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   result = command_transition_image_layout(device, transfer_pool, transfer_queue, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, image.image, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, transfer_family, graphics_family); | 
		
	
		
			
				|  |  |  |  |   result = command_transition_image_layout(device, transfer_pool, transfer_queue, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, image.image, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, transfer_family, graphics_family, VK_IMAGE_ASPECT_COLOR_BIT); | 
		
	
		
			
				|  |  |  |  |   if(result != VK_SUCCESS) { | 
		
	
		
			
				|  |  |  |  |     deallocate_buffer(device, staging); | 
		
	
		
			
				|  |  |  |  |     deallocate_image(device, image); | 
		
	
		
			
				|  |  |  |  |     return ret; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   result = command_transition_image_layout(device, graphics_pool, graphics_queue, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, image.image, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, transfer_family, graphics_family); | 
		
	
		
			
				|  |  |  |  |   result = command_transition_image_layout(device, graphics_pool, graphics_queue, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, image.image, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, transfer_family, graphics_family, VK_IMAGE_ASPECT_COLOR_BIT); | 
		
	
		
			
				|  |  |  |  |   if(result != VK_SUCCESS) { | 
		
	
		
			
				|  |  |  |  |     deallocate_buffer(device, staging); | 
		
	
		
			
				|  |  |  |  |     deallocate_image(device, image); | 
		
	
	
		
			
				
					|  |  |  | @ -1602,17 +1621,27 @@ int create_depth_image(VulkanContext* context) { | 
		
	
		
			
				|  |  |  |  |     context->depth_image_view = depth_image_view; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   result = command_transition_image_layout(context->device, context->extra_graphics_pool, context->queues.graphics, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL, context->depth_image, 0, 0, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, VK_IMAGE_ASPECT_DEPTH_BIT); | 
		
	
		
			
				|  |  |  |  |   if(result != VK_SUCCESS) { | 
		
	
		
			
				|  |  |  |  |     fprintf(stderr, "failed to transition depth image\n"); | 
		
	
		
			
				|  |  |  |  |     return 5; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   return 0; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | VkResult recreate_swap_chain(VulkanContext* context) { | 
		
	
		
			
				|  |  |  |  | VkResult recreate_swapchain(VulkanContext* context) { | 
		
	
		
			
				|  |  |  |  |   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); | 
		
	
		
			
				|  |  |  |  |   for(uint32_t i = 0; i < context->max_frames_in_flight; i++) { | 
		
	
		
			
				|  |  |  |  |     vkDestroySemaphore(context->device, context->image_available_semaphores[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); | 
		
	
	
		
			
				
					|  |  |  | @ -1665,6 +1694,14 @@ VkResult recreate_swap_chain(VulkanContext* context) { | 
		
	
		
			
				|  |  |  |  |     context->swapchain_framebuffers = framebuffers; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkSemaphore* ia_semaphores = create_semaphores(context->device, 0, context->max_frames_in_flight); | 
		
	
		
			
				|  |  |  |  |   if(ia_semaphores == 0) { | 
		
	
		
			
				|  |  |  |  |     fprintf(stderr, "failed to create vulkan image available semaphores\n"); | 
		
	
		
			
				|  |  |  |  |     return 0; | 
		
	
		
			
				|  |  |  |  |   } else { | 
		
	
		
			
				|  |  |  |  |     context->image_available_semaphores = ia_semaphores; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   return VK_SUCCESS; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
	
		
			
				
					|  |  |  | @ -1787,26 +1824,6 @@ VkCommandBuffer* create_command_buffers(VkDevice device, VkCommandPool command_p | 
		
	
		
			
				|  |  |  |  |   return command_buffers; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | VkSemaphore* create_semaphores(VkDevice device, VkSemaphoreCreateFlags flags, uint32_t count) { | 
		
	
		
			
				|  |  |  |  |   VkSemaphore* semaphores = malloc(sizeof(VkSemaphore)*count); | 
		
	
		
			
				|  |  |  |  |   if(semaphores == 0) { | 
		
	
		
			
				|  |  |  |  |     return 0; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkSemaphoreCreateInfo semaphore_info = {}; | 
		
	
		
			
				|  |  |  |  |   semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; | 
		
	
		
			
				|  |  |  |  |   semaphore_info.flags = flags; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   for(uint32_t i = 0; i < count; i++) { | 
		
	
		
			
				|  |  |  |  |     VkResult result = vkCreateSemaphore(device, &semaphore_info, 0, &semaphores[i]); | 
		
	
		
			
				|  |  |  |  |     if(result != VK_SUCCESS) { | 
		
	
		
			
				|  |  |  |  |       free(semaphores); | 
		
	
		
			
				|  |  |  |  |       return 0; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  |   return semaphores; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | VkFence* create_fences(VkDevice device, VkFenceCreateFlags flags, uint32_t count) { | 
		
	
		
			
				|  |  |  |  |   VkFence* fences = malloc(sizeof(VkFence)*count); | 
		
	
		
			
				|  |  |  |  |   if(fences == 0) { | 
		
	
	
		
			
				
					|  |  |  | @ -2406,6 +2423,18 @@ VulkanContext* init_vulkan(GLFWwindow* window, uint32_t max_frames_in_flight) { | 
		
	
		
			
				|  |  |  |  |     context->depth_format = depth_format; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkCommandPoolCreateInfo extra_pool_info = { | 
		
	
		
			
				|  |  |  |  |     .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, | 
		
	
		
			
				|  |  |  |  |     .queueFamilyIndex = context->queue_indices.graphics_family, | 
		
	
		
			
				|  |  |  |  |     .flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   result = vkCreateCommandPool(context->device, &extra_pool_info, 0, &context->extra_graphics_pool); | 
		
	
		
			
				|  |  |  |  |   if(result != VK_SUCCESS) { | 
		
	
		
			
				|  |  |  |  |     fprintf(stderr, "failed to create extra graphics command pool\n"); | 
		
	
		
			
				|  |  |  |  |     return 0; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   if(create_depth_image(context) != 0) { | 
		
	
		
			
				|  |  |  |  |     fprintf(stderr, "failed to create depth image\n"); | 
		
	
		
			
				|  |  |  |  |     return 0; | 
		
	
	
		
			
				
					|  |  |  | @ -2465,14 +2494,6 @@ VulkanContext* init_vulkan(GLFWwindow* window, uint32_t max_frames_in_flight) { | 
		
	
		
			
				|  |  |  |  |     context->swapchain_command_buffers = swapchain_command_buffers; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkCommandPoolCreateInfo extra_pool_info = { | 
		
	
		
			
				|  |  |  |  |     .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, | 
		
	
		
			
				|  |  |  |  |     .queueFamilyIndex = context->queue_indices.graphics_family, | 
		
	
		
			
				|  |  |  |  |     .flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   result = vkCreateCommandPool(context->device, &extra_pool_info, 0, &context->extra_graphics_pool); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkSemaphore* ia_semaphores = create_semaphores(context->device, 0, max_frames_in_flight); | 
		
	
		
			
				|  |  |  |  |   if(ia_semaphores == 0) { | 
		
	
		
			
				|  |  |  |  |     fprintf(stderr, "failed to create vulkan image available semaphores\n"); | 
		
	
	
		
			
				
					|  |  |  | @ -3261,7 +3282,8 @@ void main_loop(GLFWwindow* window, VulkanContext* context) { | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     VkResult result = draw_frame(context, &scene, sizeof(materials)/sizeof(Material), materials, objects_counts, objects); | 
		
	
		
			
				|  |  |  |  |     if(result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) { | 
		
	
		
			
				|  |  |  |  |       recreate_swap_chain(context); | 
		
	
		
			
				|  |  |  |  |       vkDeviceWaitIdle(context->device); | 
		
	
		
			
				|  |  |  |  |       recreate_swapchain(context); | 
		
	
		
			
				|  |  |  |  |     } else if(result != VK_SUCCESS) { | 
		
	
		
			
				|  |  |  |  |       fprintf(stderr, "draw_frame error %d\n", result); | 
		
	
		
			
				|  |  |  |  |       return; | 
		
	
	
		
			
				
					|  |  |  | 
 |