Added Win32 Import function prototype#503
Added Win32 Import function prototype#503jlacroixAMD merged 1 commit intoGPUOpen-LibrariesAndSDKs:masterfrom
Conversation
|
I am sorry but I don't want to add such a significant amount of code to avoid feature creep. Importing Win32 or D3D11 handles is a special feature that looks very detached from what VMA library does. The purpose of VMA is to simplify the most common use case which is creating buffers and images while suballocating them from larger I also don't want to add dependency on DXGI or D3D11 to the sample project. Initializing D3D11 device in the VMA sample is far out of scope of this codebase. |
|
Yes, it always allocates a dedicated block that is managed by VmaAllocation. The main feature of the block is to hold the reference to shared object and clean it up. Secondly There is D3D12 heap and Vulkan Opaque Win32 Handle/KMT, which are allocations of the block of memory, which is to be suballocated. I can see the latter being allocated with VMAPool object, but with D3D12 there is more work. My test was misleading a bit, I acknowledge it. Should I then decline the PR? |
|
Regarding your comment in #499, what do you mean by "at least add an export function and update the handle for KMT handles"? Do you mean adding |
|
You see, the problem with those extensions are, that they don't provide a uniform way to export handles. vmaGetMemoryWin32Handle2 can theoretically export any heap (D3D11/12, Win32 and KMT variations). Right now vmaGetMemoryWin32Handle only exports a Win32 Opaque, which is well managed, but limited, as D3D can't import those, only OpenGL and Vulkan can. All D3D and KMT versions are still Win32 HANDLEs, so the logic holds. I could also add FD and others support, but that would be in another PR. Now I actually think, maybe it is worth to create an extension header for those features, instead of adding everything to a single file? |
| private: | ||
| HANDLE m_hHandle; | ||
| VMA_RW_MUTEX m_Mutex; // Protects access m_Handle | ||
| bool m_NTHandle = false; // True if m_Handle is NT handle, false if it's a KMT handle. |
There was a problem hiding this comment.
I suggest renaming this variable to m_IsNTHandle.
| m_hHandle = VMA_NULL; | ||
| return res; | ||
| } | ||
| m_NTHandle = (::GetHandleInformation(m_hHandle, VMA_NULL) != 0); |
There was a problem hiding this comment.
Shouldn't you rather use IsNTHandle method here instead of duplicating its logic?
| public: | ||
| // Strengthened | ||
| VkResult GetHandle(VkDevice device, VkDeviceMemory memory, PFN_vkGetMemoryWin32HandleKHR pvkGetMemoryWin32HandleKHR, HANDLE hTargetProcess, bool useMutex, HANDLE* pHandle) noexcept | ||
| VkResult GetHandle(VkDevice device, VkDeviceMemory memory, PFN_vkGetMemoryWin32HandleKHR pvkGetMemoryWin32HandleKHR, VkExternalMemoryHandleTypeFlagBits handleType, HANDLE hTargetProcess, bool useMutex, HANDLE* pHandle) noexcept |
There was a problem hiding this comment.
Would it make sense to add an VMA_ASSERT here restricting handleType to only compatible values?
There was a problem hiding this comment.
I have added it to vmaGetMemoryWin32Handle2, since it is the only place this could matter
There was a problem hiding this comment.
OK, I trust you in implementing it the best way, since you know this are and you can test it.
|
I propose to split this change into 2 phases. 1. Extending exportI am happy to accept the part of your code related to extending export to other types of handles - the logic that starts at function I just posted few comments as a code review. 2. Adding importI have another idea. What if I add following functions that would create I think this approach would:
VMA_CALL_PRE VkResult VMA_CALL_POST vmaAllocateDedicatedMemory(
VmaAllocator VMA_NOT_NULL allocator,
const VkMemoryRequirements* VMA_NOT_NULL pVkMemoryRequirements,
const VmaAllocationCreateInfo* VMA_NOT_NULL pCreateInfo,
void* VMA_NULLABLE VMA_EXTENDS_VK_STRUCT(VkMemoryAllocateInfo) pMemoryAllocateNext,
VmaAllocation VMA_NULLABLE* VMA_NOT_NULL pAllocation,
VmaAllocationInfo* VMA_NULLABLE pAllocationInfo);
VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateDedicatedBuffer(
VmaAllocator VMA_NOT_NULL allocator,
const VkBufferCreateInfo* VMA_NOT_NULL pBufferCreateInfo,
const VmaAllocationCreateInfo* VMA_NOT_NULL pAllocationCreateInfo,
void* VMA_NULLABLE VMA_EXTENDS_VK_STRUCT(VkMemoryAllocateInfo) pMemoryAllocateNext,
VkBuffer VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pBuffer,
VmaAllocation VMA_NULLABLE* VMA_NOT_NULL pAllocation,
VmaAllocationInfo* VMA_NULLABLE pAllocationInfo);
VMA_CALL_PRE VkResult VMA_CALL_POST vmaCreateDedicatedImage(
VmaAllocator VMA_NOT_NULL allocator,
const VkImageCreateInfo* VMA_NOT_NULL pImageCreateInfo,
const VmaAllocationCreateInfo* VMA_NOT_NULL pAllocationCreateInfo,
void* VMA_NULLABLE VMA_EXTENDS_VK_STRUCT(VkMemoryAllocateInfo) pMemoryAllocateNext,
VkImage VMA_NULLABLE_NON_DISPATCHABLE* VMA_NOT_NULL pImage,
VmaAllocation VMA_NULLABLE* VMA_NOT_NULL pAllocation,
VmaAllocationInfo* VMA_NULLABLE pAllocationInfo);Would that work for you? If yes, I can implement those. I don't want to add dependency on extra Vulkan function What do you mean by "extension header"? Some new library on top of VMA? That would be out of scope of this repository. Any external repository or fork is welcome - I can link to it from README. |
|
I like that idea more, flexibility is very good! That could actually overshadow creation of dedicated allocator just for exporting memory. I think that is the best course this can go. I will deliver the export call shortly. |
|
Another question. Now that I think of it, FD and HANDLE are mutually exclusive, so it can theoretically be created in a single function call. They behave the same, only RAII wrappers would be changed a bit. I will try doing that and present it for review. EDIT: I have looked up the behavior of FD, it does not make sense to do this for FD, since it has no such UB as windows HANDLEs |
886d2c0 to
f990ad9
Compare
|
Thank you for preparing this code. It all looks good to me. However, when I tested it, it crashes on my machine. Did you test it with launching the sample app and pressing "T"? Call stack:
It's inside
I use Windows 11 24H2 (OS Build 26100.4946). |
|
I did, yet I couldn't test it after the changes, since I'm a bit away from the machine. I will do it tomorrow morning EDIT: I did a small change, that might be causing this. I wonder why it didn't throw anything on me before. If you could run it again I would be grateful. |
|
Thanks for the fix! I merged your code - to my fork for now: I will implement my part with "Dedicated" functions soon. |
|
Thanks! |
|
I've updated documentation. Can you please check if it looks correct? You can find local HTML pages in my fork, latest code of the master branch, file "docs/html/index.html". What I changed is:
|
|
I am also wondering if specifying multiple handle types is allowed and should be supported? These are bit flags, after all. |
|
Adding multiple handle export types are allowed only on memory creation. |
Well, technically, handleType can be a KMT (Kernel Mode Thunk) or an NT handle. Any NT handle must be closed with CloseHandle. KMT handles are global and they must not be closed. Also, KMT handles don't maintain reference count to underlying memory, so destroying the memory in one process will cause a device removal (analogous to SIGSEGV on GPU). |
|
How does the concept of KMT and NT handles map to handle types available in Vulkan? How do you propose to fix the documentation? |
|
I started coding something on branch add-create-dedicated, adding function I found a way to test memory import without pulling D3D11. I create a WinAPI shared memory handle using |
You don't have to. It is possible to just create a memory on Vulkan side with handle type VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT_KHR and then import it on the same device. That should create a compatible handle. |
|
OK, that's another option, but possibly testing this shared memory block is better because I also write to it using pointer obtained through WinAPI Also, this way the tests for export and import stay separate. |
KMT are explicitly stated as KMT handles, they are VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT_KHR and VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR. They are global, opaque, use the same type, but can't be freed. This is internally checked in VMA. Something like that |
Maybe, if it works :) |
Based on discussion in GPUOpen-LibrariesAndSDKs#503 - thanks @Agrael1
|
OK, I updated the docs on the master branch of my fork, adding "or other NT handle types", as you suggested. |
|
I finished implementing the functions I planned on branch add-create-dedicated: However, I have a mysterious problem. On my RTX 4090, when |
|
I can't make my test working correctly. It passes on Nvidia card, but on my AMD integrated graphics it crashes somewhere later. Maybe the test you proposed with export and import would work better? Can you please show how it should look like? |
|
Sure, I am a bit exhausted now, I will get back in an hour or so. The test is simple, just copy the test with handle export, but instead of creating buffer allocate memory with D3D12_HEAP over the pool with added flag. Then export the handle of that allocation and import it back. That should work from what I remember. The thing is, I was able to create heaps for export, but I wasn't able to create buffers over heaps that are exported to D3D11/12, but you can still import them. Which is odd, since after import you can create a buffer. But that worked on NVidia, don't know what would AMD say on that. It looks suspiciously. |
|
Hi, I have created a patch with test of importing capabilities: The test is basic, just creation doing create buffer on pool with export -> export its handle -> import in main allocator without any export capabilities. I have tried creating a D3D12 heap, but ultimately it didn't work out. I have also tested D3D11 handle locally, it works. |
Based on a patch proposed in GPUOpen-LibrariesAndSDKs#503 - thanks @Agrael1
|
Did you test the code you proposed in the patch? It failed for me on When checking for I pushed the changes to this test to my branch and fork, like before. Please let me know if all looks good to you. |
|
Yes, I have tested the code, but I think I have debugged through and stopped right before the CloseHandle. Everything seems good |
I have added an import function for Win32 Handle and also added
vmaGetMemoryWin32Handle2that can export handle with supplied handle type. Note that Allocator must be created with support for supplied handle type.Closes #499