From 2ee1a415449065709da8227f5493bbf0447bace8 Mon Sep 17 00:00:00 2001 From: Elabajaba Date: Sat, 26 Nov 2022 02:42:11 -0500 Subject: [PATCH] Stick gpu-allocator behind a feature until #3207 lands --- wgpu-hal/Cargo.toml | 4 +- wgpu-hal/src/dx12/adapter.rs | 2 +- wgpu-hal/src/dx12/device.rs | 208 ++++++++++++++++++++++++++++++++++- wgpu-hal/src/dx12/mod.rs | 11 +- 4 files changed, 220 insertions(+), 5 deletions(-) diff --git a/wgpu-hal/Cargo.toml b/wgpu-hal/Cargo.toml index 7c2aec7d03..e7bc1a6441 100644 --- a/wgpu-hal/Cargo.toml +++ b/wgpu-hal/Cargo.toml @@ -27,7 +27,9 @@ metal = ["naga/msl-out", "block", "foreign-types"] vulkan = ["naga/spv-out", "ash", "gpu-alloc", "gpu-descriptor", "libloading", "smallvec"] gles = ["naga/glsl-out", "glow", "egl", "libloading"] dx11 = ["naga/hlsl-out", "native", "libloading", "winapi/d3d11", "winapi/d3d11_1", "winapi/d3d11_2", "winapi/d3d11sdklayers", "winapi/dxgi1_6"] -dx12 = ["naga/hlsl-out", "native", "bit-set", "range-alloc", "winapi/d3d12", "winapi/d3d12shader", "winapi/d3d12sdklayers", "winapi/dxgi1_6", "gpu-allocator"] +dx12 = ["naga/hlsl-out", "native", "bit-set", "range-alloc", "winapi/d3d12", "winapi/d3d12shader", "winapi/d3d12sdklayers", "winapi/dxgi1_6"] +# TODO: This is a separate feature until Mozilla okays windows-rs, see https://github.com/gfx-rs/wgpu/issues/3207 for the tracking issue. +windows_rs = ["gpu-allocator"] renderdoc = ["libloading", "renderdoc-sys"] emscripten = ["gles"] diff --git a/wgpu-hal/src/dx12/adapter.rs b/wgpu-hal/src/dx12/adapter.rs index b216071b4e..236fec49c3 100644 --- a/wgpu-hal/src/dx12/adapter.rs +++ b/wgpu-hal/src/dx12/adapter.rs @@ -163,7 +163,7 @@ impl super::Adapter { } else { super::MemoryArchitecture::NonUnified }, - _heap_create_not_zeroed: false, //TODO: winapi support for Options7 + heap_create_not_zeroed: false, //TODO: winapi support for Options7 }; // Theoretically vram limited, but in practice 2^20 is the limit diff --git a/wgpu-hal/src/dx12/device.rs b/wgpu-hal/src/dx12/device.rs index 3b1e447497..c209386b66 100644 --- a/wgpu-hal/src/dx12/device.rs +++ b/wgpu-hal/src/dx12/device.rs @@ -12,6 +12,10 @@ use winapi::{ Interface, }; +#[cfg(not(feature = "windows_rs"))] +use winapi::um::d3d12::D3D12_RESOURCE_DESC; + +#[cfg(feature = "windows_rs")] use gpu_allocator::{ d3d12::{winapi_d3d12::D3D12_RESOURCE_DESC, AllocationCreateDesc, ToWinapi, ToWindows}, MemoryLocation, @@ -21,7 +25,8 @@ use gpu_allocator::{ const NAGA_LOCATION_SEMANTIC: &[u8] = b"LOC\0"; // TODO: find the exact value // TODO: figure out if this is even needed? -const _D3D12_HEAP_FLAG_CREATE_NOT_ZEROED: u32 = d3d12::D3D12_HEAP_FLAG_NONE; +#[allow(unused)] // TODO: Exists until windows-rs is standard, then it can probably be removed? +const D3D12_HEAP_FLAG_CREATE_NOT_ZEROED: u32 = d3d12::D3D12_HEAP_FLAG_NONE; impl super::Device { pub(super) fn new( @@ -30,6 +35,7 @@ impl super::Device { private_caps: super::PrivateCapabilities, library: &Arc, ) -> Result { + #[cfg(feature = "windows_rs")] let mem_allocator = { let device = raw.as_ptr(); @@ -183,6 +189,7 @@ impl super::Device { #[cfg(feature = "renderdoc")] render_doc: Default::default(), null_rtv_handle, + #[cfg(feature = "windows_rs")] mem_allocator: Mutex::new(mem_allocator), }) } @@ -331,6 +338,7 @@ impl super::Device { size, mip_level_count, sample_count, + #[cfg(feature = "windows_rs")] allocation: None, } } @@ -348,6 +356,7 @@ impl crate::Device for super::Device { unsafe { queue.raw.destroy() }; } + #[cfg(feature = "windows_rs")] unsafe fn create_buffer( &self, desc: &crate::BufferDescriptor, @@ -419,6 +428,83 @@ impl crate::Device for super::Device { allocation: Some(allocation), }) } + + #[cfg(not(feature = "windows_rs"))] + unsafe fn create_buffer( + &self, + desc: &crate::BufferDescriptor, + ) -> Result { + let mut resource = native::Resource::null(); + let mut size = desc.size; + if desc.usage.contains(crate::BufferUses::UNIFORM) { + let align_mask = d3d12::D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT as u64 - 1; + size = ((size - 1) | align_mask) + 1; + } + + let raw_desc = D3D12_RESOURCE_DESC { + Dimension: d3d12::D3D12_RESOURCE_DIMENSION_BUFFER, + Alignment: 0, + Width: size, + Height: 1, + DepthOrArraySize: 1, + MipLevels: 1, + Format: dxgiformat::DXGI_FORMAT_UNKNOWN, + SampleDesc: dxgitype::DXGI_SAMPLE_DESC { + Count: 1, + Quality: 0, + }, + Layout: d3d12::D3D12_TEXTURE_LAYOUT_ROW_MAJOR, + Flags: conv::map_buffer_usage_to_resource_flags(desc.usage), + }; + + 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::D3D12_HEAP_PROPERTIES { + Type: d3d12::D3D12_HEAP_TYPE_CUSTOM, + CPUPageProperty: if is_cpu_read { + d3d12::D3D12_CPU_PAGE_PROPERTY_WRITE_BACK + } else if is_cpu_write { + d3d12::D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE + } else { + d3d12::D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE + }, + MemoryPoolPreference: match self.private_caps.memory_architecture { + super::MemoryArchitecture::NonUnified if !is_cpu_read && !is_cpu_write => { + d3d12::D3D12_MEMORY_POOL_L1 + } + _ => d3d12::D3D12_MEMORY_POOL_L0, + }, + CreationNodeMask: 0, + VisibleNodeMask: 0, + }; + + let hr = unsafe { + self.raw.CreateCommittedResource( + &heap_properties, + if self.private_caps.heap_create_not_zeroed { + D3D12_HEAP_FLAG_CREATE_NOT_ZEROED + } else { + d3d12::D3D12_HEAP_FLAG_NONE + }, + &raw_desc, + d3d12::D3D12_RESOURCE_STATE_COMMON, + ptr::null(), + &d3d12::ID3D12Resource::uuidof(), + resource.mut_void(), + ) + }; + + hr.into_device_result("Buffer creation")?; + if let Some(label) = desc.label { + let cwstr = conv::map_label(label); + unsafe { resource.SetName(cwstr.as_ptr()) }; + } + + Ok(super::Buffer { resource, size }) + } + + #[cfg(feature = "windows_rs")] unsafe fn destroy_buffer(&self, mut buffer: super::Buffer) { // TODO: Destroy or Release here? unsafe { buffer.resource.destroy() }; @@ -430,6 +516,13 @@ impl crate::Device for super::Device { }; } } + + #[cfg(not(feature = "windows_rs"))] + unsafe fn destroy_buffer(&self, buffer: super::Buffer) { + unsafe { buffer.resource.destroy() }; + } + + #[cfg(feature = "windows_rs")] unsafe fn map_buffer( &self, buffer: &super::Buffer, @@ -447,13 +540,41 @@ impl crate::Device for super::Device { is_coherent: true, }) } + + #[cfg(not(feature = "windows_rs"))] + unsafe fn map_buffer( + &self, + buffer: &super::Buffer, + range: crate::MemoryRange, + ) -> Result { + let mut ptr = ptr::null_mut(); + let hr = unsafe { (*buffer.resource).Map(0, ptr::null(), &mut ptr) }; + hr.into_device_result("Map buffer")?; + Ok(crate::BufferMapping { + ptr: ptr::NonNull::new(unsafe { ptr.offset(range.start as isize).cast::() }) + .unwrap(), + //TODO: double-check this. Documentation is a bit misleading - + // it implies that Map/Unmap is needed to invalidate/flush memory. + is_coherent: true, + }) + } + + #[cfg(feature = "windows_rs")] + unsafe fn unmap_buffer(&self, buffer: &super::Buffer) -> Result<(), crate::DeviceError> { + unsafe { (*buffer.resource).Unmap(0, ptr::null()) }; + Ok(()) + } + + #[cfg(not(feature = "windows_rs"))] unsafe fn unmap_buffer(&self, buffer: &super::Buffer) -> Result<(), crate::DeviceError> { unsafe { (*buffer.resource).Unmap(0, ptr::null()) }; Ok(()) } + unsafe fn flush_mapped_ranges(&self, _buffer: &super::Buffer, _ranges: I) {} unsafe fn invalidate_mapped_ranges(&self, _buffer: &super::Buffer, _ranges: I) {} + #[cfg(feature = "windows_rs")] unsafe fn create_texture( &self, desc: &crate::TextureDescriptor, @@ -529,6 +650,86 @@ impl crate::Device for super::Device { }) } + #[cfg(not(feature = "windows_rs"))] + unsafe fn create_texture( + &self, + desc: &crate::TextureDescriptor, + ) -> Result { + let mut resource = native::Resource::null(); + + let raw_desc = D3D12_RESOURCE_DESC { + Dimension: conv::map_texture_dimension(desc.dimension), + Alignment: 0, + Width: desc.size.width as u64, + Height: desc.size.height, + DepthOrArraySize: desc.size.depth_or_array_layers as u16, + MipLevels: desc.mip_level_count as u16, + Format: if crate::FormatAspects::from(desc.format).contains(crate::FormatAspects::COLOR) + || !desc.usage.intersects( + crate::TextureUses::RESOURCE + | crate::TextureUses::STORAGE_READ + | crate::TextureUses::STORAGE_READ_WRITE, + ) { + auxil::dxgi::conv::map_texture_format(desc.format) + } else { + // This branch is needed if it's a depth texture, and it's ever needed to be viewed as SRV or UAV, + // because then we'd create a non-depth format view of it. + // Note: we can skip this branch if + // `D3D12_FEATURE_D3D12_OPTIONS3::CastingFullyTypedFormatSupported` + auxil::dxgi::conv::map_texture_format_depth_typeless(desc.format) + }, + SampleDesc: dxgitype::DXGI_SAMPLE_DESC { + Count: desc.sample_count, + Quality: 0, + }, + Layout: d3d12::D3D12_TEXTURE_LAYOUT_UNKNOWN, + Flags: conv::map_texture_usage_to_resource_flags(desc.usage), + }; + + let heap_properties = d3d12::D3D12_HEAP_PROPERTIES { + Type: d3d12::D3D12_HEAP_TYPE_CUSTOM, + CPUPageProperty: d3d12::D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE, + MemoryPoolPreference: match self.private_caps.memory_architecture { + super::MemoryArchitecture::NonUnified => d3d12::D3D12_MEMORY_POOL_L1, + super::MemoryArchitecture::Unified { .. } => d3d12::D3D12_MEMORY_POOL_L0, + }, + CreationNodeMask: 0, + VisibleNodeMask: 0, + }; + + let hr = unsafe { + self.raw.CreateCommittedResource( + &heap_properties, + if self.private_caps.heap_create_not_zeroed { + D3D12_HEAP_FLAG_CREATE_NOT_ZEROED + } else { + d3d12::D3D12_HEAP_FLAG_NONE + }, + &raw_desc, + d3d12::D3D12_RESOURCE_STATE_COMMON, + ptr::null(), // clear value + &d3d12::ID3D12Resource::uuidof(), + resource.mut_void(), + ) + }; + + hr.into_device_result("Texture creation")?; + if let Some(label) = desc.label { + let cwstr = conv::map_label(label); + unsafe { resource.SetName(cwstr.as_ptr()) }; + } + + Ok(super::Texture { + resource, + format: desc.format, + dimension: desc.dimension, + size: desc.size, + mip_level_count: desc.mip_level_count, + sample_count: desc.sample_count, + }) + } + + #[cfg(feature = "windows_rs")] unsafe fn destroy_texture(&self, mut texture: super::Texture) { unsafe { texture.resource.destroy() }; if let Some(alloc) = texture.allocation.take() { @@ -539,6 +740,11 @@ impl crate::Device for super::Device { } } + #[cfg(not(feature = "windows_rs"))] + unsafe fn destroy_texture(&self, texture: super::Texture) { + unsafe { texture.resource.destroy() }; + } + unsafe fn create_texture_view( &self, texture: &super::Texture, diff --git a/wgpu-hal/src/dx12/mod.rs b/wgpu-hal/src/dx12/mod.rs index b1d0365b6c..ff91bf244e 100644 --- a/wgpu-hal/src/dx12/mod.rs +++ b/wgpu-hal/src/dx12/mod.rs @@ -44,7 +44,6 @@ mod view; use crate::auxil::{self, dxgi::result::HResult as _}; use arrayvec::ArrayVec; -use log::error; use parking_lot::Mutex; use std::{ffi, fmt, mem, num::NonZeroU32, sync::Arc}; use winapi::{ @@ -153,7 +152,8 @@ struct PrivateCapabilities { #[allow(unused)] heterogeneous_resource_heaps: bool, memory_architecture: MemoryArchitecture, - _heap_create_not_zeroed: bool, + #[allow(unused)] // TODO: Exists until windows-rs is standard, then it can probably be removed? + heap_create_not_zeroed: bool, } #[derive(Default)] @@ -238,6 +238,7 @@ pub struct Device { #[cfg(feature = "renderdoc")] render_doc: crate::auxil::renderdoc::RenderDoc, null_rtv_handle: descriptor::Handle, + #[cfg(feature = "windows_rs")] mem_allocator: Mutex, } @@ -374,6 +375,7 @@ unsafe impl Sync for CommandBuffer {} pub struct Buffer { resource: native::Resource, size: wgt::BufferAddress, + #[cfg(feature = "windows_rs")] allocation: Option, } @@ -401,6 +403,7 @@ pub struct Texture { size: wgt::Extent3d, mip_level_count: u32, sample_count: u32, + #[cfg(feature = "windows_rs")] allocation: Option, } @@ -768,6 +771,7 @@ impl crate::Surface for Surface { size: sc.size, mip_level_count: 1, sample_count: 1, + #[cfg(feature = "windows_rs")] allocation: None, }; Ok(Some(crate::AcquiredSurfaceTexture { @@ -833,8 +837,11 @@ impl crate::Queue for Queue { } } +#[cfg(feature = "windows_rs")] impl From for crate::DeviceError { fn from(result: gpu_allocator::AllocationError) -> Self { + use log::error; + match result { gpu_allocator::AllocationError::OutOfMemory => Self::OutOfMemory, gpu_allocator::AllocationError::FailedToMap(e) => {