diff --git a/src/hud_elements.cpp b/src/hud_elements.cpp index c6db8db2063..2235a687995 100644 --- a/src/hud_elements.cpp +++ b/src/hud_elements.cpp @@ -618,27 +618,34 @@ void HudElements::image(){ // load the image if needed if(HUDElements.image_infos.loaded == false) { + unsigned maxwidth = HUDElements.params->width; + if(HUDElements.params->image_max_width != 0 && HUDElements.params->image_max_width < maxwidth) { + maxwidth = HUDElements.params->image_max_width; + } + HUDElements.image_infos.loaded = true; - if (!HUDElements.is_vulkan) { - unsigned maxwidth = HUDElements.params->width; - if(HUDElements.params->image_max_width != 0 && HUDElements.params->image_max_width < maxwidth) { - maxwidth = HUDElements.params->image_max_width; - } + if (HUDElements.is_vulkan) { + HUDElements.image_infos.vktexture = addTexture(value, &(HUDElements.image_infos.width), &(HUDElements.image_infos.height), maxwidth); + HUDElements.image_infos.valid = true; + } else { HUDElements.image_infos.valid = GL_LoadTextureFromFile(value.c_str(), &(HUDElements.image_infos.texture), &(HUDElements.image_infos.width), &(HUDElements.image_infos.height), maxwidth); - spdlog::info("Image {} loaded ({}x{})", value, HUDElements.image_infos.width, HUDElements.image_infos.height); } + spdlog::info("Image {} loaded ({}x{})", value, HUDElements.image_infos.width, HUDElements.image_infos.height); } // render the image if(HUDElements.image_infos.valid) { ImGui::TableNextRow(); ImGui::TableNextColumn(); - ImGui::PushFont(HUDElements.sw_stats->font1); - ImGui::Image((void*)(intptr_t)(HUDElements.image_infos.texture), ImVec2(HUDElements.image_infos.width, HUDElements.image_infos.height)); - ImGui::PopFont(); + + if (HUDElements.is_vulkan) { + ImGui::Image(HUDElements.image_infos.vktexture, ImVec2(HUDElements.image_infos.width, HUDElements.image_infos.height)); + } else { + ImGui::Image((void*)(intptr_t)(HUDElements.image_infos.texture), ImVec2(HUDElements.image_infos.width, HUDElements.image_infos.height)); + } } } @@ -648,19 +655,26 @@ void HudElements::background_image(){ // load the image if needed if(HUDElements.background_image_infos.loaded == false) { HUDElements.background_image_infos.loaded = true; - if (!HUDElements.is_vulkan) { + if (HUDElements.is_vulkan) { + HUDElements.background_image_infos.vktexture = addTexture(value, &(HUDElements.background_image_infos.width), &(HUDElements.background_image_infos.height), 0); + HUDElements.background_image_infos.valid = true; + } else { HUDElements.background_image_infos.valid = GL_LoadTextureFromFile(value.c_str(), &(HUDElements.background_image_infos.texture), &(HUDElements.background_image_infos.width), &(HUDElements.background_image_infos.height), 0); - spdlog::info("Image {} loaded ({}x{})", value, HUDElements.background_image_infos.width, HUDElements.background_image_infos.height); } + spdlog::info("Image {} loaded ({}x{})", value, HUDElements.background_image_infos.width, HUDElements.background_image_infos.height); } // render the image if(HUDElements.background_image_infos.valid) { - ImGui::GetBackgroundDrawList()->AddImage((void*)(intptr_t)(HUDElements.background_image_infos.texture), ImVec2(0, 0), ImVec2(HUDElements.background_image_infos.width, HUDElements.background_image_infos.height)); + if (HUDElements.is_vulkan) { + ImGui::GetBackgroundDrawList()->AddImage(HUDElements.background_image_infos.vktexture, ImVec2(0, 0), ImVec2(HUDElements.background_image_infos.width, HUDElements.background_image_infos.height)); + } else { + ImGui::GetBackgroundDrawList()->AddImage((void*)(intptr_t)(HUDElements.background_image_infos.texture), ImVec2(0, 0), ImVec2(HUDElements.background_image_infos.width, HUDElements.background_image_infos.height)); + } } } diff --git a/src/hud_elements.h b/src/hud_elements.h index 73f839d1484..9d979474d6d 100644 --- a/src/hud_elements.h +++ b/src/hud_elements.h @@ -14,6 +14,7 @@ struct image_infos { bool loaded; bool valid; GLuint texture; + ImTextureID vktexture; image_infos() { loaded = false; diff --git a/src/overlay.h b/src/overlay.h index 4969565219d..fbae6baaa3c 100644 --- a/src/overlay.h +++ b/src/overlay.h @@ -159,6 +159,7 @@ void center_text(const std::string& text); ImVec4 change_on_load_temp(LOAD_DATA& data, unsigned current); float get_time_stat(void *_data, int _idx); void stop_hw_updater(); +ImTextureID addTexture(const std::string& filename, int* width, int* height, int maxwidth); extern void control_client_check(struct device_data *device_data); extern void process_control_socket(struct instance_data *instance_data); @@ -166,4 +167,4 @@ extern void process_control_socket(struct instance_data *instance_data); void render_mpris_metadata(overlay_params& params, mutexed_metadata& meta, uint64_t frame_timing); #endif -#endif //MANGOHUD_OVERLAY_H \ No newline at end of file +#endif //MANGOHUD_OVERLAY_H diff --git a/src/vulkan.cpp b/src/vulkan.cpp index 48855b279ab..466ab6f4337 100644 --- a/src/vulkan.cpp +++ b/src/vulkan.cpp @@ -56,6 +56,9 @@ #include "blacklist.h" #include "pci_ids.h" +#include "stb_image.h" +#include "stb_image_resize.h" + float offset_x, offset_y, hudSpacing; int hudFirstRow, hudSecondRow; VkPhysicalDeviceDriverProperties driverProps = {}; @@ -104,6 +107,18 @@ struct overlay_draw { VkDeviceSize index_buffer_size; }; +struct texture_info { + VkImage image; + VkImageView image_view; + VkDeviceMemory mem; + VkDescriptorSet descset; + VkBuffer upload_buffer; + VkDeviceMemory upload_buffer_mem; + std::string filename; + int maxwidth; + bool uploaded; +}; + /* Mapped from VkSwapchainKHR */ struct swapchain_data { struct device_data *device; @@ -138,6 +153,9 @@ struct swapchain_data { VkBuffer upload_font_buffer; VkDeviceMemory upload_font_buffer_mem; + std::vector textures; + VkSampler texture_sampler; + /**/ ImGuiContext* imgui_context; ImVec2 window_size; @@ -149,6 +167,7 @@ struct swapchain_data { std::mutex global_lock; typedef std::lock_guard scoped_lock; std::unordered_map vk_object_to_data; +static struct swapchain_data* _swapchain_ref = NULL; thread_local ImGuiContext* __MesaImGui; @@ -363,6 +382,7 @@ static struct swapchain_data *new_swapchain_data(VkSwapchainKHR swapchain, data->swapchain = swapchain; data->window_size = ImVec2(instance_data->params.width, instance_data->params.height); map_object(HKEY(data->swapchain), data); + _swapchain_ref = data; return data; } @@ -471,12 +491,12 @@ static uint32_t vk_memory_type(struct device_data *data, return 0xFFFFFFFF; // Unable to find memoryType } -static void update_image_descriptor(struct swapchain_data *data, VkImageView image_view, VkDescriptorSet set) +static void update_image_descriptor(struct swapchain_data *data, VkImageView image_view, VkDescriptorSet set, VkSampler sampler) { struct device_data *device_data = data->device; /* Descriptor set */ VkDescriptorImageInfo desc_image[1] = {}; - desc_image[0].sampler = data->font_sampler; + desc_image[0].sampler = sampler; desc_image[0].imageView = image_view; desc_image[0].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; VkWriteDescriptorSet write_desc[1] = {}; @@ -596,7 +616,8 @@ static void create_image(struct swapchain_data *data, VkFormat format, VkImage& image, VkDeviceMemory& image_mem, - VkImageView& image_view) + VkImageView& image_view, + VkSampler sampler) { struct device_data *device_data = data->device; @@ -643,7 +664,7 @@ static void create_image(struct swapchain_data *data, VK_CHECK(device_data->vtable.CreateImageView(device_data->device, &view_info, NULL, &image_view)); - update_image_descriptor(data, image_view, descriptor_set); + update_image_descriptor(data, image_view, descriptor_set, sampler); } static VkDescriptorSet create_image_with_desc(struct swapchain_data *data, @@ -652,7 +673,8 @@ static VkDescriptorSet create_image_with_desc(struct swapchain_data *data, VkFormat format, VkImage& image, VkDeviceMemory& image_mem, - VkImageView& image_view) + VkImageView& image_view, + VkSampler sampler) { struct device_data *device_data = data->device; @@ -667,7 +689,7 @@ static VkDescriptorSet create_image_with_desc(struct swapchain_data *data, &alloc_info, &descriptor_set)); - create_image(data, descriptor_set, width, height, format, image, image_mem, image_view); + create_image(data, descriptor_set, width, height, format, image, image_mem, image_view, sampler); return descriptor_set; } @@ -692,9 +714,9 @@ static void check_fonts(struct swapchain_data* data) shutdown_swapchain_font(data); if (desc_set) - create_image(data, desc_set, width, height, VK_FORMAT_R8G8B8A8_SRGB, data->font_image, data->font_mem, data->font_image_view); + create_image(data, desc_set, width, height, VK_FORMAT_R8G8B8A8_SRGB, data->font_image, data->font_mem, data->font_image_view, data->font_sampler); else - desc_set = create_image_with_desc(data, width, height, VK_FORMAT_R8G8B8A8_SRGB, data->font_image, data->font_mem, data->font_image_view); + desc_set = create_image_with_desc(data, width, height, VK_FORMAT_R8G8B8A8_SRGB, data->font_image, data->font_mem, data->font_image_view, data->font_sampler); io.Fonts->SetTexID((ImTextureID)desc_set); data->font_uploaded = false; @@ -722,6 +744,34 @@ static void ensure_swapchain_fonts(struct swapchain_data *data, upload_image_data(device_data, command_buffer, pixels, upload_size, width, height, data->upload_font_buffer, data->upload_font_buffer_mem, data->font_image); } +ImTextureID addTexture(const std::string& filename, int* width, int* height, int maxwidth) { + struct swapchain_data *data = _swapchain_ref; + struct texture_info ti; + int original_width, original_height, channels; + + // load + unsigned char* pixels = stbi_load(filename.c_str(), &original_width, &original_height, &channels, STBI_rgb_alpha); + stbi_image_free(pixels); + + // reduce the image + float ratio = 1.0; + if(original_width > maxwidth && maxwidth != 0) { + ratio = maxwidth / ((float) original_width); + } + *width = (float)(original_width * ratio); + *height = (float)(original_height * ratio); + // + + ti.descset = create_image_with_desc(data, *width, *height, VK_FORMAT_R8G8B8A8_SRGB, ti.image, ti.mem, ti.image_view, data->texture_sampler); + ti.filename = filename; + ti.maxwidth = maxwidth; + ti.uploaded = false; + + data->textures.push_back(ti); + + return (ImTextureID) ti.descset; +} + static void CreateOrResizeBuffer(struct device_data *data, VkBuffer *buffer, VkDeviceMemory *buffer_memory, @@ -789,6 +839,35 @@ static struct overlay_draw *render_swapchain_display(struct swapchain_data *data ensure_swapchain_fonts(data, draw->command_buffer); + /* ensure_textures */ + int original_width, original_height, channels; + for(unsigned int i=0; itextures.size(); i++) { + if(data->textures[i].uploaded == false) { + data->textures[i].uploaded = true; + + // load + unsigned char* pixels = stbi_load(data->textures[i].filename.c_str(), &original_width, &original_height, &channels, STBI_rgb_alpha); + + // reduce the image + float ratio = 1.0; + if(original_width > data->textures[i].maxwidth && data->textures[i].maxwidth != 0) { + ratio = data->textures[i].maxwidth / ((float) original_width); + } + int width = (float)(original_width * ratio); + int height = (float)(original_height * ratio); + unsigned char* pixels_resized = (unsigned char*)malloc(width * height * 4); + stbir_resize_uint8(pixels, original_width, original_height, 0, + pixels_resized, width, height, 0, + 4); + stbi_image_free(pixels); + // + + size_t upload_size = width * height * 4 * sizeof(char); + upload_image_data(device_data, draw->command_buffer, pixels_resized, upload_size, width, height, data->textures[i].upload_buffer, data->textures[i].upload_buffer_mem, data->textures[i].image); + stbi_image_free(pixels_resized); + } + } + /* Bounce the image to display back to color attachment layout for * rendering on top of it. */ @@ -865,7 +944,7 @@ static struct overlay_draw *render_swapchain_display(struct swapchain_data *data /* Bind pipeline and descriptor sets */ device_data->vtable.CmdBindPipeline(draw->command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, data->pipeline); -#if 1 // disable if using >1 font textures +#if 0 // disable if using >1 font textures VkDescriptorSet desc_set[1] = { //data->descriptor_set reinterpret_cast(ImGui::GetIO().Fonts->Fonts[0]->ContainerAtlas->TexID) @@ -928,7 +1007,7 @@ static struct overlay_draw *render_swapchain_display(struct swapchain_data *data scissor.extent.width = (uint32_t)(pcmd->ClipRect.z - pcmd->ClipRect.x); scissor.extent.height = (uint32_t)(pcmd->ClipRect.w - pcmd->ClipRect.y + 1); // FIXME: Why +1 here? device_data->vtable.CmdSetScissor(draw->command_buffer, 0, 1, &scissor); -#if 0 //enable if using >1 font textures or use texture array +#if 1 //enable if using >1 font textures or use texture array VkDescriptorSet desc_set[1] = { (VkDescriptorSet)pcmd->TextureId }; device_data->vtable.CmdBindDescriptorSets(draw->command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, data->pipeline_layout, 0, 1, desc_set, 0, NULL); @@ -1061,21 +1140,37 @@ static void setup_swapchain_data_pipeline(struct swapchain_data *data) VK_CHECK(device_data->vtable.CreateSampler(device_data->device, &sampler_info, NULL, &data->font_sampler)); + /* Texture sampler */ + VkSamplerCreateInfo texture_sampler_info = {}; + texture_sampler_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + texture_sampler_info.magFilter = VK_FILTER_LINEAR; + texture_sampler_info.minFilter = VK_FILTER_LINEAR; + texture_sampler_info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + texture_sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; + texture_sampler_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; + texture_sampler_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; + texture_sampler_info.minLod = -1000; + texture_sampler_info.maxLod = 1000; + texture_sampler_info.maxAnisotropy = 1.0f; + + VK_CHECK(device_data->vtable.CreateSampler(device_data->device, &texture_sampler_info, + NULL, &data->texture_sampler)); + /* Descriptor pool */ VkDescriptorPoolSize sampler_pool_size = {}; sampler_pool_size.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; sampler_pool_size.descriptorCount = 1; VkDescriptorPoolCreateInfo desc_pool_info = {}; desc_pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - desc_pool_info.maxSets = 1; - desc_pool_info.poolSizeCount = 1; + desc_pool_info.maxSets = 3; // fonts + image + background_image + desc_pool_info.poolSizeCount = 3; // fonts + image + background_image desc_pool_info.pPoolSizes = &sampler_pool_size; VK_CHECK(device_data->vtable.CreateDescriptorPool(device_data->device, &desc_pool_info, NULL, &data->descriptor_pool)); /* Descriptor layout */ - VkSampler sampler[1] = { data->font_sampler }; + VkSampler sampler[2] = { data->font_sampler, data->texture_sampler}; VkDescriptorSetLayoutBinding binding[1] = {}; binding[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; binding[0].descriptorCount = 1; @@ -1402,6 +1497,14 @@ static void shutdown_swapchain_font(struct swapchain_data *data) device_data->vtable.DestroyBuffer(device_data->device, data->upload_font_buffer, NULL); device_data->vtable.FreeMemory(device_data->device, data->upload_font_buffer_mem, NULL); + + for(unsigned int i=0; itextures.size(); i++) { + device_data->vtable.DestroyImageView(device_data->device, data->textures[i].image_view, NULL); + device_data->vtable.DestroyImage(device_data->device, data->textures[i].image, NULL); + device_data->vtable.FreeMemory(device_data->device, data->textures[i].mem, NULL); + device_data->vtable.DestroyBuffer(device_data->device, data->textures[i].upload_buffer, NULL); + device_data->vtable.FreeMemory(device_data->device, data->textures[i].upload_buffer_mem, NULL); + } } static void shutdown_swapchain_data(struct swapchain_data *data) @@ -1437,6 +1540,7 @@ static void shutdown_swapchain_data(struct swapchain_data *data) data->descriptor_layout, NULL); device_data->vtable.DestroySampler(device_data->device, data->font_sampler, NULL); + device_data->vtable.DestroySampler(device_data->device, data->texture_sampler, NULL); shutdown_swapchain_font(data); ImGui::DestroyContext(data->imgui_context);