diff --git a/librashader-runtime-d3d12/src/lib.rs b/librashader-runtime-d3d12/src/lib.rs index e1473f4..122212f 100644 --- a/librashader-runtime-d3d12/src/lib.rs +++ b/librashader-runtime-d3d12/src/lib.rs @@ -17,6 +17,7 @@ mod util; pub mod error; pub mod options; +mod resource; use librashader_runtime::impl_filter_chain_parameters; impl_filter_chain_parameters!(FilterChainD3D12); diff --git a/librashader-runtime-d3d12/src/luts.rs b/librashader-runtime-d3d12/src/luts.rs index 13e6c5e..aebabcb 100644 --- a/librashader-runtime-d3d12/src/luts.rs +++ b/librashader-runtime-d3d12/src/luts.rs @@ -1,7 +1,10 @@ use crate::descriptor_heap::CpuStagingHeap; use crate::error; +use crate::error::assume_d3d12_init; use crate::filter_chain::FrameResiduals; use crate::mipmap::MipmapGenContext; +use crate::resource::OutlivesFrame; +use crate::resource::ResourceHandleStrategy; use crate::texture::InputTexture; use crate::util::{d3d12_get_closest_format, d3d12_resource_transition}; use d3d12_descriptor_heap::D3D12DescriptorHeap; @@ -15,19 +18,34 @@ 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_DEFAULT_SHADER_4_COMPONENT_MAPPING, D3D12_FEATURE_DATA_FORMAT_SUPPORT, D3D12_FORMAT_SUPPORT1_MIP, D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE, D3D12_FORMAT_SUPPORT1_TEXTURE2D, D3D12_MEMCPY_DEST, 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, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_SHADER_RESOURCE_VIEW_DESC, D3D12_SHADER_RESOURCE_VIEW_DESC_0, D3D12_SRV_DIMENSION_TEXTURE2D, D3D12_SUBRESOURCE_DATA, D3D12_TEX2D_SRV, D3D12_TEXTURE_COPY_LOCATION, D3D12_TEXTURE_COPY_LOCATION_0, D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT, D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX, D3D12_TEXTURE_LAYOUT_ROW_MAJOR}; -use windows::Win32::Graphics::Dxgi::Common::DXGI_SAMPLE_DESC; use std::u64; -use crate::error::assume_d3d12_init; +use windows::Win32::Graphics::Direct3D12::{ + ID3D12Device, ID3D12GraphicsCommandList, ID3D12Resource, + 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_MEMCPY_DEST, 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, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, + D3D12_SHADER_RESOURCE_VIEW_DESC, D3D12_SHADER_RESOURCE_VIEW_DESC_0, + D3D12_SRV_DIMENSION_TEXTURE2D, D3D12_SUBRESOURCE_DATA, D3D12_TEX2D_SRV, + D3D12_TEXTURE_COPY_LOCATION, D3D12_TEXTURE_COPY_LOCATION_0, + D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT, D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX, + D3D12_TEXTURE_LAYOUT_ROW_MAJOR, +}; +use windows::Win32::Graphics::Dxgi::Common::DXGI_SAMPLE_DESC; pub struct LutTexture { - resource: ManuallyDrop, + allocator_resource: ManuallyDrop, + resource: ManuallyDrop, view: InputTexture, miplevels: Option, // 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_staging: ManuallyDrop, + staging: ManuallyDrop, allocator: Arc>, } @@ -75,7 +93,7 @@ impl LutTexture { let descriptor = heap.allocate_descriptor()?; // create handles on GPU - let resource = allocator.lock().create_resource(&ResourceCreateDesc { + let allocator_resource = allocator.lock().create_resource(&ResourceCreateDesc { name: "lut alloc", memory_location: MemoryLocation::GpuOnly, resource_category: ResourceCategory::OtherTexture, @@ -102,7 +120,7 @@ impl LutTexture { }; device.CreateShaderResourceView( - resource.resource(), + allocator_resource.resource(), Some(&srv_desc), *descriptor.as_ref(), ); @@ -136,7 +154,7 @@ impl LutTexture { buffer_desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; } - let upload = allocator.lock().create_resource(&ResourceCreateDesc { + let allocator_upload = allocator.lock().create_resource(&ResourceCreateDesc { name: "lut staging", memory_location: MemoryLocation::CpuToGpu, resource_category: ResourceCategory::Buffer, @@ -155,17 +173,20 @@ impl LutTexture { SlicePitch: (4 * source.size.width * source.size.height) as isize, }]; + let resource = ManuallyDrop::new(allocator_resource.resource().clone()); + let upload = ManuallyDrop::new(allocator_upload.resource().clone()); + gc.dispose_barriers(d3d12_resource_transition( cmd, - &resource.resource(), + &allocator_resource.resource(), D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_COPY_DEST, )); - d3d12_update_subresources( + d3d12_update_subresources::( cmd, - &resource.resource(), - &upload.resource(), + &resource, + &upload, 0, 0, 1, @@ -175,32 +196,35 @@ impl LutTexture { gc.dispose_barriers(d3d12_resource_transition( cmd, - &resource.resource(), + &resource, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, )); let view = InputTexture::new( - resource.resource().clone(), + allocator_resource.resource().clone(), descriptor, source.size, ImageFormat::R8G8B8A8Unorm.into(), filter, wrap_mode, ); + Ok(LutTexture { - resource: ManuallyDrop::new(resource), - staging: ManuallyDrop::new(upload), + allocator_resource: ManuallyDrop::new(allocator_resource), + allocator_staging: ManuallyDrop::new(allocator_upload), view, miplevels: if mipmap { Some(miplevels) } else { None }, allocator: Arc::clone(&allocator), + resource, + staging: upload, }) } pub fn generate_mipmaps(&self, gen_mips: &mut MipmapGenContext) -> error::Result<()> { if let Some(miplevels) = self.miplevels { gen_mips.generate_mipmaps( - &self.resource.resource(), + &self.allocator_resource.resource(), miplevels, self.view.size, ImageFormat::R8G8B8A8Unorm.into(), @@ -219,22 +243,29 @@ impl AsRef for LutTexture { impl Drop for LutTexture { fn drop(&mut self) { - let resource = unsafe { ManuallyDrop::take(&mut self.resource) }; + // drop view handles + unsafe { + ManuallyDrop::drop(&mut self.resource); + ManuallyDrop::drop(&mut self.staging) + }; + + // deallocate + let resource = unsafe { ManuallyDrop::take(&mut self.allocator_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) }; + let staging = unsafe { ManuallyDrop::take(&mut self.allocator_staging) }; if let Err(e) = self.allocator.lock().free_resource(staging) { println!("librashader-runtime-d3d12: [warn] failed to deallocate lut staging buffer memory {e}") } } } -fn d3d12_update_subresources( +fn d3d12_update_subresources>>( cmd: &ID3D12GraphicsCommandList, - destination_resource: &ID3D12Resource, - intermediate_resource: &ID3D12Resource, + destination_resource: &ManuallyDrop, + intermediate_resource: &ManuallyDrop, intermediate_offset: u64, first_subresouce: u32, num_subresources: u32, @@ -269,7 +300,7 @@ fn d3d12_update_subresources( Some(&mut required_size), ); - update_subresources( + update_subresources::( cmd, destination_resource, intermediate_resource, @@ -286,10 +317,10 @@ fn d3d12_update_subresources( } #[allow(clippy::too_many_arguments)] -fn update_subresources( +fn update_subresources>>( cmd: &ID3D12GraphicsCommandList, - destination_resource: &ID3D12Resource, - intermediate_resource: &ID3D12Resource, + destination_resource: &ManuallyDrop, + intermediate_resource: &ManuallyDrop, first_subresouce: u32, num_subresources: u32, required_size: u64, @@ -327,16 +358,16 @@ fn update_subresources( let destination_desc = destination_resource.GetDesc(); if destination_desc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER { cmd.CopyBufferRegion( - destination_resource, + destination_resource.deref(), 0, - intermediate_resource, + intermediate_resource.deref(), layouts[0].Offset, layouts[0].Footprint.Width as u64, ); } else { for i in 0..num_subresources as usize { let dest_location = D3D12_TEXTURE_COPY_LOCATION { - pResource: ManuallyDrop::new(Some(destination_resource.clone())), + pResource: S::obtain(&destination_resource), Type: D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX, Anonymous: D3D12_TEXTURE_COPY_LOCATION_0 { SubresourceIndex: i as u32 + first_subresouce, @@ -344,7 +375,7 @@ fn update_subresources( }; let source_location = D3D12_TEXTURE_COPY_LOCATION { - pResource: ManuallyDrop::new(Some(intermediate_resource.clone())), + pResource: S::obtain(&intermediate_resource), Type: D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT, Anonymous: D3D12_TEXTURE_COPY_LOCATION_0 { PlacedFootprint: layouts[i], @@ -353,8 +384,8 @@ fn update_subresources( cmd.CopyTextureRegion(&dest_location, 0, 0, 0, &source_location, None); - gc.dispose_resource(dest_location.pResource); - gc.dispose_resource(source_location.pResource); + S::cleanup(gc, dest_location.pResource); + S::cleanup(gc, source_location.pResource); } } Ok(required_size) @@ -384,4 +415,4 @@ unsafe fn memcpy_subresource( } } } -} \ No newline at end of file +} diff --git a/librashader-runtime-d3d12/src/resource.rs b/librashader-runtime-d3d12/src/resource.rs new file mode 100644 index 0000000..7bb347e --- /dev/null +++ b/librashader-runtime-d3d12/src/resource.rs @@ -0,0 +1,37 @@ +use crate::filter_chain::FrameResiduals; +use std::mem::ManuallyDrop; +use std::ops::Deref; +use windows::Win32::Graphics::Direct3D12::ID3D12Resource; + +pub trait ResourceHandleStrategy { + unsafe fn obtain(handle: &H) -> ManuallyDrop>; + unsafe fn cleanup(gc: &mut FrameResiduals, handle: ManuallyDrop>); +} + +pub struct IncrementRefcount; + +impl ResourceHandleStrategy> for IncrementRefcount { + unsafe fn obtain( + handle: &ManuallyDrop, + ) -> ManuallyDrop> { + ManuallyDrop::new(Some(handle.deref().clone())) + } + + unsafe fn cleanup(gc: &mut FrameResiduals, handle: ManuallyDrop>) { + gc.dispose_resource(handle); + } +} + +pub struct OutlivesFrame; + +impl ResourceHandleStrategy> for OutlivesFrame { + unsafe fn obtain( + handle: &ManuallyDrop, + ) -> ManuallyDrop> { + unsafe { std::mem::transmute_copy(handle) } + } + + unsafe fn cleanup(_gc: &mut FrameResiduals, _handle: ManuallyDrop>) { + // Since the lifetime is ensured for the lifetime of the filter chain strategy, do nothing + } +} diff --git a/librashader-runtime-d3d12/src/util.rs b/librashader-runtime-d3d12/src/util.rs index 0d04698..4376210 100644 --- a/librashader-runtime-d3d12/src/util.rs +++ b/librashader-runtime-d3d12/src/util.rs @@ -9,12 +9,10 @@ use windows::Win32::Graphics::Direct3D::Dxc::{ use windows::Win32::Graphics::Direct3D12::{ ID3D12Device, ID3D12GraphicsCommandList, ID3D12Resource, D3D12_FEATURE_DATA_FORMAT_SUPPORT, - D3D12_FEATURE_FORMAT_SUPPORT, - D3D12_RESOURCE_BARRIER, D3D12_RESOURCE_BARRIER_0, D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, - D3D12_RESOURCE_BARRIER_FLAG_NONE, D3D12_RESOURCE_BARRIER_TYPE_TRANSITION - , D3D12_RESOURCE_STATES, D3D12_RESOURCE_TRANSITION_BARRIER - - , + D3D12_FEATURE_FORMAT_SUPPORT, D3D12_RESOURCE_BARRIER, D3D12_RESOURCE_BARRIER_0, + D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, D3D12_RESOURCE_BARRIER_FLAG_NONE, + D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, D3D12_RESOURCE_STATES, + D3D12_RESOURCE_TRANSITION_BARRIER, }; use windows::Win32::Graphics::Dxgi::Common::*; @@ -232,4 +230,3 @@ pub fn d3d12_resource_transition_subresource( unsafe { cmd.ResourceBarrier(&barrier) } barrier } - diff --git a/librashader-runtime-d3d12/tests/hello_triangle/mod.rs b/librashader-runtime-d3d12/tests/hello_triangle/mod.rs index 74d5fa8..825e3a3 100644 --- a/librashader-runtime-d3d12/tests/hello_triangle/mod.rs +++ b/librashader-runtime-d3d12/tests/hello_triangle/mod.rs @@ -251,7 +251,7 @@ pub mod d3d12_hello_triangle { command_queue: ID3D12CommandQueue, swap_chain: IDXGISwapChain3, frame_index: u32, - render_targets: [ID3D12Resource; FRAME_COUNT as usize], + render_targets: [ManuallyDrop; FRAME_COUNT as usize], rtv_heap: ID3D12DescriptorHeap, rtv_descriptor_size: usize, viewport: D3D12_VIEWPORT, @@ -260,7 +260,7 @@ pub mod d3d12_hello_triangle { root_signature: ID3D12RootSignature, pso: ID3D12PipelineState, command_list: ID3D12GraphicsCommandList, - framebuffer: ID3D12Resource, + framebuffer: ManuallyDrop, // we need to keep this around to keep the reference alive, even though // nothing reads from it #[allow(dead_code)] @@ -377,8 +377,8 @@ pub mod d3d12_hello_triangle { } as usize; let rtv_handle = unsafe { rtv_heap.GetCPUDescriptorHandleForHeapStart() }; - let render_targets: [ID3D12Resource; FRAME_COUNT as usize] = - array_init::try_array_init(|i: usize| -> Result { + let render_targets: [ManuallyDrop; FRAME_COUNT as usize] = + array_init::try_array_init(|i: usize| -> Result> { let render_target: ID3D12Resource = unsafe { swap_chain.GetBuffer(i as u32) }?; unsafe { self.device.CreateRenderTargetView( @@ -389,7 +389,7 @@ pub mod d3d12_hello_triangle { }, ) }; - Ok(render_target) + Ok(ManuallyDrop::new(render_target)) })?; let framebuffer: ID3D12Resource = unsafe { @@ -475,7 +475,7 @@ pub mod d3d12_hello_triangle { root_signature, pso, command_list, - framebuffer, + framebuffer: ManuallyDrop::new(framebuffer), vertex_buffer, vbv, fence, @@ -501,7 +501,7 @@ pub mod d3d12_hello_triangle { unsafe { self.device.CreateShaderResourceView( - &resources.framebuffer, + resources.framebuffer.deref(), Some(&D3D12_SHADER_RESOURCE_VIEW_DESC { Format: DXGI_FORMAT_R8G8B8A8_UNORM, ViewDimension: D3D12_SRV_DIMENSION_TEXTURE2D, @@ -601,8 +601,8 @@ pub mod d3d12_hello_triangle { unsafe { command_list.CopyResource( - &resources.framebuffer, - &resources.render_targets[resources.frame_index as usize], + &*resources.framebuffer, + &*resources.render_targets[resources.frame_index as usize], ); command_list.ResourceBarrier(&[transition_barrier( &resources.framebuffer, @@ -620,7 +620,7 @@ pub mod d3d12_hello_triangle { .frame( command_list, D3D12InputImage { - resource: resources.framebuffer.clone(), + resource: ID3D12Resource::clone(&*resources.framebuffer), descriptor: framebuffer, }, &Viewport { @@ -656,7 +656,7 @@ pub mod d3d12_hello_triangle { } fn transition_barrier( - resource: &ID3D12Resource, + resource: &ManuallyDrop, state_before: D3D12_RESOURCE_STATES, state_after: D3D12_RESOURCE_STATES, ) -> D3D12_RESOURCE_BARRIER { @@ -665,7 +665,7 @@ pub mod d3d12_hello_triangle { Flags: D3D12_RESOURCE_BARRIER_FLAG_NONE, Anonymous: D3D12_RESOURCE_BARRIER_0 { Transition: ManuallyDrop::new(D3D12_RESOURCE_TRANSITION_BARRIER { - pResource: ManuallyDrop::new(Some(resource.clone())), + pResource: unsafe { std::mem::transmute_copy(resource) }, StateBefore: state_before, StateAfter: state_after, Subresource: D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, @@ -694,7 +694,7 @@ pub mod d3d12_hello_triangle { }?; let mut device: Option = None; - unsafe { D3D12CreateDevice(&adapter, D3D_FEATURE_LEVEL_12_2, &mut device) }?; + unsafe { D3D12CreateDevice(&adapter, D3D_FEATURE_LEVEL_12_1, &mut device) }?; Ok((dxgi_factory, device.unwrap())) } diff --git a/librashader-runtime-d3d12/tests/triangle.rs b/librashader-runtime-d3d12/tests/triangle.rs index a5f83ea..f003026 100644 --- a/librashader-runtime-d3d12/tests/triangle.rs +++ b/librashader-runtime-d3d12/tests/triangle.rs @@ -6,7 +6,7 @@ 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-royale.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",