@ -22,6 +22,7 @@
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2020-09-07: Vulkan: Added VkPipeline parameter to ImGui_ImplVulkan_RenderDrawData (default to one passed to ImGui_ImplVulkan_Init).
// 2020-05-04: Vulkan: Fixed crash if initial frame has no vertices.
// 2020-04-26: Vulkan: Fixed edge case where render callbacks wouldn't be called if the ImDrawData didn't have vertices.
// 2019-08-01: Vulkan: Added support for specifying multisample count. Set ImGui_ImplVulkan_InitInfo::MSAASamples to one of the VkSampleCountFlagBits values to use, default is non-multisampled as before.
@ -80,6 +81,8 @@ static VkDescriptorSetLayout g_DescriptorSetLayout = VK_NULL_HANDLE;
static VkPipelineLayout g_PipelineLayout = VK_NULL_HANDLE ;
static VkDescriptorSet g_DescriptorSet = VK_NULL_HANDLE ;
static VkPipeline g_Pipeline = VK_NULL_HANDLE ;
static VkShaderModule g_ShaderModuleVert ;
static VkShaderModule g_ShaderModuleFrag ;
// Font data
static VkSampler g_FontSampler = VK_NULL_HANDLE ;
@ -266,11 +269,11 @@ static void CreateOrResizeBuffer(VkBuffer& buffer, VkDeviceMemory& buffer_memory
p_buffer_size = new_size ;
}
static void ImGui_ImplVulkan_SetupRenderState ( ImDrawData * draw_data , VkCommandBuffer command_buffer , ImGui_ImplVulkanH_FrameRenderBuffers * rb , int fb_width , int fb_height )
static void ImGui_ImplVulkan_SetupRenderState ( ImDrawData * draw_data , VkPipeline pipeline , Vk CommandBuffer command_buffer , ImGui_ImplVulkanH_FrameRenderBuffers * rb , int fb_width , int fb_height )
{
// Bind pipeline and descriptor sets:
{
vkCmdBindPipeline ( command_buffer , VK_PIPELINE_BIND_POINT_GRAPHICS , g_P ipeline) ;
vkCmdBindPipeline ( command_buffer , VK_PIPELINE_BIND_POINT_GRAPHICS , p ipeline) ;
VkDescriptorSet desc_set [ 1 ] = { g_DescriptorSet } ;
vkCmdBindDescriptorSets ( command_buffer , VK_PIPELINE_BIND_POINT_GRAPHICS , g_PipelineLayout , 0 , 1 , desc_set , 0 , NULL ) ;
}
@ -312,7 +315,7 @@ static void ImGui_ImplVulkan_SetupRenderState(ImDrawData* draw_data, VkCommandBu
// Render function
// (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop)
void ImGui_ImplVulkan_RenderDrawData ( ImDrawData * draw_data , VkCommandBuffer command_buffer )
void ImGui_ImplVulkan_RenderDrawData ( ImDrawData * draw_data , VkCommandBuffer command_buffer , VkPipeline pipeline )
{
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
int fb_width = ( int ) ( draw_data - > DisplaySize . x * draw_data - > FramebufferScale . x ) ;
@ -321,6 +324,8 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm
return ;
ImGui_ImplVulkan_InitInfo * v = & g_VulkanInitInfo ;
if ( pipeline = = VK_NULL_HANDLE )
pipeline = g_Pipeline ;
// Allocate array to store enough vertex/index buffers
ImGui_ImplVulkanH_WindowRenderBuffers * wrb = & g_MainWindowRenderBuffers ;
@ -374,7 +379,7 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm
}
// Setup desired Vulkan state
ImGui_ImplVulkan_SetupRenderState ( draw_data , command_buffer , rb , fb_width , fb_height ) ;
ImGui_ImplVulkan_SetupRenderState ( draw_data , pipeline , command_buffer , rb , fb_width , fb_height ) ;
// Will project scissor/clipping rectangles into framebuffer space
ImVec2 clip_off = draw_data - > DisplayPos ; // (0,0) unless using multi-viewports
@ -395,7 +400,7 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm
// User callback, registered via ImDrawList::AddCallback()
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
if ( pcmd - > UserCallback = = ImDrawCallback_ResetRenderState )
ImGui_ImplVulkan_SetupRenderState ( draw_data , command_buffer , rb , fb_width , fb_height ) ;
ImGui_ImplVulkan_SetupRenderState ( draw_data , pipeline , command_buffer , rb , fb_width , fb_height ) ;
else
pcmd - > UserCallback ( cmd_list , pcmd ) ;
}
@ -586,99 +591,103 @@ bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer)
return true ;
}
bool ImGui_ImplVulkan_CreateDeviceObjects ( )
static void ImGui_ImplVulkan_CreateShaderModules ( VkDevice device , const VkAllocationCallbacks * allocator )
{
ImGui_ImplVulkan_InitInfo * v = & g_VulkanInitInfo ;
VkResult err ;
VkShaderModule vert_module ;
VkShaderModule frag_module ;
// Create The Shader Modules:
// Create the shader modules
if ( g_ShaderModuleVert = = NULL )
{
VkShaderModuleCreateInfo vert_info = { } ;
vert_info . sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO ;
vert_info . codeSize = sizeof ( __glsl_shader_vert_spv ) ;
vert_info . pCode = ( uint32_t * ) __glsl_shader_vert_spv ;
err = vkCreateShaderModule ( v - > D evice, & vert_info , v - > A llocator, & vert_module ) ;
VkResult err = vkCreateShaderModule ( d evice, & vert_info , a llocator, & g_ShaderModuleVert ) ;
check_vk_result ( err ) ;
}
if ( g_ShaderModuleFrag = = NULL )
{
VkShaderModuleCreateInfo frag_info = { } ;
frag_info . sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO ;
frag_info . codeSize = sizeof ( __glsl_shader_frag_spv ) ;
frag_info . pCode = ( uint32_t * ) __glsl_shader_frag_spv ;
err = vkCreateShaderModule ( v - > D evice, & frag_info , v - > A llocator, & frag_module ) ;
VkResult err = vkCreateShaderModule ( d evice, & frag_info , a llocator, & g_ShaderModuleFrag ) ;
check_vk_result ( err ) ;
}
}
if ( ! g_FontSampler )
{
VkSamplerCreateInfo info = { } ;
info . sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO ;
info . magFilter = VK_FILTER_LINEAR ;
info . minFilter = VK_FILTER_LINEAR ;
info . mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR ;
info . addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT ;
info . addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT ;
info . addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT ;
info . minLod = - 1000 ;
info . maxLod = 1000 ;
info . maxAnisotropy = 1.0f ;
err = vkCreateSampler ( v - > Device , & info , v - > Allocator , & g_FontSampler ) ;
check_vk_result ( err ) ;
}
static void ImGui_ImplVulkan_CreateFontSampler ( VkDevice device , const VkAllocationCallbacks * allocator )
{
if ( g_FontSampler )
return ;
if ( ! g_DescriptorSetLayout )
{
VkSampler sampler [ 1 ] = { g_FontSampler } ;
VkDescriptorSetLayoutBinding binding [ 1 ] = { } ;
binding [ 0 ] . descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ;
binding [ 0 ] . descriptorCount = 1 ;
binding [ 0 ] . stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT ;
binding [ 0 ] . pImmutableSamplers = sampler ;
VkDescriptorSetLayoutCreateInfo info = { } ;
info . sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO ;
info . bindingCount = 1 ;
info . pBindings = binding ;
err = vkCreateDescriptorSetLayout ( v - > Device , & info , v - > Allocator , & g_DescriptorSetLayout ) ;
check_vk_result ( err ) ;
}
VkSamplerCreateInfo info = { } ;
info . sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO ;
info . magFilter = VK_FILTER_LINEAR ;
info . minFilter = VK_FILTER_LINEAR ;
info . mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR ;
info . addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT ;
info . addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT ;
info . addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT ;
info . minLod = - 1000 ;
info . maxLod = 1000 ;
info . maxAnisotropy = 1.0f ;
VkResult err = vkCreateSampler ( device , & info , allocator , & g_FontSampler ) ;
check_vk_result ( err ) ;
}
// Create Descriptor Set:
{
VkDescriptorSetAllocateInfo alloc_info = { } ;
alloc_info . sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO ;
alloc_info . descriptorPool = v - > DescriptorPool ;
alloc_info . descriptorSetCount = 1 ;
alloc_info . pSetLayouts = & g_DescriptorSetLayout ;
err = vkAllocateDescriptorSets ( v - > Device , & alloc_info , & g_DescriptorSet ) ;
check_vk_result ( err ) ;
}
static void ImGui_ImplVulkan_CreateDescriptorSetLayout ( VkDevice device , const VkAllocationCallbacks * allocator )
{
if ( g_DescriptorSetLayout )
return ;
if ( ! g_PipelineLayout )
{
// Constants: we are using 'vec2 offset' and 'vec2 scale' instead of a full 3d projection matrix
VkPushConstantRange push_constants [ 1 ] = { } ;
push_constants [ 0 ] . stageFlags = VK_SHADER_STAGE_VERTEX_BIT ;
push_constants [ 0 ] . offset = sizeof ( float ) * 0 ;
push_constants [ 0 ] . size = sizeof ( float ) * 4 ;
VkDescriptorSetLayout set_layout [ 1 ] = { g_DescriptorSetLayout } ;
VkPipelineLayoutCreateInfo layout_info = { } ;
layout_info . sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO ;
layout_info . setLayoutCount = 1 ;
layout_info . pSetLayouts = set_layout ;
layout_info . pushConstantRangeCount = 1 ;
layout_info . pPushConstantRanges = push_constants ;
err = vkCreatePipelineLayout ( v - > Device , & layout_info , v - > Allocator , & g_PipelineLayout ) ;
check_vk_result ( err ) ;
}
ImGui_ImplVulkan_CreateFontSampler ( device , allocator ) ;
VkSampler sampler [ 1 ] = { g_FontSampler } ;
VkDescriptorSetLayoutBinding binding [ 1 ] = { } ;
binding [ 0 ] . descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ;
binding [ 0 ] . descriptorCount = 1 ;
binding [ 0 ] . stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT ;
binding [ 0 ] . pImmutableSamplers = sampler ;
VkDescriptorSetLayoutCreateInfo info = { } ;
info . sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO ;
info . bindingCount = 1 ;
info . pBindings = binding ;
VkResult err = vkCreateDescriptorSetLayout ( device , & info , allocator , & g_DescriptorSetLayout ) ;
check_vk_result ( err ) ;
}
static void ImGui_ImplVulkan_CreatePipelineLayout ( VkDevice device , const VkAllocationCallbacks * allocator )
{
if ( g_PipelineLayout )
return ;
// Constants: we are using 'vec2 offset' and 'vec2 scale' instead of a full 3d projection matrix
ImGui_ImplVulkan_CreateDescriptorSetLayout ( device , allocator ) ;
VkPushConstantRange push_constants [ 1 ] = { } ;
push_constants [ 0 ] . stageFlags = VK_SHADER_STAGE_VERTEX_BIT ;
push_constants [ 0 ] . offset = sizeof ( float ) * 0 ;
push_constants [ 0 ] . size = sizeof ( float ) * 4 ;
VkDescriptorSetLayout set_layout [ 1 ] = { g_DescriptorSetLayout } ;
VkPipelineLayoutCreateInfo layout_info = { } ;
layout_info . sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO ;
layout_info . setLayoutCount = 1 ;
layout_info . pSetLayouts = set_layout ;
layout_info . pushConstantRangeCount = 1 ;
layout_info . pPushConstantRanges = push_constants ;
VkResult err = vkCreatePipelineLayout ( device , & layout_info , allocator , & g_PipelineLayout ) ;
check_vk_result ( err ) ;
}
static void ImGui_ImplVulkan_CreatePipeline ( VkDevice device , const VkAllocationCallbacks * allocator , VkPipelineCache pipelineCache , VkRenderPass renderPass , VkSampleCountFlagBits MSAASamples , VkPipeline * pipeline )
{
ImGui_ImplVulkan_CreateShaderModules ( device , allocator ) ;
VkPipelineShaderStageCreateInfo stage [ 2 ] = { } ;
stage [ 0 ] . sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO ;
stage [ 0 ] . stage = VK_SHADER_STAGE_VERTEX_BIT ;
stage [ 0 ] . module = vert_module ;
stage [ 0 ] . module = g_ShaderModuleVert ;
stage [ 0 ] . pName = " main " ;
stage [ 1 ] . sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO ;
stage [ 1 ] . stage = VK_SHADER_STAGE_FRAGMENT_BIT ;
stage [ 1 ] . module = frag_module ;
stage [ 1 ] . module = g_ShaderModuleFrag ;
stage [ 1 ] . pName = " main " ;
VkVertexInputBindingDescription binding_desc [ 1 ] = { } ;
@ -724,10 +733,7 @@ bool ImGui_ImplVulkan_CreateDeviceObjects()
VkPipelineMultisampleStateCreateInfo ms_info = { } ;
ms_info . sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO ;
if ( v - > MSAASamples ! = 0 )
ms_info . rasterizationSamples = v - > MSAASamples ;
else
ms_info . rasterizationSamples = VK_SAMPLE_COUNT_1_BIT ;
ms_info . rasterizationSamples = ( MSAASamples ! = 0 ) ? MSAASamples : VK_SAMPLE_COUNT_1_BIT ;
VkPipelineColorBlendAttachmentState color_attachment [ 1 ] = { } ;
color_attachment [ 0 ] . blendEnable = VK_TRUE ;
@ -753,6 +759,8 @@ bool ImGui_ImplVulkan_CreateDeviceObjects()
dynamic_state . dynamicStateCount = ( uint32_t ) IM_ARRAYSIZE ( dynamic_states ) ;
dynamic_state . pDynamicStates = dynamic_states ;
ImGui_ImplVulkan_CreatePipelineLayout ( device , allocator ) ;
VkGraphicsPipelineCreateInfo info = { } ;
info . sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO ;
info . flags = g_PipelineCreateFlags ;
@ -767,9 +775,97 @@ bool ImGui_ImplVulkan_CreateDeviceObjects()
info . pColorBlendState = & blend_info ;
info . pDynamicState = & dynamic_state ;
info . layout = g_PipelineLayout ;
info . renderPass = g_R enderPass;
err = vkCreateGraphicsPipelines ( v - > D evice, v - > P ipelineCache, 1 , & info , v - > A llocator, & g_P ipeline) ;
info . renderPass = r enderPass;
VkResult err = vkCreateGraphicsPipelines ( d evice, p ipelineCache, 1 , & info , a llocator, p ipeline) ;
check_vk_result ( err ) ;
}
bool ImGui_ImplVulkan_CreateDeviceObjects ( )
{
ImGui_ImplVulkan_InitInfo * v = & g_VulkanInitInfo ;
VkResult err ;
VkShaderModule vert_module ;
VkShaderModule frag_module ;
// Create The Shader Modules:
{
VkShaderModuleCreateInfo vert_info = { } ;
vert_info . sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO ;
vert_info . codeSize = sizeof ( __glsl_shader_vert_spv ) ;
vert_info . pCode = ( uint32_t * ) __glsl_shader_vert_spv ;
err = vkCreateShaderModule ( v - > Device , & vert_info , v - > Allocator , & vert_module ) ;
check_vk_result ( err ) ;
VkShaderModuleCreateInfo frag_info = { } ;
frag_info . sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO ;
frag_info . codeSize = sizeof ( __glsl_shader_frag_spv ) ;
frag_info . pCode = ( uint32_t * ) __glsl_shader_frag_spv ;
err = vkCreateShaderModule ( v - > Device , & frag_info , v - > Allocator , & frag_module ) ;
check_vk_result ( err ) ;
}
if ( ! g_FontSampler )
{
VkSamplerCreateInfo info = { } ;
info . sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO ;
info . magFilter = VK_FILTER_LINEAR ;
info . minFilter = VK_FILTER_LINEAR ;
info . mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR ;
info . addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT ;
info . addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT ;
info . addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT ;
info . minLod = - 1000 ;
info . maxLod = 1000 ;
info . maxAnisotropy = 1.0f ;
err = vkCreateSampler ( v - > Device , & info , v - > Allocator , & g_FontSampler ) ;
check_vk_result ( err ) ;
}
if ( ! g_DescriptorSetLayout )
{
VkSampler sampler [ 1 ] = { g_FontSampler } ;
VkDescriptorSetLayoutBinding binding [ 1 ] = { } ;
binding [ 0 ] . descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ;
binding [ 0 ] . descriptorCount = 1 ;
binding [ 0 ] . stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT ;
binding [ 0 ] . pImmutableSamplers = sampler ;
VkDescriptorSetLayoutCreateInfo info = { } ;
info . sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO ;
info . bindingCount = 1 ;
info . pBindings = binding ;
err = vkCreateDescriptorSetLayout ( v - > Device , & info , v - > Allocator , & g_DescriptorSetLayout ) ;
check_vk_result ( err ) ;
}
// Create Descriptor Set:
{
VkDescriptorSetAllocateInfo alloc_info = { } ;
alloc_info . sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO ;
alloc_info . descriptorPool = v - > DescriptorPool ;
alloc_info . descriptorSetCount = 1 ;
alloc_info . pSetLayouts = & g_DescriptorSetLayout ;
err = vkAllocateDescriptorSets ( v - > Device , & alloc_info , & g_DescriptorSet ) ;
check_vk_result ( err ) ;
}
if ( ! g_PipelineLayout )
{
// Constants: we are using 'vec2 offset' and 'vec2 scale' instead of a full 3d projection matrix
VkPushConstantRange push_constants [ 1 ] = { } ;
push_constants [ 0 ] . stageFlags = VK_SHADER_STAGE_VERTEX_BIT ;
push_constants [ 0 ] . offset = sizeof ( float ) * 0 ;
push_constants [ 0 ] . size = sizeof ( float ) * 4 ;
VkDescriptorSetLayout set_layout [ 1 ] = { g_DescriptorSetLayout } ;
VkPipelineLayoutCreateInfo layout_info = { } ;
layout_info . sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO ;
layout_info . setLayoutCount = 1 ;
layout_info . pSetLayouts = set_layout ;
layout_info . pushConstantRangeCount = 1 ;
layout_info . pPushConstantRanges = push_constants ;
err = vkCreatePipelineLayout ( v - > Device , & layout_info , v - > Allocator , & g_PipelineLayout ) ;
check_vk_result ( err ) ;
}
ImGui_ImplVulkan_CreatePipeline ( v - > Device , v - > Allocator , v - > PipelineCache , g_RenderPass , v - > MSAASamples , & g_Pipeline ) ;
vkDestroyShaderModule ( v - > Device , vert_module , v - > Allocator ) ;
vkDestroyShaderModule ( v - > Device , frag_module , v - > Allocator ) ;
@ -1017,6 +1113,8 @@ void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, V
wd - > ImageCount = 0 ;
if ( wd - > RenderPass )
vkDestroyRenderPass ( device , wd - > RenderPass , allocator ) ;
if ( wd - > Pipeline )
vkDestroyPipeline ( device , wd - > Pipeline , allocator ) ;
// If min image count was not specified, request different count of images dependent on selected present mode
if ( min_image_count = = 0 )
@ -1112,6 +1210,7 @@ void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, V
info . pDependencies = & dependency ;
err = vkCreateRenderPass ( device , & info , allocator , & wd - > RenderPass ) ;
check_vk_result ( err ) ;
ImGui_ImplVulkan_CreatePipeline ( device , allocator , VK_NULL_HANDLE , wd - > RenderPass , VK_SAMPLE_COUNT_1_BIT , & wd - > Pipeline ) ;
}
// Create The Image Views