From b93e998b18aeca9cf3902c4d2e5a88838be07e7d Mon Sep 17 00:00:00 2001 From: Jim Blackler Date: Mon, 14 Sep 2026 21:08:39 +0000 Subject: [PATCH 1/6] device_memory_report: guard extension device commands in vkGetInstanceProcAddr Split known device functions into core commands and extension commands. Return core device functions directly from vkGetInstanceProcAddr, but query the instance dispatch chain before handing out extension commands to ensure applications cannot falsely detect unsupported extensions. --- ...ice_memory_report_handwritten_dispatch.cpp | 31 ++++++++++++++++--- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/layersvt/device_memory_report/device_memory_report_handwritten_dispatch.cpp b/layersvt/device_memory_report/device_memory_report_handwritten_dispatch.cpp index 0c160a209d..0d17511036 100644 --- a/layersvt/device_memory_report/device_memory_report_handwritten_dispatch.cpp +++ b/layersvt/device_memory_report/device_memory_report_handwritten_dispatch.cpp @@ -30,7 +30,7 @@ static PFN_vkVoidFunction devmemreport_known_instance_functions(const char* pNam return nullptr; } -static PFN_vkVoidFunction devmemreport_known_device_functions(const char* pName) { +static PFN_vkVoidFunction devmemreport_known_core_device_functions(const char* pName) { if (strcmp(pName, "vkGetDeviceProcAddr") == 0) return reinterpret_cast(vkGetDeviceProcAddr); if (strcmp(pName, "vkCreateDevice") == 0) return reinterpret_cast(vkCreateDevice); if (strcmp(pName, "vkDestroyDevice") == 0) return reinterpret_cast(vkDestroyDevice); @@ -56,14 +56,26 @@ static PFN_vkVoidFunction devmemreport_known_device_functions(const char* pName) return nullptr; } +static PFN_vkVoidFunction devmemreport_known_device_extension_functions(const char* pName) { + return nullptr; +} + +static PFN_vkVoidFunction devmemreport_known_device_functions(const char* pName) { + PFN_vkVoidFunction func = devmemreport_known_core_device_functions(pName); + if (func) { + return func; + } + return devmemreport_known_device_extension_functions(pName); +} + EXPORT_FUNCTION VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char* pName) { PFN_vkVoidFunction func = devmemreport_known_instance_functions(pName); if (func) { return func; } - // If it's a device function, we can also return it here if we want to support GIPA for device functions. - func = devmemreport_known_device_functions(pName); + // Core device functions can be returned directly from GIPA. + func = devmemreport_known_core_device_functions(pName); if (func) { return func; } @@ -77,7 +89,18 @@ EXPORT_FUNCTION VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(V return nullptr; } - return table->GetInstanceProcAddr(instance, pName); + // For extension device commands, verify the underlying chain supports them before returning an interceptor. + PFN_vkVoidFunction down_func = table->GetInstanceProcAddr(instance, pName); + if (down_func == nullptr) { + return nullptr; + } + + func = devmemreport_known_device_extension_functions(pName); + if (func) { + return func; + } + + return down_func; } EXPORT_FUNCTION VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice device, const char* pName) { From 43e6ddcf59444a1c6494ccc3c05a5ab3b077711a Mon Sep 17 00:00:00 2001 From: Jim Blackler Date: Mon, 14 Sep 2026 21:07:58 +0000 Subject: [PATCH 2/6] device_memory_report: pass VkObjectType to OnDestroyObject Include the object type when cleaning up tracked resources on destruction so handle-to-resource tracking can distinguish between different object types (e.g. buffers vs images) that share the same handle value. --- .../device_memory_report.cpp | 2 +- .../device_memory_report.h | 3 +- ...vice_memory_report_handwritten_functions.h | 4 +-- layersvt/test/test_devicememoryreport.cpp | 30 +++++++++---------- 4 files changed, 20 insertions(+), 19 deletions(-) diff --git a/layersvt/device_memory_report/device_memory_report.cpp b/layersvt/device_memory_report/device_memory_report.cpp index 68fbd77cdf..aaa05d19f3 100644 --- a/layersvt/device_memory_report/device_memory_report.cpp +++ b/layersvt/device_memory_report/device_memory_report.cpp @@ -337,7 +337,7 @@ void DeviceMemoryReport::OnCreateBuffer(uint64_t buffer_handle, VkBufferUsageFla } } -void DeviceMemoryReport::OnDestroyObject(uint64_t object_handle) { +void DeviceMemoryReport::OnDestroyObject(VkObjectType object_type, uint64_t object_handle) { std::lock_guard lock(counter_mutex_); RemoveResourceBinding(object_handle); resources_.erase(object_handle); diff --git a/layersvt/device_memory_report/device_memory_report.h b/layersvt/device_memory_report/device_memory_report.h index 22514516aa..be7cfca966 100644 --- a/layersvt/device_memory_report/device_memory_report.h +++ b/layersvt/device_memory_report/device_memory_report.h @@ -187,9 +187,10 @@ class DeviceMemoryReport { /** * @brief Handles destruction of a Vulkan object, cleaning up tracked usage state. + * @param object_type The type of the destroyed object. * @param object_handle The 64-bit handle of the destroyed Vulkan object. */ - void OnDestroyObject(uint64_t object_handle); + void OnDestroyObject(VkObjectType object_type, uint64_t object_handle); private: /** diff --git a/layersvt/device_memory_report/device_memory_report_handwritten_functions.h b/layersvt/device_memory_report/device_memory_report_handwritten_functions.h index 78dc41d8d4..653e1dba29 100644 --- a/layersvt/device_memory_report/device_memory_report_handwritten_functions.h +++ b/layersvt/device_memory_report/device_memory_report_handwritten_functions.h @@ -348,7 +348,7 @@ VKAPI_ATTR VkResult VKAPI_CALL vkCreateImage(VkDevice device, const VkImageCreat // Intercept image destruction to clean up tracked handle state. VKAPI_ATTR void VKAPI_CALL vkDestroyImage(VkDevice device, VkImage image, const VkAllocationCallbacks* pAllocator) { if (image != VK_NULL_HANDLE) { - DeviceMemoryReport::Get().OnDestroyObject(reinterpret_cast(image)); + DeviceMemoryReport::Get().OnDestroyObject(VK_OBJECT_TYPE_IMAGE, reinterpret_cast(image)); } PFN_vkDestroyImage fpDestroyImage = (PFN_vkDestroyImage)device_dispatch_table(device)->DestroyImage; if (fpDestroyImage != NULL) { @@ -377,7 +377,7 @@ VKAPI_ATTR VkResult VKAPI_CALL vkCreateBuffer(VkDevice device, const VkBufferCre // Intercept buffer destruction to clean up tracked handle state. VKAPI_ATTR void VKAPI_CALL vkDestroyBuffer(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks* pAllocator) { if (buffer != VK_NULL_HANDLE) { - DeviceMemoryReport::Get().OnDestroyObject(reinterpret_cast(buffer)); + DeviceMemoryReport::Get().OnDestroyObject(VK_OBJECT_TYPE_BUFFER, reinterpret_cast(buffer)); } PFN_vkDestroyBuffer fpDestroyBuffer = (PFN_vkDestroyBuffer)device_dispatch_table(device)->DestroyBuffer; if (fpDestroyBuffer != NULL) { diff --git a/layersvt/test/test_devicememoryreport.cpp b/layersvt/test/test_devicememoryreport.cpp index 6fc6c639b9..b005e9c0d5 100644 --- a/layersvt/test/test_devicememoryreport.cpp +++ b/layersvt/test/test_devicememoryreport.cpp @@ -248,18 +248,18 @@ TEST_F(DeviceMemoryReportTests, UsageTypeBreakdown) { DeviceMemoryReport::MemoryReportCallback(&cb_data, nullptr); // Clean up objects - DeviceMemoryReport::Get().OnDestroyObject(color_img); - DeviceMemoryReport::Get().OnDestroyObject(depth_img); - DeviceMemoryReport::Get().OnDestroyObject(sampled_img); - DeviceMemoryReport::Get().OnDestroyObject(storage_img); - DeviceMemoryReport::Get().OnDestroyObject(transient_img); - - DeviceMemoryReport::Get().OnDestroyObject(vtx_buf); - DeviceMemoryReport::Get().OnDestroyObject(idx_buf); - DeviceMemoryReport::Get().OnDestroyObject(ubo_buf); - DeviceMemoryReport::Get().OnDestroyObject(staging_buf); - DeviceMemoryReport::Get().OnDestroyObject(storage_buf); - DeviceMemoryReport::Get().OnDestroyObject(indirect_buf); + DeviceMemoryReport::Get().OnDestroyObject(VK_OBJECT_TYPE_IMAGE, color_img); + DeviceMemoryReport::Get().OnDestroyObject(VK_OBJECT_TYPE_IMAGE, depth_img); + DeviceMemoryReport::Get().OnDestroyObject(VK_OBJECT_TYPE_IMAGE, sampled_img); + DeviceMemoryReport::Get().OnDestroyObject(VK_OBJECT_TYPE_IMAGE, storage_img); + DeviceMemoryReport::Get().OnDestroyObject(VK_OBJECT_TYPE_IMAGE, transient_img); + + DeviceMemoryReport::Get().OnDestroyObject(VK_OBJECT_TYPE_BUFFER, vtx_buf); + DeviceMemoryReport::Get().OnDestroyObject(VK_OBJECT_TYPE_BUFFER, idx_buf); + DeviceMemoryReport::Get().OnDestroyObject(VK_OBJECT_TYPE_BUFFER, ubo_buf); + DeviceMemoryReport::Get().OnDestroyObject(VK_OBJECT_TYPE_BUFFER, staging_buf); + DeviceMemoryReport::Get().OnDestroyObject(VK_OBJECT_TYPE_BUFFER, storage_buf); + DeviceMemoryReport::Get().OnDestroyObject(VK_OBJECT_TYPE_BUFFER, indirect_buf); EXPECT_TRUE(true); } @@ -315,7 +315,7 @@ TEST_F(DeviceMemoryReportTests, MemoryAliasingAndOverlap) { // - Interval [0, 4000) is removed. Remaining intervals: [2000, 6000) U [8000, 9500). // - Recalculated bound_size = 4,000 + 1,500 = 5,500 B. // - Updated unbound headroom: unbound_memory = 10,000 - 5,500 = 4,500 B. - DeviceMemoryReport::Get().OnDestroyObject(image_a); + DeviceMemoryReport::Get().OnDestroyObject(VK_OBJECT_TYPE_IMAGE, image_a); // Step 6: Free physical memory slab. // - All remaining sub-allocations on this slab are cleaned up and unbound counter is reset. @@ -323,8 +323,8 @@ TEST_F(DeviceMemoryReportTests, MemoryAliasingAndOverlap) { DeviceMemoryReport::MemoryReportCallback(&cb_data, nullptr); // Step 7: Clean up remaining virtual resource object handles. - DeviceMemoryReport::Get().OnDestroyObject(image_b); - DeviceMemoryReport::Get().OnDestroyObject(buffer_c); + DeviceMemoryReport::Get().OnDestroyObject(VK_OBJECT_TYPE_IMAGE, image_b); + DeviceMemoryReport::Get().OnDestroyObject(VK_OBJECT_TYPE_BUFFER, buffer_c); EXPECT_TRUE(true); } From 8285df4d86a7df9d40141b52226f2f19594edf09 Mon Sep 17 00:00:00 2001 From: Jim Blackler Date: Wed, 16 Sep 2026 15:44:05 +0000 Subject: [PATCH 3/6] Revert "device_memory_report: pass VkObjectType to OnDestroyObject" This reverts commit 43e6ddcf59444a1c6494ccc3c05a5ab3b077711a. --- .../device_memory_report.cpp | 2 +- .../device_memory_report.h | 3 +- ...vice_memory_report_handwritten_functions.h | 4 +-- layersvt/test/test_devicememoryreport.cpp | 30 +++++++++---------- 4 files changed, 19 insertions(+), 20 deletions(-) diff --git a/layersvt/device_memory_report/device_memory_report.cpp b/layersvt/device_memory_report/device_memory_report.cpp index aaa05d19f3..68fbd77cdf 100644 --- a/layersvt/device_memory_report/device_memory_report.cpp +++ b/layersvt/device_memory_report/device_memory_report.cpp @@ -337,7 +337,7 @@ void DeviceMemoryReport::OnCreateBuffer(uint64_t buffer_handle, VkBufferUsageFla } } -void DeviceMemoryReport::OnDestroyObject(VkObjectType object_type, uint64_t object_handle) { +void DeviceMemoryReport::OnDestroyObject(uint64_t object_handle) { std::lock_guard lock(counter_mutex_); RemoveResourceBinding(object_handle); resources_.erase(object_handle); diff --git a/layersvt/device_memory_report/device_memory_report.h b/layersvt/device_memory_report/device_memory_report.h index be7cfca966..22514516aa 100644 --- a/layersvt/device_memory_report/device_memory_report.h +++ b/layersvt/device_memory_report/device_memory_report.h @@ -187,10 +187,9 @@ class DeviceMemoryReport { /** * @brief Handles destruction of a Vulkan object, cleaning up tracked usage state. - * @param object_type The type of the destroyed object. * @param object_handle The 64-bit handle of the destroyed Vulkan object. */ - void OnDestroyObject(VkObjectType object_type, uint64_t object_handle); + void OnDestroyObject(uint64_t object_handle); private: /** diff --git a/layersvt/device_memory_report/device_memory_report_handwritten_functions.h b/layersvt/device_memory_report/device_memory_report_handwritten_functions.h index 653e1dba29..78dc41d8d4 100644 --- a/layersvt/device_memory_report/device_memory_report_handwritten_functions.h +++ b/layersvt/device_memory_report/device_memory_report_handwritten_functions.h @@ -348,7 +348,7 @@ VKAPI_ATTR VkResult VKAPI_CALL vkCreateImage(VkDevice device, const VkImageCreat // Intercept image destruction to clean up tracked handle state. VKAPI_ATTR void VKAPI_CALL vkDestroyImage(VkDevice device, VkImage image, const VkAllocationCallbacks* pAllocator) { if (image != VK_NULL_HANDLE) { - DeviceMemoryReport::Get().OnDestroyObject(VK_OBJECT_TYPE_IMAGE, reinterpret_cast(image)); + DeviceMemoryReport::Get().OnDestroyObject(reinterpret_cast(image)); } PFN_vkDestroyImage fpDestroyImage = (PFN_vkDestroyImage)device_dispatch_table(device)->DestroyImage; if (fpDestroyImage != NULL) { @@ -377,7 +377,7 @@ VKAPI_ATTR VkResult VKAPI_CALL vkCreateBuffer(VkDevice device, const VkBufferCre // Intercept buffer destruction to clean up tracked handle state. VKAPI_ATTR void VKAPI_CALL vkDestroyBuffer(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks* pAllocator) { if (buffer != VK_NULL_HANDLE) { - DeviceMemoryReport::Get().OnDestroyObject(VK_OBJECT_TYPE_BUFFER, reinterpret_cast(buffer)); + DeviceMemoryReport::Get().OnDestroyObject(reinterpret_cast(buffer)); } PFN_vkDestroyBuffer fpDestroyBuffer = (PFN_vkDestroyBuffer)device_dispatch_table(device)->DestroyBuffer; if (fpDestroyBuffer != NULL) { diff --git a/layersvt/test/test_devicememoryreport.cpp b/layersvt/test/test_devicememoryreport.cpp index b005e9c0d5..6fc6c639b9 100644 --- a/layersvt/test/test_devicememoryreport.cpp +++ b/layersvt/test/test_devicememoryreport.cpp @@ -248,18 +248,18 @@ TEST_F(DeviceMemoryReportTests, UsageTypeBreakdown) { DeviceMemoryReport::MemoryReportCallback(&cb_data, nullptr); // Clean up objects - DeviceMemoryReport::Get().OnDestroyObject(VK_OBJECT_TYPE_IMAGE, color_img); - DeviceMemoryReport::Get().OnDestroyObject(VK_OBJECT_TYPE_IMAGE, depth_img); - DeviceMemoryReport::Get().OnDestroyObject(VK_OBJECT_TYPE_IMAGE, sampled_img); - DeviceMemoryReport::Get().OnDestroyObject(VK_OBJECT_TYPE_IMAGE, storage_img); - DeviceMemoryReport::Get().OnDestroyObject(VK_OBJECT_TYPE_IMAGE, transient_img); - - DeviceMemoryReport::Get().OnDestroyObject(VK_OBJECT_TYPE_BUFFER, vtx_buf); - DeviceMemoryReport::Get().OnDestroyObject(VK_OBJECT_TYPE_BUFFER, idx_buf); - DeviceMemoryReport::Get().OnDestroyObject(VK_OBJECT_TYPE_BUFFER, ubo_buf); - DeviceMemoryReport::Get().OnDestroyObject(VK_OBJECT_TYPE_BUFFER, staging_buf); - DeviceMemoryReport::Get().OnDestroyObject(VK_OBJECT_TYPE_BUFFER, storage_buf); - DeviceMemoryReport::Get().OnDestroyObject(VK_OBJECT_TYPE_BUFFER, indirect_buf); + DeviceMemoryReport::Get().OnDestroyObject(color_img); + DeviceMemoryReport::Get().OnDestroyObject(depth_img); + DeviceMemoryReport::Get().OnDestroyObject(sampled_img); + DeviceMemoryReport::Get().OnDestroyObject(storage_img); + DeviceMemoryReport::Get().OnDestroyObject(transient_img); + + DeviceMemoryReport::Get().OnDestroyObject(vtx_buf); + DeviceMemoryReport::Get().OnDestroyObject(idx_buf); + DeviceMemoryReport::Get().OnDestroyObject(ubo_buf); + DeviceMemoryReport::Get().OnDestroyObject(staging_buf); + DeviceMemoryReport::Get().OnDestroyObject(storage_buf); + DeviceMemoryReport::Get().OnDestroyObject(indirect_buf); EXPECT_TRUE(true); } @@ -315,7 +315,7 @@ TEST_F(DeviceMemoryReportTests, MemoryAliasingAndOverlap) { // - Interval [0, 4000) is removed. Remaining intervals: [2000, 6000) U [8000, 9500). // - Recalculated bound_size = 4,000 + 1,500 = 5,500 B. // - Updated unbound headroom: unbound_memory = 10,000 - 5,500 = 4,500 B. - DeviceMemoryReport::Get().OnDestroyObject(VK_OBJECT_TYPE_IMAGE, image_a); + DeviceMemoryReport::Get().OnDestroyObject(image_a); // Step 6: Free physical memory slab. // - All remaining sub-allocations on this slab are cleaned up and unbound counter is reset. @@ -323,8 +323,8 @@ TEST_F(DeviceMemoryReportTests, MemoryAliasingAndOverlap) { DeviceMemoryReport::MemoryReportCallback(&cb_data, nullptr); // Step 7: Clean up remaining virtual resource object handles. - DeviceMemoryReport::Get().OnDestroyObject(VK_OBJECT_TYPE_IMAGE, image_b); - DeviceMemoryReport::Get().OnDestroyObject(VK_OBJECT_TYPE_BUFFER, buffer_c); + DeviceMemoryReport::Get().OnDestroyObject(image_b); + DeviceMemoryReport::Get().OnDestroyObject(buffer_c); EXPECT_TRUE(true); } From 61a4e2585e869d244d7cf0d127e70d803cc20502 Mon Sep 17 00:00:00 2001 From: Jim Blackler Date: Wed, 16 Sep 2026 15:48:46 +0000 Subject: [PATCH 4/6] device_memory_report: move KHR commands to extension dispatch and add null guards Move vkBindBufferMemory2KHR, vkBindImageMemory2KHR, vkGetImageMemoryRequirements2KHR, and vkGetBufferMemoryRequirements2KHR from devmemreport_known_core_device_functions to devmemreport_known_device_extension_functions so vkGetInstanceProcAddr checks underlying driver support before returning interceptors. Additionally, add null checks in vkBindBufferMemory2KHR and vkBindImageMemory2KHR before dereferencing the device dispatch table. --- .../device_memory_report_handwritten_dispatch.cpp | 8 ++++---- .../device_memory_report_handwritten_functions.h | 6 ++++++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/layersvt/device_memory_report/device_memory_report_handwritten_dispatch.cpp b/layersvt/device_memory_report/device_memory_report_handwritten_dispatch.cpp index 0d17511036..f7b5a9d408 100644 --- a/layersvt/device_memory_report/device_memory_report_handwritten_dispatch.cpp +++ b/layersvt/device_memory_report/device_memory_report_handwritten_dispatch.cpp @@ -41,22 +41,22 @@ static PFN_vkVoidFunction devmemreport_known_core_device_functions(const char* p if (strcmp(pName, "vkBindImageMemory") == 0) return reinterpret_cast(vkBindImageMemory); if (strcmp(pName, "vkBindBufferMemory2") == 0) return reinterpret_cast(vkBindBufferMemory2); if (strcmp(pName, "vkBindImageMemory2") == 0) return reinterpret_cast(vkBindImageMemory2); - if (strcmp(pName, "vkBindBufferMemory2KHR") == 0) return reinterpret_cast(vkBindBufferMemory2KHR); - if (strcmp(pName, "vkBindImageMemory2KHR") == 0) return reinterpret_cast(vkBindImageMemory2KHR); if (strcmp(pName, "vkCreateImage") == 0) return reinterpret_cast(vkCreateImage); if (strcmp(pName, "vkDestroyImage") == 0) return reinterpret_cast(vkDestroyImage); if (strcmp(pName, "vkCreateBuffer") == 0) return reinterpret_cast(vkCreateBuffer); if (strcmp(pName, "vkDestroyBuffer") == 0) return reinterpret_cast(vkDestroyBuffer); if (strcmp(pName, "vkGetImageMemoryRequirements") == 0) return reinterpret_cast(vkGetImageMemoryRequirements); if (strcmp(pName, "vkGetImageMemoryRequirements2") == 0) return reinterpret_cast(vkGetImageMemoryRequirements2); - if (strcmp(pName, "vkGetImageMemoryRequirements2KHR") == 0) return reinterpret_cast(vkGetImageMemoryRequirements2KHR); if (strcmp(pName, "vkGetBufferMemoryRequirements") == 0) return reinterpret_cast(vkGetBufferMemoryRequirements); if (strcmp(pName, "vkGetBufferMemoryRequirements2") == 0) return reinterpret_cast(vkGetBufferMemoryRequirements2); - if (strcmp(pName, "vkGetBufferMemoryRequirements2KHR") == 0) return reinterpret_cast(vkGetBufferMemoryRequirements2KHR); return nullptr; } static PFN_vkVoidFunction devmemreport_known_device_extension_functions(const char* pName) { + if (strcmp(pName, "vkBindBufferMemory2KHR") == 0) return reinterpret_cast(vkBindBufferMemory2KHR); + if (strcmp(pName, "vkBindImageMemory2KHR") == 0) return reinterpret_cast(vkBindImageMemory2KHR); + if (strcmp(pName, "vkGetImageMemoryRequirements2KHR") == 0) return reinterpret_cast(vkGetImageMemoryRequirements2KHR); + if (strcmp(pName, "vkGetBufferMemoryRequirements2KHR") == 0) return reinterpret_cast(vkGetBufferMemoryRequirements2KHR); return nullptr; } diff --git a/layersvt/device_memory_report/device_memory_report_handwritten_functions.h b/layersvt/device_memory_report/device_memory_report_handwritten_functions.h index 78dc41d8d4..4527d0d26e 100644 --- a/layersvt/device_memory_report/device_memory_report_handwritten_functions.h +++ b/layersvt/device_memory_report/device_memory_report_handwritten_functions.h @@ -293,6 +293,9 @@ VKAPI_ATTR VkResult VKAPI_CALL vkBindBufferMemory2(VkDevice device, uint32_t bin // Intercept memory binding via vkBindBufferMemory2KHR to correlate buffer object handles with device memory allocations. VKAPI_ATTR VkResult VKAPI_CALL vkBindBufferMemory2KHR(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo* pBindInfos) { + if (device_dispatch_table(device)->BindBufferMemory2KHR == nullptr) { + return VK_ERROR_EXTENSION_NOT_PRESENT; + } VkResult result = device_dispatch_table(device)->BindBufferMemory2KHR(device, bindInfoCount, pBindInfos); if (result == VK_SUCCESS && pBindInfos != nullptr) { RecordBufferBindings(bindInfoCount, pBindInfos); @@ -319,6 +322,9 @@ VKAPI_ATTR VkResult VKAPI_CALL vkBindImageMemory2(VkDevice device, uint32_t bind // Intercept memory binding via vkBindImageMemory2KHR to correlate image object handles with device memory allocations. VKAPI_ATTR VkResult VKAPI_CALL vkBindImageMemory2KHR(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos) { + if (device_dispatch_table(device)->BindImageMemory2KHR == nullptr) { + return VK_ERROR_EXTENSION_NOT_PRESENT; + } VkResult result = device_dispatch_table(device)->BindImageMemory2KHR(device, bindInfoCount, pBindInfos); if (result == VK_SUCCESS && pBindInfos != nullptr) { RecordImageBinds(bindInfoCount, pBindInfos); From 7286c23f3de0a3f970c6c5eb7e801791d9480150 Mon Sep 17 00:00:00 2001 From: Jim Blackler Date: Wed, 16 Sep 2026 20:54:02 +0000 Subject: [PATCH 5/6] device_memory_report: replace extension null guards with assertions in KHR bind functions --- .../device_memory_report_handwritten_functions.h | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/layersvt/device_memory_report/device_memory_report_handwritten_functions.h b/layersvt/device_memory_report/device_memory_report_handwritten_functions.h index 4527d0d26e..6761dc3dbe 100644 --- a/layersvt/device_memory_report/device_memory_report_handwritten_functions.h +++ b/layersvt/device_memory_report/device_memory_report_handwritten_functions.h @@ -293,9 +293,7 @@ VKAPI_ATTR VkResult VKAPI_CALL vkBindBufferMemory2(VkDevice device, uint32_t bin // Intercept memory binding via vkBindBufferMemory2KHR to correlate buffer object handles with device memory allocations. VKAPI_ATTR VkResult VKAPI_CALL vkBindBufferMemory2KHR(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo* pBindInfos) { - if (device_dispatch_table(device)->BindBufferMemory2KHR == nullptr) { - return VK_ERROR_EXTENSION_NOT_PRESENT; - } + assert(device_dispatch_table(device)->BindBufferMemory2KHR != nullptr); VkResult result = device_dispatch_table(device)->BindBufferMemory2KHR(device, bindInfoCount, pBindInfos); if (result == VK_SUCCESS && pBindInfos != nullptr) { RecordBufferBindings(bindInfoCount, pBindInfos); @@ -322,9 +320,7 @@ VKAPI_ATTR VkResult VKAPI_CALL vkBindImageMemory2(VkDevice device, uint32_t bind // Intercept memory binding via vkBindImageMemory2KHR to correlate image object handles with device memory allocations. VKAPI_ATTR VkResult VKAPI_CALL vkBindImageMemory2KHR(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos) { - if (device_dispatch_table(device)->BindImageMemory2KHR == nullptr) { - return VK_ERROR_EXTENSION_NOT_PRESENT; - } + assert(device_dispatch_table(device)->BindImageMemory2KHR != nullptr); VkResult result = device_dispatch_table(device)->BindImageMemory2KHR(device, bindInfoCount, pBindInfos); if (result == VK_SUCCESS && pBindInfos != nullptr) { RecordImageBinds(bindInfoCount, pBindInfos); From 83c41c7b2624168ab86f9cc9c776575353d980cc Mon Sep 17 00:00:00 2001 From: Jim Blackler Date: Wed, 16 Sep 2026 20:54:34 +0000 Subject: [PATCH 6/6] device_memory_report: split global functions in GIPA and check instance earlier --- ...ice_memory_report_handwritten_dispatch.cpp | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/layersvt/device_memory_report/device_memory_report_handwritten_dispatch.cpp b/layersvt/device_memory_report/device_memory_report_handwritten_dispatch.cpp index f7b5a9d408..aa7ca0b2fc 100644 --- a/layersvt/device_memory_report/device_memory_report_handwritten_dispatch.cpp +++ b/layersvt/device_memory_report/device_memory_report_handwritten_dispatch.cpp @@ -19,14 +19,18 @@ extern "C" { -static PFN_vkVoidFunction devmemreport_known_instance_functions(const char* pName) { +static PFN_vkVoidFunction devmemreport_known_global_functions(const char* pName) { if (strcmp(pName, "vkGetInstanceProcAddr") == 0) return reinterpret_cast(vkGetInstanceProcAddr); if (strcmp(pName, "vkCreateInstance") == 0) return reinterpret_cast(vkCreateInstance); + if (strcmp(pName, "vkEnumerateInstanceExtensionProperties") == 0) return reinterpret_cast(vkEnumerateInstanceExtensionProperties); + if (strcmp(pName, "vkEnumerateInstanceLayerProperties") == 0) return reinterpret_cast(vkEnumerateInstanceLayerProperties); + return nullptr; +} + +static PFN_vkVoidFunction devmemreport_known_instance_functions(const char* pName) { if (strcmp(pName, "vkDestroyInstance") == 0) return reinterpret_cast(vkDestroyInstance); if (strcmp(pName, "vkEnumeratePhysicalDevices") == 0) return reinterpret_cast(vkEnumeratePhysicalDevices); if (strcmp(pName, "vkEnumeratePhysicalDeviceGroups") == 0) return reinterpret_cast(vkEnumeratePhysicalDeviceGroups); - if (strcmp(pName, "vkEnumerateInstanceExtensionProperties") == 0) return reinterpret_cast(vkEnumerateInstanceExtensionProperties); - if (strcmp(pName, "vkEnumerateInstanceLayerProperties") == 0) return reinterpret_cast(vkEnumerateInstanceLayerProperties); return nullptr; } @@ -69,7 +73,16 @@ static PFN_vkVoidFunction devmemreport_known_device_functions(const char* pName) } EXPORT_FUNCTION VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char* pName) { - PFN_vkVoidFunction func = devmemreport_known_instance_functions(pName); + PFN_vkVoidFunction func = devmemreport_known_global_functions(pName); + if (func) { + return func; + } + + if (instance == nullptr) { + return nullptr; + } + + func = devmemreport_known_instance_functions(pName); if (func) { return func; } @@ -80,10 +93,6 @@ EXPORT_FUNCTION VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(V return func; } - if (instance == nullptr) { - return nullptr; - } - auto table = instance_dispatch_table(instance); if (table == NULL || table->GetInstanceProcAddr == NULL) { return nullptr;