mirror of
https://github.com/ocornut/imgui.git
synced 2026-11-06 06:25:54 +01:00
Merge 89601b2a64704d664a9a8a52774f735f0ae6538f into 4dbb921b228c33a78eca4914898709b7ac93671e
This commit is contained in:
commit
61d5a3e830
@ -2,7 +2,7 @@
|
||||
// This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..)
|
||||
|
||||
// Implemented features:
|
||||
// [!] Renderer: User texture binding. Use a VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE 'VkDescriptorSet' as texture identifier. Call ImGui_ImplVulkan_AddTexture() to register one. Read the FAQ about ImTextureID/ImTextureRef + https://github.com/ocornut/imgui/pull/914 for discussions.
|
||||
// [!] Renderer: User texture binding. Pool mode: use a VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE 'VkDescriptorSet' as texture identifier (ImGui_ImplVulkan_AddTexture()). Descriptor-heap mode (VK_EXT_descriptor_heap): use a heap index (ImTextureID); index 0 is reserved (ImTextureID_Invalid). Read the FAQ about ImTextureID/ImTextureRef + https://github.com/ocornut/imgui/pull/914 for discussions.
|
||||
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
|
||||
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
|
||||
// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
|
||||
@ -27,6 +27,7 @@
|
||||
|
||||
// CHANGELOG
|
||||
// (minor and older changes stripped away, please see git history for details)
|
||||
// 2026-08-05: Vulkan: Added optional VK_EXT_descriptor_heap support via ImGui_ImplVulkan_InitInfo::DescriptorHeapInfo (app-owned Register*/UnRegister* callbacks). ImTextureID is a non-zero heap index. Requires IMGUI_IMPL_VULKAN_HAS_DESCRIPTOR_HEAP (headers with VK_EXT_descriptor_heap). (#9374)
|
||||
// 2026-04-23: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. (#9378)
|
||||
// 2026-04-22: *BREAKING CHANGE* redesigned to use separate ImageView + Sampler instead of Combined Image Sampler. This change allows us to facilitate changing samplers, in line with other backends.
|
||||
// - When registering custom textures: changed ImGui_ImplVulkan_AddTexture() signature to remove Sampler.
|
||||
@ -241,6 +242,11 @@ static PFN_vkCmdBeginRenderingKHR ImGuiImplVulkanFuncs_vkCmdBeginRenderingKHR;
|
||||
static PFN_vkCmdEndRenderingKHR ImGuiImplVulkanFuncs_vkCmdEndRenderingKHR;
|
||||
#endif
|
||||
|
||||
#ifdef IMGUI_IMPL_VULKAN_HAS_DESCRIPTOR_HEAP
|
||||
// VK_EXT_descriptor_heap (not exported by most Vulkan loaders; resolve like dynamic rendering)
|
||||
static PFN_vkCmdPushDataEXT ImGuiImplVulkanFuncs_vkCmdPushDataEXT = nullptr;
|
||||
#endif
|
||||
|
||||
// Reusable buffers used for rendering 1 current in-flight frame, for ImGui_ImplVulkan_RenderDrawData()
|
||||
// [Please zero-clear before use!]
|
||||
struct ImGui_ImplVulkan_FrameRenderBuffers
|
||||
@ -268,6 +274,7 @@ struct ImGui_ImplVulkan_Texture
|
||||
VkImage Image;
|
||||
VkImageView ImageView;
|
||||
VkDescriptorSet DescriptorSet;
|
||||
uint32_t DescriptorHeapIndex;
|
||||
|
||||
ImGui_ImplVulkan_Texture() { memset((void*)this, 0, sizeof(*this)); }
|
||||
};
|
||||
@ -296,6 +303,8 @@ struct ImGui_ImplVulkan_Data
|
||||
VkDescriptorSet SamplerNearestDS;
|
||||
VkCommandPool TexCommandPool;
|
||||
VkCommandBuffer TexCommandBuffer;
|
||||
uint32_t DescriptorHeapSamplerLinear;
|
||||
uint32_t DescriptorHeapSamplerNearest;
|
||||
|
||||
// Render buffers for main window
|
||||
ImGui_ImplVulkan_WindowRenderBuffers MainWindowRenderBuffers;
|
||||
@ -422,6 +431,78 @@ static uint32_t __glsl_shader_frag_spv[] =
|
||||
0x00010038
|
||||
};
|
||||
|
||||
// backends/vulkan/glsl_shader_heap.frag, compiled with:
|
||||
// # glslangValidator -V --target-env spirv1.2 -x -o glsl_shader.frag.u32 glsl_shader.frag
|
||||
#ifdef IMGUI_IMPL_VULKAN_HAS_DESCRIPTOR_HEAP
|
||||
/*
|
||||
#version 460 core
|
||||
#extension GL_EXT_descriptor_heap : require
|
||||
#extension GL_EXT_nonuniform_qualifier : require
|
||||
|
||||
layout(location = 0) out vec4 fColor;
|
||||
layout(descriptor_heap) uniform texture2D _Textures[];
|
||||
layout(descriptor_heap) uniform sampler _Samplers[];
|
||||
layout(location = 0) in struct { vec4 Color; vec2 UV; } In;
|
||||
layout(push_constant) uniform uPushConstant { vec2 uScale; vec2 uTranslate; uvec2 uID; } pc;
|
||||
void main()
|
||||
{
|
||||
fColor = In.Color * texture(sampler2D(_Textures[pc.uID.x], _Samplers[pc.uID.y]), In.UV.st);
|
||||
}
|
||||
*/
|
||||
static uint32_t __glsl_shader_heap_frag_spv[] =
|
||||
{
|
||||
0x07230203,0x00010200,0x0008000b,0x00000036,0x00000000,0x00020011,0x00000001,0x00020011,
|
||||
0x00001179,0x00020011,0x00001408,0x0007000a,0x5f565053,0x5f545845,0x63736564,0x74706972,
|
||||
0x685f726f,0x00706165,0x0008000a,0x5f565053,0x5f52484b,0x79746e75,0x5f646570,0x6e696f70,
|
||||
0x73726574,0x00000000,0x0006000b,0x00000001,0x4c534c47,0x6474732e,0x3035342e,0x00000000,
|
||||
0x0003000e,0x00000000,0x00000001,0x0007000f,0x00000004,0x00000004,0x6e69616d,0x00000000,
|
||||
0x00000009,0x0000000d,0x00030010,0x00000004,0x00000007,0x00030003,0x00000002,0x000001cc,
|
||||
0x00070004,0x455f4c47,0x645f5458,0x72637365,0x6f747069,0x65685f72,0x00007061,0x00080004,
|
||||
0x455f4c47,0x6e5f5458,0x6e756e6f,0x726f6669,0x75715f6d,0x66696c61,0x00726569,0x00040005,
|
||||
0x00000004,0x6e69616d,0x00000000,0x00040005,0x00000009,0x6c6f4366,0x0000726f,0x00030005,
|
||||
0x0000000b,0x00000000,0x00050006,0x0000000b,0x00000000,0x6f6c6f43,0x00000072,0x00040006,
|
||||
0x0000000b,0x00000001,0x00005655,0x00030005,0x0000000d,0x00006e49,0x00060005,0x00000014,
|
||||
0x6f736572,0x65637275,0x6165685f,0x00000070,0x00060005,0x00000017,0x73755075,0x6e6f4368,
|
||||
0x6e617473,0x00000074,0x00050006,0x00000017,0x00000000,0x61635375,0x0000656c,0x00060006,
|
||||
0x00000017,0x00000001,0x61725475,0x616c736e,0x00006574,0x00040006,0x00000017,0x00000002,
|
||||
0x00444975,0x00030005,0x00000019,0x00006370,0x00060005,0x00000025,0x706d6173,0x5f72656c,
|
||||
0x70616568,0x00000000,0x00040047,0x00000009,0x0000001e,0x00000000,0x00040047,0x0000000d,
|
||||
0x0000001e,0x00000000,0x00040047,0x00000014,0x0000000b,0x00001403,0x00030047,0x00000017,
|
||||
0x00000002,0x00050048,0x00000017,0x00000000,0x00000023,0x00000000,0x00050048,0x00000017,
|
||||
0x00000001,0x00000023,0x00000008,0x00050048,0x00000017,0x00000002,0x00000023,0x00000010,
|
||||
0x0004014c,0x00000023,0x00001404,0x00000022,0x00040047,0x00000025,0x0000000b,0x00001402,
|
||||
0x0004014c,0x0000002c,0x00001404,0x0000002b,0x00020013,0x00000002,0x00030021,0x00000003,
|
||||
0x00000002,0x00030016,0x00000006,0x00000020,0x00040017,0x00000007,0x00000006,0x00000004,
|
||||
0x00040020,0x00000008,0x00000003,0x00000007,0x0004003b,0x00000008,0x00000009,0x00000003,
|
||||
0x00040017,0x0000000a,0x00000006,0x00000002,0x0004001e,0x0000000b,0x00000007,0x0000000a,
|
||||
0x00040020,0x0000000c,0x00000001,0x0000000b,0x0004003b,0x0000000c,0x0000000d,0x00000001,
|
||||
0x00040015,0x0000000e,0x00000020,0x00000001,0x0004002b,0x0000000e,0x0000000f,0x00000000,
|
||||
0x00040020,0x00000010,0x00000001,0x00000007,0x00031141,0x00000013,0x00000000,0x00041142,
|
||||
0x00000013,0x00000014,0x00000000,0x00040015,0x00000015,0x00000020,0x00000000,0x00040017,
|
||||
0x00000016,0x00000015,0x00000002,0x0005001e,0x00000017,0x0000000a,0x0000000a,0x00000016,
|
||||
0x00040020,0x00000018,0x00000009,0x00000017,0x0004003b,0x00000018,0x00000019,0x00000009,
|
||||
0x0004002b,0x0000000e,0x0000001a,0x00000002,0x0004002b,0x00000015,0x0000001b,0x00000000,
|
||||
0x00040020,0x0000001c,0x00000009,0x00000015,0x00090019,0x0000001f,0x00000006,0x00000001,
|
||||
0x00000000,0x00000000,0x00000000,0x00000001,0x00000000,0x00031141,0x00000020,0x00000002,
|
||||
0x00041409,0x0000000e,0x00000022,0x0000001f,0x0003001d,0x00000023,0x0000001f,0x00041142,
|
||||
0x00000013,0x00000025,0x00000000,0x0004002b,0x00000015,0x00000026,0x00000001,0x0002001a,
|
||||
0x00000029,0x00041409,0x0000000e,0x0000002b,0x00000029,0x0003001d,0x0000002c,0x00000029,
|
||||
0x0003001b,0x0000002e,0x0000001f,0x0004002b,0x0000000e,0x00000030,0x00000001,0x00040020,
|
||||
0x00000031,0x00000001,0x0000000a,0x00050036,0x00000002,0x00000004,0x00000000,0x00000003,
|
||||
0x000200f8,0x00000005,0x00050041,0x00000010,0x00000011,0x0000000d,0x0000000f,0x0004003d,
|
||||
0x00000007,0x00000012,0x00000011,0x00060041,0x0000001c,0x0000001d,0x00000019,0x0000001a,
|
||||
0x0000001b,0x0004003d,0x00000015,0x0000001e,0x0000001d,0x00061143,0x00000013,0x00000021,
|
||||
0x00000023,0x00000014,0x0000001e,0x0004003d,0x0000001f,0x00000024,0x00000021,0x00060041,
|
||||
0x0000001c,0x00000027,0x00000019,0x0000001a,0x00000026,0x0004003d,0x00000015,0x00000028,
|
||||
0x00000027,0x00061143,0x00000013,0x0000002a,0x0000002c,0x00000025,0x00000028,0x0004003d,
|
||||
0x00000029,0x0000002d,0x0000002a,0x00050056,0x0000002e,0x0000002f,0x00000024,0x0000002d,
|
||||
0x00050041,0x00000031,0x00000032,0x0000000d,0x00000030,0x0004003d,0x0000000a,0x00000033,
|
||||
0x00000032,0x00050057,0x00000007,0x00000034,0x0000002f,0x00000033,0x00050085,0x00000007,
|
||||
0x00000035,0x00000012,0x00000034,0x0003003e,0x00000009,0x00000035,0x000100fd,0x00010038
|
||||
};
|
||||
#endif // IMGUI_IMPL_VULKAN_HAS_DESCRIPTOR_HEAP
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// FUNCTIONS
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -522,23 +603,80 @@ static void ImGui_ImplVulkan_SetupRenderState(ImDrawData* draw_data, VkPipeline
|
||||
viewport.maxDepth = 1.0f;
|
||||
vkCmdSetViewport(command_buffer, 0, 1, &viewport);
|
||||
|
||||
// Setup scale and translation:
|
||||
// Our visible imgui space lies from draw_data->DisplayPps (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
|
||||
float constants[4];
|
||||
constants[0] = 2.0f / draw_data->DisplaySize.x; // Scale
|
||||
constants[1] = 2.0f / draw_data->DisplaySize.y;
|
||||
constants[2] = -1.0f - draw_data->DisplayPos.x * constants[0]; // Translate
|
||||
constants[3] = -1.0f - draw_data->DisplayPos.y * constants[1];
|
||||
vkCmdPushConstants(command_buffer, bd->PipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(float) * 4, constants);
|
||||
struct push_data
|
||||
{
|
||||
float constants[4];
|
||||
// First ID is texture, second is sampler.
|
||||
uint32_t ids[2];
|
||||
} pd;
|
||||
pd.constants[0] = 2.0f / draw_data->DisplaySize.x; // Scale
|
||||
pd.constants[1] = 2.0f / draw_data->DisplaySize.y;
|
||||
pd.constants[2] = -1.0f - draw_data->DisplayPos.x * pd.constants[0]; // Translate
|
||||
pd.constants[3] = -1.0f - draw_data->DisplayPos.y * pd.constants[1];
|
||||
#ifdef IMGUI_IMPL_VULKAN_HAS_DESCRIPTOR_HEAP
|
||||
if (bd->VulkanInitInfo.DescriptorHeapInfo)
|
||||
{
|
||||
pd.ids[0] = 0;
|
||||
pd.ids[1] = bd->DescriptorHeapSamplerLinear;
|
||||
|
||||
// Setup sampler
|
||||
vkCmdBindDescriptorSets(bd->RenderState->CommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 1, 1, &bd->SamplerLinearDS, 0, nullptr);
|
||||
VkPushDataInfoEXT push{};
|
||||
push.sType = VK_STRUCTURE_TYPE_PUSH_DATA_INFO_EXT;
|
||||
push.data.address = &pd;
|
||||
push.data.size = sizeof(pd);
|
||||
ImGuiImplVulkanFuncs_vkCmdPushDataEXT(bd->RenderState->CommandBuffer, &push);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
// Setup scale and translation:
|
||||
// Our visible imgui space lies from draw_data->DisplayPps (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
|
||||
vkCmdPushConstants(command_buffer, bd->PipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(float) * 4, pd.constants);
|
||||
|
||||
// Setup sampler
|
||||
vkCmdBindDescriptorSets(bd->RenderState->CommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 1, 1, &bd->SamplerLinearDS, 0, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw callbacks
|
||||
static void ImGui_ImplVulkan_DrawCallback_ResetRenderState(const ImDrawList*, const ImDrawCmd*) {} // Intentionally empty. Used as an identifier for rendering loop to call its code. Simpler to implement this way.
|
||||
static void ImGui_ImplVulkan_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); vkCmdBindDescriptorSets(bd->RenderState->CommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->RenderState->PipelineLayout, 1, 1, &bd->SamplerLinearDS, 0, nullptr); }
|
||||
static void ImGui_ImplVulkan_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*) { ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); vkCmdBindDescriptorSets(bd->RenderState->CommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->RenderState->PipelineLayout, 1, 1, &bd->SamplerNearestDS, 0, nullptr); }
|
||||
static void ImGui_ImplVulkan_DrawCallback_SetSamplerLinear(const ImDrawList*, const ImDrawCmd*)
|
||||
{
|
||||
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
|
||||
#ifdef IMGUI_IMPL_VULKAN_HAS_DESCRIPTOR_HEAP
|
||||
if (bd->VulkanInitInfo.DescriptorHeapInfo)
|
||||
{
|
||||
VkPushDataInfoEXT push{};
|
||||
push.sType = VK_STRUCTURE_TYPE_PUSH_DATA_INFO_EXT;
|
||||
push.data.address = &bd->DescriptorHeapSamplerLinear;
|
||||
push.data.size = 4;
|
||||
push.offset = 20;
|
||||
ImGuiImplVulkanFuncs_vkCmdPushDataEXT(bd->RenderState->CommandBuffer, &push);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
vkCmdBindDescriptorSets(bd->RenderState->CommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 1, 1, &bd->SamplerLinearDS, 0, nullptr);
|
||||
}
|
||||
}
|
||||
static void ImGui_ImplVulkan_DrawCallback_SetSamplerNearest(const ImDrawList*, const ImDrawCmd*)
|
||||
{
|
||||
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
|
||||
#ifdef IMGUI_IMPL_VULKAN_HAS_DESCRIPTOR_HEAP
|
||||
if (bd->VulkanInitInfo.DescriptorHeapInfo)
|
||||
{
|
||||
VkPushDataInfoEXT push{};
|
||||
push.sType = VK_STRUCTURE_TYPE_PUSH_DATA_INFO_EXT;
|
||||
push.data.address = &bd->DescriptorHeapSamplerNearest;
|
||||
push.data.size = 4;
|
||||
push.offset = 20;
|
||||
ImGuiImplVulkanFuncs_vkCmdPushDataEXT(bd->RenderState->CommandBuffer, &push);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
vkCmdBindDescriptorSets(bd->RenderState->CommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 1, 1, &bd->SamplerNearestDS, 0, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
// If you want to use your own sampler, you can create your own callback, access ImGui_ImplVulkan_RenderState for command-buffer and pipeline layout, e.g.
|
||||
/*
|
||||
@ -679,9 +817,29 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm
|
||||
vkCmdSetScissor(command_buffer, 0, 1, &scissor);
|
||||
|
||||
// Bind DescriptorSets for image view (font or user texture) and samplers
|
||||
VkDescriptorSet image_view = (VkDescriptorSet)pcmd->GetTexID();
|
||||
ImTextureID image_id = pcmd->GetTexID();
|
||||
VkDescriptorSet image_view = (VkDescriptorSet)image_id;
|
||||
if (image_view != last_image_view)
|
||||
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 0, 1, &image_view, 0, nullptr);
|
||||
{
|
||||
#ifdef IMGUI_IMPL_VULKAN_HAS_DESCRIPTOR_HEAP
|
||||
if (v->DescriptorHeapInfo)
|
||||
{
|
||||
// ImTextureID is the heap index. Index 0 is ImTextureID_Invalid / reserved.
|
||||
uint32_t heap_index = (uint32_t)(ImU64)image_id;
|
||||
IM_ASSERT(heap_index != 0 && "ImTextureID 0 is invalid in descriptor-heap mode (RegisterImage must not return 0)");
|
||||
VkPushDataInfoEXT push{};
|
||||
push.sType = VK_STRUCTURE_TYPE_PUSH_DATA_INFO_EXT;
|
||||
push.data.address = &heap_index;
|
||||
push.data.size = sizeof(heap_index);
|
||||
push.offset = 16;
|
||||
ImGuiImplVulkanFuncs_vkCmdPushDataEXT(command_buffer, &push);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 0, 1, &image_view, 0, nullptr);
|
||||
}
|
||||
}
|
||||
last_image_view = image_view;
|
||||
|
||||
// Draw
|
||||
@ -708,11 +866,21 @@ static void ImGui_ImplVulkan_DestroyTexture(ImTextureData* tex)
|
||||
{
|
||||
if (ImGui_ImplVulkan_Texture* backend_tex = (ImGui_ImplVulkan_Texture*)tex->BackendUserData)
|
||||
{
|
||||
IM_ASSERT(backend_tex->DescriptorSet == (VkDescriptorSet)tex->TexID);
|
||||
IM_ASSERT(backend_tex->DescriptorSet == (VkDescriptorSet)tex->TexID
|
||||
#ifdef IMGUI_IMPL_VULKAN_HAS_DESCRIPTOR_HEAP
|
||||
|| backend_tex->DescriptorHeapIndex == (uint32_t)(ImU64)tex->TexID
|
||||
#endif
|
||||
);
|
||||
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
|
||||
ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;
|
||||
ImGui_ImplVulkan_RemoveTexture(backend_tex->DescriptorSet);
|
||||
vkDestroyImageView(v->Device, backend_tex->ImageView, v->Allocator);
|
||||
if (backend_tex->DescriptorSet != VK_NULL_HANDLE)
|
||||
ImGui_ImplVulkan_RemoveTexture(backend_tex->DescriptorSet);
|
||||
#ifdef IMGUI_IMPL_VULKAN_HAS_DESCRIPTOR_HEAP
|
||||
else if (v->DescriptorHeapInfo)
|
||||
v->DescriptorHeapInfo->UnRegisterImage(v->DescriptorHeapInfo->UserContext, backend_tex->DescriptorHeapIndex);
|
||||
#endif
|
||||
if (backend_tex->ImageView != VK_NULL_HANDLE)
|
||||
vkDestroyImageView(v->Device, backend_tex->ImageView, v->Allocator);
|
||||
vkDestroyImage(v->Device, backend_tex->Image, v->Allocator);
|
||||
vkFreeMemory(v->Device, backend_tex->Memory, v->Allocator);
|
||||
IM_DELETE(backend_tex);
|
||||
@ -770,25 +938,35 @@ void ImGui_ImplVulkan_UpdateTexture(ImTextureData* tex)
|
||||
check_vk_result(err);
|
||||
}
|
||||
|
||||
// Create the Image View:
|
||||
VkImageViewCreateInfo info = {};
|
||||
info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
info.image = backend_tex->Image;
|
||||
info.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
info.format = VK_FORMAT_R8G8B8A8_UNORM;
|
||||
info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
info.subresourceRange.levelCount = 1;
|
||||
info.subresourceRange.layerCount = 1;
|
||||
#ifdef IMGUI_IMPL_VULKAN_HAS_DESCRIPTOR_HEAP
|
||||
if (v->DescriptorHeapInfo)
|
||||
{
|
||||
VkImageViewCreateInfo info = {};
|
||||
info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
info.image = backend_tex->Image;
|
||||
info.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
info.format = VK_FORMAT_R8G8B8A8_UNORM;
|
||||
info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
info.subresourceRange.levelCount = 1;
|
||||
info.subresourceRange.layerCount = 1;
|
||||
backend_tex->DescriptorHeapIndex =
|
||||
v->DescriptorHeapInfo->RegisterImage(v->DescriptorHeapInfo->UserContext, &info);
|
||||
IM_ASSERT(backend_tex->DescriptorHeapIndex != 0 && "RegisterImage must not return 0 (reserved as ImTextureID_Invalid)");
|
||||
tex->SetTexID((ImTextureID)(ImU64)backend_tex->DescriptorHeapIndex);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
// Create the Image View:
|
||||
err = vkCreateImageView(v->Device, &info, v->Allocator, &backend_tex->ImageView);
|
||||
check_vk_result(err);
|
||||
|
||||
// Create the Descriptor Set
|
||||
backend_tex->DescriptorSet = ImGui_ImplVulkan_AddTexture(backend_tex->ImageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
// Store identifiers
|
||||
tex->SetTexID((ImTextureID)backend_tex->DescriptorSet);
|
||||
}
|
||||
|
||||
// Create the Descriptor Set
|
||||
backend_tex->DescriptorSet = ImGui_ImplVulkan_AddTexture(backend_tex->ImageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
|
||||
// Store identifiers
|
||||
tex->SetTexID((ImTextureID)backend_tex->DescriptorSet);
|
||||
tex->BackendUserData = backend_tex;
|
||||
}
|
||||
|
||||
@ -952,6 +1130,13 @@ static void ImGui_ImplVulkan_CreateShaderModules(VkDevice device, const VkAlloca
|
||||
default_frag_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
||||
default_frag_info.codeSize = sizeof(__glsl_shader_frag_spv);
|
||||
default_frag_info.pCode = (uint32_t*)__glsl_shader_frag_spv;
|
||||
#ifdef IMGUI_IMPL_VULKAN_HAS_DESCRIPTOR_HEAP
|
||||
if (v->DescriptorHeapInfo)
|
||||
{
|
||||
default_frag_info.codeSize = sizeof(__glsl_shader_heap_frag_spv);
|
||||
default_frag_info.pCode = (uint32_t*)__glsl_shader_heap_frag_spv;
|
||||
}
|
||||
#endif
|
||||
VkShaderModuleCreateInfo* p_frag_info = (v->CustomShaderFragCreateInfo.sType == VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO) ? &v->CustomShaderFragCreateInfo : &default_frag_info;
|
||||
VkResult err = vkCreateShaderModule(device, p_frag_info, allocator, &bd->ShaderModuleFrag);
|
||||
check_vk_result(err);
|
||||
@ -1065,14 +1250,35 @@ static VkPipeline ImGui_ImplVulkan_CreatePipeline(VkDevice device, const VkAlloc
|
||||
create_info.renderPass = info->RenderPass;
|
||||
create_info.subpass = info->Subpass;
|
||||
|
||||
#ifdef IMGUI_IMPL_VULKAN_HAS_DESCRIPTOR_HEAP
|
||||
VkPipelineCreateFlags2CreateInfo ci_heap_flags{};
|
||||
ci_heap_flags.sType = VK_STRUCTURE_TYPE_PIPELINE_CREATE_FLAGS_2_CREATE_INFO;
|
||||
ci_heap_flags.flags = VK_PIPELINE_CREATE_2_DESCRIPTOR_HEAP_BIT_EXT;
|
||||
#endif
|
||||
|
||||
#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING
|
||||
VkPipelineRenderingCreateInfo pipeline_rendering_create_info = {};
|
||||
if (bd->VulkanInitInfo.UseDynamicRendering)
|
||||
{
|
||||
IM_ASSERT(info->PipelineRenderingCreateInfo.sType == VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR && "PipelineRenderingCreateInfo::sType must be VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR");
|
||||
IM_ASSERT(info->PipelineRenderingCreateInfo.pNext == nullptr && "PipelineRenderingCreateInfo::pNext must be nullptr");
|
||||
create_info.pNext = &info->PipelineRenderingCreateInfo;
|
||||
pipeline_rendering_create_info = info->PipelineRenderingCreateInfo;
|
||||
#ifdef IMGUI_IMPL_VULKAN_HAS_DESCRIPTOR_HEAP
|
||||
if (bd->VulkanInitInfo.DescriptorHeapInfo)
|
||||
pipeline_rendering_create_info.pNext = &ci_heap_flags;
|
||||
#endif
|
||||
create_info.pNext = &pipeline_rendering_create_info;
|
||||
create_info.renderPass = VK_NULL_HANDLE; // Just make sure it's actually nullptr.
|
||||
}
|
||||
#endif
|
||||
#ifdef IMGUI_IMPL_VULKAN_HAS_DESCRIPTOR_HEAP
|
||||
if (bd->VulkanInitInfo.DescriptorHeapInfo)
|
||||
{
|
||||
if (create_info.pNext == nullptr)
|
||||
{
|
||||
create_info.pNext = &ci_heap_flags;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
VkPipeline pipeline;
|
||||
VkResult err = vkCreateGraphicsPipelines(device, pipelineCache, 1, &create_info, allocator, &pipeline);
|
||||
@ -1169,17 +1375,39 @@ bool ImGui_ImplVulkan_CreateDeviceObjects()
|
||||
info.maxAnisotropy = 1.0f;
|
||||
err = vkCreateSampler(v->Device, &info, v->Allocator, &bd->SamplerLinear);
|
||||
check_vk_result(err);
|
||||
bd->SamplerLinearDS = ImGui_ImplVulkan_CreateSamplerDS(bd->SamplerLinear);
|
||||
#ifdef IMGUI_IMPL_VULKAN_HAS_DESCRIPTOR_HEAP
|
||||
if (v->DescriptorHeapInfo)
|
||||
{
|
||||
bd->DescriptorHeapSamplerLinear =
|
||||
v->DescriptorHeapInfo->RegisterSampler(v->DescriptorHeapInfo->UserContext, &info);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
bd->SamplerLinearDS = ImGui_ImplVulkan_CreateSamplerDS(bd->SamplerLinear);
|
||||
}
|
||||
|
||||
info.magFilter = VK_FILTER_NEAREST;
|
||||
info.minFilter = VK_FILTER_NEAREST;
|
||||
info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
||||
err = vkCreateSampler(v->Device, &info, v->Allocator, &bd->SamplerNearest);
|
||||
check_vk_result(err);
|
||||
bd->SamplerNearestDS = ImGui_ImplVulkan_CreateSamplerDS(bd->SamplerNearest);
|
||||
#ifdef IMGUI_IMPL_VULKAN_HAS_DESCRIPTOR_HEAP
|
||||
if (v->DescriptorHeapInfo)
|
||||
{
|
||||
bd->DescriptorHeapSamplerNearest =
|
||||
v->DescriptorHeapInfo->RegisterSampler(v->DescriptorHeapInfo->UserContext, &info);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
bd->SamplerNearestDS = ImGui_ImplVulkan_CreateSamplerDS(bd->SamplerNearest);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IMGUI_IMPL_VULKAN_HAS_DESCRIPTOR_HEAP
|
||||
if (!bd->PipelineLayout && !v->DescriptorHeapInfo)
|
||||
#else
|
||||
if (!bd->PipelineLayout)
|
||||
#endif
|
||||
{
|
||||
// Constants: we are using 'vec2 offset' and 'vec2 scale' instead of a full 3d projection matrix
|
||||
VkPushConstantRange push_constants[1] = {};
|
||||
@ -1278,6 +1506,13 @@ void ImGui_ImplVulkan_DestroyDeviceObjects()
|
||||
if (bd->PipelineLayout) { vkDestroyPipelineLayout(v->Device, bd->PipelineLayout, v->Allocator); bd->PipelineLayout = VK_NULL_HANDLE; }
|
||||
if (bd->Pipeline) { vkDestroyPipeline(v->Device, bd->Pipeline, v->Allocator); bd->Pipeline = VK_NULL_HANDLE; }
|
||||
if (bd->DescriptorPool) { vkDestroyDescriptorPool(v->Device, bd->DescriptorPool, v->Allocator); bd->DescriptorPool = VK_NULL_HANDLE; }
|
||||
#ifdef IMGUI_IMPL_VULKAN_HAS_DESCRIPTOR_HEAP
|
||||
if (v->DescriptorHeapInfo)
|
||||
{
|
||||
v->DescriptorHeapInfo->UnRegisterSampler(v->DescriptorHeapInfo->UserContext, bd->DescriptorHeapSamplerLinear);
|
||||
v->DescriptorHeapInfo->UnRegisterSampler(v->DescriptorHeapInfo->UserContext, bd->DescriptorHeapSamplerNearest);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING
|
||||
@ -1330,6 +1565,9 @@ bool ImGui_ImplVulkan_LoadFunctions(uint32_t api_version, PFN_vkVoidFunction(
|
||||
#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING
|
||||
ImGui_ImplVulkan_LoadDynamicRenderingFunctions(api_version, loader_func, user_data);
|
||||
#endif
|
||||
#ifdef IMGUI_IMPL_VULKAN_HAS_DESCRIPTOR_HEAP
|
||||
ImGuiImplVulkanFuncs_vkCmdPushDataEXT = reinterpret_cast<PFN_vkCmdPushDataEXT>(loader_func("vkCmdPushDataEXT", user_data));
|
||||
#endif
|
||||
#else
|
||||
IM_UNUSED(loader_func);
|
||||
IM_UNUSED(user_data);
|
||||
@ -1359,6 +1597,18 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info)
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef IMGUI_IMPL_VULKAN_HAS_DESCRIPTOR_HEAP
|
||||
if (info->DescriptorHeapInfo != nullptr)
|
||||
{
|
||||
#ifndef IMGUI_IMPL_VULKAN_USE_LOADER
|
||||
ImGuiImplVulkanFuncs_vkCmdPushDataEXT = reinterpret_cast<PFN_vkCmdPushDataEXT>(vkGetDeviceProcAddr(info->Device, "vkCmdPushDataEXT"));
|
||||
#endif
|
||||
IM_ASSERT(ImGuiImplVulkanFuncs_vkCmdPushDataEXT != nullptr && "vkCmdPushDataEXT not available (enable VK_EXT_descriptor_heap)");
|
||||
IM_ASSERT(info->DescriptorHeapInfo->RegisterImage != nullptr && info->DescriptorHeapInfo->UnRegisterImage != nullptr);
|
||||
IM_ASSERT(info->DescriptorHeapInfo->RegisterSampler != nullptr && info->DescriptorHeapInfo->UnRegisterSampler != nullptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
IMGUI_CHECKVERSION();
|
||||
IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!");
|
||||
@ -1382,6 +1632,11 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info)
|
||||
IM_ASSERT(info->Queue != VK_NULL_HANDLE);
|
||||
IM_ASSERT(info->MinImageCount >= 2);
|
||||
IM_ASSERT(info->ImageCount >= info->MinImageCount);
|
||||
#ifdef IMGUI_IMPL_VULKAN_HAS_DESCRIPTOR_HEAP
|
||||
if (info->DescriptorHeapInfo != nullptr) // If using descriptor heap then DescriptorPool and DescriptorPoolSize must be unset.
|
||||
IM_ASSERT(info->DescriptorPool == VK_NULL_HANDLE && info->DescriptorPoolSize == 0);
|
||||
else
|
||||
#endif
|
||||
if (info->DescriptorPool != VK_NULL_HANDLE) // Either DescriptorPool or DescriptorPoolSize must be set, not both!
|
||||
IM_ASSERT(info->DescriptorPoolSize == 0);
|
||||
else
|
||||
@ -1444,6 +1699,9 @@ VkDescriptorSet ImGui_ImplVulkan_AddTexture(VkImageView image_view, VkImageLayou
|
||||
{
|
||||
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
|
||||
ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;
|
||||
#ifdef IMGUI_IMPL_VULKAN_HAS_DESCRIPTOR_HEAP
|
||||
IM_ASSERT(v->DescriptorHeapInfo == nullptr && "ImGui_ImplVulkan_AddTexture() is unavailable when using DescriptorHeapInfo; use DescriptorHeapInfo::RegisterImage");
|
||||
#endif
|
||||
VkDescriptorPool pool = bd->DescriptorPool ? bd->DescriptorPool : v->DescriptorPool;
|
||||
|
||||
// Create Descriptor Set:
|
||||
@ -1487,16 +1745,35 @@ void ImGui_ImplVulkan_RemoveTexture(VkDescriptorSet descriptor_set)
|
||||
{
|
||||
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
|
||||
ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;
|
||||
#ifdef IMGUI_IMPL_VULKAN_HAS_DESCRIPTOR_HEAP
|
||||
IM_ASSERT(v->DescriptorHeapInfo == nullptr && "ImGui_ImplVulkan_RemoveTexture() is unavailable when using DescriptorHeapInfo; use DescriptorHeapInfo::UnRegisterImage");
|
||||
#endif
|
||||
VkDescriptorPool pool = bd->DescriptorPool ? bd->DescriptorPool : v->DescriptorPool;
|
||||
vkFreeDescriptorSets(v->Device, pool, 1, &descriptor_set);
|
||||
}
|
||||
|
||||
void ImGui_ImplVulkan_DestroyFrameRenderBuffers(VkDevice device, ImGui_ImplVulkan_FrameRenderBuffers* buffers, const VkAllocationCallbacks* allocator)
|
||||
{
|
||||
if (buffers->VertexBuffer) { vkDestroyBuffer(device, buffers->VertexBuffer, allocator); buffers->VertexBuffer = VK_NULL_HANDLE; }
|
||||
if (buffers->VertexBufferMemory) { vkFreeMemory(device, buffers->VertexBufferMemory, allocator); buffers->VertexBufferMemory = VK_NULL_HANDLE; }
|
||||
if (buffers->IndexBuffer) { vkDestroyBuffer(device, buffers->IndexBuffer, allocator); buffers->IndexBuffer = VK_NULL_HANDLE; }
|
||||
if (buffers->IndexBufferMemory) { vkFreeMemory(device, buffers->IndexBufferMemory, allocator); buffers->IndexBufferMemory = VK_NULL_HANDLE; }
|
||||
if (buffers->VertexBuffer)
|
||||
{
|
||||
vkDestroyBuffer(device, buffers->VertexBuffer, allocator);
|
||||
buffers->VertexBuffer = VK_NULL_HANDLE;
|
||||
}
|
||||
if (buffers->VertexBufferMemory)
|
||||
{
|
||||
vkFreeMemory(device, buffers->VertexBufferMemory, allocator);
|
||||
buffers->VertexBufferMemory = VK_NULL_HANDLE;
|
||||
}
|
||||
if (buffers->IndexBuffer)
|
||||
{
|
||||
vkDestroyBuffer(device, buffers->IndexBuffer, allocator);
|
||||
buffers->IndexBuffer = VK_NULL_HANDLE;
|
||||
}
|
||||
if (buffers->IndexBufferMemory)
|
||||
{
|
||||
vkFreeMemory(device, buffers->IndexBufferMemory, allocator);
|
||||
buffers->IndexBufferMemory = VK_NULL_HANDLE;
|
||||
}
|
||||
buffers->VertexBufferSize = 0;
|
||||
buffers->IndexBufferSize = 0;
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..)
|
||||
|
||||
// Implemented features:
|
||||
// [!] Renderer: User texture binding. Use a VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE 'VkDescriptorSet' as texture identifier. Call ImGui_ImplVulkan_AddTexture() to register one. Read the FAQ about ImTextureID/ImTextureRef + https://github.com/ocornut/imgui/pull/914 for discussions.
|
||||
// [!] Renderer: User texture binding. Pool mode: use a VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE 'VkDescriptorSet' as texture identifier (ImGui_ImplVulkan_AddTexture()). Descriptor-heap mode (VK_EXT_descriptor_heap): use a heap index (ImTextureID); index 0 is reserved (ImTextureID_Invalid). Read the FAQ about ImTextureID/ImTextureRef + https://github.com/ocornut/imgui/pull/914 for discussions.
|
||||
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
|
||||
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
|
||||
// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
|
||||
@ -76,6 +76,9 @@
|
||||
#if defined(VK_VERSION_1_3) || defined(VK_KHR_dynamic_rendering)
|
||||
#define IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING
|
||||
#endif
|
||||
#if defined(VK_EXT_descriptor_heap)
|
||||
#define IMGUI_IMPL_VULKAN_HAS_DESCRIPTOR_HEAP
|
||||
#endif
|
||||
|
||||
// Backend uses a small number of descriptors per font atlas + as many as additional calls done to ImGui_ImplVulkan_AddTexture().
|
||||
#define IMGUI_IMPL_VULKAN_MINIMUM_SAMPLED_IMAGE_POOL_SIZE (8) // Minimum per atlas
|
||||
@ -93,6 +96,19 @@ struct ImGui_ImplVulkan_PipelineInfo
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef IMGUI_IMPL_VULKAN_HAS_DESCRIPTOR_HEAP
|
||||
// App owns heap slots via Register*/UnRegister* (like DX12 SrvDescriptorAllocFn/FreeFn).
|
||||
// ImTextureID is the heap index returned by RegisterImage. Index 0 is reserved (ImTextureID_Invalid == 0).
|
||||
struct ImGui_ImplVulkan_DescriptorHeapInfo
|
||||
{
|
||||
uint32_t (*RegisterImage)(void*, const VkImageViewCreateInfo*); // Return non-zero heap index used as ImTextureID
|
||||
void (*UnRegisterImage)(void*, uint32_t);
|
||||
uint32_t (*RegisterSampler)(void*, const VkSamplerCreateInfo*); // Indices may be 0 (not used as ImTextureID)
|
||||
void (*UnRegisterSampler)(void*, uint32_t);
|
||||
void* UserContext;
|
||||
};
|
||||
#endif
|
||||
|
||||
// Initialization data, for ImGui_ImplVulkan_Init()
|
||||
// [Please zero-clear before use!]
|
||||
// - About descriptor pool:
|
||||
@ -101,6 +117,18 @@ struct ImGui_ImplVulkan_PipelineInfo
|
||||
// - As an convenience, by setting DescriptorPoolSize > 0 the backend will create one for you.
|
||||
// - About dynamic rendering:
|
||||
// - When using dynamic rendering, set UseDynamicRendering=true + fill PipelineInfoMain.PipelineRenderingCreateInfo structure.
|
||||
// - About descriptor heap (requires VK_EXT_descriptor_heap in your Vulkan headers → IMGUI_IMPL_VULKAN_HAS_DESCRIPTOR_HEAP):
|
||||
// - When using descriptor heaps, set DescriptorHeapInfo and leave DescriptorPool / DescriptorPoolSize unset.
|
||||
// - The application owns heap slots via Register*/UnRegister* callbacks.
|
||||
// - ImTextureID is the heap index returned by RegisterImage. Index 0 is reserved (conflicts with ImTextureID_Invalid).
|
||||
// - DescriptorHeapInfo pointer must remain valid for the backend lifetime.
|
||||
// - ImGui_ImplVulkan_AddTexture()/RemoveTexture() are pool-path only.
|
||||
// - Device extensions / features the application must enable:
|
||||
// - VK_EXT_descriptor_heap (feature: descriptorHeap).
|
||||
// - VK_KHR_maintenance5 (formal dependency of descriptor_heap; used for VkPipelineCreateFlags2 / DESCRIPTOR_HEAP pipeline flag).
|
||||
// - VK_KHR_buffer_device_address, or Vulkan 1.2+ where BDA is core (formal dependency; enable the bufferDeviceAddress feature either way).
|
||||
// - VK_KHR_shader_untyped_pointers (feature: shaderUntypedPointers): required by the default heap shaders (layout(descriptor_heap)).
|
||||
// Not a formal dependency of VK_EXT_descriptor_heap; mapping-based custom shaders could omit it.
|
||||
struct ImGui_ImplVulkan_InitInfo
|
||||
{
|
||||
uint32_t ApiVersion; // Fill with API version of Instance, e.g. VK_API_VERSION_1_3 or your value of VkApplicationInfo::apiVersion. May be lower than header version (VK_HEADER_VERSION_COMPLETE)
|
||||
@ -136,6 +164,13 @@ struct ImGui_ImplVulkan_InitInfo
|
||||
// - Shader inputs/outputs need to match ours. Code/data pointed to by the structure needs to survive for whole during of backend usage.
|
||||
VkShaderModuleCreateInfo CustomShaderVertCreateInfo;
|
||||
VkShaderModuleCreateInfo CustomShaderFragCreateInfo;
|
||||
|
||||
#ifdef IMGUI_IMPL_VULKAN_HAS_DESCRIPTOR_HEAP
|
||||
// (Optional) If set, use VK_EXT_descriptor_heap (app-owned Register*/UnRegister* callbacks; see comment above).
|
||||
// ImTextureID = RegisterImage(...) heap index (non-zero). ImGui_ImplVulkan_AddTexture() is unavailable in this mode.
|
||||
// App must enable the device extensions/features listed under "About descriptor heap".
|
||||
const ImGui_ImplVulkan_DescriptorHeapInfo *DescriptorHeapInfo;
|
||||
#endif
|
||||
};
|
||||
|
||||
// Follow "Getting Started" link and check examples/ folder to learn about using backends!
|
||||
@ -154,6 +189,8 @@ IMGUI_IMPL_API void ImGui_ImplVulkan_CreateMainPipeline(const ImGui_
|
||||
IMGUI_IMPL_API void ImGui_ImplVulkan_UpdateTexture(ImTextureData* tex);
|
||||
|
||||
// Register a texture (VkDescriptorSet for a VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE == ImTextureID)
|
||||
// - Pool path only. Not available when InitInfo::DescriptorHeapInfo is set (asserts).
|
||||
// - Heap mode: ImTextureID = DescriptorHeapInfo::RegisterImage(...) heap index; free with UnRegisterImage.
|
||||
IMGUI_IMPL_API VkDescriptorSet ImGui_ImplVulkan_AddTexture(VkImageView image_view, VkImageLayout image_layout);
|
||||
IMGUI_IMPL_API void ImGui_ImplVulkan_RemoveTexture(VkDescriptorSet descriptor_set);
|
||||
|
||||
|
||||
@ -4,3 +4,4 @@
|
||||
## -o: output file
|
||||
glslangValidator -V -x -o glsl_shader.frag.u32 glsl_shader.frag
|
||||
glslangValidator -V -x -o glsl_shader.vert.u32 glsl_shader.vert
|
||||
glslangValidator -V --target-env spirv1.2 -x -o glsl_shader_heap.frag.u32 glsl_shader_heap.frag
|
||||
|
||||
18
backends/vulkan/glsl_shader_heap.frag
Normal file
18
backends/vulkan/glsl_shader_heap.frag
Normal file
@ -0,0 +1,18 @@
|
||||
#version 460 core
|
||||
#extension GL_EXT_descriptor_heap : require
|
||||
#extension GL_EXT_nonuniform_qualifier : require
|
||||
layout(location = 0) out vec4 fColor;
|
||||
|
||||
layout(descriptor_heap) uniform texture2D _Textures[];
|
||||
layout(descriptor_heap) uniform sampler _Samplers[];
|
||||
|
||||
layout(location = 0) in struct {
|
||||
vec4 Color;
|
||||
vec2 UV;
|
||||
} In;
|
||||
|
||||
layout(push_constant) uniform uPushConstant { vec2 uScale; vec2 uTranslate; uvec2 uID; } pc;
|
||||
void main()
|
||||
{
|
||||
fColor = In.Color * texture(sampler2D(_Textures[pc.uID.x], _Samplers[pc.uID.y]), In.UV.st);
|
||||
}
|
||||
@ -41,6 +41,144 @@
|
||||
static VkDebugReportCallbackEXT g_DebugReport = VK_NULL_HANDLE;
|
||||
#endif
|
||||
|
||||
static void check_vk_result(VkResult err);
|
||||
|
||||
#ifdef IMGUI_IMPL_VULKAN_HAS_DESCRIPTOR_HEAP
|
||||
// Config for example app
|
||||
static const int APP_RESOURCE_HEAP_SIZE = 64;
|
||||
static const int APP_SAMPLER_HEAP_SIZE = 64;
|
||||
|
||||
// Explicitly loaded VK_EXT_descriptor_heap entry points.
|
||||
// Stored as members so names can match the Vulkan entry points without colliding with prototypes.
|
||||
struct DescriptorHeapFunctions
|
||||
{
|
||||
PFN_vkWriteResourceDescriptorsEXT vkWriteResourceDescriptorsEXT = nullptr;
|
||||
PFN_vkCmdBindResourceHeapEXT vkCmdBindResourceHeapEXT = nullptr;
|
||||
PFN_vkCmdBindSamplerHeapEXT vkCmdBindSamplerHeapEXT = nullptr;
|
||||
PFN_vkWriteSamplerDescriptorsEXT vkWriteSamplerDescriptorsEXT = nullptr;
|
||||
PFN_vkGetBufferDeviceAddress vkGetBufferDeviceAddress = nullptr;
|
||||
|
||||
void Load(VkDevice device)
|
||||
{
|
||||
vkWriteResourceDescriptorsEXT = reinterpret_cast<PFN_vkWriteResourceDescriptorsEXT>(vkGetDeviceProcAddr(device, "vkWriteResourceDescriptorsEXT"));
|
||||
vkCmdBindResourceHeapEXT = reinterpret_cast<PFN_vkCmdBindResourceHeapEXT>(vkGetDeviceProcAddr(device, "vkCmdBindResourceHeapEXT"));
|
||||
vkCmdBindSamplerHeapEXT = reinterpret_cast<PFN_vkCmdBindSamplerHeapEXT>(vkGetDeviceProcAddr(device, "vkCmdBindSamplerHeapEXT"));
|
||||
vkWriteSamplerDescriptorsEXT = reinterpret_cast<PFN_vkWriteSamplerDescriptorsEXT>(vkGetDeviceProcAddr(device, "vkWriteSamplerDescriptorsEXT"));
|
||||
vkGetBufferDeviceAddress = reinterpret_cast<PFN_vkGetBufferDeviceAddress>(vkGetDeviceProcAddr(device, "vkGetBufferDeviceAddress"));
|
||||
if (vkGetBufferDeviceAddress == nullptr)
|
||||
vkGetBufferDeviceAddress = reinterpret_cast<PFN_vkGetBufferDeviceAddress>(vkGetDeviceProcAddr(device, "vkGetBufferDeviceAddressKHR"));
|
||||
IM_ASSERT(vkWriteResourceDescriptorsEXT && vkCmdBindResourceHeapEXT && vkCmdBindSamplerHeapEXT && vkWriteSamplerDescriptorsEXT && vkGetBufferDeviceAddress);
|
||||
}
|
||||
};
|
||||
static DescriptorHeapFunctions g_DescHeapFns;
|
||||
|
||||
// Simple free-list allocator modeled after example_win32_directx12
|
||||
struct ExampleDescriptorHeapAllocator
|
||||
{
|
||||
VkBuffer Buffer = VK_NULL_HANDLE;
|
||||
VkDeviceMemory Memory = VK_NULL_HANDLE;
|
||||
void* Mapped = nullptr;
|
||||
VkBindHeapInfoEXT BindInfo = {};
|
||||
VkDeviceSize Stride = 0;
|
||||
int Capacity = 0;
|
||||
ImVector<int> FreeIndices;
|
||||
|
||||
void Create(VkDevice device, VkPhysicalDevice physical_device, VkDeviceSize descriptor_size, VkDeviceSize alignment, VkDeviceSize reserved_range, int capacity, const VkAllocationCallbacks* allocator)
|
||||
{
|
||||
IM_ASSERT(Buffer == VK_NULL_HANDLE && FreeIndices.empty());
|
||||
Capacity = capacity;
|
||||
Stride = descriptor_size;
|
||||
|
||||
VkDeviceSize descriptors_bytes = descriptor_size * (VkDeviceSize)capacity;
|
||||
VkDeviceSize total_size = descriptors_bytes + reserved_range;
|
||||
VkDeviceSize buffer_size_aligned = (total_size + alignment - 1) & ~(alignment - 1);
|
||||
|
||||
VkBufferCreateInfo buffer_info = {};
|
||||
buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||
buffer_info.size = buffer_size_aligned;
|
||||
buffer_info.usage = VK_BUFFER_USAGE_DESCRIPTOR_HEAP_BIT_EXT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
|
||||
buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
VkResult err = vkCreateBuffer(device, &buffer_info, allocator, &Buffer);
|
||||
check_vk_result(err);
|
||||
|
||||
VkMemoryRequirements mem_req;
|
||||
vkGetBufferMemoryRequirements(device, Buffer, &mem_req);
|
||||
|
||||
VkPhysicalDeviceMemoryProperties mem_props;
|
||||
vkGetPhysicalDeviceMemoryProperties(physical_device, &mem_props);
|
||||
const VkMemoryPropertyFlags required_flags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
|
||||
uint32_t mem_index = (uint32_t)-1;
|
||||
for (uint32_t i = 0; i < mem_props.memoryTypeCount; i++)
|
||||
{
|
||||
if ((mem_req.memoryTypeBits & (1u << i)) == 0)
|
||||
continue;
|
||||
if ((mem_props.memoryTypes[i].propertyFlags & required_flags) == required_flags)
|
||||
{
|
||||
mem_index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
IM_ASSERT(mem_index != (uint32_t)-1 && "No HOST_VISIBLE|HOST_COHERENT memory type compatible with descriptor heap buffer");
|
||||
|
||||
VkMemoryAllocateFlagsInfo alloc_flags = {};
|
||||
alloc_flags.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO;
|
||||
alloc_flags.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;
|
||||
VkMemoryAllocateInfo alloc_info = {};
|
||||
alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
alloc_info.pNext = &alloc_flags;
|
||||
alloc_info.allocationSize = mem_req.size > buffer_size_aligned ? mem_req.size : buffer_size_aligned;
|
||||
alloc_info.memoryTypeIndex = mem_index;
|
||||
err = vkAllocateMemory(device, &alloc_info, allocator, &Memory);
|
||||
check_vk_result(err);
|
||||
err = vkMapMemory(device, Memory, 0, alloc_info.allocationSize, 0, &Mapped);
|
||||
check_vk_result(err);
|
||||
err = vkBindBufferMemory(device, Buffer, Memory, 0);
|
||||
check_vk_result(err);
|
||||
|
||||
VkBufferDeviceAddressInfo addr_info = {};
|
||||
addr_info.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO;
|
||||
addr_info.buffer = Buffer;
|
||||
|
||||
BindInfo = {};
|
||||
BindInfo.sType = VK_STRUCTURE_TYPE_BIND_HEAP_INFO_EXT;
|
||||
BindInfo.heapRange.address = g_DescHeapFns.vkGetBufferDeviceAddress(device, &addr_info);
|
||||
BindInfo.heapRange.size = total_size;
|
||||
BindInfo.reservedRangeOffset = descriptors_bytes;
|
||||
BindInfo.reservedRangeSize = reserved_range;
|
||||
|
||||
FreeIndices.reserve(capacity > 1 ? capacity - 1 : 0);
|
||||
// Slot 0 reserved: ImTextureID_Invalid is 0, so RegisterImage indices used as ImTextureID must be non-zero.
|
||||
for (int n = capacity - 1; n >= 1; n--)
|
||||
FreeIndices.push_back(n);
|
||||
}
|
||||
void Destroy(VkDevice device, const VkAllocationCallbacks* allocator)
|
||||
{
|
||||
if (Buffer) { vkDestroyBuffer(device, Buffer, allocator); Buffer = VK_NULL_HANDLE; }
|
||||
if (Memory) { vkFreeMemory(device, Memory, allocator); Memory = VK_NULL_HANDLE; }
|
||||
Mapped = nullptr;
|
||||
FreeIndices.clear();
|
||||
Capacity = 0;
|
||||
Stride = 0;
|
||||
BindInfo = {};
|
||||
}
|
||||
int Alloc()
|
||||
{
|
||||
IM_ASSERT(FreeIndices.Size > 0);
|
||||
int idx = FreeIndices.back();
|
||||
FreeIndices.pop_back();
|
||||
return idx;
|
||||
}
|
||||
void Free(int idx)
|
||||
{
|
||||
FreeIndices.push_back(idx);
|
||||
}
|
||||
VkHostAddressRangeEXT DescriptorAddress(int idx) const
|
||||
{
|
||||
return VkHostAddressRangeEXT{ (char*)Mapped + (VkDeviceSize)idx * Stride, Stride };
|
||||
}
|
||||
};
|
||||
#endif // IMGUI_IMPL_VULKAN_HAS_DESCRIPTOR_HEAP
|
||||
|
||||
// Data
|
||||
static VkAllocationCallbacks* g_Allocator = nullptr;
|
||||
static VkInstance g_Instance = VK_NULL_HANDLE;
|
||||
@ -54,6 +192,12 @@ static VkDescriptorPool g_DescriptorPool = VK_NULL_HANDLE;
|
||||
static ImGui_ImplVulkanH_Window g_MainWindowData;
|
||||
static uint32_t g_MinImageCount = 2;
|
||||
static bool g_SwapChainRebuild = false;
|
||||
#ifdef IMGUI_IMPL_VULKAN_HAS_DESCRIPTOR_HEAP
|
||||
static bool g_UsingDescriptorHeap = false;
|
||||
static ExampleDescriptorHeapAllocator g_ResourceHeapAlloc;
|
||||
static ExampleDescriptorHeapAllocator g_SamplerHeapAlloc;
|
||||
static ImGui_ImplVulkan_DescriptorHeapInfo g_DescriptorHeapInfo;
|
||||
#endif
|
||||
|
||||
static void glfw_error_callback(int error, const char* description)
|
||||
{
|
||||
@ -85,7 +229,31 @@ static bool IsExtensionAvailable(const ImVector<VkExtensionProperties>& properti
|
||||
return false;
|
||||
}
|
||||
|
||||
static void SetupVulkan(ImVector<const char*> instance_extensions)
|
||||
#ifdef IMGUI_IMPL_VULKAN_HAS_DESCRIPTOR_HEAP
|
||||
static bool PhysicalDeviceHasExtension(VkPhysicalDevice physical_device, const char* extension)
|
||||
{
|
||||
uint32_t properties_count = 0;
|
||||
vkEnumerateDeviceExtensionProperties(physical_device, nullptr, &properties_count, nullptr);
|
||||
ImVector<VkExtensionProperties> properties;
|
||||
properties.resize(properties_count);
|
||||
vkEnumerateDeviceExtensionProperties(physical_device, nullptr, &properties_count, properties.Data);
|
||||
return IsExtensionAvailable(properties, extension);
|
||||
}
|
||||
|
||||
// Extensions required by this example's VK_EXT_descriptor_heap path (Vulkan 1.1 instance → BDA is an extension).
|
||||
// Formal deps of VK_EXT_descriptor_heap: maintenance5 + (buffer_device_address | Vulkan 1.2).
|
||||
// shader_untyped_pointers is required by ImGui's default layout(descriptor_heap) shaders, not by the Vulkan extension itself.
|
||||
// See "About descriptor heap" in imgui_impl_vulkan.h.
|
||||
static bool PhysicalDeviceSupportsImGuiDescriptorHeap(VkPhysicalDevice physical_device)
|
||||
{
|
||||
return PhysicalDeviceHasExtension(physical_device, VK_EXT_DESCRIPTOR_HEAP_EXTENSION_NAME)
|
||||
&& PhysicalDeviceHasExtension(physical_device, VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME)
|
||||
&& PhysicalDeviceHasExtension(physical_device, VK_KHR_SHADER_UNTYPED_POINTERS_EXTENSION_NAME)
|
||||
&& PhysicalDeviceHasExtension(physical_device, VK_KHR_MAINTENANCE_5_EXTENSION_NAME);
|
||||
}
|
||||
#endif // IMGUI_IMPL_VULKAN_HAS_DESCRIPTOR_HEAP
|
||||
|
||||
static void SetupVulkan(ImVector<const char*> instance_extensions, bool require_descriptor_heap)
|
||||
{
|
||||
VkResult err;
|
||||
#ifdef IMGUI_IMPL_VULKAN_USE_VOLK
|
||||
@ -127,6 +295,10 @@ static void SetupVulkan(ImVector<const char*> instance_extensions)
|
||||
// Create Vulkan Instance
|
||||
create_info.enabledExtensionCount = (uint32_t)instance_extensions.Size;
|
||||
create_info.ppEnabledExtensionNames = instance_extensions.Data;
|
||||
VkApplicationInfo app_info = {};
|
||||
app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
|
||||
app_info.apiVersion = VK_API_VERSION_1_1;
|
||||
create_info.pApplicationInfo = &app_info;
|
||||
err = vkCreateInstance(&create_info, g_Allocator, &g_Instance);
|
||||
check_vk_result(err);
|
||||
#ifdef IMGUI_IMPL_VULKAN_USE_VOLK
|
||||
@ -147,10 +319,48 @@ static void SetupVulkan(ImVector<const char*> instance_extensions)
|
||||
#endif
|
||||
}
|
||||
|
||||
// Select Physical Device (GPU)
|
||||
g_PhysicalDevice = ImGui_ImplVulkanH_SelectPhysicalDevice(g_Instance);
|
||||
#ifdef IMGUI_IMPL_VULKAN_HAS_DESCRIPTOR_HEAP
|
||||
if (require_descriptor_heap)
|
||||
{
|
||||
uint32_t device_count = 0;
|
||||
vkEnumeratePhysicalDevices(g_Instance, &device_count, nullptr);
|
||||
ImVector<VkPhysicalDevice> physical_devices;
|
||||
physical_devices.resize(device_count);
|
||||
vkEnumeratePhysicalDevices(g_Instance, &device_count, physical_devices.Data);
|
||||
|
||||
VkPhysicalDevice device_with_heap = VK_NULL_HANDLE;
|
||||
for (uint32_t i = 0; i < device_count; i++)
|
||||
{
|
||||
if (PhysicalDeviceSupportsImGuiDescriptorHeap(physical_devices[i]))
|
||||
{
|
||||
device_with_heap = physical_devices[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (device_with_heap == VK_NULL_HANDLE)
|
||||
{
|
||||
fprintf(stderr, "Error: --require-descriptor-heap requested but no device with VK_EXT_descriptor_heap and its required dependencies was found.\n");
|
||||
fprintf(stderr, " Required: %s, %s, %s, %s\n",
|
||||
VK_EXT_DESCRIPTOR_HEAP_EXTENSION_NAME,
|
||||
VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME,
|
||||
VK_KHR_SHADER_UNTYPED_POINTERS_EXTENSION_NAME,
|
||||
VK_KHR_MAINTENANCE_5_EXTENSION_NAME);
|
||||
exit(1);
|
||||
}
|
||||
g_PhysicalDevice = device_with_heap;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
(void)require_descriptor_heap;
|
||||
g_PhysicalDevice = ImGui_ImplVulkanH_SelectPhysicalDevice(g_Instance);
|
||||
}
|
||||
IM_ASSERT(g_PhysicalDevice != VK_NULL_HANDLE);
|
||||
|
||||
VkPhysicalDeviceProperties chosen_props;
|
||||
vkGetPhysicalDeviceProperties(g_PhysicalDevice, &chosen_props);
|
||||
|
||||
// Select graphics queue family
|
||||
g_QueueFamily = ImGui_ImplVulkanH_SelectQueueFamilyIndex(g_PhysicalDevice);
|
||||
IM_ASSERT(g_QueueFamily != (uint32_t)-1);
|
||||
@ -170,6 +380,21 @@ static void SetupVulkan(ImVector<const char*> instance_extensions)
|
||||
if (IsExtensionAvailable(properties, VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME))
|
||||
device_extensions.push_back(VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME);
|
||||
#endif
|
||||
#ifdef IMGUI_IMPL_VULKAN_HAS_DESCRIPTOR_HEAP
|
||||
if (PhysicalDeviceSupportsImGuiDescriptorHeap(g_PhysicalDevice))
|
||||
{
|
||||
device_extensions.push_back(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
|
||||
device_extensions.push_back(VK_KHR_MAINTENANCE_5_EXTENSION_NAME);
|
||||
device_extensions.push_back(VK_KHR_SHADER_UNTYPED_POINTERS_EXTENSION_NAME);
|
||||
device_extensions.push_back(VK_EXT_DESCRIPTOR_HEAP_EXTENSION_NAME);
|
||||
g_UsingDescriptorHeap = true;
|
||||
}
|
||||
else if (require_descriptor_heap)
|
||||
{
|
||||
fprintf(stderr, "Error: --require-descriptor-heap but selected device is missing a required dependency.\n");
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
|
||||
const float queue_priority[] = { 1.0f };
|
||||
VkDeviceQueueCreateInfo queue_info[1] = {};
|
||||
@ -183,14 +408,77 @@ static void SetupVulkan(ImVector<const char*> instance_extensions)
|
||||
create_info.pQueueCreateInfos = queue_info;
|
||||
create_info.enabledExtensionCount = (uint32_t)device_extensions.Size;
|
||||
create_info.ppEnabledExtensionNames = device_extensions.Data;
|
||||
|
||||
#ifdef IMGUI_IMPL_VULKAN_HAS_DESCRIPTOR_HEAP
|
||||
VkPhysicalDeviceBufferDeviceAddressFeatures buffer_device_addr = {};
|
||||
buffer_device_addr.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES;
|
||||
buffer_device_addr.bufferDeviceAddress = VK_TRUE;
|
||||
VkPhysicalDeviceDescriptorHeapFeaturesEXT desc_heap_feat = {};
|
||||
desc_heap_feat.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_HEAP_FEATURES_EXT;
|
||||
desc_heap_feat.pNext = &buffer_device_addr;
|
||||
desc_heap_feat.descriptorHeap = VK_TRUE;
|
||||
VkPhysicalDeviceShaderUntypedPointersFeaturesKHR untyped_pointers = {};
|
||||
untyped_pointers.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_UNTYPED_POINTERS_FEATURES_KHR;
|
||||
untyped_pointers.pNext = &desc_heap_feat;
|
||||
untyped_pointers.shaderUntypedPointers = VK_TRUE;
|
||||
if (g_UsingDescriptorHeap)
|
||||
create_info.pNext = &untyped_pointers;
|
||||
#endif
|
||||
|
||||
err = vkCreateDevice(g_PhysicalDevice, &create_info, g_Allocator, &g_Device);
|
||||
check_vk_result(err);
|
||||
vkGetDeviceQueue(g_Device, g_QueueFamily, 0, &g_Queue);
|
||||
}
|
||||
|
||||
// Create Descriptor Pool
|
||||
// If you wish to load e.g. additional textures you may need to alter pools sizes and maxSets.
|
||||
#ifdef IMGUI_IMPL_VULKAN_HAS_DESCRIPTOR_HEAP
|
||||
if (g_UsingDescriptorHeap)
|
||||
{
|
||||
g_DescHeapFns.Load(g_Device);
|
||||
|
||||
VkPhysicalDeviceDescriptorHeapPropertiesEXT descriptor_heap_properties = {};
|
||||
descriptor_heap_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_HEAP_PROPERTIES_EXT;
|
||||
VkPhysicalDeviceProperties2 properties2 = {};
|
||||
properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
|
||||
properties2.pNext = &descriptor_heap_properties;
|
||||
vkGetPhysicalDeviceProperties2(g_PhysicalDevice, &properties2);
|
||||
|
||||
g_ResourceHeapAlloc.Create(g_Device, g_PhysicalDevice, descriptor_heap_properties.imageDescriptorSize, descriptor_heap_properties.resourceHeapAlignment,
|
||||
descriptor_heap_properties.minResourceHeapReservedRange, APP_RESOURCE_HEAP_SIZE, g_Allocator);
|
||||
g_SamplerHeapAlloc.Create(g_Device, g_PhysicalDevice, descriptor_heap_properties.samplerDescriptorSize, descriptor_heap_properties.samplerHeapAlignment,
|
||||
descriptor_heap_properties.minSamplerHeapReservedRange, APP_SAMPLER_HEAP_SIZE, g_Allocator);
|
||||
|
||||
// Allocating descriptors is up to the application (like DX12 SrvDescriptorAllocFn/FreeFn).
|
||||
// ImTextureID = heap index from RegisterImage; index 0 is reserved (ImTextureID_Invalid).
|
||||
g_DescriptorHeapInfo = {};
|
||||
g_DescriptorHeapInfo.UserContext = nullptr;
|
||||
g_DescriptorHeapInfo.RegisterImage = [](void*, const VkImageViewCreateInfo* ci) -> uint32_t {
|
||||
int idx = g_ResourceHeapAlloc.Alloc();
|
||||
VkImageDescriptorInfoEXT image = {};
|
||||
image.sType = VK_STRUCTURE_TYPE_IMAGE_DESCRIPTOR_INFO_EXT;
|
||||
image.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
image.pView = ci;
|
||||
VkResourceDescriptorInfoEXT resource = {};
|
||||
resource.sType = VK_STRUCTURE_TYPE_RESOURCE_DESCRIPTOR_INFO_EXT;
|
||||
resource.type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
|
||||
resource.data.pImage = ℑ
|
||||
VkHostAddressRangeEXT addr = g_ResourceHeapAlloc.DescriptorAddress(idx);
|
||||
check_vk_result(g_DescHeapFns.vkWriteResourceDescriptorsEXT(g_Device, 1, &resource, &addr));
|
||||
return (uint32_t)idx;
|
||||
};
|
||||
g_DescriptorHeapInfo.UnRegisterImage = [](void*, uint32_t idx) { g_ResourceHeapAlloc.Free((int)idx); };
|
||||
g_DescriptorHeapInfo.RegisterSampler = [](void*, const VkSamplerCreateInfo* ci) -> uint32_t {
|
||||
int idx = g_SamplerHeapAlloc.Alloc();
|
||||
VkHostAddressRangeEXT addr = g_SamplerHeapAlloc.DescriptorAddress(idx);
|
||||
check_vk_result(g_DescHeapFns.vkWriteSamplerDescriptorsEXT(g_Device, 1, ci, &addr));
|
||||
return (uint32_t)idx;
|
||||
};
|
||||
g_DescriptorHeapInfo.UnRegisterSampler = [](void*, uint32_t idx) { g_SamplerHeapAlloc.Free((int)idx); };
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
// Create Descriptor Pool
|
||||
// If you wish to load e.g. additional textures you may need to alter pools sizes and maxSets.
|
||||
VkDescriptorPoolSize pool_sizes[] =
|
||||
{
|
||||
{ VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, IMGUI_IMPL_VULKAN_MINIMUM_SAMPLED_IMAGE_POOL_SIZE },
|
||||
@ -244,7 +532,17 @@ static void SetupVulkanWindow(ImGui_ImplVulkanH_Window* wd, VkSurfaceKHR surface
|
||||
|
||||
static void CleanupVulkan()
|
||||
{
|
||||
vkDestroyDescriptorPool(g_Device, g_DescriptorPool, g_Allocator);
|
||||
#ifdef IMGUI_IMPL_VULKAN_HAS_DESCRIPTOR_HEAP
|
||||
if (g_UsingDescriptorHeap)
|
||||
{
|
||||
g_ResourceHeapAlloc.Destroy(g_Device, g_Allocator);
|
||||
g_SamplerHeapAlloc.Destroy(g_Device, g_Allocator);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
vkDestroyDescriptorPool(g_Device, g_DescriptorPool, g_Allocator);
|
||||
}
|
||||
|
||||
#ifdef APP_USE_VULKAN_DEBUG_REPORT
|
||||
// Remove the debug report callback
|
||||
@ -303,6 +601,14 @@ static void FrameRender(ImGui_ImplVulkanH_Window* wd, ImDrawData* draw_data)
|
||||
vkCmdBeginRenderPass(fd->CommandBuffer, &info, VK_SUBPASS_CONTENTS_INLINE);
|
||||
}
|
||||
|
||||
#ifdef IMGUI_IMPL_VULKAN_HAS_DESCRIPTOR_HEAP
|
||||
if (g_UsingDescriptorHeap)
|
||||
{
|
||||
g_DescHeapFns.vkCmdBindResourceHeapEXT(fd->CommandBuffer, &g_ResourceHeapAlloc.BindInfo);
|
||||
g_DescHeapFns.vkCmdBindSamplerHeapEXT(fd->CommandBuffer, &g_SamplerHeapAlloc.BindInfo);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Record dear imgui primitives into command buffer
|
||||
ImGui_ImplVulkan_RenderDrawData(draw_data, fd->CommandBuffer);
|
||||
|
||||
@ -350,8 +656,38 @@ static void FramePresent(ImGui_ImplVulkanH_Window* wd)
|
||||
}
|
||||
|
||||
// Main code
|
||||
int main(int, char**)
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
bool require_descriptor_heap = false;
|
||||
for (int i = 1; i < argc; i++)
|
||||
{
|
||||
if (strcmp(argv[i], "--require-descriptor-heap") == 0)
|
||||
{
|
||||
#ifdef IMGUI_IMPL_VULKAN_HAS_DESCRIPTOR_HEAP
|
||||
require_descriptor_heap = true;
|
||||
#else
|
||||
fprintf(stderr, "Error: --require-descriptor-heap requested but Vulkan headers lack VK_EXT_descriptor_heap (IMGUI_IMPL_VULKAN_HAS_DESCRIPTOR_HEAP undefined).\n");
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
else if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0)
|
||||
{
|
||||
printf("Usage: %s [--require-descriptor-heap]\n", argv[0]);
|
||||
#ifdef IMGUI_IMPL_VULKAN_HAS_DESCRIPTOR_HEAP
|
||||
printf(" --require-descriptor-heap Require a device with VK_EXT_descriptor_heap (exit on failure).\n");
|
||||
printf(" (default) Use ImGui_ImplVulkanH_SelectPhysicalDevice; enable heap if available.\n");
|
||||
#else
|
||||
printf(" --require-descriptor-heap Unavailable (Vulkan headers lack VK_EXT_descriptor_heap).\n");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Unknown argument: %s (try --help)\n", argv[i]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
glfwSetErrorCallback(glfw_error_callback);
|
||||
if (!glfwInit())
|
||||
return 1;
|
||||
@ -371,7 +707,7 @@ int main(int, char**)
|
||||
const char** glfw_extensions = glfwGetRequiredInstanceExtensions(&extensions_count);
|
||||
for (uint32_t i = 0; i < extensions_count; i++)
|
||||
extensions.push_back(glfw_extensions[i]);
|
||||
SetupVulkan(extensions);
|
||||
SetupVulkan(extensions, require_descriptor_heap);
|
||||
|
||||
// Create Window Surface
|
||||
VkSurfaceKHR surface;
|
||||
@ -418,6 +754,10 @@ int main(int, char**)
|
||||
init_info.PipelineInfoMain.Subpass = 0;
|
||||
init_info.PipelineInfoMain.MSAASamples = VK_SAMPLE_COUNT_1_BIT;
|
||||
init_info.CheckVkResultFn = check_vk_result;
|
||||
#ifdef IMGUI_IMPL_VULKAN_HAS_DESCRIPTOR_HEAP
|
||||
if (g_UsingDescriptorHeap)
|
||||
init_info.DescriptorHeapInfo = &g_DescriptorHeapInfo;
|
||||
#endif
|
||||
ImGui_ImplVulkan_Init(&init_info);
|
||||
|
||||
// Load Fonts
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user