diff --git a/src/vulkan.cpp b/src/vulkan.cpp index 27f55017..46c958ad 100644 --- a/src/vulkan.cpp +++ b/src/vulkan.cpp @@ -63,12 +63,12 @@ namespace MangoHud { namespace GL { #endif struct vk_image { - bool uploaded; VkImage image; VkImageView image_view; VkDeviceMemory mem; - VkBuffer buffer; - VkDeviceMemory buffer_mem; + uint32_t width, height; + size_t size; + bool uploaded; }; /* Mapped from VkInstace/VkPhysicalDevice */ @@ -97,9 +97,11 @@ struct device_data { VkPhysicalDeviceProperties properties; struct queue_data *graphic_queue; + struct queue_data *transfer_queue; std::vector queues; + VkCommandPool command_pool; VkDescriptorPool descriptor_pool; VkDescriptorSetLayout descriptor_layout; VkDescriptorSet descriptor_set; @@ -315,6 +317,15 @@ static VkDescriptorSet alloc_descriptor_set(const struct device_data *device_dat static void setup_device_pipeline(struct device_data *device_data) { + /* Command buffer pool for transfers */ + VkCommandPoolCreateInfo cmd_buffer_pool_info = {}; + cmd_buffer_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + cmd_buffer_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + cmd_buffer_pool_info.queueFamilyIndex = device_data->transfer_queue->family_index; + VK_CHECK(device_data->vtable.CreateCommandPool(device_data->device, + &cmd_buffer_pool_info, + NULL, &device_data->command_pool)); + /* Sampler */ VkSamplerCreateInfo sampler_info = {}; sampler_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; @@ -360,7 +371,6 @@ static void setup_device_pipeline(struct device_data *device_data) /* Descriptor set */ device_data->descriptor_set = alloc_descriptor_set(device_data); - } static struct queue_data *new_queue_data(VkQueue queue, @@ -375,9 +385,11 @@ static struct queue_data *new_queue_data(VkQueue queue, data->family_index = family_index; map_object(HKEY(data->queue), data); + SPDLOG_DEBUG("queue: 0x{:02x}", data->flags); if (data->flags & VK_QUEUE_GRAPHICS_BIT) device_data->graphic_queue = data; - + if (data->flags & VK_QUEUE_TRANSFER_BIT) + device_data->transfer_queue = data; return data; } @@ -694,10 +706,10 @@ static void create_image(struct device_data *device_data, uint32_t width, uint32_t height, VkFormat format, - VkImage& image, - VkDeviceMemory& image_mem, - VkImageView& image_view) + vk_image& image) { + image.width = width; + image.height = height; VkImageCreateInfo image_info = {}; image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; @@ -714,10 +726,10 @@ static void create_image(struct device_data *device_data, image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; VK_CHECK(device_data->vtable.CreateImage(device_data->device, &image_info, - NULL, &image)); + NULL, &image.image)); VkMemoryRequirements font_image_req; device_data->vtable.GetImageMemoryRequirements(device_data->device, - image, &font_image_req); + image.image, &font_image_req); VkMemoryAllocateInfo image_alloc_info = {}; image_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; image_alloc_info.allocationSize = font_image_req.size; @@ -725,22 +737,82 @@ static void create_image(struct device_data *device_data, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, font_image_req.memoryTypeBits); VK_CHECK(device_data->vtable.AllocateMemory(device_data->device, &image_alloc_info, - NULL, &image_mem)); + NULL, &image.mem)); VK_CHECK(device_data->vtable.BindImageMemory(device_data->device, - image, - image_mem, 0)); + image.image, + image.mem, 0)); /* Font image view */ VkImageViewCreateInfo view_info = {}; view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - view_info.image = image; + view_info.image = image.image; view_info.viewType = VK_IMAGE_VIEW_TYPE_2D; view_info.format = format; view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; view_info.subresourceRange.levelCount = 1; view_info.subresourceRange.layerCount = 1; VK_CHECK(device_data->vtable.CreateImageView(device_data->device, &view_info, - NULL, &image_view)); + NULL, &image.image_view)); +} + +static void upload_font_image(struct device_data *device_data, vk_image *img, void *pixels, size_t upload_size) +{ + if (img->uploaded) + return; + + auto start = Clock::now(); + VkCommandBuffer cmd_buffer; + VkCommandBufferAllocateInfo cmd_buffer_info = {}; + cmd_buffer_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + cmd_buffer_info.commandPool = device_data->command_pool; + cmd_buffer_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + cmd_buffer_info.commandBufferCount = 1; + VK_CHECK(device_data->vtable.AllocateCommandBuffers(device_data->device, + &cmd_buffer_info, + &cmd_buffer)); + VK_CHECK(device_data->set_device_loader_data(device_data->device, + cmd_buffer)); + + VkCommandBufferBeginInfo buffer_begin_info = {}; + buffer_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + VK_CHECK(device_data->vtable.BeginCommandBuffer(cmd_buffer, &buffer_begin_info)); + + VkBuffer buffer; + VkDeviceMemory buffer_mem; + upload_image_data(device_data, cmd_buffer, pixels, upload_size, img->width, img->height, + buffer, buffer_mem, device_data->font_img.image); + + device_data->vtable.EndCommandBuffer(cmd_buffer); + + VkFence fence; + VkFenceCreateInfo fence_info = {}; + fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + VK_CHECK(device_data->vtable.CreateFence(device_data->device, + &fence_info, + NULL, + &fence)); + + VkSubmitInfo submit_info = {}; + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &cmd_buffer; + + SPDLOG_DEBUG("transfer queue: {}, {}", (void*)device_data->transfer_queue->queue, (void*)device_data->graphic_queue->queue); + VkResult r; + VK_CHECK(r = device_data->vtable.QueueSubmit(device_data->transfer_queue->queue, 1, &submit_info, fence)); + + if (r == VK_SUCCESS) + VK_CHECK(device_data->vtable.WaitForFences(device_data->device, 1, &fence, VK_TRUE, UINT64_MAX)); + device_data->vtable.FreeCommandBuffers(device_data->device, device_data->command_pool, 1, &cmd_buffer); + device_data->vtable.DestroyFence(device_data->device, fence, NULL); + + device_data->vtable.DestroyBuffer(device_data->device, buffer, NULL); + device_data->vtable.FreeMemory(device_data->device, buffer_mem, NULL); + + img->uploaded = true; + auto dur = Clock::now() - start; + auto dur_us = std::chrono::duration_cast(dur).count(); + SPDLOG_DEBUG("upload duration: {} us, {} bytes, {:0.02f} MiB/s", dur_us, upload_size, upload_size/(dur_us/1e6f)/(1024*1024)); } static void check_fonts(struct device_data* device_data) @@ -750,8 +822,14 @@ static void check_fonts(struct device_data* device_data) return; std::unique_lock lk(device_data->font_mutex); + if (params.font_params_hash == device_data->font_params_hash) + return; + SPDLOG_DEBUG("Recreating font image"); + device_data->font_params_hash = params.font_params_hash; + create_fonts(device_data->font_atlas, params, device_data->font_alt, device_data->font_text); + unsigned char* pixels; int width, height; device_data->font_atlas->GetTexDataAsAlpha8(&pixels, &width, &height); @@ -759,15 +837,15 @@ static void check_fonts(struct device_data* device_data) // wait for rendering to complete, if any VK_CHECK(device_data->vtable.DeviceWaitIdle(device_data->device)); shutdown_device_font(device_data); - create_image(device_data, width, height, VK_FORMAT_R8_UNORM, device_data->font_img.image, device_data->font_img.mem, device_data->font_img.image_view); + create_image(device_data, width, height, VK_FORMAT_R8_UNORM, device_data->font_img); - device_data->font_img.uploaded = false; - device_data->font_params_hash = params.font_params_hash; SPDLOG_DEBUG("Default font tex size: {}x{}px", width, height); - SPDLOG_DEBUG("Update font image descriptor {}", (void*)device_data->descriptor_set); update_image_descriptor(device_data, device_data->font_img.image_view, device_data->descriptor_set); device_data->font_atlas->SetTexID((ImTextureID)device_data->descriptor_set); + +// std::thread(upload_font_image, device_data, &device_data->font_img, pixels, width * height * 1 * sizeof(char)).detach(); + upload_font_image(device_data, &device_data->font_img, pixels, width * height * 1 * sizeof(char)); } static void check_fonts(struct swapchain_data* data) @@ -781,23 +859,6 @@ static void check_fonts(struct swapchain_data* data) } } -static void ensure_swapchain_fonts(struct swapchain_data *data, - VkCommandBuffer command_buffer) -{ - struct device_data *device_data = data->device; - - if (device_data->font_img.uploaded) - return; - - device_data->font_img.uploaded = true; - unsigned char* pixels; - int width, height; - device_data->font_atlas->GetTexDataAsAlpha8(&pixels, &width, &height); - size_t upload_size = width * height * 1 * sizeof(char); - upload_image_data(device_data, command_buffer, pixels, upload_size, width, height, - device_data->font_img.buffer, device_data->font_img.buffer_mem, device_data->font_img.image); -} - static void CreateOrResizeBuffer(struct device_data *data, VkBuffer *buffer, VkDeviceMemory *buffer_memory, @@ -863,7 +924,7 @@ static struct overlay_draw *render_swapchain_display(struct swapchain_data *data device_data->vtable.BeginCommandBuffer(draw->command_buffer, &buffer_begin_info); - ensure_swapchain_fonts(data, draw->command_buffer); +// ensure_swapchain_fonts(data->device, draw->command_buffer); /* Bounce the image to display back to color attachment layout for * rendering on top of it. @@ -1416,8 +1477,8 @@ static void shutdown_device_font(struct device_data *device_data) device_data->vtable.DestroyImage(device_data->device, device_data->font_img.image, NULL); device_data->vtable.FreeMemory(device_data->device, device_data->font_img.mem, NULL); - device_data->vtable.DestroyBuffer(device_data->device, device_data->font_img.buffer, NULL); - device_data->vtable.FreeMemory(device_data->device, device_data->font_img.buffer_mem, NULL); +// device_data->vtable.DestroyBuffer(device_data->device, device_data->font_img.buffer, NULL); +// device_data->vtable.FreeMemory(device_data->device, device_data->font_img.buffer_mem, NULL); device_data->font_img = {}; } @@ -1826,6 +1887,7 @@ static void overlay_DestroyDevice( device_data->vtable.DestroySampler(device_data->device, device_data->sampler, NULL); + device_data->vtable.DestroyCommandPool(device_data->device, device_data->command_pool, NULL); device_data->vtable.DestroyDevice(device, pAllocator); destroy_device_data(device_data); }