mirror of
https://github.com/ocornut/imgui.git
synced 2026-09-27 00:13:29 +03:00
Vulkan: Use GPU device address for ImTextureID in descriptor heap mode
This commit is contained in:
parent
8fb2aea07b
commit
c33ea3ccb6
3 changed files with 69 additions and 28 deletions
|
|
@ -244,6 +244,17 @@ static PFN_vkCmdEndRenderingKHR ImGuiImplVulkanFuncs_vkCmdEndRenderingKHR;
|
|||
#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;
|
||||
|
||||
// Convert GPU descriptor handle (device address) back to a heap index for PushData.
|
||||
static uint32_t ImGui_ImplVulkan_DescriptorHeapIndexFromTexID(const ImGui_ImplVulkan_DescriptorHeapInfo* info, ImTextureID tex_id)
|
||||
{
|
||||
IM_ASSERT(tex_id != ImTextureID_Invalid);
|
||||
IM_ASSERT(info->ResourceHeapAddress != 0 && info->ImageDescriptorSize != 0);
|
||||
const VkDeviceAddress addr = (VkDeviceAddress)(ImU64)tex_id;
|
||||
IM_ASSERT(addr >= info->ResourceHeapAddress);
|
||||
IM_ASSERT(((addr - info->ResourceHeapAddress) % info->ImageDescriptorSize) == 0);
|
||||
return (uint32_t)((addr - info->ResourceHeapAddress) / info->ImageDescriptorSize);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Reusable buffers used for rendering 1 current in-flight frame, for ImGui_ImplVulkan_RenderDrawData()
|
||||
|
|
@ -273,7 +284,7 @@ struct ImGui_ImplVulkan_Texture
|
|||
VkImage Image;
|
||||
VkImageView ImageView;
|
||||
VkDescriptorSet DescriptorSet;
|
||||
uint32_t DescriptorHeapIndex;
|
||||
uint64_t DescriptorHeapGpuHandle; // Device address into resource heap (== ImTextureID in heap mode)
|
||||
|
||||
ImGui_ImplVulkan_Texture() { memset((void*)this, 0, sizeof(*this)); }
|
||||
};
|
||||
|
|
@ -823,11 +834,8 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm
|
|||
#ifdef IMGUI_IMPL_VULKAN_HAS_DESCRIPTOR_HEAP
|
||||
if (v->DescriptorHeapInfo)
|
||||
{
|
||||
// Heap-mode TexIDs are tagged (index | 0x80000000). Use ImU64 for bit ops (ImTextureID may be redefined; default is ImU64).
|
||||
// Push a uint32_t index (not &image_id) so size=4 is endian-safe.
|
||||
const ImU64 tex_id_u64 = (ImU64)image_id;
|
||||
IM_ASSERT((tex_id_u64 & 0x80000000ull) != 0 && "ImTextureID is not a descriptor-heap index (do not use ImGui_ImplVulkan_AddTexture when DescriptorHeapInfo is set; use DescriptorHeapInfo::RegisterImage and tag with 0x80000000)");
|
||||
uint32_t heap_index = (uint32_t)(tex_id_u64 & 0x7FFFFFFFull);
|
||||
// ImTextureID is a GPU descriptor device address.
|
||||
uint32_t heap_index = ImGui_ImplVulkan_DescriptorHeapIndexFromTexID(v->DescriptorHeapInfo, image_id);
|
||||
VkPushDataInfoEXT push{};
|
||||
push.sType = VK_STRUCTURE_TYPE_PUSH_DATA_INFO_EXT;
|
||||
push.data.address = &heap_index;
|
||||
|
|
@ -867,15 +875,18 @@ 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 ||
|
||||
backend_tex->DescriptorHeapIndex == (uint32_t)((ImU64)tex->TexID & 0x7FFFFFFFull));
|
||||
IM_ASSERT(backend_tex->DescriptorSet == (VkDescriptorSet)tex->TexID
|
||||
#ifdef IMGUI_IMPL_VULKAN_HAS_DESCRIPTOR_HEAP
|
||||
|| backend_tex->DescriptorHeapGpuHandle == (uint64_t)(ImU64)tex->TexID
|
||||
#endif
|
||||
);
|
||||
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
|
||||
ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;
|
||||
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);
|
||||
v->DescriptorHeapInfo->UnRegisterImage(v->DescriptorHeapInfo->UserContext, backend_tex->DescriptorHeapGpuHandle);
|
||||
#endif
|
||||
if (backend_tex->ImageView != VK_NULL_HANDLE)
|
||||
vkDestroyImageView(v->Device, backend_tex->ImageView, v->Allocator);
|
||||
|
|
@ -947,10 +958,10 @@ void ImGui_ImplVulkan_UpdateTexture(ImTextureData* tex)
|
|||
#ifdef IMGUI_IMPL_VULKAN_HAS_DESCRIPTOR_HEAP
|
||||
if (v->DescriptorHeapInfo)
|
||||
{
|
||||
backend_tex->DescriptorHeapIndex =
|
||||
backend_tex->DescriptorHeapGpuHandle =
|
||||
v->DescriptorHeapInfo->RegisterImage(v->DescriptorHeapInfo->UserContext, &info);
|
||||
// Store identifiers (ImU64 cast so tagging works if ImTextureID is customized)
|
||||
tex->SetTexID((ImTextureID)(ImU64)(backend_tex->DescriptorHeapIndex | 0x80000000u));
|
||||
IM_ASSERT(backend_tex->DescriptorHeapGpuHandle != 0 && "RegisterImage must return a non-zero device address");
|
||||
tex->SetTexID((ImTextureID)backend_tex->DescriptorHeapGpuHandle);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
|
@ -1602,6 +1613,10 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info)
|
|||
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(sizeof(ImTextureID) >= sizeof(VkDeviceAddress) && "Descriptor heap mode needs 64-bit ImTextureID");
|
||||
IM_ASSERT(info->DescriptorHeapInfo->ResourceHeapAddress != 0 && info->DescriptorHeapInfo->ImageDescriptorSize != 0);
|
||||
IM_ASSERT(info->DescriptorHeapInfo->RegisterImage != nullptr && info->DescriptorHeapInfo->UnRegisterImage != nullptr);
|
||||
IM_ASSERT(info->DescriptorHeapInfo->RegisterSampler != nullptr && info->DescriptorHeapInfo->UnRegisterSampler != nullptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -1696,7 +1711,7 @@ 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 and set ImTextureID to (index | 0x80000000)");
|
||||
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;
|
||||
|
||||
|
|
|
|||
|
|
@ -97,13 +97,22 @@ struct ImGui_ImplVulkan_PipelineInfo
|
|||
};
|
||||
|
||||
#ifdef IMGUI_IMPL_VULKAN_HAS_DESCRIPTOR_HEAP
|
||||
// App owns heap slots. ImTextureID is the descriptor's device address in the resource heap (like D3D12_GPU_DESCRIPTOR_HANDLE.ptr).
|
||||
// Backend converts to a heap index for vkCmdPushDataEXT via (tex_id - ResourceHeapAddress) / ImageDescriptorSize.
|
||||
// Requires a 64-bit ImTextureID (Dear ImGui default since 1.91.4). Do not redefine ImTextureID to a 32-bit type.
|
||||
struct ImGui_ImplVulkan_DescriptorHeapInfo
|
||||
{
|
||||
uint32_t (*RegisterSampler)(void *, const VkSamplerCreateInfo *);
|
||||
void (*UnRegisterSampler)(void *, uint32_t);
|
||||
uint32_t (*RegisterImage)(void *, const VkImageViewCreateInfo *);
|
||||
void (*UnRegisterImage)(void *, uint32_t);
|
||||
void *UserContext;
|
||||
VkDeviceAddress ResourceHeapAddress; // Bound resource heap base (vkGetBufferDeviceAddress of heap buffer)
|
||||
VkDeviceSize ImageDescriptorSize; // imageDescriptorSize from VkPhysicalDeviceDescriptorHeapPropertiesEXT
|
||||
|
||||
// RegisterImage returns GPU descriptor handle (device address / VkDeviceAddress). UnRegisterImage takes that same handle.
|
||||
// Returned value is stored as ImTextureID; needs sizeof(ImTextureID) >= 8.
|
||||
uint64_t (*RegisterImage)(void*, const VkImageViewCreateInfo*);
|
||||
void (*UnRegisterImage)(void*, uint64_t);
|
||||
// Samplers are not ImTextureIDs; indices are fine (including 0).
|
||||
uint32_t (*RegisterSampler)(void*, const VkSamplerCreateInfo*);
|
||||
void (*UnRegisterSampler)(void*, uint32_t);
|
||||
void* UserContext;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
|
@ -117,9 +126,10 @@ struct ImGui_ImplVulkan_DescriptorHeapInfo
|
|||
// - 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.
|
||||
// - Like DX12's SrvDescriptorAllocFn/FreeFn: the application owns heap allocation via Register*/UnRegister* callbacks.
|
||||
// - ImGui_ImplVulkan_AddTexture()/RemoveTexture() are unavailable in this mode (pool path only).
|
||||
// - User textures: call RegisterImage yourself and use ImTextureID = (heap_index | 0x80000000); free with UnRegisterImage.
|
||||
// - The application owns heap slots via Register*/UnRegister* callbacks.
|
||||
// - ImTextureID is the GPU descriptor device address returned by RegisterImage.
|
||||
// Requires a 64-bit ImTextureID.
|
||||
// - ImGui_ImplVulkan_AddTexture()/RemoveTexture() are pool-path only.
|
||||
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)
|
||||
|
|
@ -158,7 +168,7 @@ struct ImGui_ImplVulkan_InitInfo
|
|||
|
||||
#ifdef IMGUI_IMPL_VULKAN_HAS_DESCRIPTOR_HEAP
|
||||
// (Optional) If set, use VK_EXT_descriptor_heap (app-owned Register*/UnRegister* callbacks; see comment above).
|
||||
// ImTextureID must be (RegisterImage() index | 0x80000000). ImGui_ImplVulkan_AddTexture() is unavailable in this mode.
|
||||
// ImTextureID = RegisterImage(...) device address. ImGui_ImplVulkan_AddTexture() is unavailable in this mode.
|
||||
const ImGui_ImplVulkan_DescriptorHeapInfo *DescriptorHeapInfo;
|
||||
#endif
|
||||
};
|
||||
|
|
@ -180,7 +190,7 @@ IMGUI_IMPL_API void ImGui_ImplVulkan_UpdateTexture(ImTextureData* te
|
|||
|
||||
// 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: use DescriptorHeapInfo::RegisterImage / UnRegisterImage and ImTextureID = (heap_index | 0x80000000).
|
||||
// - Heap mode: ImTextureID = DescriptorHeapInfo::RegisterImage(...) device address; 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);
|
||||
|
||||
|
|
|
|||
|
|
@ -146,8 +146,8 @@ struct ExampleDescriptorHeapAllocator
|
|||
BindInfo.reservedRangeSize = reserved_range;
|
||||
|
||||
FreeIndices.reserve(capacity);
|
||||
for (int n = capacity; n > 0; n--)
|
||||
FreeIndices.push_back(n - 1);
|
||||
for (int n = capacity - 1; n >= 0; n--)
|
||||
FreeIndices.push_back(n);
|
||||
}
|
||||
void Destroy(VkDevice device, const VkAllocationCallbacks* allocator)
|
||||
{
|
||||
|
|
@ -170,6 +170,16 @@ struct ExampleDescriptorHeapAllocator
|
|||
{
|
||||
FreeIndices.push_back(idx);
|
||||
}
|
||||
VkDeviceAddress GpuHandleFromIndex(int idx) const
|
||||
{
|
||||
return BindInfo.heapRange.address + (VkDeviceAddress)idx * (VkDeviceAddress)Stride;
|
||||
}
|
||||
int IndexFromGpuHandle(VkDeviceAddress gpu_handle) const
|
||||
{
|
||||
IM_ASSERT(gpu_handle >= BindInfo.heapRange.address);
|
||||
IM_ASSERT(((gpu_handle - BindInfo.heapRange.address) % Stride) == 0);
|
||||
return (int)((gpu_handle - BindInfo.heapRange.address) / Stride);
|
||||
}
|
||||
VkHostAddressRangeEXT DescriptorAddress(int idx) const
|
||||
{
|
||||
return VkHostAddressRangeEXT{ (char*)Mapped + (VkDeviceSize)idx * Stride, Stride };
|
||||
|
|
@ -417,8 +427,12 @@ static void SetupVulkan(ImVector<const char*> instance_extensions, bool require_
|
|||
descriptor_heap_properties.minSamplerHeapReservedRange, APP_SAMPLER_HEAP_SIZE, g_Allocator);
|
||||
|
||||
// Allocating descriptors is up to the application, so we provide callbacks (same idea as DX12 SrvDescriptorAllocFn/FreeFn).
|
||||
// ImTextureID = GPU descriptor device address (like D3D12_GPU_DESCRIPTOR_HANDLE.ptr); slot 0 is usable.
|
||||
g_DescriptorHeapInfo = {};
|
||||
g_DescriptorHeapInfo.ResourceHeapAddress = g_ResourceHeapAlloc.BindInfo.heapRange.address;
|
||||
g_DescriptorHeapInfo.ImageDescriptorSize = g_ResourceHeapAlloc.Stride;
|
||||
g_DescriptorHeapInfo.UserContext = nullptr;
|
||||
g_DescriptorHeapInfo.RegisterImage = [](void*, const VkImageViewCreateInfo* ci) -> uint32_t {
|
||||
g_DescriptorHeapInfo.RegisterImage = [](void*, const VkImageViewCreateInfo* ci) -> uint64_t {
|
||||
int idx = g_ResourceHeapAlloc.Alloc();
|
||||
VkImageDescriptorInfoEXT image = {};
|
||||
image.sType = VK_STRUCTURE_TYPE_IMAGE_DESCRIPTOR_INFO_EXT;
|
||||
|
|
@ -430,9 +444,11 @@ static void SetupVulkan(ImVector<const char*> instance_extensions, bool require_
|
|||
resource.data.pImage = ℑ
|
||||
VkHostAddressRangeEXT addr = g_ResourceHeapAlloc.DescriptorAddress(idx);
|
||||
check_vk_result(g_DescHeapFns.vkWriteResourceDescriptorsEXT(g_Device, 1, &resource, &addr));
|
||||
return (uint32_t)idx;
|
||||
return (uint64_t)g_ResourceHeapAlloc.GpuHandleFromIndex(idx);
|
||||
};
|
||||
g_DescriptorHeapInfo.UnRegisterImage = [](void*, uint64_t gpu_handle) {
|
||||
g_ResourceHeapAlloc.Free(g_ResourceHeapAlloc.IndexFromGpuHandle((VkDeviceAddress)gpu_handle));
|
||||
};
|
||||
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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue