Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ pub enum AllocationError {
CastableFormatsRequiresEnhancedBarriers,
#[error("Castable formats require at least `Device12`")]
CastableFormatsRequiresAtLeastDevice12,

#[error("Allocating exportable memory requires the allocator be created with external memory support")]
ExternalMemoryUnsupported,
}

pub type Result<V, E = AllocationError> = ::std::result::Result<V, E>;
38 changes: 38 additions & 0 deletions src/vulkan/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ pub struct AllocationCreateDesc<'a> {
pub linear: bool,
/// Determines how this allocation should be managed.
pub allocation_scheme: AllocationScheme,
/// Determines whether the memory should be usable with `VK_KHR_external_memory_fd` or `VK_KHR_external_memory_win32`
pub external_use: bool,
}

/// Wrapper type to only mark a raw pointer [`Send`] + [`Sync`] without having to
Expand All @@ -62,6 +64,8 @@ pub struct AllocatorCreateDesc {
pub debug_settings: AllocatorDebugSettings,
pub buffer_device_address: bool,
pub allocation_sizes: AllocationSizes,
/// Whether the device supports the proper external memory extension like `VK_KHR_external_memory_fd`
pub external_memory: bool,
}

/// A piece of allocated memory.
Expand Down Expand Up @@ -343,9 +347,11 @@ pub(crate) struct MemoryBlock {
pub(crate) sub_allocator: Box<dyn SubAllocator>,
#[cfg(feature = "visualizer")]
pub(crate) dedicated_allocation: bool,
pub(crate) exportable: bool,
}

impl MemoryBlock {
#[allow(clippy::too_many_arguments, clippy::fn_params_excessive_bools)]
fn new(
device: &ash::Device,
size: u64,
Expand All @@ -354,6 +360,7 @@ impl MemoryBlock {
buffer_device_address: bool,
allocation_scheme: AllocationScheme,
requires_personal_block: bool,
exportable: bool,
) -> Result<Self> {
let device_memory = {
let alloc_info = vk::MemoryAllocateInfo::default()
Expand All @@ -368,6 +375,20 @@ impl MemoryBlock {
} else {
alloc_info
};
#[cfg(windows)]
let mut export_info = vk::ExportMemoryAllocateInfoKHR::default()
.handle_types(vk::ExternalMemoryHandleTypeFlags::OPAQUE_WIN32_KHR);
#[cfg(all(unix, not(target_vendor = "apple")))]
let mut export_info = vk::ExportMemoryAllocateInfoKHR::default()
.handle_types(vk::ExternalMemoryHandleTypeFlags::OPAQUE_FD_KHR);

// On other platforms you can't create an external capable allocator, so this would be unreachable
#[cfg(any(windows, all(unix, not(target_vendor = "apple"))))]
Copy link
Member

Choose a reason for hiding this comment

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

I think on other platforms then we should fail with an error rather then silently failing to create an exportable texture.

Copy link
Author

@inner-daemons inner-daemons Jul 17, 2025

Choose a reason for hiding this comment

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

The error would occur elsewhere, see lines 843-845

let alloc_info = if exportable {
alloc_info.push_next(&mut export_info)
} else {
alloc_info
};

// Flag the memory as dedicated if required.
let mut dedicated_memory_info = vk::MemoryDedicatedAllocateInfo::default();
Expand Down Expand Up @@ -430,6 +451,7 @@ impl MemoryBlock {
sub_allocator,
#[cfg(feature = "visualizer")]
dedicated_allocation: allocation_scheme != AllocationScheme::GpuAllocatorManaged,
exportable,
})
}

Expand Down Expand Up @@ -490,6 +512,7 @@ impl MemoryType {
self.buffer_device_address,
desc.allocation_scheme,
requires_personal_block,
desc.external_use,
)?;

let mut block_index = None;
Expand Down Expand Up @@ -541,6 +564,9 @@ impl MemoryType {
let mut empty_block_index = None;
for (mem_block_i, mem_block) in self.memory_blocks.iter_mut().enumerate().rev() {
if let Some(mem_block) = mem_block {
if mem_block.exportable != desc.external_use {
continue;
}
let allocation = mem_block.sub_allocator.allocate(
size,
alignment,
Expand Down Expand Up @@ -590,6 +616,7 @@ impl MemoryType {
self.buffer_device_address,
desc.allocation_scheme,
false,
desc.external_use,
)?;

let new_block_index = if let Some(block_index) = empty_block_index {
Expand Down Expand Up @@ -684,6 +711,7 @@ pub struct Allocator {
pub(crate) memory_heaps: Vec<vk::MemoryHeap>,
device: ash::Device,
pub(crate) buffer_image_granularity: u64,
pub(crate) external_memory_support: bool,
pub(crate) debug_settings: AllocatorDebugSettings,
allocation_sizes: AllocationSizes,
}
Expand All @@ -701,6 +729,12 @@ impl Allocator {
"AllocatorCreateDesc field `physical_device` is null.".into(),
));
}
#[cfg(not(any(windows, all(unix, not(target_vendor = "apple")))))]
if desc.external_memory {
return Err(AllocationError::InvalidAllocatorCreateDesc(
"External memory is enabled but currently only supported on windows and non-apple unix platforms".into(),
));
}

let mem_props = unsafe {
desc.instance
Expand Down Expand Up @@ -763,6 +797,7 @@ impl Allocator {
buffer_image_granularity: granularity,
debug_settings: desc.debug_settings,
allocation_sizes: desc.allocation_sizes,
external_memory_support: desc.external_memory,
})
}

Expand Down Expand Up @@ -790,6 +825,9 @@ impl Allocator {
if size == 0 || !alignment.is_power_of_two() {
return Err(AllocationError::InvalidAllocationCreateDesc);
}
if desc.external_use && !self.external_memory_support {
return Err(AllocationError::ExternalMemoryUnsupported);
}

let mem_loc_preferred_bits = match desc.location {
MemoryLocation::GpuOnly => vk::MemoryPropertyFlags::DEVICE_LOCAL,
Expand Down
Loading