From 0cb3880d7f0100f49ed2689f12999e94ed0782de Mon Sep 17 00:00:00 2001 From: chyyran Date: Mon, 30 Sep 2024 01:42:16 -0400 Subject: [PATCH] rt(d3d12): allow construction of D3D12InputImage without a descriptor handle --- .../src/runtime/d3d12/filter_chain.rs | 4 +- librashader-cli/src/render/d3d12/mod.rs | 5 +- librashader-runtime-d3d12/src/filter_chain.rs | 19 +++- librashader-runtime-d3d12/src/framebuffer.rs | 14 +-- librashader-runtime-d3d12/src/luts.rs | 2 +- librashader-runtime-d3d12/src/texture.rs | 86 ++++++++++++------- 6 files changed, 85 insertions(+), 45 deletions(-) diff --git a/librashader-capi/src/runtime/d3d12/filter_chain.rs b/librashader-capi/src/runtime/d3d12/filter_chain.rs index 01251f4..525f929 100644 --- a/librashader-capi/src/runtime/d3d12/filter_chain.rs +++ b/librashader-capi/src/runtime/d3d12/filter_chain.rs @@ -283,9 +283,9 @@ extern_fn! { } }; - let image = D3D12InputImage { + let image = D3D12InputImage::External { resource: image.resource.to_ref(), - descriptor: Some(image.descriptor), + descriptor: image.descriptor, }; unsafe { chain.frame(&command_list, image, &viewport, frame_count, options.as_ref())?; diff --git a/librashader-cli/src/render/d3d12/mod.rs b/librashader-cli/src/render/d3d12/mod.rs index 15712a5..bf6f8c1 100644 --- a/librashader-cli/src/render/d3d12/mod.rs +++ b/librashader-cli/src/render/d3d12/mod.rs @@ -154,10 +154,7 @@ impl RenderTest for Direct3D12 { for frame in 0..=frame_count { filter_chain.frame( &cmd, - D3D12InputImage { - resource: self.texture.to_ref(), - descriptor: None, - }, + D3D12InputImage::Managed(self.texture.to_ref()), &viewport, frame, options.as_ref(), diff --git a/librashader-runtime-d3d12/src/filter_chain.rs b/librashader-runtime-d3d12/src/filter_chain.rs index d39ce1b..8aea2fa 100644 --- a/librashader-runtime-d3d12/src/filter_chain.rs +++ b/librashader-runtime-d3d12/src/filter_chain.rs @@ -67,7 +67,7 @@ pub struct FilterChainD3D12 { pub(crate) output_framebuffers: Box<[OwnedImage]>, pub(crate) feedback_framebuffers: Box<[OwnedImage]>, pub(crate) history_framebuffers: VecDeque, - staging_heap: D3D12DescriptorHeap, + pub(crate) staging_heap: D3D12DescriptorHeap, pub(crate) rtv_heap: D3D12DescriptorHeap, work_heap: ID3D12DescriptorHeap, @@ -735,7 +735,22 @@ impl FilterChainD3D12 { Some(fbo.create_shader_resource_view(&mut self.staging_heap, filter, wrap_mode)?); } - let original = unsafe { InputTexture::new_from_raw(input, filter, wrap_mode, &self.common.d3d12, &mut self.staging_heap)? }; + let original = unsafe { + match input { + D3D12InputImage::Managed(input) => InputTexture::new_from_resource( + input, + filter, + wrap_mode, + &self.common.d3d12, + &mut self.staging_heap, + )?, + D3D12InputImage::External { + resource, + descriptor, + } => InputTexture::new_from_raw(resource, descriptor, filter, wrap_mode), + } + }; + let mut source = original.clone(); // swap output and feedback **before** recording command buffers diff --git a/librashader-runtime-d3d12/src/framebuffer.rs b/librashader-runtime-d3d12/src/framebuffer.rs index 70fc50f..110fc31 100644 --- a/librashader-runtime-d3d12/src/framebuffer.rs +++ b/librashader-runtime-d3d12/src/framebuffer.rs @@ -27,10 +27,10 @@ use windows::Win32::Graphics::Direct3D12::{ D3D12_RESOURCE_DIMENSION_TEXTURE2D, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, - D3D12_RESOURCE_STATE_RENDER_TARGET, - D3D12_SHADER_RESOURCE_VIEW_DESC, D3D12_SHADER_RESOURCE_VIEW_DESC_0, - D3D12_SRV_DIMENSION_TEXTURE2D, D3D12_TEX2D_SRV, D3D12_TEXTURE_COPY_LOCATION, - D3D12_TEXTURE_COPY_LOCATION_0, D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX, + D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_SHADER_RESOURCE_VIEW_DESC, + D3D12_SHADER_RESOURCE_VIEW_DESC_0, D3D12_SRV_DIMENSION_TEXTURE2D, D3D12_TEX2D_SRV, + D3D12_TEXTURE_COPY_LOCATION, D3D12_TEXTURE_COPY_LOCATION_0, + D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX, }; use windows::Win32::Graphics::Dxgi::Common::{DXGI_FORMAT, DXGI_SAMPLE_DESC}; @@ -295,7 +295,7 @@ impl OwnedImage { ); } - Ok(InputTexture::new( + Ok(InputTexture::new_owned( &self.resource, descriptor, self.size, @@ -309,7 +309,9 @@ impl OwnedImage { &self, heap: &mut D3D12DescriptorHeap, ) -> error::Result { - D3D12OutputView::new_from_resource_internal(self.resource.to_ref(), &self.device, heap) + unsafe { + D3D12OutputView::new_from_resource_internal(self.resource.to_ref(), &self.device, heap) + } } pub fn scale( diff --git a/librashader-runtime-d3d12/src/luts.rs b/librashader-runtime-d3d12/src/luts.rs index 4b24d6e..8e74330 100644 --- a/librashader-runtime-d3d12/src/luts.rs +++ b/librashader-runtime-d3d12/src/luts.rs @@ -201,7 +201,7 @@ impl LutTexture { D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, ); - let view = InputTexture::new( + let view = InputTexture::new_owned( &resource, descriptor, source.size, diff --git a/librashader-runtime-d3d12/src/texture.rs b/librashader-runtime-d3d12/src/texture.rs index 1813151..c766b1c 100644 --- a/librashader-runtime-d3d12/src/texture.rs +++ b/librashader-runtime-d3d12/src/texture.rs @@ -1,14 +1,21 @@ use crate::descriptor_heap::{CpuStagingHeap, RenderTargetHeap}; -use crate::{error, FilterChainD3D12}; +use crate::error::FilterChainError; use crate::resource::{OutlivesFrame, ResourceHandleStrategy}; +use crate::{error, FilterChainD3D12}; use d3d12_descriptor_heap::{D3D12DescriptorHeap, D3D12DescriptorHeapSlot}; use librashader_common::{FilterMode, GetSize, Size, WrapMode}; use std::mem::ManuallyDrop; use std::ops::Deref; use windows::core::InterfaceRef; -use windows::Win32::Graphics::Direct3D12::{ID3D12Device, ID3D12Resource, D3D12_CPU_DESCRIPTOR_HANDLE, D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING, D3D12_RENDER_TARGET_VIEW_DESC, D3D12_RENDER_TARGET_VIEW_DESC_0, D3D12_RESOURCE_DIMENSION_TEXTURE2D, D3D12_RTV_DIMENSION_TEXTURE2D, D3D12_SHADER_RESOURCE_VIEW_DESC, D3D12_SHADER_RESOURCE_VIEW_DESC_0, D3D12_SRV_DIMENSION_TEXTURE2D, D3D12_TEX2D_RTV, D3D12_TEX2D_SRV}; +use windows::Win32::Graphics::Direct3D12::{ + ID3D12Device, ID3D12Resource, D3D12_CPU_DESCRIPTOR_HANDLE, + D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING, D3D12_RENDER_TARGET_VIEW_DESC, + D3D12_RENDER_TARGET_VIEW_DESC_0, D3D12_RESOURCE_DIMENSION_TEXTURE2D, + D3D12_RTV_DIMENSION_TEXTURE2D, D3D12_SHADER_RESOURCE_VIEW_DESC, + D3D12_SHADER_RESOURCE_VIEW_DESC_0, D3D12_SRV_DIMENSION_TEXTURE2D, D3D12_TEX2D_RTV, + D3D12_TEX2D_SRV, +}; use windows::Win32::Graphics::Dxgi::Common::DXGI_FORMAT; -use crate::error::FilterChainError; /// A **non-owning** reference to a ID3D12Resource. /// This does not `AddRef` or `Release` the underlying interface. @@ -16,18 +23,16 @@ pub type D3D12ResourceRef<'a> = InterfaceRef<'a, ID3D12Resource>; /// An image for use as shader resource view. #[derive(Clone)] -pub struct D3D12InputImage<'a> { - pub resource: InterfaceRef<'a, ID3D12Resource>, - pub descriptor: Option, -} - -impl<'a> From> for D3D12InputImage<'a> { - fn from(value: InterfaceRef<'a, ID3D12Resource>) -> Self { - Self { - resource: value, - descriptor: None - } - } +pub enum D3D12InputImage<'a> { + /// The filter chain manages the CPU descriptor to the shader resource view. + Managed(InterfaceRef<'a, ID3D12Resource>), + /// The CPU descriptor to the shader resource view is managed externally. + External { + /// The ID3D12Resource that holds the image data. + resource: InterfaceRef<'a, ID3D12Resource>, + /// The CPU descriptor to the shader resource view. + descriptor: D3D12_CPU_DESCRIPTOR_HANDLE, + }, } #[derive(Clone)] @@ -85,6 +90,9 @@ impl D3D12OutputView { } // unsafe since the lifetime of the handle has to survive + /// Create a new D3D12OutputView from a CPU descriptor handle of a render target view. + /// + /// SAFETY: the handle must be valid until the command list is submitted. pub unsafe fn new_from_raw( handle: D3D12_CPU_DESCRIPTOR_HANDLE, size: Size, @@ -101,15 +109,17 @@ impl D3D12OutputView { /// Create a new output view from a resource ref, linked to the chain. /// /// The output view will be automatically disposed on drop. - pub fn new_from_resource( + /// + /// SAFETY: the image must be valid until the command list is submitted. + pub unsafe fn new_from_resource( image: D3D12ResourceRef, - chain: &mut FilterChainD3D12 + chain: &mut FilterChainD3D12, ) -> error::Result { - Self::new_from_resource_internal(image, &chain.common.d3d12, &mut chain.rtv_heap) + unsafe { Self::new_from_resource_internal(image, &chain.common.d3d12, &mut chain.rtv_heap) } } /// Create a new output view from a resource ref - pub(crate) fn new_from_resource_internal( + pub(crate) unsafe fn new_from_resource_internal( image: D3D12ResourceRef, device: &ID3D12Device, heap: &mut D3D12DescriptorHeap, @@ -145,7 +155,7 @@ impl D3D12OutputView { } } -pub struct InputTexture { +pub(crate) struct InputTexture { pub(crate) resource: ManuallyDrop, pub(crate) descriptor: InputDescriptor, pub(crate) size: Size, @@ -157,7 +167,7 @@ pub struct InputTexture { impl InputTexture { // Create a new input texture, with runtime lifetime tracking. // The source owned framebuffer must outlive this input. - pub fn new( + pub fn new_owned( resource: &ManuallyDrop, handle: D3D12DescriptorHeapSlot, size: Size, @@ -168,7 +178,7 @@ impl InputTexture { let srv = InputDescriptor::Owned(handle); InputTexture { // SAFETY: `new` is only used for owned textures. We know this because - // we also hold `handle`, so the texture is at least + // we also hold `handle`, so the texture must be valid for at least // as valid for the lifetime of handle. // Also, resource is non-null by construction. // Option and have the same layout. @@ -182,19 +192,19 @@ impl InputTexture { } // unsafe since the lifetime of the handle has to survive - pub unsafe fn new_from_raw( - image: D3D12InputImage, + pub unsafe fn new_from_resource<'a>( + image: InterfaceRef<'a, ID3D12Resource>, filter: FilterMode, wrap_mode: WrapMode, device: &ID3D12Device, heap: &mut D3D12DescriptorHeap, ) -> error::Result { - let desc = unsafe { image.resource.GetDesc() }; + let desc = unsafe { image.GetDesc() }; if desc.Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE2D { return Err(FilterChainError::InvalidDimensionError(desc.Dimension)); } - let descriptor = image.descriptor.map_or_else(|| { + let descriptor = { let slot = heap.allocate_descriptor()?; unsafe { let srv_desc = D3D12_SHADER_RESOURCE_VIEW_DESC { @@ -208,14 +218,14 @@ impl InputTexture { }, }, }; - device.CreateShaderResourceView(image.resource.deref(), Some(&srv_desc), *slot.as_ref()); + device.CreateShaderResourceView(image.deref(), Some(&srv_desc), *slot.as_ref()); } Ok::<_, FilterChainError>(InputDescriptor::Owned(slot)) - }, |raw| Ok(InputDescriptor::Raw(raw)))?; + }?; Ok(InputTexture { - resource: unsafe { std::mem::transmute(image.resource) }, + resource: unsafe { std::mem::transmute(image) }, descriptor, size: Size::new(desc.Width as u32, desc.Height), format: desc.Format, @@ -224,7 +234,23 @@ impl InputTexture { }) } - + // unsafe since the lifetime of the handle has to survive + pub unsafe fn new_from_raw( + image: InterfaceRef, + descriptor: D3D12_CPU_DESCRIPTOR_HANDLE, + filter: FilterMode, + wrap_mode: WrapMode, + ) -> InputTexture { + let desc = unsafe { image.GetDesc() }; + InputTexture { + resource: unsafe { std::mem::transmute(image) }, + descriptor: InputDescriptor::Raw(descriptor), + size: Size::new(desc.Width as u32, desc.Height), + format: desc.Format, + wrap_mode, + filter, + } + } } impl Clone for InputTexture {