mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-11-25 08:13:27 +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);
|
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
|
// 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
|
// 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.
|
// 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
|
image_format_list: phd_capabilities.device_api_version >= vk::API_VERSION_1_2
|
||||||
|| phd_capabilities.supports_extension(khr::image_format_list::NAME),
|
|| 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 {
|
let capabilities = crate::Capabilities {
|
||||||
limits: phd_capabilities.to_wgpu_limits(),
|
limits: phd_capabilities.to_wgpu_limits(),
|
||||||
|
@ -686,6 +686,7 @@ impl super::Device {
|
|||||||
super::Texture {
|
super::Texture {
|
||||||
raw: vk_image,
|
raw: vk_image,
|
||||||
drop_guard,
|
drop_guard,
|
||||||
|
external_memory: None,
|
||||||
block: None,
|
block: None,
|
||||||
usage: desc.usage,
|
usage: desc.usage,
|
||||||
format: desc.format,
|
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
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// - `vk_buffer`'s memory must be managed by the caller
|
/// - `vk_buffer`'s memory must be managed by the caller
|
||||||
@ -1028,74 +1190,16 @@ impl crate::Device for super::Device {
|
|||||||
&self,
|
&self,
|
||||||
desc: &crate::TextureDescriptor,
|
desc: &crate::TextureDescriptor,
|
||||||
) -> Result<super::Texture, crate::DeviceError> {
|
) -> Result<super::Texture, crate::DeviceError> {
|
||||||
let copy_size = desc.copy_extent();
|
let image = self.create_image_without_memory(desc, None)?;
|
||||||
|
|
||||||
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 block = unsafe {
|
let block = unsafe {
|
||||||
self.mem_allocator.lock().alloc(
|
self.mem_allocator.lock().alloc(
|
||||||
&*self.shared,
|
&*self.shared,
|
||||||
gpu_alloc::Request {
|
gpu_alloc::Request {
|
||||||
size: req.size,
|
size: image.requirements.size,
|
||||||
align_mask: req.alignment - 1,
|
align_mask: image.requirements.alignment - 1,
|
||||||
usage: gpu_alloc::UsageFlags::FAST_DEVICE_ACCESS,
|
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 {
|
unsafe {
|
||||||
self.shared
|
self.shared
|
||||||
.raw
|
.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)?
|
.map_err(super::map_host_device_oom_err)?
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(label) = desc.label {
|
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);
|
self.counters.textures.add(1);
|
||||||
|
|
||||||
Ok(super::Texture {
|
Ok(super::Texture {
|
||||||
raw,
|
raw: image.raw,
|
||||||
drop_guard: None,
|
drop_guard: None,
|
||||||
|
external_memory: None,
|
||||||
block: Some(block),
|
block: Some(block),
|
||||||
usage: desc.usage,
|
usage: desc.usage,
|
||||||
format: desc.format,
|
format: desc.format,
|
||||||
raw_flags,
|
raw_flags: image.raw_flags,
|
||||||
copy_size,
|
copy_size: image.copy_size,
|
||||||
view_formats: wgt_view_formats,
|
view_formats: image.view_formats,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
unsafe fn destroy_texture(&self, texture: super::Texture) {
|
unsafe fn destroy_texture(&self, texture: super::Texture) {
|
||||||
if texture.drop_guard.is_none() {
|
if texture.drop_guard.is_none() {
|
||||||
unsafe { self.shared.raw.destroy_image(texture.raw, 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 {
|
if let Some(block) = texture.block {
|
||||||
self.counters.texture_memory.sub(block.size() as isize);
|
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) -> ! {
|
fn handle_unexpected(err: vk::Result) -> ! {
|
||||||
panic!("Unexpected Vulkan error: `{err}`")
|
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],
|
raw: swapchain.images[index as usize],
|
||||||
drop_guard: None,
|
drop_guard: None,
|
||||||
block: None,
|
block: None,
|
||||||
|
external_memory: None,
|
||||||
usage: swapchain.config.usage,
|
usage: swapchain.config.usage,
|
||||||
format: swapchain.config.format,
|
format: swapchain.config.format,
|
||||||
raw_flags,
|
raw_flags,
|
||||||
|
@ -532,6 +532,8 @@ struct PrivateCapabilities {
|
|||||||
robust_image_access2: bool,
|
robust_image_access2: bool,
|
||||||
zero_initialize_workgroup_memory: bool,
|
zero_initialize_workgroup_memory: bool,
|
||||||
image_format_list: bool,
|
image_format_list: bool,
|
||||||
|
#[cfg(windows)]
|
||||||
|
external_memory_win32: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
bitflags::bitflags!(
|
bitflags::bitflags!(
|
||||||
@ -760,6 +762,7 @@ impl crate::DynAccelerationStructure for AccelerationStructure {}
|
|||||||
pub struct Texture {
|
pub struct Texture {
|
||||||
raw: vk::Image,
|
raw: vk::Image,
|
||||||
drop_guard: Option<crate::DropGuard>,
|
drop_guard: Option<crate::DropGuard>,
|
||||||
|
external_memory: Option<vk::DeviceMemory>,
|
||||||
block: Option<gpu_alloc::MemoryBlock<vk::DeviceMemory>>,
|
block: Option<gpu_alloc::MemoryBlock<vk::DeviceMemory>>,
|
||||||
usage: crate::TextureUses,
|
usage: crate::TextureUses,
|
||||||
format: wgt::TextureFormat,
|
format: wgt::TextureFormat,
|
||||||
|
Loading…
Reference in New Issue
Block a user