diff --git a/wgpu-hal/src/auxil/dxgi/mod.rs b/wgpu-hal/src/auxil/dxgi/mod.rs index 9b945923b87..1ab2e850031 100644 --- a/wgpu-hal/src/auxil/dxgi/mod.rs +++ b/wgpu-hal/src/auxil/dxgi/mod.rs @@ -3,5 +3,6 @@ pub mod conv; pub mod exception; pub mod factory; +pub mod name; pub mod result; pub mod time; diff --git a/wgpu-hal/src/auxil/dxgi/name.rs b/wgpu-hal/src/auxil/dxgi/name.rs new file mode 100644 index 00000000000..d120e4ed15e --- /dev/null +++ b/wgpu-hal/src/auxil/dxgi/name.rs @@ -0,0 +1,24 @@ +use windows::Win32::Graphics::Direct3D12::ID3D12Object; + +use crate::auxil::dxgi::result::HResult; + +/// Helper trait for setting the name of a D3D12 object. +/// +/// This is implemented on all types that can be converted to an [`ID3D12Object`]. +pub trait ObjectExt { + fn set_name(&self, name: &str) -> Result<(), crate::DeviceError>; +} + +impl ObjectExt for T +where + // Windows impls `From` for all parent interfaces, so we can use that to convert to ID3D12Object. + // + // This includes implementations for references. + for<'a> &'a ID3D12Object: From<&'a T>, +{ + fn set_name(&self, name: &str) -> Result<(), crate::DeviceError> { + let name = windows::core::HSTRING::from(name); + let object: &ID3D12Object = self.into(); + unsafe { object.SetName(&name).into_device_result("SetName") } + } +} diff --git a/wgpu-hal/src/dx12/command.rs b/wgpu-hal/src/dx12/command.rs index 5ca6b87cdc9..a14cada4f0f 100644 --- a/wgpu-hal/src/dx12/command.rs +++ b/wgpu-hal/src/dx12/command.rs @@ -8,7 +8,10 @@ use windows_core::Interface; use super::conv; use crate::{ - auxil::{self, dxgi::result::HResult as _}, + auxil::{ + self, + dxgi::{name::ObjectExt, result::HResult as _}, + }, dx12::borrow_interface_temporarily, AccelerationStructureEntries, }; @@ -328,8 +331,7 @@ impl crate::CommandEncoder for super::CommandEncoder { }; if let Some(label) = label { - unsafe { list.SetName(&windows::core::HSTRING::from(label)) } - .into_device_result("SetName")?; + list.set_name(label)?; } self.list = Some(list); diff --git a/wgpu-hal/src/dx12/conv.rs b/wgpu-hal/src/dx12/conv.rs index b636dbc8d54..9c6300af941 100644 --- a/wgpu-hal/src/dx12/conv.rs +++ b/wgpu-hal/src/dx12/conv.rs @@ -1,4 +1,4 @@ -use windows::Win32::Graphics::{Direct3D, Direct3D12}; +use windows::Win32::Graphics::{Direct3D, Direct3D12, Dxgi}; pub fn map_buffer_usage_to_resource_flags( usage: wgt::BufferUses, @@ -12,6 +12,26 @@ pub fn map_buffer_usage_to_resource_flags( flags } +pub fn map_buffer_descriptor( + desc: &crate::BufferDescriptor<'_>, +) -> Direct3D12::D3D12_RESOURCE_DESC { + Direct3D12::D3D12_RESOURCE_DESC { + Dimension: Direct3D12::D3D12_RESOURCE_DIMENSION_BUFFER, + Alignment: 0, + Width: desc.size, + Height: 1, + DepthOrArraySize: 1, + MipLevels: 1, + Format: Dxgi::Common::DXGI_FORMAT_UNKNOWN, + SampleDesc: Dxgi::Common::DXGI_SAMPLE_DESC { + Count: 1, + Quality: 0, + }, + Layout: Direct3D12::D3D12_TEXTURE_LAYOUT_ROW_MAJOR, + Flags: map_buffer_usage_to_resource_flags(desc.usage), + } +} + pub fn map_texture_dimension(dim: wgt::TextureDimension) -> Direct3D12::D3D12_RESOURCE_DIMENSION { match dim { wgt::TextureDimension::D1 => Direct3D12::D3D12_RESOURCE_DIMENSION_TEXTURE1D, diff --git a/wgpu-hal/src/dx12/device.rs b/wgpu-hal/src/dx12/device.rs index 1cd108b6c7c..b9663f5ee31 100644 --- a/wgpu-hal/src/dx12/device.rs +++ b/wgpu-hal/src/dx12/device.rs @@ -22,7 +22,10 @@ use windows::{ use super::{conv, descriptor, D3D12Lib}; use crate::{ - auxil::{self, dxgi::result::HResult}, + auxil::{ + self, + dxgi::{name::ObjectExt, result::HResult}, + }, dx12::{ borrow_optional_interface_temporarily, shader_compilation, suballocation, DynamicStorageBufferOffsets, Event, @@ -383,7 +386,10 @@ impl super::Device { size, mip_level_count, sample_count, - allocation: suballocation::Allocation::none(suballocation::AllocationType::Texture), + allocation: suballocation::Allocation::none( + suballocation::AllocationType::Texture, + format.theoretical_memory_footprint(size), + ), } } @@ -394,7 +400,10 @@ impl super::Device { super::Buffer { resource, size, - allocation: suballocation::Allocation::none(suballocation::AllocationType::Buffer), + allocation: suballocation::Allocation::none( + suballocation::AllocationType::Buffer, + size, + ), } } } @@ -406,40 +415,17 @@ impl crate::Device for super::Device { &self, desc: &crate::BufferDescriptor, ) -> Result { - let alloc_size = if desc.usage.contains(wgt::BufferUses::UNIFORM) { - desc.size - .next_multiple_of(Direct3D12::D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT.into()) - } else { - desc.size - }; + let mut desc = desc.clone(); - let raw_desc = Direct3D12::D3D12_RESOURCE_DESC { - Dimension: Direct3D12::D3D12_RESOURCE_DIMENSION_BUFFER, - Alignment: 0, - Width: alloc_size, - Height: 1, - DepthOrArraySize: 1, - MipLevels: 1, - Format: Dxgi::Common::DXGI_FORMAT_UNKNOWN, - SampleDesc: Dxgi::Common::DXGI_SAMPLE_DESC { - Count: 1, - Quality: 0, - }, - Layout: Direct3D12::D3D12_TEXTURE_LAYOUT_ROW_MAJOR, - Flags: conv::map_buffer_usage_to_resource_flags(desc.usage), - }; - - let (resource, allocation) = suballocation::create_buffer( - suballocation::DeviceAllocationContext::from(self), - desc, - raw_desc, - )?; - - if let Some(label) = desc.label { - unsafe { resource.SetName(&windows::core::HSTRING::from(label)) } - .into_device_result("SetName")?; + if desc.usage.contains(wgt::BufferUses::UNIFORM) { + desc.size = desc + .size + .next_multiple_of(Direct3D12::D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT.into()) } + let (resource, allocation) = + suballocation::DeviceAllocationContext::from(self).create_buffer(&desc)?; + self.counters.buffers.add(1); Ok(super::Buffer { @@ -450,11 +436,8 @@ impl crate::Device for super::Device { } unsafe fn destroy_buffer(&self, buffer: super::Buffer) { - suballocation::free_resource( - suballocation::DeviceAllocationContext::from(self), - buffer.resource, - buffer.allocation, - ); + suballocation::DeviceAllocationContext::from(self) + .free_resource(buffer.resource, buffer.allocation); self.counters.buffers.sub(1); } @@ -515,16 +498,8 @@ impl crate::Device for super::Device { Flags: conv::map_texture_usage_to_resource_flags(desc.usage), }; - let (resource, allocation) = suballocation::create_texture( - suballocation::DeviceAllocationContext::from(self), - desc, - raw_desc, - )?; - - if let Some(label) = desc.label { - unsafe { resource.SetName(&windows::core::HSTRING::from(label)) } - .into_device_result("SetName")?; - } + let (resource, allocation) = + suballocation::DeviceAllocationContext::from(self).create_texture(desc, raw_desc)?; self.counters.textures.add(1); @@ -540,11 +515,8 @@ impl crate::Device for super::Device { } unsafe fn destroy_texture(&self, texture: super::Texture) { - suballocation::free_resource( - suballocation::DeviceAllocationContext::from(self), - texture.resource, - texture.allocation, - ); + suballocation::DeviceAllocationContext::from(self) + .free_resource(texture.resource, texture.allocation); self.counters.textures.sub(1); } @@ -741,8 +713,7 @@ impl crate::Device for super::Device { .into_device_result("Command allocator creation")?; if let Some(label) = desc.label { - unsafe { allocator.SetName(&windows::core::HSTRING::from(label)) } - .into_device_result("SetName")?; + allocator.set_name(label)?; } self.counters.command_encoders.add(1); @@ -1336,8 +1307,7 @@ impl crate::Device for super::Device { }; if let Some(label) = desc.label { - unsafe { raw.SetName(&windows::core::HSTRING::from(label)) } - .into_device_result("SetName")?; + raw.set_name(label)?; } self.counters.pipeline_layouts.add(1); @@ -1560,37 +1530,15 @@ impl crate::Device for super::Device { }; let buffer_desc = crate::BufferDescriptor { - label: None, + label: Some(&label), size: buffer_size, usage: wgt::BufferUses::STORAGE_READ_ONLY | wgt::BufferUses::MAP_WRITE, // D3D12 backend doesn't care about the memory flags memory_flags: crate::MemoryFlags::empty(), }; - let raw_buffer_desc = Direct3D12::D3D12_RESOURCE_DESC { - Dimension: Direct3D12::D3D12_RESOURCE_DIMENSION_BUFFER, - Alignment: 0, - Width: buffer_size, - Height: 1, - DepthOrArraySize: 1, - MipLevels: 1, - Format: Dxgi::Common::DXGI_FORMAT_UNKNOWN, - SampleDesc: Dxgi::Common::DXGI_SAMPLE_DESC { - Count: 1, - Quality: 0, - }, - Layout: Direct3D12::D3D12_TEXTURE_LAYOUT_ROW_MAJOR, - Flags: Direct3D12::D3D12_RESOURCE_FLAG_NONE, - }; - - let (buffer, allocation) = suballocation::create_buffer( - suballocation::DeviceAllocationContext::from(self), - &buffer_desc, - raw_buffer_desc, - )?; - - unsafe { buffer.SetName(&windows::core::HSTRING::from(&*label)) } - .into_device_result("SetName")?; + let (buffer, allocation) = + suballocation::DeviceAllocationContext::from(self).create_buffer(&buffer_desc)?; let mut mapping = ptr::null_mut::(); unsafe { buffer.Map(0, None, Some(&mut mapping)) }.into_device_result("Map")?; @@ -1669,11 +1617,8 @@ impl crate::Device for super::Device { } if let Some(sampler_buffer) = group.sampler_index_buffer { - suballocation::free_resource( - suballocation::DeviceAllocationContext::from(self), - sampler_buffer.buffer, - sampler_buffer.allocation, - ); + suballocation::DeviceAllocationContext::from(self) + .free_resource(sampler_buffer.buffer, sampler_buffer.allocation); } self.counters.bind_groups.sub(1); @@ -1878,8 +1823,7 @@ impl crate::Device for super::Device { }; if let Some(label) = desc.label { - unsafe { raw.SetName(&windows::core::HSTRING::from(label)) } - .into_device_result("SetName")?; + raw.set_name(label)?; } self.counters.render_pipelines.add(1); @@ -1942,8 +1886,7 @@ impl crate::Device for super::Device { })?; if let Some(label) = desc.label { - unsafe { raw.SetName(&windows::core::HSTRING::from(label)) } - .into_device_result("SetName")?; + raw.set_name(label)?; } self.counters.compute_pipelines.add(1); @@ -2001,8 +1944,7 @@ impl crate::Device for super::Device { let raw = raw.ok_or(crate::DeviceError::Unexpected)?; if let Some(label) = desc.label { - unsafe { raw.SetName(&windows::core::HSTRING::from(label)) } - .into_device_result("SetName")?; + raw.set_name(label)?; } self.counters.query_sets.add(1); @@ -2292,16 +2234,8 @@ impl crate::Device for super::Device { Flags: Direct3D12::D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, }; - let (resource, allocation) = suballocation::create_acceleration_structure( - suballocation::DeviceAllocationContext::from(self), - desc, - raw_desc, - )?; - - if let Some(label) = desc.label { - unsafe { resource.SetName(&windows::core::HSTRING::from(label)) } - .into_device_result("SetName")?; - } + let (resource, allocation) = suballocation::DeviceAllocationContext::from(self) + .create_acceleration_structure(desc, raw_desc)?; // for some reason there is no counter for acceleration structures @@ -2315,8 +2249,7 @@ impl crate::Device for super::Device { &self, acceleration_structure: super::AccelerationStructure, ) { - suballocation::free_resource( - suballocation::DeviceAllocationContext::from(self), + suballocation::DeviceAllocationContext::from(self).free_resource( acceleration_structure.resource, acceleration_structure.allocation, ); diff --git a/wgpu-hal/src/dx12/mod.rs b/wgpu-hal/src/dx12/mod.rs index c26cbf80f4c..09c4f884202 100644 --- a/wgpu-hal/src/dx12/mod.rs +++ b/wgpu-hal/src/dx12/mod.rs @@ -834,6 +834,9 @@ unsafe impl Sync for CommandBuffer {} #[derive(Debug)] pub struct Buffer { resource: Direct3D12::ID3D12Resource, + // While the allocation also has _a_ size, it may not + // be the same as the original size of the buffer, + // as the allocation size varies for assorted reasons. size: wgt::BufferAddress, allocation: suballocation::Allocation, } @@ -1375,7 +1378,10 @@ impl crate::Surface for Surface { size: sc.size, mip_level_count: 1, sample_count: 1, - allocation: suballocation::Allocation::none(suballocation::AllocationType::Texture), + allocation: suballocation::Allocation::none( + suballocation::AllocationType::Texture, + sc.format.theoretical_memory_footprint(sc.size), + ), }; Ok(Some(crate::AcquiredSurfaceTexture { texture, diff --git a/wgpu-hal/src/dx12/suballocation.rs b/wgpu-hal/src/dx12/suballocation.rs index d045820caa1..fcb1e93b08b 100644 --- a/wgpu-hal/src/dx12/suballocation.rs +++ b/wgpu-hal/src/dx12/suballocation.rs @@ -5,7 +5,10 @@ use gpu_allocator::{ use parking_lot::Mutex; use windows::Win32::Graphics::Direct3D12; -use crate::auxil::dxgi::result::HResult as _; +use crate::{ + auxil::dxgi::{name::ObjectExt, result::HResult as _}, + dx12::conv, +}; #[derive(Debug)] pub(crate) enum AllocationType { @@ -14,15 +17,47 @@ pub(crate) enum AllocationType { AccelerationStructure, } +#[derive(Debug)] +enum AllocationInner { + /// This resource is suballocated from a heap. + Placed { + inner: gpu_allocator::d3d12::Allocation, + }, + /// This resource is a committed resource and does not belong to a + /// suballocated heap. We store an approximate size, so we can manage our counters + /// correctly. + /// + /// This is only used for Intel Xe drivers, which have a bug that + /// prevents suballocation from working correctly. + Committed { size: u64 }, +} + #[derive(Debug)] pub(crate) struct Allocation { - inner: Option, + inner: AllocationInner, ty: AllocationType, } impl Allocation { - pub fn none(ty: AllocationType) -> Self { - Self { inner: None, ty } + pub fn placed(inner: gpu_allocator::d3d12::Allocation, ty: AllocationType) -> Self { + Self { + inner: AllocationInner::Placed { inner }, + ty, + } + } + + pub fn none(ty: AllocationType, size: u64) -> Self { + Self { + inner: AllocationInner::Committed { size }, + ty, + } + } + + pub fn size(&self) -> u64 { + match self.inner { + AllocationInner::Placed { ref inner } => inner.size(), + AllocationInner::Committed { size } => size, + } } } @@ -92,195 +127,368 @@ impl<'a> From<&'a super::CommandEncoder> for DeviceAllocationContext<'a> { } } -pub(crate) fn create_buffer( - ctx: DeviceAllocationContext, - desc: &crate::BufferDescriptor, - raw_desc: Direct3D12::D3D12_RESOURCE_DESC, -) -> Result<(Direct3D12::ID3D12Resource, Allocation), crate::DeviceError> { - let is_cpu_read = desc.usage.contains(wgt::BufferUses::MAP_READ); - let is_cpu_write = desc.usage.contains(wgt::BufferUses::MAP_WRITE); - - // Workaround for Intel Xe drivers - if !ctx.shared.private_caps.suballocation_supported { - let resource = create_committed_buffer(ctx, desc, raw_desc)?; - return Ok((resource, Allocation::none(AllocationType::Buffer))); - } +impl<'a> DeviceAllocationContext<'a> { + /////////////////////// + // Resource Creation // + /////////////////////// + + pub(crate) fn create_buffer( + &self, + desc: &crate::BufferDescriptor, + ) -> Result<(Direct3D12::ID3D12Resource, Allocation), crate::DeviceError> { + let is_cpu_read = desc.usage.contains(wgt::BufferUses::MAP_READ); + let is_cpu_write = desc.usage.contains(wgt::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 (resource, allocation) = if self.shared.private_caps.suballocation_supported { + self.create_placed_buffer(desc, location)? + } else { + self.create_committed_buffer(desc, location)? + }; - 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, - }; + if let Some(label) = desc.label { + resource.set_name(label)?; + } - let name = desc.label.unwrap_or("Unlabeled buffer"); + self.counters.buffer_memory.add(allocation.size() as isize); - let mut allocator = ctx.mem_allocator.lock(); + Ok((resource, allocation)) + } - let allocation_desc = AllocationCreateDesc::from_d3d12_resource_desc( - allocator.device(), - &raw_desc, - name, - location, - ); - let allocation = allocator.allocate(&allocation_desc)?; - let mut resource = None; + pub(crate) fn create_texture( + &self, + desc: &crate::TextureDescriptor, + raw_desc: Direct3D12::D3D12_RESOURCE_DESC, + ) -> Result<(Direct3D12::ID3D12Resource, Allocation), crate::DeviceError> { + let (resource, allocation) = if self.shared.private_caps.suballocation_supported { + self.create_placed_texture(desc, raw_desc)? + } else { + self.create_committed_texture(desc, raw_desc)? + }; - unsafe { - ctx.raw.CreatePlacedResource( - allocation.heap(), - allocation.offset(), - &raw_desc, - Direct3D12::D3D12_RESOURCE_STATE_COMMON, - None, - &mut resource, - ) + if let Some(label) = desc.label { + resource.set_name(label)?; + } + + self.counters.texture_memory.add(allocation.size() as isize); + + Ok((resource, allocation)) } - .into_device_result("Placed buffer creation")?; - let resource = resource.ok_or(crate::DeviceError::Unexpected)?; + pub(crate) fn create_acceleration_structure( + &self, + desc: &crate::AccelerationStructureDescriptor, + raw_desc: Direct3D12::D3D12_RESOURCE_DESC, + ) -> Result<(Direct3D12::ID3D12Resource, Allocation), crate::DeviceError> { + let (resource, allocation) = if self.shared.private_caps.suballocation_supported { + self.create_placed_acceleration_structure(desc, raw_desc)? + } else { + self.create_committed_acceleration_structure(desc, raw_desc)? + }; - ctx.counters.buffer_memory.add(allocation.size() as isize); + if let Some(label) = desc.label { + resource.set_name(label)?; + } - Ok(( - resource, - Allocation { - inner: Some(allocation), - ty: AllocationType::Buffer, - }, - )) -} + self.counters + .acceleration_structure_memory + .add(allocation.size() as isize); -pub(crate) fn create_texture( - ctx: DeviceAllocationContext, - desc: &crate::TextureDescriptor, - raw_desc: Direct3D12::D3D12_RESOURCE_DESC, -) -> Result<(Direct3D12::ID3D12Resource, Allocation), crate::DeviceError> { - // Workaround for Intel Xe drivers - if !ctx.shared.private_caps.suballocation_supported { - let resource = create_committed_texture(ctx, desc, raw_desc)?; - return Ok((resource, Allocation::none(AllocationType::Texture))); + Ok((resource, allocation)) } - let location = MemoryLocation::GpuOnly; + ////////////////////////// + // Resource Destruction // + ////////////////////////// + + pub(crate) fn free_resource( + &self, + resource: Direct3D12::ID3D12Resource, + allocation: Allocation, + ) { + // Make sure the resource is released before we free the allocation. + drop(resource); + + let counter = match allocation.ty { + AllocationType::Buffer => &self.counters.buffer_memory, + AllocationType::Texture => &self.counters.texture_memory, + AllocationType::AccelerationStructure => &self.counters.acceleration_structure_memory, + }; + counter.sub(allocation.size() as isize); + + if let AllocationInner::Placed { inner } = allocation.inner { + match self.mem_allocator.lock().free(inner) { + Ok(_) => (), + // TODO: Don't panic here + Err(e) => panic!("Failed to destroy dx12 {:?}, {e}", allocation.ty), + }; + } + } - let name = desc.label.unwrap_or("Unlabeled texture"); + /////////////////////////////// + // Placed Resource Creation /// + /////////////////////////////// - let mut allocator = ctx.mem_allocator.lock(); - let allocation_desc = AllocationCreateDesc::from_d3d12_resource_desc( - allocator.device(), - &raw_desc, - name, - location, - ); - let allocation = allocator.allocate(&allocation_desc)?; - let mut resource = None; + fn create_placed_buffer( + &self, + desc: &crate::BufferDescriptor<'_>, + location: MemoryLocation, + ) -> Result<(Direct3D12::ID3D12Resource, Allocation), crate::DeviceError> { + let raw_desc = conv::map_buffer_descriptor(desc); - unsafe { - ctx.raw.CreatePlacedResource( - allocation.heap(), - allocation.offset(), + let name = desc.label.unwrap_or("Unlabeled buffer"); + + let mut allocator = self.mem_allocator.lock(); + + let allocation_desc = AllocationCreateDesc::from_d3d12_resource_desc( + allocator.device(), &raw_desc, - Direct3D12::D3D12_RESOURCE_STATE_COMMON, - None, // clear value - &mut resource, - ) + name, + location, + ); + + let allocation = allocator.allocate(&allocation_desc)?; + let mut resource = None; + unsafe { + self.raw.CreatePlacedResource( + allocation.heap(), + allocation.offset(), + &raw_desc, + Direct3D12::D3D12_RESOURCE_STATE_COMMON, + None, + &mut resource, + ) + } + .into_device_result("Placed buffer creation")?; + + let resource = resource.ok_or(crate::DeviceError::Unexpected)?; + let wrapped_allocation = Allocation::placed(allocation, AllocationType::Buffer); + + Ok((resource, wrapped_allocation)) } - .into_device_result("Placed texture creation")?; - let resource = resource.ok_or(crate::DeviceError::Unexpected)?; + fn create_placed_texture( + &self, + desc: &crate::TextureDescriptor<'_>, + raw_desc: Direct3D12::D3D12_RESOURCE_DESC, + ) -> Result<(Direct3D12::ID3D12Resource, Allocation), crate::DeviceError> { + let location = MemoryLocation::GpuOnly; - ctx.counters.texture_memory.add(allocation.size() as isize); + let name = desc.label.unwrap_or("Unlabeled texture"); - Ok(( - resource, - Allocation { - inner: Some(allocation), - ty: AllocationType::Texture, - }, - )) -} + let mut allocator = self.mem_allocator.lock(); -pub(crate) fn create_acceleration_structure( - ctx: DeviceAllocationContext, - desc: &crate::AccelerationStructureDescriptor, - raw_desc: Direct3D12::D3D12_RESOURCE_DESC, -) -> Result<(Direct3D12::ID3D12Resource, Allocation), crate::DeviceError> { - // Workaround for Intel Xe drivers - if !ctx.shared.private_caps.suballocation_supported { - let resource = create_committed_acceleration_structure(ctx, desc, raw_desc)?; - return Ok(( - resource, - Allocation::none(AllocationType::AccelerationStructure), - )); - } + let allocation_desc = AllocationCreateDesc::from_d3d12_resource_desc( + allocator.device(), + &raw_desc, + name, + location, + ); + + let allocation = allocator.allocate(&allocation_desc)?; + let mut resource = None; + unsafe { + self.raw.CreatePlacedResource( + allocation.heap(), + allocation.offset(), + &raw_desc, + Direct3D12::D3D12_RESOURCE_STATE_COMMON, + None, // clear value + &mut resource, + ) + } + .into_device_result("Placed texture creation")?; + + let resource = resource.ok_or(crate::DeviceError::Unexpected)?; + let wrapped_allocation = Allocation::placed(allocation, AllocationType::Texture); - let location = MemoryLocation::GpuOnly; + Ok((resource, wrapped_allocation)) + } - let name = desc.label.unwrap_or("Unlabeled acceleration structure"); + fn create_placed_acceleration_structure( + &self, + desc: &crate::AccelerationStructureDescriptor<'_>, + raw_desc: Direct3D12::D3D12_RESOURCE_DESC, + ) -> Result<(Direct3D12::ID3D12Resource, Allocation), crate::DeviceError> { + let location = MemoryLocation::GpuOnly; - let mut allocator = ctx.mem_allocator.lock(); + let name = desc.label.unwrap_or("Unlabeled acceleration structure"); - let allocation_desc = AllocationCreateDesc::from_d3d12_resource_desc( - allocator.device(), - &raw_desc, - name, - location, - ); - let allocation = allocator.allocate(&allocation_desc)?; - let mut resource = None; + let mut allocator = self.mem_allocator.lock(); - unsafe { - ctx.raw.CreatePlacedResource( - allocation.heap(), - allocation.offset(), + let allocation_desc = AllocationCreateDesc::from_d3d12_resource_desc( + allocator.device(), &raw_desc, - Direct3D12::D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE, - None, - &mut resource, - ) + name, + location, + ); + + let allocation = allocator.allocate(&allocation_desc)?; + let mut resource = None; + unsafe { + self.raw.CreatePlacedResource( + allocation.heap(), + allocation.offset(), + &raw_desc, + Direct3D12::D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE, + None, + &mut resource, + ) + } + .into_device_result("Placed acceleration structure creation")?; + + let resource = resource.ok_or(crate::DeviceError::Unexpected)?; + let wrapped_allocation = + Allocation::placed(allocation, AllocationType::AccelerationStructure); + + Ok((resource, wrapped_allocation)) } - .into_device_result("Placed acceleration structure creation")?; - let resource = resource.ok_or(crate::DeviceError::Unexpected)?; + ///////////////////////////////// + // Committed Resource Creation // + ///////////////////////////////// + + fn create_committed_buffer( + &self, + desc: &crate::BufferDescriptor, + location: MemoryLocation, + ) -> Result<(Direct3D12::ID3D12Resource, Allocation), crate::DeviceError> { + let raw_desc = conv::map_buffer_descriptor(desc); + + let is_uma = matches!( + self.shared.private_caps.memory_architecture, + crate::dx12::MemoryArchitecture::Unified { .. } + ); + + let heap_properties = Direct3D12::D3D12_HEAP_PROPERTIES { + Type: Direct3D12::D3D12_HEAP_TYPE_CUSTOM, + CPUPageProperty: match location { + MemoryLocation::GpuOnly => Direct3D12::D3D12_CPU_PAGE_PROPERTY_UNKNOWN, + MemoryLocation::CpuToGpu => Direct3D12::D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE, + MemoryLocation::GpuToCpu => Direct3D12::D3D12_CPU_PAGE_PROPERTY_WRITE_BACK, + _ => unreachable!(), + }, + MemoryPoolPreference: match (is_uma, location) { + // On dedicated GPUs, we only use L1 for GPU-only allocations. + (false, MemoryLocation::GpuOnly) => Direct3D12::D3D12_MEMORY_POOL_L1, + (_, _) => Direct3D12::D3D12_MEMORY_POOL_L0, + }, + CreationNodeMask: 0, + VisibleNodeMask: 0, + }; + + let mut resource = None; + + unsafe { + self.raw.CreateCommittedResource( + &heap_properties, + if self.shared.private_caps.heap_create_not_zeroed { + Direct3D12::D3D12_HEAP_FLAG_CREATE_NOT_ZEROED + } else { + Direct3D12::D3D12_HEAP_FLAG_NONE + }, + &raw_desc, + Direct3D12::D3D12_RESOURCE_STATE_COMMON, + None, + &mut resource, + ) + } + .into_device_result("Committed buffer creation")?; - ctx.counters - .acceleration_structure_memory - .add(allocation.size() as isize); + let resource = resource.ok_or(crate::DeviceError::Unexpected)?; + let wrapped_allocation = Allocation::none(AllocationType::Buffer, desc.size); - Ok(( - resource, - Allocation { - inner: Some(allocation), - ty: AllocationType::AccelerationStructure, - }, - )) -} + Ok((resource, wrapped_allocation)) + } -pub(crate) fn free_resource( - ctx: DeviceAllocationContext, - resource: Direct3D12::ID3D12Resource, - allocation: Allocation, -) { - // Make sure the resource is released before we free the allocation. - drop(resource); + fn create_committed_texture( + &self, + desc: &crate::TextureDescriptor, + raw_desc: Direct3D12::D3D12_RESOURCE_DESC, + ) -> Result<(Direct3D12::ID3D12Resource, Allocation), crate::DeviceError> { + let heap_properties = Direct3D12::D3D12_HEAP_PROPERTIES { + Type: Direct3D12::D3D12_HEAP_TYPE_CUSTOM, + CPUPageProperty: Direct3D12::D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE, + MemoryPoolPreference: match self.shared.private_caps.memory_architecture { + crate::dx12::MemoryArchitecture::NonUnified => Direct3D12::D3D12_MEMORY_POOL_L1, + crate::dx12::MemoryArchitecture::Unified { .. } => Direct3D12::D3D12_MEMORY_POOL_L0, + }, + CreationNodeMask: 0, + VisibleNodeMask: 0, + }; + + let mut resource = None; + + unsafe { + self.raw.CreateCommittedResource( + &heap_properties, + if self.shared.private_caps.heap_create_not_zeroed { + Direct3D12::D3D12_HEAP_FLAG_CREATE_NOT_ZEROED + } else { + Direct3D12::D3D12_HEAP_FLAG_NONE + }, + &raw_desc, + Direct3D12::D3D12_RESOURCE_STATE_COMMON, + None, // clear value + &mut resource, + ) + } + .into_device_result("Committed texture creation")?; - let Some(inner) = allocation.inner else { - return; - }; + let resource = resource.ok_or(crate::DeviceError::Unexpected)?; + let wrapped_allocation = Allocation::none( + AllocationType::Texture, + desc.format.theoretical_memory_footprint(desc.size), + ); - let counter = match allocation.ty { - AllocationType::Buffer => &ctx.counters.buffer_memory, - AllocationType::Texture => &ctx.counters.texture_memory, - AllocationType::AccelerationStructure => &ctx.counters.acceleration_structure_memory, - }; - counter.sub(inner.size() as isize); + Ok((resource, wrapped_allocation)) + } - match ctx.mem_allocator.lock().free(inner) { - Ok(_) => (), - // TODO: Don't panic here - Err(e) => panic!("Failed to destroy dx12 {:?}, {e}", allocation.ty), - }; + fn create_committed_acceleration_structure( + &self, + desc: &crate::AccelerationStructureDescriptor, + raw_desc: Direct3D12::D3D12_RESOURCE_DESC, + ) -> Result<(Direct3D12::ID3D12Resource, Allocation), crate::DeviceError> { + let heap_properties = Direct3D12::D3D12_HEAP_PROPERTIES { + Type: Direct3D12::D3D12_HEAP_TYPE_CUSTOM, + CPUPageProperty: Direct3D12::D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE, + MemoryPoolPreference: match self.shared.private_caps.memory_architecture { + crate::dx12::MemoryArchitecture::NonUnified => Direct3D12::D3D12_MEMORY_POOL_L1, + crate::dx12::MemoryArchitecture::Unified { .. } => Direct3D12::D3D12_MEMORY_POOL_L0, + }, + CreationNodeMask: 0, + VisibleNodeMask: 0, + }; + + let mut resource = None; + + unsafe { + self.raw.CreateCommittedResource( + &heap_properties, + if self.shared.private_caps.heap_create_not_zeroed { + Direct3D12::D3D12_HEAP_FLAG_CREATE_NOT_ZEROED + } else { + Direct3D12::D3D12_HEAP_FLAG_NONE + }, + &raw_desc, + Direct3D12::D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE, + None, + &mut resource, + ) + } + .into_device_result("Committed acceleration structure creation")?; + + let resource = resource.ok_or(crate::DeviceError::Unexpected)?; + let wrapped_allocation = Allocation::none(AllocationType::AccelerationStructure, desc.size); + + Ok((resource, wrapped_allocation)) + } } impl From for crate::DeviceError { @@ -319,125 +527,3 @@ impl From for crate::DeviceError { } } } - -pub(crate) fn create_committed_buffer( - ctx: DeviceAllocationContext, - desc: &crate::BufferDescriptor, - raw_desc: Direct3D12::D3D12_RESOURCE_DESC, -) -> Result { - let is_cpu_read = desc.usage.contains(wgt::BufferUses::MAP_READ); - let is_cpu_write = desc.usage.contains(wgt::BufferUses::MAP_WRITE); - - let heap_properties = Direct3D12::D3D12_HEAP_PROPERTIES { - Type: Direct3D12::D3D12_HEAP_TYPE_CUSTOM, - CPUPageProperty: if is_cpu_read { - Direct3D12::D3D12_CPU_PAGE_PROPERTY_WRITE_BACK - } else if is_cpu_write { - Direct3D12::D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE - } else { - Direct3D12::D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE - }, - MemoryPoolPreference: match ctx.shared.private_caps.memory_architecture { - crate::dx12::MemoryArchitecture::NonUnified if !is_cpu_read && !is_cpu_write => { - Direct3D12::D3D12_MEMORY_POOL_L1 - } - _ => Direct3D12::D3D12_MEMORY_POOL_L0, - }, - CreationNodeMask: 0, - VisibleNodeMask: 0, - }; - - let mut resource = None; - - unsafe { - ctx.raw.CreateCommittedResource( - &heap_properties, - if ctx.shared.private_caps.heap_create_not_zeroed { - Direct3D12::D3D12_HEAP_FLAG_CREATE_NOT_ZEROED - } else { - Direct3D12::D3D12_HEAP_FLAG_NONE - }, - &raw_desc, - Direct3D12::D3D12_RESOURCE_STATE_COMMON, - None, - &mut resource, - ) - } - .into_device_result("Committed buffer creation")?; - - resource.ok_or(crate::DeviceError::Unexpected) -} - -pub(crate) fn create_committed_texture( - ctx: DeviceAllocationContext, - _desc: &crate::TextureDescriptor, - raw_desc: Direct3D12::D3D12_RESOURCE_DESC, -) -> Result { - let heap_properties = Direct3D12::D3D12_HEAP_PROPERTIES { - Type: Direct3D12::D3D12_HEAP_TYPE_CUSTOM, - CPUPageProperty: Direct3D12::D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE, - MemoryPoolPreference: match ctx.shared.private_caps.memory_architecture { - crate::dx12::MemoryArchitecture::NonUnified => Direct3D12::D3D12_MEMORY_POOL_L1, - crate::dx12::MemoryArchitecture::Unified { .. } => Direct3D12::D3D12_MEMORY_POOL_L0, - }, - CreationNodeMask: 0, - VisibleNodeMask: 0, - }; - - let mut resource = None; - - unsafe { - ctx.raw.CreateCommittedResource( - &heap_properties, - if ctx.shared.private_caps.heap_create_not_zeroed { - Direct3D12::D3D12_HEAP_FLAG_CREATE_NOT_ZEROED - } else { - Direct3D12::D3D12_HEAP_FLAG_NONE - }, - &raw_desc, - Direct3D12::D3D12_RESOURCE_STATE_COMMON, - None, // clear value - &mut resource, - ) - } - .into_device_result("Committed texture creation")?; - - resource.ok_or(crate::DeviceError::Unexpected) -} - -pub(crate) fn create_committed_acceleration_structure( - ctx: DeviceAllocationContext, - _desc: &crate::AccelerationStructureDescriptor, - raw_desc: Direct3D12::D3D12_RESOURCE_DESC, -) -> Result { - let heap_properties = Direct3D12::D3D12_HEAP_PROPERTIES { - Type: Direct3D12::D3D12_HEAP_TYPE_CUSTOM, - CPUPageProperty: Direct3D12::D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE, - MemoryPoolPreference: match ctx.shared.private_caps.memory_architecture { - crate::dx12::MemoryArchitecture::NonUnified => Direct3D12::D3D12_MEMORY_POOL_L1, - _ => Direct3D12::D3D12_MEMORY_POOL_L0, - }, - CreationNodeMask: 0, - VisibleNodeMask: 0, - }; - - let mut resource = None; - - unsafe { - ctx.raw.CreateCommittedResource( - &heap_properties, - if ctx.shared.private_caps.heap_create_not_zeroed { - Direct3D12::D3D12_HEAP_FLAG_CREATE_NOT_ZEROED - } else { - Direct3D12::D3D12_HEAP_FLAG_NONE - }, - &raw_desc, - Direct3D12::D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE, - None, - &mut resource, - ) - } - .into_device_result("Committed acceleration structure creation")?; - - resource.ok_or(crate::DeviceError::Unexpected) -} diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index b53d31871e5..f3d8b6a2f8b 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -3540,6 +3540,47 @@ impl TextureFormat { pub fn is_srgb(&self) -> bool { *self != self.remove_srgb_suffix() } + + /// Returns the theoretical memory footprint of a texture with the given format and dimensions. + /// + /// Actual memory usage may greatly exceed this value due to alignment and padding. + #[must_use] + pub fn theoretical_memory_footprint(&self, size: Extent3d) -> u64 { + let (block_width, block_height) = self.block_dimensions(); + + let block_size = self.block_copy_size(None); + + let approximate_block_size = match block_size { + Some(size) => size, + None => match self { + // One f16 per pixel + Self::Depth16Unorm => 2, + // One u24 per pixel, padded to 4 bytes + Self::Depth24Plus => 4, + // One u24 per pixel, plus one u8 per pixel + Self::Depth24PlusStencil8 => 4, + // One f32 per pixel + Self::Depth32Float => 4, + // One f32 per pixel, plus one u8 per pixel, with 3 bytes intermediary padding + Self::Depth32FloatStencil8 => 8, + // One u8 per pixel + Self::Stencil8 => 1, + // Two chroma bytes per block, one luma byte per block + Self::NV12 => 3, + f => { + log::warn!("Memory footprint for format {:?} is not implemented", f); + 0 + } + }, + }; + + let width_blocks = size.width.div_ceil(block_width) as u64; + let height_blocks = size.height.div_ceil(block_height) as u64; + + let total_blocks = width_blocks * height_blocks * size.depth_or_array_layers as u64; + + total_blocks * approximate_block_size as u64 + } } #[test]