|  |  |  | @ -98,175 +98,336 @@ VkResult load_font(const char* atlas_file, const char* metadata_file, FontData* | 
		
	
		
			
				|  |  |  |  |   return VK_SUCCESS; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | VkResult render_thread(GLFWwindow* window, RenderContext* render_context) { | 
		
	
		
			
				|  |  |  |  | typedef struct TextPointersMemoryStruct { | 
		
	
		
			
				|  |  |  |  |   VmaAllocation pointers_memory; | 
		
	
		
			
				|  |  |  |  |   VmaAllocation draw_memory; | 
		
	
		
			
				|  |  |  |  |   VmaAllocation strings_memory; | 
		
	
		
			
				|  |  |  |  |   VmaAllocation codes_memory; | 
		
	
		
			
				|  |  |  |  |   VmaAllocation characters_memory; | 
		
	
		
			
				|  |  |  |  |   VmaAllocation draw_clear_memory; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkBuffer pointers_buffer; | 
		
	
		
			
				|  |  |  |  |   VkBuffer draw_buffer; | 
		
	
		
			
				|  |  |  |  |   VkBuffer draw_clear_buffer; | 
		
	
		
			
				|  |  |  |  |   VkBuffer strings_buffer; | 
		
	
		
			
				|  |  |  |  |   VkBuffer codes_buffer; | 
		
	
		
			
				|  |  |  |  |   VkBuffer characters_buffer; | 
		
	
		
			
				|  |  |  |  | } TextPointersMemory; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | VkResult create_text_pointers( | 
		
	
		
			
				|  |  |  |  |     uint32_t max_strings, | 
		
	
		
			
				|  |  |  |  |     uint32_t max_characters, | 
		
	
		
			
				|  |  |  |  |     VkDevice device, | 
		
	
		
			
				|  |  |  |  |     VmaAllocator allocator, | 
		
	
		
			
				|  |  |  |  |     VkCommandPool transfer_pool, | 
		
	
		
			
				|  |  |  |  |     Queue transfer_queue, | 
		
	
		
			
				|  |  |  |  |     TextPointersMemory* memory, | 
		
	
		
			
				|  |  |  |  |     VkDeviceAddress* address) { | 
		
	
		
			
				|  |  |  |  |   VkResult result; | 
		
	
		
			
				|  |  |  |  |   UIContext ui_context; | 
		
	
		
			
				|  |  |  |  |   VkBuffer colored_rect_buffer; | 
		
	
		
			
				|  |  |  |  |   VkBuffer text_buffer; | 
		
	
		
			
				|  |  |  |  |   VmaAllocation colored_rect_memory; | 
		
	
		
			
				|  |  |  |  |   VmaAllocation text_memory; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   result = init_pipelines(render_context->device, render_context->allocator, render_context->swapchain_extent, render_context->window_scale, render_context->render_pass, render_context->transfer_queue, render_context->transfer_pool, &ui_context); | 
		
	
		
			
				|  |  |  |  |   VmaAllocationCreateInfo memory_info = { | 
		
	
		
			
				|  |  |  |  |     .usage = VMA_MEMORY_USAGE_GPU_ONLY, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkBufferCreateInfo pointers_info = { | 
		
	
		
			
				|  |  |  |  |     .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | 
		
	
		
			
				|  |  |  |  |     .size = sizeof(StringPointers), | 
		
	
		
			
				|  |  |  |  |     .usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, | 
		
	
		
			
				|  |  |  |  |     .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   result = vmaCreateBuffer(allocator, &pointers_info, &memory_info, &memory->pointers_buffer, &memory->pointers_memory, NULL); | 
		
	
		
			
				|  |  |  |  |   if(result != VK_SUCCESS) { | 
		
	
		
			
				|  |  |  |  |     return result; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   FontData test_font = {}; | 
		
	
		
			
				|  |  |  |  |   uint32_t* test_atlas; | 
		
	
		
			
				|  |  |  |  |   SymbolInfo* test_symbols; | 
		
	
		
			
				|  |  |  |  |   result = load_font("tools/test.png", "tools/test.meta", &test_font, &test_symbols, &test_atlas); | 
		
	
		
			
				|  |  |  |  |   VkBufferCreateInfo draw_info = { | 
		
	
		
			
				|  |  |  |  |     .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | 
		
	
		
			
				|  |  |  |  |     .size = sizeof(DrawCommand), | 
		
	
		
			
				|  |  |  |  |     .usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, | 
		
	
		
			
				|  |  |  |  |     .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   result = vmaCreateBuffer(allocator, &draw_info, &memory_info, &memory->draw_buffer, &memory->draw_memory, NULL); | 
		
	
		
			
				|  |  |  |  |   if(result != VK_SUCCESS) { | 
		
	
		
			
				|  |  |  |  |     return result; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   FontDescriptor test_font_descriptor; | 
		
	
		
			
				|  |  |  |  |   result = create_text_descriptor(render_context->device, render_context->allocator, ui_context.font_layout, ui_context.font_pool, &test_font, test_symbols, test_atlas, render_context->transfer_pool, render_context->transfer_queue, &test_font_descriptor); | 
		
	
		
			
				|  |  |  |  |   VkBufferCreateInfo draw_clear_info = { | 
		
	
		
			
				|  |  |  |  |     .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | 
		
	
		
			
				|  |  |  |  |     .size = sizeof(DrawCommand), | 
		
	
		
			
				|  |  |  |  |     .usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT, | 
		
	
		
			
				|  |  |  |  |     .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   result = vmaCreateBuffer(allocator, &draw_clear_info, &memory_info, &memory->draw_clear_buffer, &memory->draw_clear_memory, NULL); | 
		
	
		
			
				|  |  |  |  |   if(result != VK_SUCCESS) { | 
		
	
		
			
				|  |  |  |  |     return result; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkBufferCreateInfo colored_rect_buffer_info = { | 
		
	
		
			
				|  |  |  |  |   VkBufferCreateInfo strings_info = { | 
		
	
		
			
				|  |  |  |  |     .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | 
		
	
		
			
				|  |  |  |  |     .usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, | 
		
	
		
			
				|  |  |  |  |     .size = 3*sizeof(ColoredRect), | 
		
	
		
			
				|  |  |  |  |     .size = max_strings*sizeof(String), | 
		
	
		
			
				|  |  |  |  |     .usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, | 
		
	
		
			
				|  |  |  |  |     .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VmaAllocationCreateInfo colored_rect_memory_info = { | 
		
	
		
			
				|  |  |  |  |     .usage = VMA_MEMORY_USAGE_CPU_TO_GPU, | 
		
	
		
			
				|  |  |  |  |   result = vmaCreateBuffer(allocator, &strings_info, &memory_info, &memory->strings_buffer, &memory->strings_memory, NULL); | 
		
	
		
			
				|  |  |  |  |   if(result != VK_SUCCESS) { | 
		
	
		
			
				|  |  |  |  |     return result; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkBufferCreateInfo codes_info = { | 
		
	
		
			
				|  |  |  |  |     .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | 
		
	
		
			
				|  |  |  |  |     .size = max_characters*sizeof(DrawCommand), | 
		
	
		
			
				|  |  |  |  |     .usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, | 
		
	
		
			
				|  |  |  |  |     .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   result = vmaCreateBuffer(render_context->allocator, &colored_rect_buffer_info, &colored_rect_memory_info, &colored_rect_buffer, &colored_rect_memory, NULL); | 
		
	
		
			
				|  |  |  |  |   result = vmaCreateBuffer(allocator, &codes_info, &memory_info, &memory->codes_buffer, &memory->codes_memory, NULL); | 
		
	
		
			
				|  |  |  |  |   if(result != VK_SUCCESS) { | 
		
	
		
			
				|  |  |  |  |     return result; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   ColoredRect* colored_rects; | 
		
	
		
			
				|  |  |  |  |   VkBufferCreateInfo characters_info = { | 
		
	
		
			
				|  |  |  |  |     .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | 
		
	
		
			
				|  |  |  |  |     .size = max_characters*sizeof(DrawCommand), | 
		
	
		
			
				|  |  |  |  |     .usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, | 
		
	
		
			
				|  |  |  |  |     .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   result = vmaMapMemory(render_context->allocator, colored_rect_memory, (void**)&colored_rects); | 
		
	
		
			
				|  |  |  |  |   result = vmaCreateBuffer(allocator, &characters_info, &memory_info, &memory->characters_buffer, &memory->characters_memory, NULL); | 
		
	
		
			
				|  |  |  |  |   if(result != VK_SUCCESS) { | 
		
	
		
			
				|  |  |  |  |     return result; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   colored_rects[0] = colored_rect(100.0, 100.0, 1.0, 0.0, 0.0, 1.0,   0.0,   0.0, 0.5); | 
		
	
		
			
				|  |  |  |  |   colored_rects[1] = colored_rect(100.0, 100.0, 0.0, 1.0, 0.0, 1.0,   0.0, 100.0, 0.5); | 
		
	
		
			
				|  |  |  |  |   colored_rects[2] = colored_rect(100.0, 100.0, 0.0, 0.0, 1.0, 1.0, 100.0,   0.0, 0.5); | 
		
	
		
			
				|  |  |  |  |   VkBufferDeviceAddressInfo pointers_address = { | 
		
	
		
			
				|  |  |  |  |     .sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, | 
		
	
		
			
				|  |  |  |  |     .buffer = memory->pointers_buffer, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   vmaUnmapMemory(render_context->allocator, colored_rect_memory); | 
		
	
		
			
				|  |  |  |  |   VkBufferDeviceAddressInfo strings_address = { | 
		
	
		
			
				|  |  |  |  |     .sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, | 
		
	
		
			
				|  |  |  |  |     .buffer = memory->strings_buffer, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkBufferDeviceAddressInfo codes_address = { | 
		
	
		
			
				|  |  |  |  |     .sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, | 
		
	
		
			
				|  |  |  |  |     .buffer = memory->codes_buffer, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkBufferDeviceAddressInfo characters_address = { | 
		
	
		
			
				|  |  |  |  |     .sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, | 
		
	
		
			
				|  |  |  |  |     .buffer = memory->characters_buffer, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkBufferDeviceAddressInfo draw_address = { | 
		
	
		
			
				|  |  |  |  |     .sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, | 
		
	
		
			
				|  |  |  |  |     .buffer = memory->draw_buffer, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkBufferCreateInfo text_buffer_info = { | 
		
	
		
			
				|  |  |  |  |   VkBuffer temp_buffer; | 
		
	
		
			
				|  |  |  |  |   VmaAllocation temp_memory; | 
		
	
		
			
				|  |  |  |  |   VkBufferCreateInfo temp_buffer_info = { | 
		
	
		
			
				|  |  |  |  |     .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | 
		
	
		
			
				|  |  |  |  |     .usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, | 
		
	
		
			
				|  |  |  |  |     .size = 2*sizeof(Char), | 
		
	
		
			
				|  |  |  |  |     .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT, | 
		
	
		
			
				|  |  |  |  |     .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | 
		
	
		
			
				|  |  |  |  |     .size = sizeof(StringPointers) + | 
		
	
		
			
				|  |  |  |  |             sizeof(DrawCommand), | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VmaAllocationCreateInfo text_memory_info = { | 
		
	
		
			
				|  |  |  |  |   VmaAllocationCreateInfo temp_memory_info = { | 
		
	
		
			
				|  |  |  |  |     .usage = VMA_MEMORY_USAGE_CPU_TO_GPU, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  |   result = vmaCreateBuffer(allocator, &temp_buffer_info, &temp_memory_info, &temp_buffer, &temp_memory, NULL); | 
		
	
		
			
				|  |  |  |  |   if(result != VK_SUCCESS) { | 
		
	
		
			
				|  |  |  |  |     return result; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   result = vmaCreateBuffer(render_context->allocator, &text_buffer_info, &text_memory_info, &text_buffer, &text_memory, NULL); | 
		
	
		
			
				|  |  |  |  |   void* mapped; | 
		
	
		
			
				|  |  |  |  |   result = vmaMapMemory(allocator, temp_memory, &mapped); | 
		
	
		
			
				|  |  |  |  |   if(result != VK_SUCCESS) { | 
		
	
		
			
				|  |  |  |  |     return result; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   Char* text; | 
		
	
		
			
				|  |  |  |  |   DrawCommand draw = { | 
		
	
		
			
				|  |  |  |  |     .index_count = 6, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   memcpy(mapped + 0, &draw, sizeof(DrawCommand)); | 
		
	
		
			
				|  |  |  |  |   StringPointers pointers = { | 
		
	
		
			
				|  |  |  |  |     .strings = vkGetBufferDeviceAddress(device, &strings_address), | 
		
	
		
			
				|  |  |  |  |     .codes = vkGetBufferDeviceAddress(device, &codes_address), | 
		
	
		
			
				|  |  |  |  |     .characters = vkGetBufferDeviceAddress(device, &characters_address), | 
		
	
		
			
				|  |  |  |  |     .draw = vkGetBufferDeviceAddress(device, &draw_address), | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  |   memcpy(mapped + sizeof(DrawCommand), &pointers, sizeof(StringPointers)); | 
		
	
		
			
				|  |  |  |  |   vmaUnmapMemory(allocator, temp_memory); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   result = vmaMapMemory(render_context->allocator, text_memory, (void**)&text); | 
		
	
		
			
				|  |  |  |  |   VkCommandBuffer command_buffer = command_begin_single(device, transfer_pool); | 
		
	
		
			
				|  |  |  |  |   VkBufferCopy copy_draw = { | 
		
	
		
			
				|  |  |  |  |     .size = sizeof(DrawCommand), | 
		
	
		
			
				|  |  |  |  |     .srcOffset = 0, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  |   vkCmdCopyBuffer(command_buffer, temp_buffer, memory->draw_buffer, 1, ©_draw); | 
		
	
		
			
				|  |  |  |  |   vkCmdCopyBuffer(command_buffer, temp_buffer, memory->draw_clear_buffer, 1, ©_draw); | 
		
	
		
			
				|  |  |  |  |   VkBufferCopy copy_pointers = { | 
		
	
		
			
				|  |  |  |  |     .size = sizeof(StringPointers), | 
		
	
		
			
				|  |  |  |  |     .srcOffset = sizeof(DrawCommand), | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  |   vkCmdCopyBuffer(command_buffer, temp_buffer, memory->pointers_buffer, 1, ©_pointers); | 
		
	
		
			
				|  |  |  |  |   result = command_end_single(device, command_buffer, transfer_pool, transfer_queue); | 
		
	
		
			
				|  |  |  |  |   if(result != VK_SUCCESS) { | 
		
	
		
			
				|  |  |  |  |     return result; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  |   vmaDestroyBuffer(allocator, temp_buffer, temp_memory); | 
		
	
		
			
				|  |  |  |  |   *address = vkGetBufferDeviceAddress(device, &pointers_address); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   text[0].color[0] = 1.0f; | 
		
	
		
			
				|  |  |  |  |   text[0].color[1] = 1.0f; | 
		
	
		
			
				|  |  |  |  |   text[0].color[2] = 1.0f; | 
		
	
		
			
				|  |  |  |  |   text[0].color[3] = 1.0f; | 
		
	
		
			
				|  |  |  |  |   text[0].pos[0] = 200.0f; | 
		
	
		
			
				|  |  |  |  |   text[0].pos[1] = 200.0f; | 
		
	
		
			
				|  |  |  |  |   text[0].size = 200.0f; | 
		
	
		
			
				|  |  |  |  |   text[0].code = 1; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   text[1].color[0] = 1.0f; | 
		
	
		
			
				|  |  |  |  |   text[1].color[1] = 1.0f; | 
		
	
		
			
				|  |  |  |  |   text[1].color[2] = 1.0f; | 
		
	
		
			
				|  |  |  |  |   text[1].color[3] = 1.0f; | 
		
	
		
			
				|  |  |  |  |   text[1].pos[0] = 400.0f; | 
		
	
		
			
				|  |  |  |  |   text[1].pos[1] = 200.0f; | 
		
	
		
			
				|  |  |  |  |   text[1].size = 200.0f; | 
		
	
		
			
				|  |  |  |  |   text[1].code = 14; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   vmaUnmapMemory(render_context->allocator, text_memory); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkBuffer draw_buffer; | 
		
	
		
			
				|  |  |  |  |   VmaAllocation draw_memory; | 
		
	
		
			
				|  |  |  |  |   return VK_SUCCESS; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkBufferCreateInfo draw_buffer_info = { | 
		
	
		
			
				|  |  |  |  | VkResult create_transfer_buffer(VkDeviceSize size, VmaAllocator allocator, VkBuffer* buffer, VmaAllocation* memory, void** mapped) { | 
		
	
		
			
				|  |  |  |  |   VkBufferCreateInfo buffer_info = { | 
		
	
		
			
				|  |  |  |  |     .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | 
		
	
		
			
				|  |  |  |  |     .usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, | 
		
	
		
			
				|  |  |  |  |     .size = sizeof(DrawCommand), | 
		
	
		
			
				|  |  |  |  |     .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT, | 
		
	
		
			
				|  |  |  |  |     .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | 
		
	
		
			
				|  |  |  |  |     .size = size, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VmaAllocationCreateInfo draw_memory_info = { | 
		
	
		
			
				|  |  |  |  |     .usage = VMA_MEMORY_USAGE_GPU_ONLY, | 
		
	
		
			
				|  |  |  |  |   VmaAllocationCreateInfo memory_info = { | 
		
	
		
			
				|  |  |  |  |     .usage = VMA_MEMORY_USAGE_CPU_TO_GPU, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  |    | 
		
	
		
			
				|  |  |  |  |   result = vmaCreateBuffer(render_context->allocator, &draw_buffer_info, &draw_memory_info, &draw_buffer, &draw_memory, NULL); | 
		
	
		
			
				|  |  |  |  |   VkResult result = vmaCreateBuffer(allocator, &buffer_info, &memory_info, buffer, memory, NULL); | 
		
	
		
			
				|  |  |  |  |   if(result != VK_SUCCESS) { | 
		
	
		
			
				|  |  |  |  |     return result; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   result = vmaMapMemory(allocator, *memory, mapped); | 
		
	
		
			
				|  |  |  |  |   if(result != VK_SUCCESS) { | 
		
	
		
			
				|  |  |  |  |     vmaDestroyBuffer(allocator, *buffer, *memory); | 
		
	
		
			
				|  |  |  |  |     return result; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   return VK_SUCCESS; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | VkResult render_thread(GLFWwindow* window, RenderContext* render_context) { | 
		
	
		
			
				|  |  |  |  |   VkResult result; | 
		
	
		
			
				|  |  |  |  |   UIContext ui_context; | 
		
	
		
			
				|  |  |  |  |   VkBuffer colored_rect_buffer; | 
		
	
		
			
				|  |  |  |  |   VmaAllocation colored_rect_memory; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   result = init_pipelines(render_context->device, render_context->allocator, render_context->swapchain_extent, render_context->window_scale, render_context->render_pass, render_context->transfer_queue, render_context->transfer_pool, &ui_context); | 
		
	
		
			
				|  |  |  |  |   if(result != VK_SUCCESS) { | 
		
	
		
			
				|  |  |  |  |     return result; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   FontData test_font = {}; | 
		
	
		
			
				|  |  |  |  |   uint32_t* test_atlas; | 
		
	
		
			
				|  |  |  |  |   SymbolInfo* test_symbols; | 
		
	
		
			
				|  |  |  |  |   result = load_font("tools/test.png", "tools/test.meta", &test_font, &test_symbols, &test_atlas); | 
		
	
		
			
				|  |  |  |  |   if(result != VK_SUCCESS) { | 
		
	
		
			
				|  |  |  |  |     return result; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkBuffer text_pointer_buffer; | 
		
	
		
			
				|  |  |  |  |   VmaAllocation text_pointer_memory; | 
		
	
		
			
				|  |  |  |  |   FontDescriptor test_font_descriptor; | 
		
	
		
			
				|  |  |  |  |   result = create_text_descriptor(render_context->device, render_context->allocator, ui_context.font_layout, ui_context.font_pool, &test_font, test_symbols, test_atlas, render_context->transfer_pool, render_context->transfer_queue, &test_font_descriptor); | 
		
	
		
			
				|  |  |  |  |   if(result != VK_SUCCESS) { | 
		
	
		
			
				|  |  |  |  |     return result; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkBufferCreateInfo text_pointer_buffer_info = { | 
		
	
		
			
				|  |  |  |  |   VkBufferCreateInfo colored_rect_buffer_info = { | 
		
	
		
			
				|  |  |  |  |     .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, | 
		
	
		
			
				|  |  |  |  |     .usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, | 
		
	
		
			
				|  |  |  |  |     .size = sizeof(TextPointers), | 
		
	
		
			
				|  |  |  |  |     .usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, | 
		
	
		
			
				|  |  |  |  |     .size = 3*sizeof(ColoredRect), | 
		
	
		
			
				|  |  |  |  |     .sharingMode = VK_SHARING_MODE_EXCLUSIVE, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VmaAllocationCreateInfo text_pointer_memory_info = { | 
		
	
		
			
				|  |  |  |  |   VmaAllocationCreateInfo colored_rect_memory_info = { | 
		
	
		
			
				|  |  |  |  |     .usage = VMA_MEMORY_USAGE_CPU_TO_GPU, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   result = vmaCreateBuffer(render_context->allocator, &text_pointer_buffer_info, &text_pointer_memory_info, &text_pointer_buffer, &text_pointer_memory, NULL); | 
		
	
		
			
				|  |  |  |  |   result = vmaCreateBuffer(render_context->allocator, &colored_rect_buffer_info, &colored_rect_memory_info, &colored_rect_buffer, &colored_rect_memory, NULL); | 
		
	
		
			
				|  |  |  |  |   if(result != VK_SUCCESS) { | 
		
	
		
			
				|  |  |  |  |     return result; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   TextPointers* pointers; | 
		
	
		
			
				|  |  |  |  |   ColoredRect* colored_rects; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   result = vmaMapMemory(render_context->allocator, text_pointer_memory, (void**)&pointers); | 
		
	
		
			
				|  |  |  |  |   result = vmaMapMemory(render_context->allocator, colored_rect_memory, (void**)&colored_rects); | 
		
	
		
			
				|  |  |  |  |   if(result != VK_SUCCESS) { | 
		
	
		
			
				|  |  |  |  |     return result; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  |   VkBufferDeviceAddressInfo test_address_info = { | 
		
	
		
			
				|  |  |  |  |     .sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, | 
		
	
		
			
				|  |  |  |  |     .buffer = text_buffer, | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   colored_rects[0] = colored_rect(100.0, 100.0, 1.0, 0.0, 0.0, 1.0,   0.0,   0.0, 0.5); | 
		
	
		
			
				|  |  |  |  |   colored_rects[1] = colored_rect(100.0, 100.0, 0.0, 1.0, 0.0, 1.0,   0.0, 100.0, 0.5); | 
		
	
		
			
				|  |  |  |  |   colored_rects[2] = colored_rect(100.0, 100.0, 0.0, 0.0, 1.0, 1.0, 100.0,   0.0, 0.5); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   vmaUnmapMemory(render_context->allocator, colored_rect_memory); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   TextPointersMemory text_pointers; | 
		
	
		
			
				|  |  |  |  |   VkDeviceAddress text_pointers_address; | 
		
	
		
			
				|  |  |  |  |   result = create_text_pointers(10, 100, render_context->device, render_context->allocator, render_context->transfer_pool, render_context->transfer_queue, &text_pointers, &text_pointers_address); | 
		
	
		
			
				|  |  |  |  |   if(result != VK_SUCCESS) { | 
		
	
		
			
				|  |  |  |  |     return result; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkBuffer temp_buffer; | 
		
	
		
			
				|  |  |  |  |   VmaAllocation temp_memory; | 
		
	
		
			
				|  |  |  |  |   void* mapped; | 
		
	
		
			
				|  |  |  |  |   result = create_transfer_buffer(sizeof(String) + 2*sizeof(uint32_t), render_context->allocator, &temp_buffer, &temp_memory, (void**)&mapped); | 
		
	
		
			
				|  |  |  |  |   if(result != VK_SUCCESS) { | 
		
	
		
			
				|  |  |  |  |     return result; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   String* mapped_string = (String*)mapped; | 
		
	
		
			
				|  |  |  |  |   mapped_string->pos[0] = 200.0; | 
		
	
		
			
				|  |  |  |  |   mapped_string->pos[1] = 200.0; | 
		
	
		
			
				|  |  |  |  |   mapped_string->pos[1] = 0.5; | 
		
	
		
			
				|  |  |  |  |   mapped_string->color[0] = 1.0; | 
		
	
		
			
				|  |  |  |  |   mapped_string->color[1] = 1.0; | 
		
	
		
			
				|  |  |  |  |   mapped_string->color[2] = 1.0; | 
		
	
		
			
				|  |  |  |  |   mapped_string->color[3] = 1.0; | 
		
	
		
			
				|  |  |  |  |   mapped_string->size = 200.0; | 
		
	
		
			
				|  |  |  |  |   mapped_string->length = 2; | 
		
	
		
			
				|  |  |  |  |   mapped_string->offset = 0; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   uint32* mapped_codes = (uint32_t*)(mapped + sizeof(String)); | 
		
	
		
			
				|  |  |  |  |   mapped_codes[0] = 4; | 
		
	
		
			
				|  |  |  |  |   mapped_codes[1] = 5; | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkCommandBuffer command_buffer = command_begin_single(render_context->device, render_context->transfer_pool); | 
		
	
		
			
				|  |  |  |  |   VkBufferCopy copy_string = { | 
		
	
		
			
				|  |  |  |  |     .size = sizeof(String), | 
		
	
		
			
				|  |  |  |  |     .srcOffset = 0, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  |   pointers->characters = vkGetBufferDeviceAddress(render_context->device, &test_address_info); | 
		
	
		
			
				|  |  |  |  |   VkBufferDeviceAddressInfo draw_address_info = { | 
		
	
		
			
				|  |  |  |  |     .sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, | 
		
	
		
			
				|  |  |  |  |     .buffer = draw_buffer, | 
		
	
		
			
				|  |  |  |  |   vkCmdCopyBuffer(command_buffer, temp_buffer, text_pointers.strings_buffer, 1, ©_string); | 
		
	
		
			
				|  |  |  |  |   VkBufferCopy copy_codes = { | 
		
	
		
			
				|  |  |  |  |     .size = 2*sizeof(uint32_t), | 
		
	
		
			
				|  |  |  |  |     .srcOffset = sizeof(String), | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  |   pointers->draw = vkGetBufferDeviceAddress(render_context->device, &draw_address_info); | 
		
	
		
			
				|  |  |  |  |   vmaUnmapMemory(render_context->allocator, text_pointer_memory); | 
		
	
		
			
				|  |  |  |  |   vkCmdCopyBuffer(command_buffer, temp_buffer, text_pointers.codes_buffer, 1, ©_codes); | 
		
	
		
			
				|  |  |  |  |   result = command_end_single(render_context->device, command_buffer, render_context->transfer_pool, render_context->transfer_queue); | 
		
	
		
			
				|  |  |  |  |   if(result != VK_SUCCESS) { | 
		
	
		
			
				|  |  |  |  |     return result; | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   VkBufferDeviceAddressInfo pointers_address_info = { | 
		
	
		
			
				|  |  |  |  |     .sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, | 
		
	
		
			
				|  |  |  |  |     .buffer = text_pointer_buffer, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  |   vkQueueWaitIdle(render_context->transfer_queue.handle); | 
		
	
		
			
				|  |  |  |  |   vmaUnmapMemory(render_context->allocator, temp_memory); | 
		
	
		
			
				|  |  |  |  |   vmaDestroyBuffer(render_context->allocator, temp_buffer, temp_memory); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   UILayer test_layer = { | 
		
	
		
			
				|  |  |  |  |     .colored_rects = colored_rect_buffer, | 
		
	
		
			
				|  |  |  |  |     .colored_rect_count = 3, | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     .font = test_font_descriptor, | 
		
	
		
			
				|  |  |  |  |     .text_count = 2, | 
		
	
		
			
				|  |  |  |  |     .texts = text_buffer, | 
		
	
		
			
				|  |  |  |  |     .texts_address = vkGetBufferDeviceAddress(render_context->device, &pointers_address_info), | 
		
	
		
			
				|  |  |  |  |     .chars_size = 10*sizeof(Character), | 
		
	
		
			
				|  |  |  |  |     .chars = text_pointers.characters_buffer, | 
		
	
		
			
				|  |  |  |  |     .string_count = 2, | 
		
	
		
			
				|  |  |  |  |     .string_pointers = text_pointers_address, | 
		
	
		
			
				|  |  |  |  |     .string_draw = text_pointers.draw_buffer, | 
		
	
		
			
				|  |  |  |  |     .string_draw_clear = text_pointers.draw_clear_buffer, | 
		
	
		
			
				|  |  |  |  |   }; | 
		
	
		
			
				|  |  |  |  |   fprintf(stderr, "GPU Buffer: 0x%llX\n", text_pointers_address); | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   while(glfwWindowShouldClose(window) == 0) { | 
		
	
		
			
				|  |  |  |  |     glfwPollEvents(); | 
		
	
	
		
			
				
					|  |  |  | 
 |