mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-11-21 22:33:49 +00:00
Vulkan: create texture from d3d11 shared handle (#6161)
This commit is contained in:
parent
a398d9990e
commit
8b99c3c4f5
@ -970,6 +970,11 @@ impl PhysicalDeviceProperties {
|
||||
extensions.push(ext::robustness2::NAME);
|
||||
}
|
||||
|
||||
// Optional `VK_KHR_external_memory_win32`
|
||||
if self.supports_extension(khr::external_memory_win32::NAME) {
|
||||
extensions.push(khr::external_memory_win32::NAME);
|
||||
}
|
||||
|
||||
// Require `VK_KHR_draw_indirect_count` if the associated feature was requested
|
||||
// Even though Vulkan 1.2 has promoted the extension to core, we must require the extension to avoid
|
||||
// large amounts of spaghetti involved with using PhysicalDeviceVulkan12Features.
|
||||
@ -1539,6 +1544,9 @@ impl super::Instance {
|
||||
}),
|
||||
image_format_list: phd_capabilities.device_api_version >= vk::API_VERSION_1_2
|
||||
|| phd_capabilities.supports_extension(khr::image_format_list::NAME),
|
||||
#[cfg(windows)]
|
||||
external_memory_win32: phd_capabilities
|
||||
.supports_extension(khr::external_memory_win32::NAME),
|
||||
};
|
||||
let capabilities = crate::Capabilities {
|
||||
limits: phd_capabilities.to_wgpu_limits(),
|
||||
|
@ -686,6 +686,7 @@ impl super::Device {
|
||||
super::Texture {
|
||||
raw: vk_image,
|
||||
drop_guard,
|
||||
external_memory: None,
|
||||
block: None,
|
||||
usage: desc.usage,
|
||||
format: desc.format,
|
||||
@ -695,6 +696,167 @@ impl super::Device {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn find_memory_type_index(
|
||||
&self,
|
||||
type_bits_req: u32,
|
||||
flags_req: vk::MemoryPropertyFlags,
|
||||
) -> Option<usize> {
|
||||
let mem_properties = unsafe {
|
||||
self.shared
|
||||
.instance
|
||||
.raw
|
||||
.get_physical_device_memory_properties(self.shared.physical_device)
|
||||
};
|
||||
|
||||
// https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceMemoryProperties.html
|
||||
for (i, mem_ty) in mem_properties.memory_types_as_slice().iter().enumerate() {
|
||||
let types_bits = 1 << i;
|
||||
let is_required_memory_type = type_bits_req & types_bits != 0;
|
||||
let has_required_properties = mem_ty.property_flags & flags_req == flags_req;
|
||||
if is_required_memory_type && has_required_properties {
|
||||
return Some(i);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn create_image_without_memory(
|
||||
&self,
|
||||
desc: &crate::TextureDescriptor,
|
||||
external_memory_image_create_info: Option<&mut vk::ExternalMemoryImageCreateInfo>,
|
||||
) -> Result<ImageWithoutMemory, crate::DeviceError> {
|
||||
let copy_size = desc.copy_extent();
|
||||
|
||||
let mut raw_flags = vk::ImageCreateFlags::empty();
|
||||
if desc.is_cube_compatible() {
|
||||
raw_flags |= vk::ImageCreateFlags::CUBE_COMPATIBLE;
|
||||
}
|
||||
|
||||
let original_format = self.shared.private_caps.map_texture_format(desc.format);
|
||||
let mut vk_view_formats = vec![];
|
||||
let mut wgt_view_formats = vec![];
|
||||
if !desc.view_formats.is_empty() {
|
||||
raw_flags |= vk::ImageCreateFlags::MUTABLE_FORMAT;
|
||||
wgt_view_formats.clone_from(&desc.view_formats);
|
||||
wgt_view_formats.push(desc.format);
|
||||
|
||||
if self.shared.private_caps.image_format_list {
|
||||
vk_view_formats = desc
|
||||
.view_formats
|
||||
.iter()
|
||||
.map(|f| self.shared.private_caps.map_texture_format(*f))
|
||||
.collect();
|
||||
vk_view_formats.push(original_format)
|
||||
}
|
||||
}
|
||||
if desc.format.is_multi_planar_format() {
|
||||
raw_flags |= vk::ImageCreateFlags::MUTABLE_FORMAT;
|
||||
}
|
||||
|
||||
let mut vk_info = vk::ImageCreateInfo::default()
|
||||
.flags(raw_flags)
|
||||
.image_type(conv::map_texture_dimension(desc.dimension))
|
||||
.format(original_format)
|
||||
.extent(conv::map_copy_extent(©_size))
|
||||
.mip_levels(desc.mip_level_count)
|
||||
.array_layers(desc.array_layer_count())
|
||||
.samples(vk::SampleCountFlags::from_raw(desc.sample_count))
|
||||
.tiling(vk::ImageTiling::OPTIMAL)
|
||||
.usage(conv::map_texture_usage(desc.usage))
|
||||
.sharing_mode(vk::SharingMode::EXCLUSIVE)
|
||||
.initial_layout(vk::ImageLayout::UNDEFINED);
|
||||
|
||||
let mut format_list_info = vk::ImageFormatListCreateInfo::default();
|
||||
if !vk_view_formats.is_empty() {
|
||||
format_list_info = format_list_info.view_formats(&vk_view_formats);
|
||||
vk_info = vk_info.push_next(&mut format_list_info);
|
||||
}
|
||||
|
||||
if let Some(ext_info) = external_memory_image_create_info {
|
||||
vk_info = vk_info.push_next(ext_info);
|
||||
}
|
||||
|
||||
let raw = unsafe { self.shared.raw.create_image(&vk_info, None) }.map_err(map_err)?;
|
||||
fn map_err(err: vk::Result) -> crate::DeviceError {
|
||||
// We don't use VK_EXT_image_compression_control
|
||||
// VK_ERROR_COMPRESSION_EXHAUSTED_EXT
|
||||
super::map_host_device_oom_and_ioca_err(err)
|
||||
}
|
||||
let req = unsafe { self.shared.raw.get_image_memory_requirements(raw) };
|
||||
|
||||
Ok(ImageWithoutMemory {
|
||||
raw,
|
||||
requirements: req,
|
||||
copy_size,
|
||||
view_formats: wgt_view_formats,
|
||||
raw_flags,
|
||||
})
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// - Vulkan 1.1+ (or VK_KHR_external_memory)
|
||||
/// - The `d3d11_shared_handle` must be valid and respecting `desc`
|
||||
/// - `VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT` flag is used because we need to hold a reference to the handle
|
||||
#[cfg(windows)]
|
||||
pub unsafe fn texture_from_d3d11_shared_handle(
|
||||
&self,
|
||||
d3d11_shared_handle: windows::Win32::Foundation::HANDLE,
|
||||
desc: &crate::TextureDescriptor,
|
||||
) -> Result<super::Texture, crate::DeviceError> {
|
||||
if !self.shared.private_caps.external_memory_win32 {
|
||||
log::error!("VK_KHR_external_memory extension is required");
|
||||
return Err(crate::DeviceError::ResourceCreationFailed);
|
||||
}
|
||||
|
||||
let mut external_memory_image_info = vk::ExternalMemoryImageCreateInfo::default()
|
||||
.handle_types(vk::ExternalMemoryHandleTypeFlags::D3D11_TEXTURE);
|
||||
|
||||
let image =
|
||||
self.create_image_without_memory(desc, Some(&mut external_memory_image_info))?;
|
||||
|
||||
let mut import_memory_info = vk::ImportMemoryWin32HandleInfoKHR::default()
|
||||
.handle_type(vk::ExternalMemoryHandleTypeFlags::D3D11_TEXTURE)
|
||||
.handle(d3d11_shared_handle.0 as _);
|
||||
|
||||
let mem_type_index = self
|
||||
.find_memory_type_index(
|
||||
image.requirements.memory_type_bits,
|
||||
vk::MemoryPropertyFlags::DEVICE_LOCAL,
|
||||
)
|
||||
.ok_or(crate::DeviceError::ResourceCreationFailed)?;
|
||||
|
||||
let memory_allocate_info = vk::MemoryAllocateInfo::default()
|
||||
.allocation_size(image.requirements.size)
|
||||
.memory_type_index(mem_type_index as _)
|
||||
.push_next(&mut import_memory_info);
|
||||
let memory = unsafe { self.shared.raw.allocate_memory(&memory_allocate_info, None) }
|
||||
.map_err(super::map_host_device_oom_err)?;
|
||||
|
||||
unsafe { self.shared.raw.bind_image_memory(image.raw, memory, 0) }
|
||||
.map_err(super::map_host_device_oom_err)?;
|
||||
|
||||
if let Some(label) = desc.label {
|
||||
unsafe { self.shared.set_object_name(image.raw, label) };
|
||||
}
|
||||
|
||||
self.counters.textures.add(1);
|
||||
|
||||
Ok(super::Texture {
|
||||
raw: image.raw,
|
||||
drop_guard: None,
|
||||
external_memory: Some(memory),
|
||||
block: None,
|
||||
usage: desc.usage,
|
||||
format: desc.format,
|
||||
raw_flags: image.raw_flags,
|
||||
copy_size: image.copy_size,
|
||||
view_formats: image.view_formats,
|
||||
})
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// - `vk_buffer`'s memory must be managed by the caller
|
||||
@ -1028,74 +1190,16 @@ impl crate::Device for super::Device {
|
||||
&self,
|
||||
desc: &crate::TextureDescriptor,
|
||||
) -> Result<super::Texture, crate::DeviceError> {
|
||||
let copy_size = desc.copy_extent();
|
||||
|
||||
let mut raw_flags = vk::ImageCreateFlags::empty();
|
||||
if desc.is_cube_compatible() {
|
||||
raw_flags |= vk::ImageCreateFlags::CUBE_COMPATIBLE;
|
||||
}
|
||||
|
||||
let original_format = self.shared.private_caps.map_texture_format(desc.format);
|
||||
let mut vk_view_formats = vec![];
|
||||
let mut wgt_view_formats = vec![];
|
||||
if !desc.view_formats.is_empty() {
|
||||
raw_flags |= vk::ImageCreateFlags::MUTABLE_FORMAT;
|
||||
wgt_view_formats.clone_from(&desc.view_formats);
|
||||
wgt_view_formats.push(desc.format);
|
||||
|
||||
if self.shared.private_caps.image_format_list {
|
||||
vk_view_formats = desc
|
||||
.view_formats
|
||||
.iter()
|
||||
.map(|f| self.shared.private_caps.map_texture_format(*f))
|
||||
.collect();
|
||||
vk_view_formats.push(original_format)
|
||||
}
|
||||
}
|
||||
if desc.format.is_multi_planar_format() {
|
||||
raw_flags |= vk::ImageCreateFlags::MUTABLE_FORMAT;
|
||||
}
|
||||
|
||||
let mut vk_info = vk::ImageCreateInfo::default()
|
||||
.flags(raw_flags)
|
||||
.image_type(conv::map_texture_dimension(desc.dimension))
|
||||
.format(original_format)
|
||||
.extent(conv::map_copy_extent(©_size))
|
||||
.mip_levels(desc.mip_level_count)
|
||||
.array_layers(desc.array_layer_count())
|
||||
.samples(vk::SampleCountFlags::from_raw(desc.sample_count))
|
||||
.tiling(vk::ImageTiling::OPTIMAL)
|
||||
.usage(conv::map_texture_usage(desc.usage))
|
||||
.sharing_mode(vk::SharingMode::EXCLUSIVE)
|
||||
.initial_layout(vk::ImageLayout::UNDEFINED);
|
||||
|
||||
let mut format_list_info = vk::ImageFormatListCreateInfo::default();
|
||||
if !vk_view_formats.is_empty() {
|
||||
format_list_info = format_list_info.view_formats(&vk_view_formats);
|
||||
vk_info = vk_info.push_next(&mut format_list_info);
|
||||
}
|
||||
|
||||
let raw = unsafe {
|
||||
self.shared
|
||||
.raw
|
||||
.create_image(&vk_info, None)
|
||||
.map_err(map_err)?
|
||||
};
|
||||
fn map_err(err: vk::Result) -> crate::DeviceError {
|
||||
// We don't use VK_EXT_image_compression_control
|
||||
// VK_ERROR_COMPRESSION_EXHAUSTED_EXT
|
||||
super::map_host_device_oom_and_ioca_err(err)
|
||||
}
|
||||
let req = unsafe { self.shared.raw.get_image_memory_requirements(raw) };
|
||||
let image = self.create_image_without_memory(desc, None)?;
|
||||
|
||||
let block = unsafe {
|
||||
self.mem_allocator.lock().alloc(
|
||||
&*self.shared,
|
||||
gpu_alloc::Request {
|
||||
size: req.size,
|
||||
align_mask: req.alignment - 1,
|
||||
size: image.requirements.size,
|
||||
align_mask: image.requirements.alignment - 1,
|
||||
usage: gpu_alloc::UsageFlags::FAST_DEVICE_ACCESS,
|
||||
memory_types: req.memory_type_bits & self.valid_ash_memory_types,
|
||||
memory_types: image.requirements.memory_type_bits & self.valid_ash_memory_types,
|
||||
},
|
||||
)?
|
||||
};
|
||||
@ -1105,31 +1209,35 @@ impl crate::Device for super::Device {
|
||||
unsafe {
|
||||
self.shared
|
||||
.raw
|
||||
.bind_image_memory(raw, *block.memory(), block.offset())
|
||||
.bind_image_memory(image.raw, *block.memory(), block.offset())
|
||||
.map_err(super::map_host_device_oom_err)?
|
||||
};
|
||||
|
||||
if let Some(label) = desc.label {
|
||||
unsafe { self.shared.set_object_name(raw, label) };
|
||||
unsafe { self.shared.set_object_name(image.raw, label) };
|
||||
}
|
||||
|
||||
self.counters.textures.add(1);
|
||||
|
||||
Ok(super::Texture {
|
||||
raw,
|
||||
raw: image.raw,
|
||||
drop_guard: None,
|
||||
external_memory: None,
|
||||
block: Some(block),
|
||||
usage: desc.usage,
|
||||
format: desc.format,
|
||||
raw_flags,
|
||||
copy_size,
|
||||
view_formats: wgt_view_formats,
|
||||
raw_flags: image.raw_flags,
|
||||
copy_size: image.copy_size,
|
||||
view_formats: image.view_formats,
|
||||
})
|
||||
}
|
||||
unsafe fn destroy_texture(&self, texture: super::Texture) {
|
||||
if texture.drop_guard.is_none() {
|
||||
unsafe { self.shared.raw.destroy_image(texture.raw, None) };
|
||||
}
|
||||
if let Some(memory) = texture.external_memory {
|
||||
unsafe { self.shared.raw.free_memory(memory, None) };
|
||||
}
|
||||
if let Some(block) = texture.block {
|
||||
self.counters.texture_memory.sub(block.size() as isize);
|
||||
|
||||
@ -2584,3 +2692,11 @@ impl From<gpu_descriptor::AllocationError> for crate::DeviceError {
|
||||
fn handle_unexpected(err: vk::Result) -> ! {
|
||||
panic!("Unexpected Vulkan error: `{err}`")
|
||||
}
|
||||
|
||||
struct ImageWithoutMemory {
|
||||
raw: vk::Image,
|
||||
requirements: vk::MemoryRequirements,
|
||||
copy_size: crate::CopyExtent,
|
||||
view_formats: Vec<wgt::TextureFormat>,
|
||||
raw_flags: vk::ImageCreateFlags,
|
||||
}
|
||||
|
@ -1095,6 +1095,7 @@ impl crate::Surface for super::Surface {
|
||||
raw: swapchain.images[index as usize],
|
||||
drop_guard: None,
|
||||
block: None,
|
||||
external_memory: None,
|
||||
usage: swapchain.config.usage,
|
||||
format: swapchain.config.format,
|
||||
raw_flags,
|
||||
|
@ -532,6 +532,8 @@ struct PrivateCapabilities {
|
||||
robust_image_access2: bool,
|
||||
zero_initialize_workgroup_memory: bool,
|
||||
image_format_list: bool,
|
||||
#[cfg(windows)]
|
||||
external_memory_win32: bool,
|
||||
}
|
||||
|
||||
bitflags::bitflags!(
|
||||
@ -760,6 +762,7 @@ impl crate::DynAccelerationStructure for AccelerationStructure {}
|
||||
pub struct Texture {
|
||||
raw: vk::Image,
|
||||
drop_guard: Option<crate::DropGuard>,
|
||||
external_memory: Option<vk::DeviceMemory>,
|
||||
block: Option<gpu_alloc::MemoryBlock<vk::DeviceMemory>>,
|
||||
usage: crate::TextureUses,
|
||||
format: wgt::TextureFormat,
|
||||
|
Loading…
Reference in New Issue
Block a user