rt(d3d12): allow construction of D3D12InputImage without a descriptor handle

This commit is contained in:
chyyran 2024-09-30 01:42:16 -04:00 committed by Ronny Chan
parent c526b7043a
commit 0cb3880d7f
6 changed files with 85 additions and 45 deletions

View file

@ -283,9 +283,9 @@ extern_fn! {
} }
}; };
let image = D3D12InputImage { let image = D3D12InputImage::External {
resource: image.resource.to_ref(), resource: image.resource.to_ref(),
descriptor: Some(image.descriptor), descriptor: image.descriptor,
}; };
unsafe { unsafe {
chain.frame(&command_list, image, &viewport, frame_count, options.as_ref())?; chain.frame(&command_list, image, &viewport, frame_count, options.as_ref())?;

View file

@ -154,10 +154,7 @@ impl RenderTest for Direct3D12 {
for frame in 0..=frame_count { for frame in 0..=frame_count {
filter_chain.frame( filter_chain.frame(
&cmd, &cmd,
D3D12InputImage { D3D12InputImage::Managed(self.texture.to_ref()),
resource: self.texture.to_ref(),
descriptor: None,
},
&viewport, &viewport,
frame, frame,
options.as_ref(), options.as_ref(),

View file

@ -67,7 +67,7 @@ pub struct FilterChainD3D12 {
pub(crate) output_framebuffers: Box<[OwnedImage]>, pub(crate) output_framebuffers: Box<[OwnedImage]>,
pub(crate) feedback_framebuffers: Box<[OwnedImage]>, pub(crate) feedback_framebuffers: Box<[OwnedImage]>,
pub(crate) history_framebuffers: VecDeque<OwnedImage>, pub(crate) history_framebuffers: VecDeque<OwnedImage>,
staging_heap: D3D12DescriptorHeap<CpuStagingHeap>, pub(crate) staging_heap: D3D12DescriptorHeap<CpuStagingHeap>,
pub(crate) rtv_heap: D3D12DescriptorHeap<RenderTargetHeap>, pub(crate) rtv_heap: D3D12DescriptorHeap<RenderTargetHeap>,
work_heap: ID3D12DescriptorHeap, work_heap: ID3D12DescriptorHeap,
@ -735,7 +735,22 @@ impl FilterChainD3D12 {
Some(fbo.create_shader_resource_view(&mut self.staging_heap, filter, wrap_mode)?); 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(); let mut source = original.clone();
// swap output and feedback **before** recording command buffers // swap output and feedback **before** recording command buffers

View file

@ -27,10 +27,10 @@ use windows::Win32::Graphics::Direct3D12::{
D3D12_RESOURCE_DIMENSION_TEXTURE2D, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET, D3D12_RESOURCE_DIMENSION_TEXTURE2D, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET,
D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_DEST, 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_COPY_SOURCE, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_SHADER_RESOURCE_VIEW_DESC,
D3D12_SHADER_RESOURCE_VIEW_DESC, D3D12_SHADER_RESOURCE_VIEW_DESC_0, D3D12_SHADER_RESOURCE_VIEW_DESC_0, D3D12_SRV_DIMENSION_TEXTURE2D, D3D12_TEX2D_SRV,
D3D12_SRV_DIMENSION_TEXTURE2D, D3D12_TEX2D_SRV, D3D12_TEXTURE_COPY_LOCATION, D3D12_TEXTURE_COPY_LOCATION, D3D12_TEXTURE_COPY_LOCATION_0,
D3D12_TEXTURE_COPY_LOCATION_0, D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX, D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX,
}; };
use windows::Win32::Graphics::Dxgi::Common::{DXGI_FORMAT, DXGI_SAMPLE_DESC}; 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, &self.resource,
descriptor, descriptor,
self.size, self.size,
@ -309,7 +309,9 @@ impl OwnedImage {
&self, &self,
heap: &mut D3D12DescriptorHeap<RenderTargetHeap>, heap: &mut D3D12DescriptorHeap<RenderTargetHeap>,
) -> error::Result<D3D12OutputView> { ) -> error::Result<D3D12OutputView> {
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( pub fn scale(

View file

@ -201,7 +201,7 @@ impl LutTexture {
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
); );
let view = InputTexture::new( let view = InputTexture::new_owned(
&resource, &resource,
descriptor, descriptor,
source.size, source.size,

View file

@ -1,14 +1,21 @@
use crate::descriptor_heap::{CpuStagingHeap, RenderTargetHeap}; use crate::descriptor_heap::{CpuStagingHeap, RenderTargetHeap};
use crate::{error, FilterChainD3D12}; use crate::error::FilterChainError;
use crate::resource::{OutlivesFrame, ResourceHandleStrategy}; use crate::resource::{OutlivesFrame, ResourceHandleStrategy};
use crate::{error, FilterChainD3D12};
use d3d12_descriptor_heap::{D3D12DescriptorHeap, D3D12DescriptorHeapSlot}; use d3d12_descriptor_heap::{D3D12DescriptorHeap, D3D12DescriptorHeapSlot};
use librashader_common::{FilterMode, GetSize, Size, WrapMode}; use librashader_common::{FilterMode, GetSize, Size, WrapMode};
use std::mem::ManuallyDrop; use std::mem::ManuallyDrop;
use std::ops::Deref; use std::ops::Deref;
use windows::core::InterfaceRef; 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 windows::Win32::Graphics::Dxgi::Common::DXGI_FORMAT;
use crate::error::FilterChainError;
/// A **non-owning** reference to a ID3D12Resource. /// A **non-owning** reference to a ID3D12Resource.
/// This does not `AddRef` or `Release` the underlying interface. /// 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. /// An image for use as shader resource view.
#[derive(Clone)] #[derive(Clone)]
pub struct D3D12InputImage<'a> { pub enum D3D12InputImage<'a> {
pub resource: InterfaceRef<'a, ID3D12Resource>, /// The filter chain manages the CPU descriptor to the shader resource view.
pub descriptor: Option<D3D12_CPU_DESCRIPTOR_HANDLE>, Managed(InterfaceRef<'a, ID3D12Resource>),
} /// The CPU descriptor to the shader resource view is managed externally.
External {
impl<'a> From<InterfaceRef<'a, ID3D12Resource>> for D3D12InputImage<'a> { /// The ID3D12Resource that holds the image data.
fn from(value: InterfaceRef<'a, ID3D12Resource>) -> Self { resource: InterfaceRef<'a, ID3D12Resource>,
Self { /// The CPU descriptor to the shader resource view.
resource: value, descriptor: D3D12_CPU_DESCRIPTOR_HANDLE,
descriptor: None },
}
}
} }
#[derive(Clone)] #[derive(Clone)]
@ -85,6 +90,9 @@ impl D3D12OutputView {
} }
// unsafe since the lifetime of the handle has to survive // 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( pub unsafe fn new_from_raw(
handle: D3D12_CPU_DESCRIPTOR_HANDLE, handle: D3D12_CPU_DESCRIPTOR_HANDLE,
size: Size<u32>, size: Size<u32>,
@ -101,15 +109,17 @@ impl D3D12OutputView {
/// Create a new output view from a resource ref, linked to the chain. /// Create a new output view from a resource ref, linked to the chain.
/// ///
/// The output view will be automatically disposed on drop. /// 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, image: D3D12ResourceRef,
chain: &mut FilterChainD3D12 chain: &mut FilterChainD3D12,
) -> error::Result<D3D12OutputView> { ) -> error::Result<D3D12OutputView> {
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 /// 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, image: D3D12ResourceRef,
device: &ID3D12Device, device: &ID3D12Device,
heap: &mut D3D12DescriptorHeap<RenderTargetHeap>, heap: &mut D3D12DescriptorHeap<RenderTargetHeap>,
@ -145,7 +155,7 @@ impl D3D12OutputView {
} }
} }
pub struct InputTexture { pub(crate) struct InputTexture {
pub(crate) resource: ManuallyDrop<ID3D12Resource>, pub(crate) resource: ManuallyDrop<ID3D12Resource>,
pub(crate) descriptor: InputDescriptor, pub(crate) descriptor: InputDescriptor,
pub(crate) size: Size<u32>, pub(crate) size: Size<u32>,
@ -157,7 +167,7 @@ pub struct InputTexture {
impl InputTexture { impl InputTexture {
// Create a new input texture, with runtime lifetime tracking. // Create a new input texture, with runtime lifetime tracking.
// The source owned framebuffer must outlive this input. // The source owned framebuffer must outlive this input.
pub fn new( pub fn new_owned(
resource: &ManuallyDrop<ID3D12Resource>, resource: &ManuallyDrop<ID3D12Resource>,
handle: D3D12DescriptorHeapSlot<CpuStagingHeap>, handle: D3D12DescriptorHeapSlot<CpuStagingHeap>,
size: Size<u32>, size: Size<u32>,
@ -168,7 +178,7 @@ impl InputTexture {
let srv = InputDescriptor::Owned(handle); let srv = InputDescriptor::Owned(handle);
InputTexture { InputTexture {
// SAFETY: `new` is only used for owned textures. We know this because // 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. // as valid for the lifetime of handle.
// Also, resource is non-null by construction. // Also, resource is non-null by construction.
// Option<T> and <T> have the same layout. // Option<T> and <T> have the same layout.
@ -182,19 +192,19 @@ impl InputTexture {
} }
// unsafe since the lifetime of the handle has to survive // unsafe since the lifetime of the handle has to survive
pub unsafe fn new_from_raw( pub unsafe fn new_from_resource<'a>(
image: D3D12InputImage, image: InterfaceRef<'a, ID3D12Resource>,
filter: FilterMode, filter: FilterMode,
wrap_mode: WrapMode, wrap_mode: WrapMode,
device: &ID3D12Device, device: &ID3D12Device,
heap: &mut D3D12DescriptorHeap<CpuStagingHeap>, heap: &mut D3D12DescriptorHeap<CpuStagingHeap>,
) -> error::Result<InputTexture> { ) -> error::Result<InputTexture> {
let desc = unsafe { image.resource.GetDesc() }; let desc = unsafe { image.GetDesc() };
if desc.Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE2D { if desc.Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE2D {
return Err(FilterChainError::InvalidDimensionError(desc.Dimension)); return Err(FilterChainError::InvalidDimensionError(desc.Dimension));
} }
let descriptor = image.descriptor.map_or_else(|| { let descriptor = {
let slot = heap.allocate_descriptor()?; let slot = heap.allocate_descriptor()?;
unsafe { unsafe {
let srv_desc = D3D12_SHADER_RESOURCE_VIEW_DESC { 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)) Ok::<_, FilterChainError>(InputDescriptor::Owned(slot))
}, |raw| Ok(InputDescriptor::Raw(raw)))?; }?;
Ok(InputTexture { Ok(InputTexture {
resource: unsafe { std::mem::transmute(image.resource) }, resource: unsafe { std::mem::transmute(image) },
descriptor, descriptor,
size: Size::new(desc.Width as u32, desc.Height), size: Size::new(desc.Width as u32, desc.Height),
format: desc.Format, 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<ID3D12Resource>,
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 { impl Clone for InputTexture {