From 2e7c3b3273e51dc1a97398ee5231c7e1577820b5 Mon Sep 17 00:00:00 2001 From: chyyran Date: Sun, 25 Aug 2024 01:24:05 -0400 Subject: [PATCH] rt(d3d12): use gpu_allocator instead of CreateCommittedResource --- Cargo.lock | 3 + librashader-runtime-d3d12/Cargo.toml | 2 + librashader-runtime-d3d12/src/buffer.rs | 113 +++++++------- librashader-runtime-d3d12/src/draw_quad.rs | 12 +- librashader-runtime-d3d12/src/error.rs | 4 +- librashader-runtime-d3d12/src/filter_chain.rs | 37 ++++- librashader-runtime-d3d12/src/framebuffer.rs | 99 +++++++----- librashader-runtime-d3d12/src/luts.rs | 143 ++++++++++++------ librashader-runtime-d3d12/tests/triangle.rs | 4 +- 9 files changed, 267 insertions(+), 150 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 78101a5..1336ee2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1265,6 +1265,7 @@ dependencies = [ "log", "presser", "thiserror", + "windows 0.58.0", ] [[package]] @@ -1774,6 +1775,7 @@ dependencies = [ "bitvec", "bytemuck", "gfx-maths", + "gpu-allocator 0.27.0", "librashader-cache", "librashader-common", "librashader-preprocess", @@ -1781,6 +1783,7 @@ dependencies = [ "librashader-reflect", "librashader-runtime", "mach-siegbert-vogt-dxcsa", + "parking_lot", "rayon", "thiserror", "widestring", diff --git a/librashader-runtime-d3d12/Cargo.toml b/librashader-runtime-d3d12/Cargo.toml index b322a3b..6352c71 100644 --- a/librashader-runtime-d3d12/Cargo.toml +++ b/librashader-runtime-d3d12/Cargo.toml @@ -29,6 +29,8 @@ array-concat = "0.5.2" mach-siegbert-vogt-dxcsa = "0.1.3" rayon = "1.6.1" +gpu-allocator = { version = "0.27.0", features = ["d3d12"], default-features = false} +parking_lot = "0.12.3" [target.'cfg(windows)'.dependencies.windows] workspace = true diff --git a/librashader-runtime-d3d12/src/buffer.rs b/librashader-runtime-d3d12/src/buffer.rs index 72e9fe7..a0f3754 100644 --- a/librashader-runtime-d3d12/src/buffer.rs +++ b/librashader-runtime-d3d12/src/buffer.rs @@ -1,19 +1,25 @@ use crate::error; -use crate::error::assume_d3d12_init; +use gpu_allocator::d3d12::{ + Allocator, Resource, ResourceCategory, ResourceCreateDesc, ResourceStateOrBarrierLayout, + ResourceType, +}; +use gpu_allocator::MemoryLocation; +use parking_lot::Mutex; use std::ffi::c_void; use std::mem::ManuallyDrop; use std::ops::{Deref, DerefMut, Range}; use std::ptr::NonNull; +use std::sync::Arc; use windows::Win32::Graphics::Direct3D12::{ - ID3D12Device, ID3D12GraphicsCommandList, ID3D12Resource, D3D12_CPU_PAGE_PROPERTY_UNKNOWN, - D3D12_HEAP_FLAG_NONE, D3D12_HEAP_PROPERTIES, D3D12_HEAP_TYPE_UPLOAD, D3D12_MEMORY_POOL_UNKNOWN, - D3D12_RANGE, D3D12_RESOURCE_DESC, D3D12_RESOURCE_DIMENSION_BUFFER, - D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_TEXTURE_LAYOUT_ROW_MAJOR, + ID3D12GraphicsCommandList, ID3D12Resource, D3D12_RANGE, D3D12_RESOURCE_DESC, + D3D12_RESOURCE_DIMENSION_BUFFER, D3D12_RESOURCE_STATE_GENERIC_READ, + D3D12_TEXTURE_LAYOUT_ROW_MAJOR, }; use windows::Win32::Graphics::Dxgi::Common::DXGI_SAMPLE_DESC; pub struct D3D12Buffer { - handle: ID3D12Resource, + resource: ManuallyDrop, + allocator: Arc>, size: usize, } @@ -28,51 +34,51 @@ impl<'a> Drop for D3D12BufferMapHandle<'a> { } } -impl D3D12Buffer { - pub fn new(device: &ID3D12Device, size: usize) -> error::Result { - unsafe { - let mut buffer: Option = None; - device.CreateCommittedResource( - &D3D12_HEAP_PROPERTIES { - Type: D3D12_HEAP_TYPE_UPLOAD, - CPUPageProperty: D3D12_CPU_PAGE_PROPERTY_UNKNOWN, - MemoryPoolPreference: D3D12_MEMORY_POOL_UNKNOWN, - ..Default::default() - }, - D3D12_HEAP_FLAG_NONE, - &D3D12_RESOURCE_DESC { - Dimension: D3D12_RESOURCE_DIMENSION_BUFFER, - Width: size as u64, - Height: 1, - DepthOrArraySize: 1, - MipLevels: 1, - Layout: D3D12_TEXTURE_LAYOUT_ROW_MAJOR, - SampleDesc: DXGI_SAMPLE_DESC { - Count: 1, - Quality: 0, - }, - ..Default::default() - }, - D3D12_RESOURCE_STATE_GENERIC_READ, - None, - &mut buffer, - )?; - - assume_d3d12_init!(buffer, "CreateCommittedResource"); - - Ok(D3D12Buffer { - handle: buffer, - size, - }) +impl Drop for D3D12Buffer { + fn drop(&mut self) { + let resource = unsafe { ManuallyDrop::take(&mut self.resource) }; + if let Err(e) = self.allocator.lock().free_resource(resource) { + println!("librashader-runtime-d3d12: [warn] failed to deallocate buffer memory {e}") } } +} + +impl D3D12Buffer { + pub fn new(allocator: &Arc>, size: usize) -> error::Result { + let resource = allocator.lock().create_resource(&ResourceCreateDesc { + name: "d3d12buffer", + memory_location: MemoryLocation::CpuToGpu, + resource_category: ResourceCategory::Buffer, + resource_desc: &D3D12_RESOURCE_DESC { + Dimension: D3D12_RESOURCE_DIMENSION_BUFFER, + Width: size as u64, + Height: 1, + DepthOrArraySize: 1, + MipLevels: 1, + Layout: D3D12_TEXTURE_LAYOUT_ROW_MAJOR, + SampleDesc: DXGI_SAMPLE_DESC { + Count: 1, + Quality: 0, + }, + ..Default::default() + }, + castable_formats: &[], + clear_value: None, + initial_state_or_layout: ResourceStateOrBarrierLayout::ResourceState( + D3D12_RESOURCE_STATE_GENERIC_READ, + ), + resource_type: &ResourceType::Placed, + })?; + + Ok(Self { + resource: ManuallyDrop::new(resource), + size, + allocator: Arc::clone(&allocator), + }) + } pub fn gpu_address(&self) -> u64 { - unsafe { self.handle.GetGPUVirtualAddress() } - } - - pub fn into_raw(self) -> ID3D12Resource { - self.handle + unsafe { self.resource.resource().GetGPUVirtualAddress() } } pub fn map(&mut self, range: Option>) -> error::Result { @@ -88,10 +94,12 @@ impl D3D12Buffer { unsafe { let mut ptr = std::ptr::null_mut(); - self.handle.Map(0, Some(&range), Some(&mut ptr))?; + self.resource + .resource() + .Map(0, Some(&range), Some(&mut ptr))?; let slice = std::slice::from_raw_parts_mut(ptr.cast(), size); Ok(D3D12BufferMapHandle { - handle: &self.handle, + handle: &self.resource.resource(), slice, }) } @@ -115,7 +123,10 @@ impl RawD3D12Buffer { let range = D3D12_RANGE { Begin: 0, End: 0 }; let mut ptr = std::ptr::null_mut(); unsafe { - buffer.handle.Map(0, Some(&range), Some(&mut ptr))?; + buffer + .resource + .resource() + .Map(0, Some(&range), Some(&mut ptr))?; } // panic-safety: If Map returns Ok then ptr is not null @@ -134,7 +145,7 @@ impl RawD3D12Buffer { impl Drop for RawD3D12Buffer { fn drop(&mut self) { unsafe { - self.buffer.handle.Unmap(0, None); + self.buffer.resource.resource().Unmap(0, None); ManuallyDrop::drop(&mut self.buffer); } } diff --git a/librashader-runtime-d3d12/src/draw_quad.rs b/librashader-runtime-d3d12/src/draw_quad.rs index 0bf9e59..7d05223 100644 --- a/librashader-runtime-d3d12/src/draw_quad.rs +++ b/librashader-runtime-d3d12/src/draw_quad.rs @@ -2,11 +2,14 @@ use crate::buffer::D3D12Buffer; use crate::error; use array_concat::concat_arrays; use bytemuck::offset_of; +use gpu_allocator::d3d12::Allocator; use librashader_runtime::quad::{QuadType, VertexInput}; +use parking_lot::Mutex; +use std::sync::Arc; use windows::core::PCSTR; use windows::Win32::Graphics::Direct3D::D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; use windows::Win32::Graphics::Direct3D12::{ - ID3D12Device, ID3D12GraphicsCommandList, ID3D12GraphicsCommandList4, ID3D12Resource, + ID3D12GraphicsCommandList, ID3D12GraphicsCommandList4, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, D3D12_INPUT_ELEMENT_DESC, D3D12_VERTEX_BUFFER_VIEW, }; use windows::Win32::Graphics::Dxgi::Common::DXGI_FORMAT_R32G32_FLOAT; @@ -52,15 +55,15 @@ const FINAL_VBO_DATA: [VertexInput; 4] = [ static VBO_DATA: &[VertexInput; 8] = &concat_arrays!(OFFSCREEN_VBO_DATA, FINAL_VBO_DATA); pub(crate) struct DrawQuad { - _buffer: ID3D12Resource, + _buffer: D3D12Buffer, view: D3D12_VERTEX_BUFFER_VIEW, } impl DrawQuad { - pub fn new(device: &ID3D12Device) -> error::Result { + pub fn new(allocator: &Arc>) -> error::Result { let stride = std::mem::size_of::() as u32; let size = 2 * std::mem::size_of::<[VertexInput; 4]>() as u32; - let mut buffer = D3D12Buffer::new(device, size as usize)?; + let mut buffer = D3D12Buffer::new(allocator, size as usize)?; buffer .map(None)? .slice @@ -72,7 +75,6 @@ impl DrawQuad { StrideInBytes: stride, }; - let buffer = buffer.into_raw(); Ok(DrawQuad { _buffer: buffer, view, diff --git a/librashader-runtime-d3d12/src/error.rs b/librashader-runtime-d3d12/src/error.rs index 1d1bb4d..fae2d09 100644 --- a/librashader-runtime-d3d12/src/error.rs +++ b/librashader-runtime-d3d12/src/error.rs @@ -5,7 +5,7 @@ use thiserror::Error; /// Cumulative error type for Direct3D12 filter chains. #[derive(Error, Debug)] pub enum FilterChainError { - #[error("invariant assumption about d3d11 did not hold. report this as an issue.")] + #[error("invariant assumption about d3d12 did not hold. report this as an issue.")] Direct3DOperationError(&'static str), #[error("direct3d driver error")] Direct3DError(#[from] windows::core::Error), @@ -21,6 +21,8 @@ pub enum FilterChainError { LutLoadError(#[from] ImageError), #[error("heap overflow")] DescriptorHeapOverflow(usize), + #[error("allocation error")] + AllocationError(#[from] gpu_allocator::AllocationError), } /// Result type for Direct3D 12 filter chains. diff --git a/librashader-runtime-d3d12/src/filter_chain.rs b/librashader-runtime-d3d12/src/filter_chain.rs index 2f6e7bd..058ce71 100644 --- a/librashader-runtime-d3d12/src/filter_chain.rs +++ b/librashader-runtime-d3d12/src/filter_chain.rs @@ -14,6 +14,7 @@ use crate::options::{FilterChainOptionsD3D12, FrameOptionsD3D12}; use crate::samplers::SamplerSet; use crate::texture::{D3D12InputImage, D3D12OutputView, InputTexture, OutputDescriptor}; use crate::{error, util}; +use gpu_allocator::d3d12::{Allocator, AllocatorCreateDesc, ID3D12DeviceVersion}; use librashader_common::map::FastHashMap; use librashader_common::{ImageFormat, Size, Viewport}; use librashader_presets::{ShaderPassConfig, ShaderPreset, TextureConfig}; @@ -27,9 +28,11 @@ use librashader_runtime::binding::{BindingUtil, TextureInput}; use librashader_runtime::image::{Image, ImageError, UVDirection}; use librashader_runtime::quad::QuadType; use librashader_runtime::uniforms::UniformStorage; +use parking_lot::Mutex; use std::collections::VecDeque; use std::mem::ManuallyDrop; use std::path::Path; +use std::sync::Arc; use windows::core::Interface; use windows::Win32::Foundation::CloseHandle; use windows::Win32::Graphics::Direct3D::Dxc::{ @@ -93,6 +96,7 @@ pub(crate) struct FilterCommon { pub mipmap_gen: D3D12MipmapGen, pub root_signature: D3D12RootSignature, pub draw_quad: DrawQuad, + allocator: Arc>, } pub(crate) struct FrameResiduals { @@ -275,7 +279,13 @@ impl FilterChainD3D12 { let samplers = SamplerSet::new(device)?; let mipmap_gen = D3D12MipmapGen::new(device, false)?; - let draw_quad = DrawQuad::new(device)?; + let allocator = Arc::new(Mutex::new(Allocator::new(&AllocatorCreateDesc { + device: ID3D12DeviceVersion::Device(device.clone()), + debug_settings: Default::default(), + allocation_sizes: Default::default(), + })?)); + + let draw_quad = DrawQuad::new(&allocator)?; let mut staging_heap = D3D12DescriptorHeap::new( device, (MAX_BINDINGS_COUNT as usize) * shader_count @@ -294,6 +304,7 @@ impl FilterChainD3D12 { let (texture_heap, sampler_heap, filters, mut mipmap_heap) = FilterChainD3D12::init_passes( device, &root_signature, + &allocator, passes, hlsl_passes, &semantics, @@ -306,6 +317,7 @@ impl FilterChainD3D12 { let luts = FilterChainD3D12::load_luts( device, cmd, + &allocator, &mut staging_heap, &mut mipmap_heap, &mut residuals, @@ -315,6 +327,7 @@ impl FilterChainD3D12 { let framebuffer_gen = || { OwnedImage::new( device, + &allocator, Size::new(1, 1), ImageFormat::R8G8B8A8Unorm.into(), false, @@ -341,6 +354,7 @@ impl FilterChainD3D12 { common: FilterCommon { d3d12: device.clone(), samplers, + allocator: allocator, output_textures, feedback_textures, luts, @@ -375,6 +389,7 @@ impl FilterChainD3D12 { fn load_luts( device: &ID3D12Device, cmd: &ID3D12GraphicsCommandList, + allocator: &Arc>, staging_heap: &mut D3D12DescriptorHeap, mipmap_heap: &mut D3D12DescriptorHeap, gc: &mut FrameResiduals, @@ -392,6 +407,7 @@ impl FilterChainD3D12 { for (index, (texture, image)) in textures.iter().zip(images).enumerate() { let texture = LutTexture::new( device, + allocator, staging_heap, cmd, &image, @@ -425,6 +441,7 @@ impl FilterChainD3D12 { fn init_passes( device: &ID3D12Device, root_signature: &D3D12RootSignature, + allocator: &Arc>, passes: Vec, hlsl_passes: Vec, semantics: &ShaderSemantics, @@ -535,8 +552,8 @@ impl FilterChainD3D12 { .map_or(1, |push| push.size as usize); let uniform_storage = UniformStorage::new_with_storage( - RawD3D12Buffer::new(D3D12Buffer::new(device, ubo_size)?)?, - RawD3D12Buffer::new(D3D12Buffer::new(device, push_size)?)?, + RawD3D12Buffer::new(D3D12Buffer::new(allocator, ubo_size)?)?, + RawD3D12Buffer::new(D3D12Buffer::new(allocator, push_size)?)?, ); let uniform_bindings = @@ -584,7 +601,13 @@ impl FilterChainD3D12 { // old back will get dropped.. do we need to defer? let _old_back = std::mem::replace( &mut back, - OwnedImage::new(&self.common.d3d12, input.size, input.format, false)?, + OwnedImage::new( + &self.common.d3d12, + &self.common.allocator, + input.size, + input.format, + false, + )?, ); } unsafe { @@ -731,7 +754,7 @@ impl FilterChainD3D12 { util::d3d12_resource_transition( cmd, - &target.handle, + &target.handle.resource(), D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET, ); @@ -754,7 +777,7 @@ impl FilterChainD3D12 { util::d3d12_resource_transition( cmd, - &target.handle, + &target.handle.resource(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, ); @@ -765,7 +788,7 @@ impl FilterChainD3D12 { &mut self.mipmap_heap, |ctx| { ctx.generate_mipmaps( - &target.handle, + &target.handle.resource(), target.max_mipmap, target.size, target.format.into(), diff --git a/librashader-runtime-d3d12/src/framebuffer.rs b/librashader-runtime-d3d12/src/framebuffer.rs index 896f691..0530182 100644 --- a/librashader-runtime-d3d12/src/framebuffer.rs +++ b/librashader-runtime-d3d12/src/framebuffer.rs @@ -1,22 +1,27 @@ use crate::descriptor_heap::{CpuStagingHeap, D3D12DescriptorHeap, RenderTargetHeap}; -use crate::error::{assume_d3d12_init, FilterChainError}; +use crate::error::FilterChainError; use crate::filter_chain::FrameResiduals; use crate::texture::{D3D12OutputView, InputTexture}; use crate::util::d3d12_get_closest_format; use crate::{error, util}; +use gpu_allocator::d3d12::{ + Allocator, Resource, ResourceCategory, ResourceCreateDesc, ResourceStateOrBarrierLayout, + ResourceType, +}; +use gpu_allocator::MemoryLocation; use librashader_common::{FilterMode, ImageFormat, Size, WrapMode}; use librashader_presets::Scale2D; use librashader_runtime::scaling::{MipmapSize, ScaleFramebuffer, ViewportSize}; +use parking_lot::Mutex; use std::mem::ManuallyDrop; use std::ops::Deref; +use std::sync::Arc; use windows::Win32::Graphics::Direct3D12::{ - ID3D12Device, ID3D12GraphicsCommandList, ID3D12Resource, D3D12_BOX, - D3D12_CPU_PAGE_PROPERTY_UNKNOWN, D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING, + ID3D12Device, ID3D12GraphicsCommandList, D3D12_BOX, D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING, D3D12_FEATURE_DATA_FORMAT_SUPPORT, D3D12_FORMAT_SUPPORT1_MIP, D3D12_FORMAT_SUPPORT1_RENDER_TARGET, D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE, D3D12_FORMAT_SUPPORT1_TEXTURE2D, D3D12_FORMAT_SUPPORT2_UAV_TYPED_LOAD, - D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE, D3D12_HEAP_FLAG_NONE, D3D12_HEAP_PROPERTIES, - D3D12_HEAP_TYPE_DEFAULT, D3D12_MEMORY_POOL_UNKNOWN, D3D12_RENDER_TARGET_VIEW_DESC, + D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE, D3D12_RENDER_TARGET_VIEW_DESC, D3D12_RENDER_TARGET_VIEW_DESC_0, D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, D3D12_RESOURCE_DESC, D3D12_RESOURCE_DIMENSION_TEXTURE2D, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_DEST, @@ -28,13 +33,14 @@ use windows::Win32::Graphics::Direct3D12::{ }; use windows::Win32::Graphics::Dxgi::Common::{DXGI_FORMAT, DXGI_SAMPLE_DESC}; -#[derive(Debug, Clone)] +#[derive(Debug)] pub(crate) struct OwnedImage { - pub(crate) handle: ID3D12Resource, + pub(crate) handle: ManuallyDrop, pub(crate) size: Size, pub(crate) format: DXGI_FORMAT, pub(crate) max_mipmap: u16, device: ID3D12Device, + allocator: Arc>, } static CLEAR: &[f32; 4] = &[0.0, 0.0, 0.0, 0.0]; @@ -64,6 +70,7 @@ impl OwnedImage { pub fn new( device: &ID3D12Device, + allocator: &Arc>, size: Size, format: DXGI_FORMAT, mipmap: bool, @@ -105,31 +112,46 @@ impl OwnedImage { } desc.Format = d3d12_get_closest_format(device, format_support); - let mut resource: Option = None; - unsafe { - device.CreateCommittedResource( - &D3D12_HEAP_PROPERTIES { - Type: D3D12_HEAP_TYPE_DEFAULT, - CPUPageProperty: D3D12_CPU_PAGE_PROPERTY_UNKNOWN, - MemoryPoolPreference: D3D12_MEMORY_POOL_UNKNOWN, - CreationNodeMask: 1, - VisibleNodeMask: 1, - }, - D3D12_HEAP_FLAG_NONE, - &desc, + + let resource = allocator.lock().create_resource(&ResourceCreateDesc { + name: "ownedimage", + memory_location: MemoryLocation::GpuOnly, + resource_category: ResourceCategory::RtvDsvTexture, + resource_desc: &desc, + castable_formats: &[], + clear_value: None, + initial_state_or_layout: ResourceStateOrBarrierLayout::ResourceState( D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, - None, - &mut resource, - )?; - } - assume_d3d12_init!(resource, "CreateCommittedResource"); + ), + resource_type: &ResourceType::Placed, + })?; + + // let mut resource: Option = None; + // unsafe { + // device.CreateCommittedResource( + // &D3D12_HEAP_PROPERTIES { + // Type: D3D12_HEAP_TYPE_DEFAULT, + // CPUPageProperty: D3D12_CPU_PAGE_PROPERTY_UNKNOWN, + // MemoryPoolPreference: D3D12_MEMORY_POOL_UNKNOWN, + // CreationNodeMask: 1, + // VisibleNodeMask: 1, + // }, + // D3D12_HEAP_FLAG_NONE, + // &desc, + // D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, + // None, + // &mut resource, + // )?; + // } + // assume_d3d12_init!(resource, "CreateCommittedResource"); Ok(OwnedImage { - handle: resource, + handle: ManuallyDrop::new(resource), size, format: desc.Format, device: device.clone(), max_mipmap: miplevels as u16, + allocator: Arc::clone(&allocator), }) } @@ -149,7 +171,7 @@ impl OwnedImage { D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, ), util::d3d12_get_resource_transition_subresource( - &self.handle, + &self.handle.resource(), D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, @@ -160,7 +182,7 @@ impl OwnedImage { cmd.ResourceBarrier(&barriers); let dst = D3D12_TEXTURE_COPY_LOCATION { - pResource: ManuallyDrop::new(Some(self.handle.clone())), + pResource: ManuallyDrop::new(Some(self.handle.resource().clone())), Type: D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX, Anonymous: D3D12_TEXTURE_COPY_LOCATION_0 { SubresourceIndex: 0, @@ -203,7 +225,7 @@ impl OwnedImage { D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, ), util::d3d12_get_resource_transition_subresource( - &self.handle, + &self.handle.resource(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, @@ -224,7 +246,7 @@ impl OwnedImage { ) -> error::Result<()> { util::d3d12_resource_transition( cmd, - &self.handle, + &self.handle.resource(), D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET, ); @@ -235,7 +257,7 @@ impl OwnedImage { util::d3d12_resource_transition( cmd, - &self.handle, + &self.handle.resource(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, ); @@ -265,14 +287,14 @@ impl OwnedImage { }; self.device.CreateShaderResourceView( - &self.handle, + self.handle.resource(), Some(&srv_desc), *descriptor.deref().as_ref(), ); } Ok(InputTexture::new( - self.handle.clone(), + self.handle.resource().clone(), descriptor, self.size, self.format, @@ -300,7 +322,7 @@ impl OwnedImage { }; self.device.CreateRenderTargetView( - &self.handle, + self.handle.resource(), Some(&rtv_desc), *descriptor.deref().as_ref(), ); @@ -330,7 +352,7 @@ impl OwnedImage { || (!mipmap && self.max_mipmap != 1) || format != self.format { - let mut new = OwnedImage::new(&self.device, size, format, mipmap)?; + let mut new = OwnedImage::new(&self.device, &self.allocator, size, format, mipmap)?; std::mem::swap(self, &mut new); } Ok(size) @@ -361,3 +383,12 @@ impl ScaleFramebuffer for OwnedImage { ) } } + +impl Drop for OwnedImage { + fn drop(&mut self) { + let resource = unsafe { ManuallyDrop::take(&mut self.handle) }; + if let Err(e) = self.allocator.lock().free_resource(resource) { + println!("librashader-runtime-d3d12: [warn] failed to deallocate owned image buffer memory {e}") + } + } +} diff --git a/librashader-runtime-d3d12/src/luts.rs b/librashader-runtime-d3d12/src/luts.rs index ce17754..6044614 100644 --- a/librashader-runtime-d3d12/src/luts.rs +++ b/librashader-runtime-d3d12/src/luts.rs @@ -1,20 +1,25 @@ use crate::descriptor_heap::{CpuStagingHeap, D3D12DescriptorHeap}; use crate::error; -use crate::error::assume_d3d12_init; use crate::filter_chain::FrameResiduals; use crate::mipmap::MipmapGenContext; use crate::texture::InputTexture; use crate::util::{d3d12_get_closest_format, d3d12_resource_transition, d3d12_update_subresources}; +use gpu_allocator::d3d12::{ + Allocator, Resource, ResourceCategory, ResourceCreateDesc, ResourceStateOrBarrierLayout, + ResourceType, +}; +use gpu_allocator::MemoryLocation; use librashader_common::{FilterMode, ImageFormat, WrapMode}; use librashader_runtime::image::Image; use librashader_runtime::scaling::MipmapSize; +use parking_lot::Mutex; +use std::mem::ManuallyDrop; use std::ops::Deref; +use std::sync::Arc; use windows::Win32::Graphics::Direct3D12::{ - ID3D12Device, ID3D12GraphicsCommandList, ID3D12Resource, D3D12_CPU_PAGE_PROPERTY_UNKNOWN, - D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING, D3D12_FEATURE_DATA_FORMAT_SUPPORT, - D3D12_FORMAT_SUPPORT1_MIP, D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE, - D3D12_FORMAT_SUPPORT1_TEXTURE2D, D3D12_HEAP_FLAG_NONE, D3D12_HEAP_PROPERTIES, - D3D12_HEAP_TYPE_DEFAULT, D3D12_HEAP_TYPE_UPLOAD, D3D12_MEMORY_POOL_UNKNOWN, + ID3D12Device, ID3D12GraphicsCommandList, D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING, + D3D12_FEATURE_DATA_FORMAT_SUPPORT, D3D12_FORMAT_SUPPORT1_MIP, + D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE, D3D12_FORMAT_SUPPORT1_TEXTURE2D, D3D12_PLACED_SUBRESOURCE_FOOTPRINT, D3D12_RESOURCE_DESC, D3D12_RESOURCE_DIMENSION_BUFFER, D3D12_RESOURCE_DIMENSION_TEXTURE2D, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_GENERIC_READ, @@ -25,15 +30,19 @@ use windows::Win32::Graphics::Direct3D12::{ use windows::Win32::Graphics::Dxgi::Common::DXGI_SAMPLE_DESC; pub struct LutTexture { - resource: ID3D12Resource, + resource: ManuallyDrop, view: InputTexture, miplevels: Option, - _staging: ID3D12Resource, + // Staging heap needs to be kept alive until the command list is submitted, which is + // really annoying. We could probably do better but it's safer to keep it around. + staging: ManuallyDrop, + allocator: Arc>, } impl LutTexture { pub(crate) fn new( device: &ID3D12Device, + allocator: &Arc>, heap: &mut D3D12DescriptorHeap, cmd: &ID3D12GraphicsCommandList, source: &Image, @@ -74,24 +83,19 @@ impl LutTexture { let descriptor = heap.alloc_slot()?; // create handles on GPU - let mut resource: Option = None; - unsafe { - device.CreateCommittedResource( - &D3D12_HEAP_PROPERTIES { - Type: D3D12_HEAP_TYPE_DEFAULT, - CPUPageProperty: D3D12_CPU_PAGE_PROPERTY_UNKNOWN, - MemoryPoolPreference: D3D12_MEMORY_POOL_UNKNOWN, - CreationNodeMask: 1, - VisibleNodeMask: 1, - }, - D3D12_HEAP_FLAG_NONE, - &desc, + let resource = allocator.lock().create_resource(&ResourceCreateDesc { + name: "lut alloc", + memory_location: MemoryLocation::GpuOnly, + resource_category: ResourceCategory::OtherTexture, + resource_desc: &desc, + castable_formats: &[], + clear_value: None, + initial_state_or_layout: ResourceStateOrBarrierLayout::ResourceState( D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, - None, - &mut resource, - )?; - } - assume_d3d12_init!(resource, "CreateCommittedResource"); + ), + resource_type: &ResourceType::Placed, + })?; + unsafe { let srv_desc = D3D12_SHADER_RESOURCE_VIEW_DESC { Format: desc.Format, @@ -106,7 +110,7 @@ impl LutTexture { }; device.CreateShaderResourceView( - &resource, + resource.resource(), Some(&srv_desc), *descriptor.deref().as_ref(), ); @@ -139,25 +143,40 @@ impl LutTexture { buffer_desc.SampleDesc.Count = 1; buffer_desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; } - let mut upload: Option = None; - unsafe { - device.CreateCommittedResource( - &D3D12_HEAP_PROPERTIES { - Type: D3D12_HEAP_TYPE_UPLOAD, - CPUPageProperty: D3D12_CPU_PAGE_PROPERTY_UNKNOWN, - MemoryPoolPreference: D3D12_MEMORY_POOL_UNKNOWN, - CreationNodeMask: 1, - VisibleNodeMask: 1, - }, - D3D12_HEAP_FLAG_NONE, - &buffer_desc, + let upload = allocator.lock().create_resource(&ResourceCreateDesc { + name: "lut staging", + memory_location: MemoryLocation::CpuToGpu, + resource_category: ResourceCategory::Buffer, + resource_desc: &buffer_desc, + castable_formats: &[], + clear_value: None, + initial_state_or_layout: ResourceStateOrBarrierLayout::ResourceState( D3D12_RESOURCE_STATE_GENERIC_READ, - None, - &mut upload, - )?; - } - assume_d3d12_init!(upload, "CreateCommittedResource"); + ), + resource_type: &ResourceType::Placed, + })?; + + // + // let mut upload: Option = None; + // + // unsafe { + // device.CreateCommittedResource( + // &D3D12_HEAP_PROPERTIES { + // Type: D3D12_HEAP_TYPE_UPLOAD, + // CPUPageProperty: D3D12_CPU_PAGE_PROPERTY_UNKNOWN, + // MemoryPoolPreference: D3D12_MEMORY_POOL_UNKNOWN, + // CreationNodeMask: 1, + // VisibleNodeMask: 1, + // }, + // D3D12_HEAP_FLAG_NONE, + // &buffer_desc, + // D3D12_RESOURCE_STATE_GENERIC_READ, + // None, + // &mut upload, + // )?; + // } + // assume_d3d12_init!(upload, "CreateCommittedResource"); let subresource = [D3D12_SUBRESOURCE_DATA { pData: source.bytes.as_ptr().cast(), @@ -167,22 +186,31 @@ impl LutTexture { d3d12_resource_transition( cmd, - &resource, + &resource.resource(), D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_COPY_DEST, ); - d3d12_update_subresources(cmd, &resource, &upload, 0, 0, 1, &subresource, gc)?; + d3d12_update_subresources( + cmd, + &resource.resource(), + &upload.resource(), + 0, + 0, + 1, + &subresource, + gc, + )?; d3d12_resource_transition( cmd, - &resource, + &resource.resource(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, ); let view = InputTexture::new( - resource.clone(), + resource.resource().clone(), descriptor, source.size, ImageFormat::R8G8B8A8Unorm.into(), @@ -190,17 +218,18 @@ impl LutTexture { wrap_mode, ); Ok(LutTexture { - resource, - _staging: upload, + resource: ManuallyDrop::new(resource), + staging: ManuallyDrop::new(upload), view, miplevels: if mipmap { Some(miplevels) } else { None }, + allocator: Arc::clone(&allocator), }) } pub fn generate_mipmaps(&self, gen_mips: &mut MipmapGenContext) -> error::Result<()> { if let Some(miplevels) = self.miplevels { gen_mips.generate_mipmaps( - &self.resource, + &self.resource.resource(), miplevels, self.view.size, ImageFormat::R8G8B8A8Unorm.into(), @@ -216,3 +245,17 @@ impl AsRef for LutTexture { &self.view } } + +impl Drop for LutTexture { + fn drop(&mut self) { + let resource = unsafe { ManuallyDrop::take(&mut self.resource) }; + if let Err(e) = self.allocator.lock().free_resource(resource) { + println!("librashader-runtime-d3d12: [warn] failed to deallocate lut buffer memory {e}") + } + + let staging = unsafe { ManuallyDrop::take(&mut self.staging) }; + if let Err(e) = self.allocator.lock().free_resource(staging) { + println!("librashader-runtime-d3d12: [warn] failed to deallocate lut staging buffer memory {e}") + } + } +} diff --git a/librashader-runtime-d3d12/tests/triangle.rs b/librashader-runtime-d3d12/tests/triangle.rs index 5da3666..db45df4 100644 --- a/librashader-runtime-d3d12/tests/triangle.rs +++ b/librashader-runtime-d3d12/tests/triangle.rs @@ -6,11 +6,11 @@ use crate::hello_triangle::{DXSample, SampleCommandLine}; fn triangle_d3d12() { let sample = hello_triangle::d3d12_hello_triangle::Sample::new( // "../test/shaders_slang/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp", - "../test/shaders_slang/crt/crt-lottes.slangp", + // "../test/shaders_slang/crt/crt-lottes.slangp", // "../test/basic.slangp", // "../test/shaders_slang/handheld/console-border/gbc-lcd-grid-v2.slangp", // "../test/Mega_Bezel_Packs/Duimon-Mega-Bezel/Presets/Advanced/Nintendo_GBA_SP/GBA_SP-[ADV]-[LCD-GRID]-[Night].slangp", - // "../test/slang-shaders/test/feedback.slangp", + "../test/shaders_slang/test/feedback.slangp", // "../test/shaders_slang/test/history.slangp", // "../test/shaders_slang/crt/crt-royale.slangp", // "../test/slang-shaders/vhs/VHSPro.slangp",