@ -51,6 +51,9 @@
# include "blacklist.h"
# include "pci_ids.h"
# include "stb_image.h"
# include "stb_image_resize.h"
using namespace std ;
float offset_x , offset_y , hudSpacing ;
@ -63,6 +66,22 @@ namespace MangoHud { namespace GL {
} }
# endif
struct vk_image {
VkImage image ;
VkImageView view ;
VkDeviceMemory mem ;
uint32_t width , height ;
size_t size ;
bool uploaded ;
} ;
struct texture_info {
vk_image image ;
VkDescriptorSet descset ;
std : : string filename ;
int maxwidth ;
} ;
/* Mapped from VkInstace/VkPhysicalDevice */
struct instance_data {
struct vk_instance_dispatch_table vtable ;
@ -158,12 +177,16 @@ struct swapchain_data {
std : : list < overlay_draw * > draws ; /* List of struct overlay_draw */
bool font_uploaded ;
VkImage font_image ;
VkImageView font_image_view ;
VkDeviceMemory font_mem ;
//VkImage font_image;
//VkImageView font_image_view;
//VkDeviceMemory font_mem;
VkBuffer upload_font_buffer ;
VkDeviceMemory upload_font_buffer_mem ;
struct vk_image font_image ;
size_t font_params_hash = 0 ;
std : : vector < struct texture_info > textures ;
/**/
ImGuiContext * imgui_context ;
ImFontAtlas * font_atlas ;
@ -214,6 +237,7 @@ static void unmap_object(uint64_t obj)
/**/
static void shutdown_swapchain_font ( struct swapchain_data * ) ;
ImTextureID add_texture ( swapchain_stats * stats , const std : : string & filename , int * width , int * height , int maxwidth ) ;
static VkLayerInstanceCreateInfo * get_instance_chain_info ( const VkInstanceCreateInfo * pCreateInfo ,
VkLayerFunction func )
@ -291,6 +315,22 @@ static struct device_data *new_device_data(VkDevice device, struct instance_data
return data ;
}
static VkDescriptorSet alloc_descriptor_set ( const struct swapchain_data * data )
{
VkDescriptorSet descriptor_set { } ;
struct device_data * device_data = data - > device ;
VkDescriptorSetAllocateInfo alloc_info { } ;
alloc_info . sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO ;
alloc_info . descriptorPool = data - > descriptor_pool ;
alloc_info . descriptorSetCount = 1 ;
alloc_info . pSetLayouts = & data - > descriptor_layout ;
VK_CHECK ( device_data - > vtable . AllocateDescriptorSets ( device_data - > device ,
& alloc_info ,
& descriptor_set ) ) ;
return descriptor_set ;
}
static struct queue_data * new_queue_data ( VkQueue queue ,
const VkQueueFamilyProperties * family_props ,
uint32_t family_index ,
@ -623,9 +663,7 @@ static void create_image(struct swapchain_data *data,
uint32_t width ,
uint32_t height ,
VkFormat format ,
VkImage & image ,
VkDeviceMemory & image_mem ,
VkImageView & image_view )
vk_image & image )
{
struct device_data * device_data = data - > device ;
@ -644,10 +682,10 @@ static void create_image(struct swapchain_data *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 ;
@ -655,33 +693,31 @@ static void create_image(struct swapchain_data *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 . view) ) ;
update_image_descriptor ( data , image _ view, descriptor_set ) ;
update_image_descriptor ( data , image . view, descriptor_set ) ;
}
static VkDescriptorSet create_image_with_desc ( struct swapchain_data * data ,
uint32_t width ,
uint32_t height ,
VkFormat format ,
VkImage & image ,
VkDeviceMemory & image_mem ,
VkImageView & image_view )
vk_image & image )
{
struct device_data * device_data = data - > device ;
@ -696,10 +732,71 @@ 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 );
return descriptor_set ;
}
// TODO Synchronous image data upload, make it async
static void submit_image_upload_cmd ( struct swapchain_data * data , vk_image * img , void * pixels , size_t upload_size )
{
if ( img - > uploaded )
return ;
struct device_data * device_data = data - > device ;
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 = 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 , 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 ;
VkResult r ;
VK_CHECK ( r = device_data - > vtable . QueueSubmit ( device_data - > graphic_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 , 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 < std : : chrono : : microseconds > ( dur ) . count ( ) ;
SPDLOG_DEBUG ( " upload duration: {} us, {} bytes, {:0.02f} MiB/s " , dur_us , upload_size , upload_size / ( dur_us / 1e6 f ) / ( 1024 * 1024 ) ) ;
}
static void check_fonts ( struct swapchain_data * data )
{
struct device_data * device_data = data - > device ;
@ -720,9 +817,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_UNORM , data - > font_image , data - > font_mem , data - > font_image_view );
create_image ( data , desc_set , width , height , VK_FORMAT_R8G8B8A8_UNORM , data - > font_image );
else
desc_set = create_image_with_desc ( data , width , height , VK_FORMAT_R8G8B8A8_UNORM , data - > font_image , data - > font_mem , data - > font_image_view );
desc_set = create_image_with_desc ( data , width , height , VK_FORMAT_R8G8B8A8_UNORM , data - > font_image );
data - > font_atlas - > SetTexID ( ( ImTextureID ) desc_set ) ;
data - > font_uploaded = false ;
@ -746,7 +843,37 @@ static void ensure_swapchain_fonts(struct swapchain_data *data,
int width , height ;
data - > font_atlas - > GetTexDataAsRGBA32 ( & pixels , & width , & height ) ;
size_t upload_size = width * height * 4 * sizeof ( char ) ;
upload_image_data ( device_data , command_buffer , pixels , upload_size , width , height , data - > upload_font_buffer , data - > upload_font_buffer_mem , data - > font_image ) ;
upload_image_data ( device_data , command_buffer , pixels , upload_size , width , height , data - > upload_font_buffer , data - > upload_font_buffer_mem , data - > font_image . image ) ;
}
ImTextureID add_texture ( swapchain_stats * stats , const std : : string & filename , int * width , int * height , int maxwidth ) {
struct texture_info ti { } ;
int original_width , original_height , channels ;
// FIXME hacks
struct swapchain_data * data = reinterpret_cast < swapchain_data * > ( ( char * ) stats - ( ( char * ) & ( ( swapchain_data * ) 0 ) - > sw_stats ) ) ;
// load
int ret = stbi_info ( filename . c_str ( ) , & original_width , & original_height , & channels ) ;
if ( ! ret )
return nullptr ;
// reduce the image
float ratio = 1.0 ;
if ( original_width > maxwidth & & maxwidth ! = 0 ) {
ratio = maxwidth / static_cast < float > ( original_width ) ;
}
* width = original_width * ratio ;
* height = original_height * ratio ;
ti . descset = alloc_descriptor_set ( data ) ;
create_image ( data , ti . descset , * width , * height , VK_FORMAT_R8G8B8A8_UNORM , ti . image ) ;
update_image_descriptor ( data , ti . image . view , ti . descset ) ;
ti . filename = filename ;
ti . maxwidth = maxwidth ;
data - > textures . push_back ( ti ) ;
return ( ImTextureID ) ti . descset ;
}
static void CreateOrResizeBuffer ( struct device_data * data ,
@ -816,6 +943,39 @@ static struct overlay_draw *render_swapchain_display(struct swapchain_data *data
ensure_swapchain_fonts ( data , draw - > command_buffer ) ;
/* ensure_textures */
for ( auto & tex : data - > textures ) {
if ( ! tex . descset )
continue ;
if ( ! tex . image . uploaded ) {
// tex.image.uploaded = true;
// load
int width , height , channels ;
unsigned char * pixels = stbi_load ( tex . filename . c_str ( ) , & width , & height , & channels , STBI_rgb_alpha ) ;
if ( ! pixels )
{
SPDLOG_ERROR ( " Failed to load image: {} " , tex . filename ) ;
continue ;
}
// reduce the image
if ( width > tex . maxwidth & & tex . maxwidth ! = 0 ) {
unsigned char * pixels_resized = ( unsigned char * ) malloc ( width * height * STBI_rgb_alpha ) ;
stbir_resize_uint8 ( pixels , width , height , 0 , pixels_resized , tex . image . width , tex . image . height , 0 , STBI_rgb_alpha ) ;
stbi_image_free ( pixels ) ;
pixels = pixels_resized ;
}
SPDLOG_DEBUG ( " Uploading '{}' ({}x{}) " , tex . filename , tex . image . width , tex . image . height ) ;
size_t upload_size = tex . image . width * tex . image . height * STBI_rgb_alpha ;
submit_image_upload_cmd ( data , & tex . image , pixels , upload_size ) ;
stbi_image_free ( pixels ) ;
}
}
/* Bounce the image to display back to color attachment layout for
* rendering on top of it .
*/
@ -1419,16 +1579,31 @@ static void setup_swapchain_data(struct swapchain_data *data,
NULL , & data - > command_pool ) ) ;
}
static void destroy_vk_image ( struct device_data * device_data , vk_image & image )
{
device_data - > vtable . DestroyImageView ( device_data - > device , image . view , NULL ) ;
device_data - > vtable . DestroyImage ( device_data - > device , image . image , NULL ) ;
device_data - > vtable . FreeMemory ( device_data - > device , image . mem , NULL ) ;
image = { } ;
}
static void shutdown_swapchain_font ( struct swapchain_data * data )
{
struct device_data * device_data = data - > device ;
destroy_vk_image ( device_data , data - > font_image ) ;
}
device_data - > vtable . DestroyImageView ( device_data - > device , data - > font_image_view , NULL ) ;
device_data - > vtable . DestroyImage ( device_data - > device , data - > font_image , NULL ) ;
device_data - > vtable . FreeMemory ( device_data - > device , data - > font_mem , NULL ) ;
static void shutdown_textures ( struct swapchain_data * data )
{
struct device_data * device_data = data - > device ;
for ( auto & tex : data - > textures )
{
device_data - > vtable . FreeDescriptorSets ( device_data - > device , data - > descriptor_pool , 1 , & tex . descset ) ;
destroy_vk_image ( device_data , tex . image ) ;
}
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 ) ;
HUDElements. image_infos = { } ;
HUDElements. background_image_infos = { } ;
}
static void shutdown_swapchain_data ( struct swapchain_data * data )
@ -1465,6 +1640,7 @@ static void shutdown_swapchain_data(struct swapchain_data *data)
device_data - > vtable . DestroySampler ( device_data - > device , data - > font_sampler , NULL ) ;
shutdown_swapchain_font ( data ) ;
shutdown_textures ( data ) ;
IM_FREE ( data - > font_atlas ) ;
ImGui : : DestroyContext ( data - > imgui_context ) ;