summaryrefslogtreecommitdiffstats
path: root/third_party/rust/wgpu-hal/src/dx12/suballocation.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/wgpu-hal/src/dx12/suballocation.rs')
-rw-r--r--third_party/rust/wgpu-hal/src/dx12/suballocation.rs331
1 files changed, 331 insertions, 0 deletions
diff --git a/third_party/rust/wgpu-hal/src/dx12/suballocation.rs b/third_party/rust/wgpu-hal/src/dx12/suballocation.rs
new file mode 100644
index 0000000000..01ca997f21
--- /dev/null
+++ b/third_party/rust/wgpu-hal/src/dx12/suballocation.rs
@@ -0,0 +1,331 @@
+pub(crate) use allocation::{
+ create_allocator_wrapper, create_buffer_resource, create_texture_resource,
+ free_buffer_allocation, free_texture_allocation, AllocationWrapper, GpuAllocatorWrapper,
+};
+
+// This exists to work around https://github.com/gfx-rs/wgpu/issues/3207
+// Currently this will work the older, slower way if the windows_rs feature is disabled,
+// and will use the fast path of suballocating buffers and textures using gpu_allocator if
+// the windows_rs feature is enabled.
+
+// This is the fast path using gpu_allocator to suballocate buffers and textures.
+#[cfg(feature = "windows_rs")]
+mod allocation {
+ use d3d12::WeakPtr;
+ use parking_lot::Mutex;
+ use std::ptr;
+ use wgt::assertions::StrictAssertUnwrapExt;
+ use winapi::{
+ um::{
+ d3d12::{self as d3d12_ty, ID3D12Resource},
+ winnt::HRESULT,
+ },
+ Interface,
+ };
+
+ use gpu_allocator::{
+ d3d12::{AllocationCreateDesc, ToWinapi, ToWindows},
+ MemoryLocation,
+ };
+
+ #[derive(Debug)]
+ pub(crate) struct GpuAllocatorWrapper {
+ pub(crate) allocator: gpu_allocator::d3d12::Allocator,
+ }
+
+ #[derive(Debug)]
+ pub(crate) struct AllocationWrapper {
+ pub(crate) allocation: gpu_allocator::d3d12::Allocation,
+ }
+
+ pub(crate) fn create_allocator_wrapper(
+ raw: &d3d12::Device,
+ ) -> Result<Option<Mutex<GpuAllocatorWrapper>>, crate::DeviceError> {
+ let device = raw.as_ptr();
+
+ match gpu_allocator::d3d12::Allocator::new(&gpu_allocator::d3d12::AllocatorCreateDesc {
+ device: device.as_windows().clone(),
+ debug_settings: Default::default(),
+ }) {
+ Ok(allocator) => Ok(Some(Mutex::new(GpuAllocatorWrapper { allocator }))),
+ Err(e) => {
+ log::error!("Failed to create d3d12 allocator, error: {}", e);
+ Err(e)?
+ }
+ }
+ }
+
+ pub(crate) fn create_buffer_resource(
+ device: &crate::dx12::Device,
+ desc: &crate::BufferDescriptor,
+ raw_desc: d3d12_ty::D3D12_RESOURCE_DESC,
+ resource: &mut WeakPtr<ID3D12Resource>,
+ ) -> Result<(HRESULT, Option<AllocationWrapper>), crate::DeviceError> {
+ let is_cpu_read = desc.usage.contains(crate::BufferUses::MAP_READ);
+ let is_cpu_write = desc.usage.contains(crate::BufferUses::MAP_WRITE);
+ let location = match (is_cpu_read, is_cpu_write) {
+ (true, true) => MemoryLocation::CpuToGpu,
+ (true, false) => MemoryLocation::GpuToCpu,
+ (false, true) => MemoryLocation::CpuToGpu,
+ (false, false) => MemoryLocation::GpuOnly,
+ };
+
+ let name = desc.label.unwrap_or("Unlabeled buffer");
+
+ // SAFETY: allocator exists when the windows_rs feature is enabled
+ let mut allocator = unsafe {
+ device
+ .mem_allocator
+ .as_ref()
+ .strict_unwrap_unchecked()
+ .lock()
+ };
+
+ // let mut allocator = unsafe { device.mem_allocator.as_ref().unwrap_unchecked().lock() };
+ let allocation_desc = AllocationCreateDesc::from_winapi_d3d12_resource_desc(
+ allocator.allocator.device().as_winapi(),
+ &raw_desc,
+ name,
+ location,
+ );
+ let allocation = allocator.allocator.allocate(&allocation_desc)?;
+
+ let hr = unsafe {
+ device.raw.CreatePlacedResource(
+ allocation.heap().as_winapi() as *mut _,
+ allocation.offset(),
+ &raw_desc,
+ d3d12_ty::D3D12_RESOURCE_STATE_COMMON,
+ ptr::null(),
+ &d3d12_ty::ID3D12Resource::uuidof(),
+ resource.mut_void(),
+ )
+ };
+
+ Ok((hr, Some(AllocationWrapper { allocation })))
+ }
+
+ pub(crate) fn create_texture_resource(
+ device: &crate::dx12::Device,
+ desc: &crate::TextureDescriptor,
+ raw_desc: d3d12_ty::D3D12_RESOURCE_DESC,
+ resource: &mut WeakPtr<ID3D12Resource>,
+ ) -> Result<(HRESULT, Option<AllocationWrapper>), crate::DeviceError> {
+ let location = MemoryLocation::GpuOnly;
+
+ let name = desc.label.unwrap_or("Unlabeled texture");
+
+ // SAFETY: allocator exists when the windows_rs feature is enabled
+ let mut allocator = unsafe {
+ device
+ .mem_allocator
+ .as_ref()
+ .strict_unwrap_unchecked()
+ .lock()
+ };
+ let allocation_desc = AllocationCreateDesc::from_winapi_d3d12_resource_desc(
+ allocator.allocator.device().as_winapi(),
+ &raw_desc,
+ name,
+ location,
+ );
+ let allocation = allocator.allocator.allocate(&allocation_desc)?;
+
+ let hr = unsafe {
+ device.raw.CreatePlacedResource(
+ allocation.heap().as_winapi() as *mut _,
+ allocation.offset(),
+ &raw_desc,
+ d3d12_ty::D3D12_RESOURCE_STATE_COMMON,
+ ptr::null(), // clear value
+ &d3d12_ty::ID3D12Resource::uuidof(),
+ resource.mut_void(),
+ )
+ };
+
+ Ok((hr, Some(AllocationWrapper { allocation })))
+ }
+
+ pub(crate) fn free_buffer_allocation(
+ allocation: AllocationWrapper,
+ allocator: &Mutex<GpuAllocatorWrapper>,
+ ) {
+ match allocator.lock().allocator.free(allocation.allocation) {
+ Ok(_) => (),
+ // TODO: Don't panic here
+ Err(e) => panic!("Failed to destroy dx12 buffer, {e}"),
+ };
+ }
+
+ pub(crate) fn free_texture_allocation(
+ allocation: AllocationWrapper,
+ allocator: &Mutex<GpuAllocatorWrapper>,
+ ) {
+ match allocator.lock().allocator.free(allocation.allocation) {
+ Ok(_) => (),
+ // TODO: Don't panic here
+ Err(e) => panic!("Failed to destroy dx12 texture, {e}"),
+ };
+ }
+
+ #[cfg(feature = "windows_rs")]
+ impl From<gpu_allocator::AllocationError> for crate::DeviceError {
+ fn from(result: gpu_allocator::AllocationError) -> Self {
+ match result {
+ gpu_allocator::AllocationError::OutOfMemory => Self::OutOfMemory,
+ gpu_allocator::AllocationError::FailedToMap(e) => {
+ log::error!("DX12 gpu-allocator: Failed to map: {}", e);
+ Self::Lost
+ }
+ gpu_allocator::AllocationError::NoCompatibleMemoryTypeFound => {
+ log::error!("DX12 gpu-allocator: No Compatible Memory Type Found");
+ Self::Lost
+ }
+ gpu_allocator::AllocationError::InvalidAllocationCreateDesc => {
+ log::error!("DX12 gpu-allocator: Invalid Allocation Creation Description");
+ Self::Lost
+ }
+ gpu_allocator::AllocationError::InvalidAllocatorCreateDesc(e) => {
+ log::error!(
+ "DX12 gpu-allocator: Invalid Allocator Creation Description: {}",
+ e
+ );
+ Self::Lost
+ }
+ gpu_allocator::AllocationError::Internal(e) => {
+ log::error!("DX12 gpu-allocator: Internal Error: {}", e);
+ Self::Lost
+ }
+ }
+ }
+ }
+}
+
+// This is the older, slower path where it doesn't suballocate buffers.
+// Tracking issue for when it can be removed: https://github.com/gfx-rs/wgpu/issues/3207
+#[cfg(not(feature = "windows_rs"))]
+mod allocation {
+ use d3d12::WeakPtr;
+ use parking_lot::Mutex;
+ use std::ptr;
+ use winapi::{
+ um::{
+ d3d12::{self as d3d12_ty, ID3D12Resource},
+ winnt::HRESULT,
+ },
+ Interface,
+ };
+
+ const D3D12_HEAP_FLAG_CREATE_NOT_ZEROED: u32 = d3d12_ty::D3D12_HEAP_FLAG_NONE; // TODO: find the exact value
+
+ // Allocator isn't needed when not suballocating with gpu_allocator
+ #[derive(Debug)]
+ pub(crate) struct GpuAllocatorWrapper {}
+
+ // Allocations aren't needed when not suballocating with gpu_allocator
+ #[derive(Debug)]
+ pub(crate) struct AllocationWrapper {}
+
+ pub(crate) fn create_allocator_wrapper(
+ _raw: &d3d12::Device,
+ ) -> Result<Option<Mutex<GpuAllocatorWrapper>>, crate::DeviceError> {
+ Ok(None)
+ }
+
+ pub(crate) fn create_buffer_resource(
+ device: &crate::dx12::Device,
+ desc: &crate::BufferDescriptor,
+ raw_desc: d3d12_ty::D3D12_RESOURCE_DESC,
+ resource: &mut WeakPtr<ID3D12Resource>,
+ ) -> Result<(HRESULT, Option<AllocationWrapper>), crate::DeviceError> {
+ let is_cpu_read = desc.usage.contains(crate::BufferUses::MAP_READ);
+ let is_cpu_write = desc.usage.contains(crate::BufferUses::MAP_WRITE);
+
+ let heap_properties = d3d12_ty::D3D12_HEAP_PROPERTIES {
+ Type: d3d12_ty::D3D12_HEAP_TYPE_CUSTOM,
+ CPUPageProperty: if is_cpu_read {
+ d3d12_ty::D3D12_CPU_PAGE_PROPERTY_WRITE_BACK
+ } else if is_cpu_write {
+ d3d12_ty::D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE
+ } else {
+ d3d12_ty::D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE
+ },
+ MemoryPoolPreference: match device.private_caps.memory_architecture {
+ crate::dx12::MemoryArchitecture::NonUnified if !is_cpu_read && !is_cpu_write => {
+ d3d12_ty::D3D12_MEMORY_POOL_L1
+ }
+ _ => d3d12_ty::D3D12_MEMORY_POOL_L0,
+ },
+ CreationNodeMask: 0,
+ VisibleNodeMask: 0,
+ };
+
+ let hr = unsafe {
+ device.raw.CreateCommittedResource(
+ &heap_properties,
+ if device.private_caps.heap_create_not_zeroed {
+ D3D12_HEAP_FLAG_CREATE_NOT_ZEROED
+ } else {
+ d3d12_ty::D3D12_HEAP_FLAG_NONE
+ },
+ &raw_desc,
+ d3d12_ty::D3D12_RESOURCE_STATE_COMMON,
+ ptr::null(),
+ &d3d12_ty::ID3D12Resource::uuidof(),
+ resource.mut_void(),
+ )
+ };
+
+ Ok((hr, None))
+ }
+
+ pub(crate) fn create_texture_resource(
+ device: &crate::dx12::Device,
+ _desc: &crate::TextureDescriptor,
+ raw_desc: d3d12_ty::D3D12_RESOURCE_DESC,
+ resource: &mut WeakPtr<ID3D12Resource>,
+ ) -> Result<(HRESULT, Option<AllocationWrapper>), crate::DeviceError> {
+ let heap_properties = d3d12_ty::D3D12_HEAP_PROPERTIES {
+ Type: d3d12_ty::D3D12_HEAP_TYPE_CUSTOM,
+ CPUPageProperty: d3d12_ty::D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE,
+ MemoryPoolPreference: match device.private_caps.memory_architecture {
+ crate::dx12::MemoryArchitecture::NonUnified => d3d12_ty::D3D12_MEMORY_POOL_L1,
+ crate::dx12::MemoryArchitecture::Unified { .. } => d3d12_ty::D3D12_MEMORY_POOL_L0,
+ },
+ CreationNodeMask: 0,
+ VisibleNodeMask: 0,
+ };
+
+ let hr = unsafe {
+ device.raw.CreateCommittedResource(
+ &heap_properties,
+ if device.private_caps.heap_create_not_zeroed {
+ D3D12_HEAP_FLAG_CREATE_NOT_ZEROED
+ } else {
+ d3d12_ty::D3D12_HEAP_FLAG_NONE
+ },
+ &raw_desc,
+ d3d12_ty::D3D12_RESOURCE_STATE_COMMON,
+ ptr::null(), // clear value
+ &d3d12_ty::ID3D12Resource::uuidof(),
+ resource.mut_void(),
+ )
+ };
+
+ Ok((hr, None))
+ }
+
+ pub(crate) fn free_buffer_allocation(
+ _allocation: AllocationWrapper,
+ _allocator: &Mutex<GpuAllocatorWrapper>,
+ ) {
+ // No-op when not using gpu-allocator
+ }
+
+ pub(crate) fn free_texture_allocation(
+ _allocation: AllocationWrapper,
+ _allocator: &Mutex<GpuAllocatorWrapper>,
+ ) {
+ // No-op when not using gpu-allocator
+ }
+}