Vulkan: wrap external buffers as regions#9110
Conversation
|
This description sounds written by AI. Per our contribution guidelines, please disclose any AI tool usage or assert that none was used. |
|
Indeed. I did not review yet. Please don't until I do and I update description. Those things work on their own now |
|
@xFile3160 -- when ready for review, change the status away from Draft. |
1398255 to
d7ca1b1
Compare
derek-gerstmann
left a comment
There was a problem hiding this comment.
Thanks for the contribution! I suggested a few minor changes, but otherwise looks great.
@alexreinking FYI ... this PR adds new methods to the runtime api, so we should flag this for the release notes.
| int32_t offset = 0; //< indexing offset from start of region (used to adjust indices in compute shader to avoid alignment constraints for arbitrary crops) | ||
| }; | ||
|
|
||
| enum class MemoryRegionKind { |
There was a problem hiding this comment.
'Kind' is pretty vague. Perhaps rename this enum to something like MemoryOwnership.
There was a problem hiding this comment.
I'd change AllocatorOwned to just Owned, and ExternalWrapped to Wrapped.
| * owned. The device field of the halide_buffer_t must be 0 when this routine | ||
| * is called. | ||
| */ | ||
| extern int halide_vulkan_wrap_vk_buffer_with_offset(void *user_context, |
There was a problem hiding this comment.
We don't need two methods for this ... just keep this one with the offset parameter and rename it halide_vulkan_wrap_vk_buffer and delete the other one.
There was a problem hiding this comment.
yea I agree. I did the split because I wanted to preserve the zero-offset call.
| (void *)&halide_vulkan_initialize_kernels, | ||
| (void *)&halide_vulkan_release_context, | ||
| (void *)&halide_vulkan_run, | ||
| (void *)&halide_vulkan_wrap_vk_buffer, |
There was a problem hiding this comment.
We only need one of these, remove the second.
| namespace Internal { | ||
| namespace Vulkan { | ||
|
|
||
| ALWAYS_INLINE const MemoryRegion *vk_region_root(const MemoryRegion *region) { |
There was a problem hiding this comment.
This isn't returning the root ... it's returning the owner. Rename it vk_region_owner
There was a problem hiding this comment.
How is this different than ctx.allocator->owner_of()?
There was a problem hiding this comment.
So I needed an helper to follow crop aliases back to the owning region. A cropped buffer gets a MemoryRegion that is just metadata pointing back to the owning region. When we wrap buffers, we need to walk through any crop aliases to find the actual external wrapper region that owns the vkBuffer metadata and base offset. I think I encountered this specifically when dealing with nv21/nv12.
| return current; | ||
| } | ||
|
|
||
| ALWAYS_INLINE MemoryRegion *vk_region_root(MemoryRegion *region) { |
There was a problem hiding this comment.
Remove this ... overloading the same method is error prone, and the const casting is bad.
| } | ||
|
|
||
| if (region != root && region->kind == MemoryRegionKind::CropAlias) { | ||
| free(region); |
There was a problem hiding this comment.
You shouldn't be calling free() directly ... use vk_host_free() and pass on the allocation callbacks for the context.
There was a problem hiding this comment.
yep agreed, you're right. This was host metadata tho, but I will use vk_host_malloc and vk_host_free
| return nullptr; | ||
| } | ||
|
|
||
| MemoryRegion *region = reinterpret_cast<MemoryRegion *>(malloc(sizeof(MemoryRegion))); |
There was a problem hiding this comment.
You shouldn't be calling malloc() or free() directly ... use vk_host_malloc() and vk_host_free() and pass on the allocation callbacks for the context.
| // get the allocated region for the device | ||
| MemoryRegion *device_region = reinterpret_cast<MemoryRegion *>(halide_buffer->device); | ||
| #ifdef DEBUG_RUNTIME | ||
| const uint64_t device_region_size = device_region->allocation.size; |
There was a problem hiding this comment.
If this is only for printing a debug message, then move the declaration and the ifdef down below and wrap the debug() call.
| return halide_error_code_success; | ||
| } | ||
|
|
||
| WEAK int halide_vulkan_wrap_vk_buffer(void *user_context, struct halide_buffer_t *buf, uint64_t vk_buffer) { |
There was a problem hiding this comment.
We don't need two methods for this. Remove this one, and rename the other one to halide_vulkan_wrap_vk_buffer
| } | ||
|
|
||
| MemoryRegion *owner = owner_of(user_context, region); | ||
| if (owner != nullptr && owner->kind == MemoryRegionKind::ExternalWrapped) { |
There was a problem hiding this comment.
What's wrong with mapping an externally wrapped buffer()?
There was a problem hiding this comment.
so the halide allocator map() expects allovcator owned BlockResource and VkDeviceMemory. For external wrapped buffer, Halide does not know memory handle, bind offset, memory properties, host visibility, coherency and ownership. Wouldn't be unsafe to allow this?
fa83aad to
a4dac01
Compare
|
@derek-gerstmann I also updated this one, rebased it on main. |
This lets callers wrap an external
VkBufferdirectly.halide_vulkan_wrap_vk_buffer(..., offset)creates Halide-owned metadata for the buffer. The caller still owns theVkBuffer, so detach/free only releases Halide metadata.The offset is used in descriptor and copy paths. Crops are view metadata that point back to the owned or wrapped root buffer. Mapping wrapped external buffers stays unsupported because Halide only has the
VkBuffer; it does not know the backingVkDeviceMemory, memory properties, bind offset, host visibility/coherency, or ownership.Added Vulkan buffer wrap/get/offset/detach coverage.
AI disclosure:
I used OpenAI Codex to help inspect code, draft/revise the patch. I reviewed the final code and take responsibility for it.