Skip to content

Vulkan: wrap external buffers as regions#9110

Open
xFile3160 wants to merge 1 commit into
halide:mainfrom
xFile3160:vulkan-import-buffer-offsets
Open

Vulkan: wrap external buffers as regions#9110
xFile3160 wants to merge 1 commit into
halide:mainfrom
xFile3160:vulkan-import-buffer-offsets

Conversation

@xFile3160
Copy link
Copy Markdown

@xFile3160 xFile3160 commented Apr 25, 2026

This lets callers wrap an external VkBuffer directly. halide_vulkan_wrap_vk_buffer(..., offset) creates Halide-owned metadata for the buffer. The caller still owns the VkBuffer, 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 backing VkDeviceMemory, 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.

@alexreinking
Copy link
Copy Markdown
Member

This description sounds written by AI. Per our contribution guidelines, please disclose any AI tool usage or assert that none was used.

@xFile3160
Copy link
Copy Markdown
Author

Indeed. I did not review yet. Please don't until I do and I update description. Those things work on their own now

@alexreinking alexreinking marked this pull request as draft April 27, 2026 17:43
@alexreinking
Copy link
Copy Markdown
Member

@xFile3160 -- when ready for review, change the status away from Draft.

@xFile3160 xFile3160 force-pushed the vulkan-import-buffer-offsets branch from 1398255 to d7ca1b1 Compare April 28, 2026 19:27
@xFile3160 xFile3160 marked this pull request as ready for review April 28, 2026 20:28
Copy link
Copy Markdown
Contributor

@derek-gerstmann derek-gerstmann left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread src/runtime/internal/memory_resources.h Outdated
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 {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'Kind' is pretty vague. Perhaps rename this enum to something like MemoryOwnership.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd change AllocatorOwned to just Owned, and ExternalWrapped to Wrapped.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep I agree will change this.

Comment thread src/runtime/HalideRuntimeVulkan.h Outdated
* 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,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We only need one of these, remove the second.

Comment thread src/runtime/vulkan.cpp Outdated
namespace Internal {
namespace Vulkan {

ALWAYS_INLINE const MemoryRegion *vk_region_root(const MemoryRegion *region) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't returning the root ... it's returning the owner. Rename it vk_region_owner

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How is this different than ctx.allocator->owner_of()?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread src/runtime/vulkan.cpp Outdated
return current;
}

ALWAYS_INLINE MemoryRegion *vk_region_root(MemoryRegion *region) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this ... overloading the same method is error prone, and the const casting is bad.

Comment thread src/runtime/vulkan.cpp Outdated
}

if (region != root && region->kind == MemoryRegionKind::CropAlias) {
free(region);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You shouldn't be calling free() directly ... use vk_host_free() and pass on the allocation callbacks for the context.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep agreed, you're right. This was host metadata tho, but I will use vk_host_malloc and vk_host_free

Comment thread src/runtime/vulkan.cpp Outdated
return nullptr;
}

MemoryRegion *region = reinterpret_cast<MemoryRegion *>(malloc(sizeof(MemoryRegion)));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread src/runtime/vulkan.cpp
// 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;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is only for printing a debug message, then move the declaration and the ifdef down below and wrap the debug() call.

Comment thread src/runtime/vulkan.cpp Outdated
return halide_error_code_success;
}

WEAK int halide_vulkan_wrap_vk_buffer(void *user_context, struct halide_buffer_t *buf, uint64_t vk_buffer) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need two methods for this. Remove this one, and rename the other one to halide_vulkan_wrap_vk_buffer

Comment thread src/runtime/vulkan_memory.h Outdated
}

MemoryRegion *owner = owner_of(user_context, region);
if (owner != nullptr && owner->kind == MemoryRegionKind::ExternalWrapped) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's wrong with mapping an externally wrapped buffer()?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

@derek-gerstmann derek-gerstmann added enhancement New user-visible features or improvements to existing features. gpu labels May 4, 2026
@alexreinking alexreinking added the release_notes For changes that may warrant a note in README for official releases. label May 4, 2026
@xFile3160 xFile3160 force-pushed the vulkan-import-buffer-offsets branch from fa83aad to a4dac01 Compare May 18, 2026 06:45
@xFile3160
Copy link
Copy Markdown
Author

@derek-gerstmann I also updated this one, rebased it on main.
I've addressed the naming feedback for MemoryOwnership, Owned and Wrapped. I have also cropAlias: crops are view metadata not root allocations. A crop can point back to either owned or wrapped root.
I kept the wrap_vk_buffer(..., offset) and the old one now is internal glue calling this with offset = 0.
I also replaced direct malloc/free with vk_host_malloc/free like you pointed out. I reused the owner_of of the VulkanMemoryAllocator because the helper wasn't needed, was doing exactly same thing. The detach/free only releases halide metadata not the vkBuffer when external, and added test coverage.
To answer your question about map/unmap: it's not safe to map wrapped external buffers because halide has only the extenral vkbuffer. It doesn't know or own VkDeviceMemory, properties, host visibility etc.
Thanks again for all the feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New user-visible features or improvements to existing features. gpu release_notes For changes that may warrant a note in README for official releases.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants