rt(d3d12): stop leaking transition barriers

This commit is contained in:
chyyran 2024-08-25 23:54:36 -04:00 committed by Ronny Chan
parent 2e7c3b3273
commit e934f175ef
6 changed files with 87 additions and 85 deletions

View file

@ -43,7 +43,9 @@ use windows::Win32::Graphics::Direct3D12::{
ID3D12CommandAllocator, ID3D12CommandQueue, ID3D12DescriptorHeap, ID3D12Device, ID3D12Fence, ID3D12CommandAllocator, ID3D12CommandQueue, ID3D12DescriptorHeap, ID3D12Device, ID3D12Fence,
ID3D12GraphicsCommandList, ID3D12Resource, D3D12_COMMAND_LIST_TYPE_DIRECT, ID3D12GraphicsCommandList, ID3D12Resource, D3D12_COMMAND_LIST_TYPE_DIRECT,
D3D12_COMMAND_QUEUE_DESC, D3D12_COMMAND_QUEUE_FLAG_NONE, D3D12_FENCE_FLAG_NONE, D3D12_COMMAND_QUEUE_DESC, D3D12_COMMAND_QUEUE_FLAG_NONE, D3D12_FENCE_FLAG_NONE,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_BARRIER, D3D12_RESOURCE_BARRIER_TYPE_TRANSITION,
D3D12_RESOURCE_BARRIER_TYPE_UAV, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
D3D12_RESOURCE_STATE_RENDER_TARGET,
}; };
use windows::Win32::Graphics::Dxgi::Common::DXGI_FORMAT_UNKNOWN; use windows::Win32::Graphics::Dxgi::Common::DXGI_FORMAT_UNKNOWN;
use windows::Win32::System::Threading::{CreateEventA, WaitForSingleObject, INFINITE}; use windows::Win32::System::Threading::{CreateEventA, WaitForSingleObject, INFINITE};
@ -104,6 +106,7 @@ pub(crate) struct FrameResiduals {
mipmaps: Vec<D3D12DescriptorHeapSlot<ResourceWorkHeap>>, mipmaps: Vec<D3D12DescriptorHeapSlot<ResourceWorkHeap>>,
mipmap_luts: Vec<D3D12MipmapGen>, mipmap_luts: Vec<D3D12MipmapGen>,
resources: Vec<ManuallyDrop<Option<ID3D12Resource>>>, resources: Vec<ManuallyDrop<Option<ID3D12Resource>>>,
resource_barriers: Vec<D3D12_RESOURCE_BARRIER>,
} }
impl FrameResiduals { impl FrameResiduals {
@ -113,6 +116,7 @@ impl FrameResiduals {
mipmaps: Vec::new(), mipmaps: Vec::new(),
mipmap_luts: Vec::new(), mipmap_luts: Vec::new(),
resources: Vec::new(), resources: Vec::new(),
resource_barriers: Vec::new(),
} }
} }
@ -135,12 +139,30 @@ impl FrameResiduals {
self.resources.push(resource) self.resources.push(resource)
} }
/// Disposition only handles transition barriers, but it is not unsafe because
/// other things just leak and leakign is not unsafe,
pub fn dispose_barriers(&mut self, barrier: impl IntoIterator<Item = D3D12_RESOURCE_BARRIER>) {
self.resource_barriers.extend(barrier);
}
pub fn dispose(&mut self) { pub fn dispose(&mut self) {
self.outputs.clear(); self.outputs.clear();
self.mipmaps.clear(); self.mipmaps.clear();
for resource in self.resources.drain(..) { for resource in self.resources.drain(..) {
drop(ManuallyDrop::into_inner(resource)) drop(ManuallyDrop::into_inner(resource))
} }
for barrier in self.resource_barriers.drain(..) {
if barrier.Type == D3D12_RESOURCE_BARRIER_TYPE_TRANSITION {
if let Some(resource) = unsafe { barrier.Anonymous.Transition }.pResource.take() {
drop(resource)
}
} else if barrier.Type == D3D12_RESOURCE_BARRIER_TYPE_UAV {
if let Some(resource) = unsafe { barrier.Anonymous.UAV }.pResource.take() {
drop(resource)
}
}
// other barrier types should be handled manually
}
} }
} }
@ -430,10 +452,7 @@ impl FilterChainD3D12 {
gc.dispose_mipmap_handles(residual_mipmap); gc.dispose_mipmap_handles(residual_mipmap);
gc.dispose_mipmap_gen(mipmap_gen); gc.dispose_mipmap_gen(mipmap_gen);
gc.dispose_barriers(residual_barrier);
for barrier in residual_barrier {
gc.dispose_resource(barrier.pResource)
}
Ok(luts) Ok(luts)
} }
@ -640,7 +659,7 @@ impl FilterChainD3D12 {
if let Some(options) = options { if let Some(options) = options {
if options.clear_history { if options.clear_history {
for framebuffer in &mut self.history_framebuffers { for framebuffer in &mut self.history_framebuffers {
framebuffer.clear(cmd, &mut self.rtv_heap)?; framebuffer.clear(cmd, &mut self.rtv_heap, &mut self.residuals)?;
} }
} }
} }
@ -752,12 +771,13 @@ impl FilterChainD3D12 {
)?; )?;
} }
util::d3d12_resource_transition( self.residuals
cmd, .dispose_barriers(util::d3d12_resource_transition(
&target.handle.resource(), cmd,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, &target.handle.resource(),
D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
); D3D12_RESOURCE_STATE_RENDER_TARGET,
));
let view = target.create_render_target_view(&mut self.rtv_heap)?; let view = target.create_render_target_view(&mut self.rtv_heap)?;
let out = RenderTarget::identity(&view); let out = RenderTarget::identity(&view);
@ -775,15 +795,16 @@ impl FilterChainD3D12 {
QuadType::Offscreen, QuadType::Offscreen,
)?; )?;
util::d3d12_resource_transition( self.residuals
cmd, .dispose_barriers(util::d3d12_resource_transition(
&target.handle.resource(), cmd,
D3D12_RESOURCE_STATE_RENDER_TARGET, &target.handle.resource(),
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET,
); D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
));
if target.max_mipmap > 1 && !self.disable_mipmaps { if target.max_mipmap > 1 && !self.disable_mipmaps {
let (residuals, residual_uav) = self.common.mipmap_gen.mipmapping_context( let (residuals, residual_barriers) = self.common.mipmap_gen.mipmapping_context(
cmd, cmd,
&mut self.mipmap_heap, &mut self.mipmap_heap,
|ctx| { |ctx| {
@ -798,9 +819,7 @@ impl FilterChainD3D12 {
)?; )?;
self.residuals.dispose_mipmap_handles(residuals); self.residuals.dispose_mipmap_handles(residuals);
for uav in residual_uav { self.residuals.dispose_barriers(residual_barriers);
self.residuals.dispose_resource(uav.pResource)
}
} }
self.residuals.dispose_output(view.descriptor); self.residuals.dispose_output(view.descriptor);

View file

@ -180,6 +180,7 @@ impl OwnedImage {
unsafe { unsafe {
cmd.ResourceBarrier(&barriers); cmd.ResourceBarrier(&barriers);
gc.dispose_barriers(barriers);
let dst = D3D12_TEXTURE_COPY_LOCATION { let dst = D3D12_TEXTURE_COPY_LOCATION {
pResource: ManuallyDrop::new(Some(self.handle.resource().clone())), pResource: ManuallyDrop::new(Some(self.handle.resource().clone())),
@ -236,6 +237,8 @@ impl OwnedImage {
cmd.ResourceBarrier(&barriers); cmd.ResourceBarrier(&barriers);
} }
gc.dispose_barriers(barriers);
Ok(()) Ok(())
} }
@ -243,24 +246,25 @@ impl OwnedImage {
&self, &self,
cmd: &ID3D12GraphicsCommandList, cmd: &ID3D12GraphicsCommandList,
heap: &mut D3D12DescriptorHeap<RenderTargetHeap>, heap: &mut D3D12DescriptorHeap<RenderTargetHeap>,
gc: &mut FrameResiduals,
) -> error::Result<()> { ) -> error::Result<()> {
util::d3d12_resource_transition( gc.dispose_barriers(util::d3d12_resource_transition(
cmd, cmd,
&self.handle.resource(), &self.handle.resource(),
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_RENDER_TARGET,
); ));
let rtv = self.create_render_target_view(heap)?; let rtv = self.create_render_target_view(heap)?;
unsafe { cmd.ClearRenderTargetView(*rtv.descriptor.as_ref(), CLEAR, None) } unsafe { cmd.ClearRenderTargetView(*rtv.descriptor.as_ref(), CLEAR, None) }
util::d3d12_resource_transition( gc.dispose_barriers(util::d3d12_resource_transition(
cmd, cmd,
&self.handle.resource(), &self.handle.resource(),
D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_RENDER_TARGET,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
); ));
Ok(()) Ok(())
} }

View file

@ -157,39 +157,18 @@ impl LutTexture {
resource_type: &ResourceType::Placed, resource_type: &ResourceType::Placed,
})?; })?;
//
// let mut upload: Option<ID3D12Resource> = 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 { let subresource = [D3D12_SUBRESOURCE_DATA {
pData: source.bytes.as_ptr().cast(), pData: source.bytes.as_ptr().cast(),
RowPitch: 4 * source.size.width as isize, RowPitch: 4 * source.size.width as isize,
SlicePitch: (4 * source.size.width * source.size.height) as isize, SlicePitch: (4 * source.size.width * source.size.height) as isize,
}]; }];
d3d12_resource_transition( gc.dispose_barriers(d3d12_resource_transition(
cmd, cmd,
&resource.resource(), &resource.resource(),
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_COPY_DEST,
); ));
d3d12_update_subresources( d3d12_update_subresources(
cmd, cmd,
@ -202,12 +181,12 @@ impl LutTexture {
gc, gc,
)?; )?;
d3d12_resource_transition( gc.dispose_barriers(d3d12_resource_transition(
cmd, cmd,
&resource.resource(), &resource.resource(),
D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_COPY_DEST,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
); ));
let view = InputTexture::new( let view = InputTexture::new(
resource.resource().clone(), resource.resource().clone(),

View file

@ -42,7 +42,7 @@ pub struct MipmapGenContext<'a> {
cmd: &'a ID3D12GraphicsCommandList, cmd: &'a ID3D12GraphicsCommandList,
heap: &'a mut D3D12DescriptorHeap<ResourceWorkHeap>, heap: &'a mut D3D12DescriptorHeap<ResourceWorkHeap>,
residuals: Vec<D3D12DescriptorHeapSlot<ResourceWorkHeap>>, residuals: Vec<D3D12DescriptorHeapSlot<ResourceWorkHeap>>,
residual_uav_descs: Vec<D3D12_RESOURCE_UAV_BARRIER>, residual_barriers: Vec<D3D12_RESOURCE_BARRIER>,
} }
impl<'a> MipmapGenContext<'a> { impl<'a> MipmapGenContext<'a> {
@ -56,7 +56,7 @@ impl<'a> MipmapGenContext<'a> {
cmd, cmd,
heap, heap,
residuals: Vec::new(), residuals: Vec::new(),
residual_uav_descs: Vec::new(), residual_barriers: Vec::new(),
} }
} }
@ -74,7 +74,7 @@ impl<'a> MipmapGenContext<'a> {
.gen .gen
.generate_mipmaps(self.cmd, resource, miplevels, size, format, self.heap)?; .generate_mipmaps(self.cmd, resource, miplevels, size, format, self.heap)?;
self.residuals.extend(residuals_heap); self.residuals.extend(residuals_heap);
self.residual_uav_descs.extend(residual_barriers); self.residual_barriers.extend(residual_barriers);
} }
Ok(()) Ok(())
@ -84,9 +84,9 @@ impl<'a> MipmapGenContext<'a> {
self, self,
) -> ( ) -> (
Vec<D3D12DescriptorHeapSlot<ResourceWorkHeap>>, Vec<D3D12DescriptorHeapSlot<ResourceWorkHeap>>,
Vec<D3D12_RESOURCE_UAV_BARRIER>, Vec<D3D12_RESOURCE_BARRIER>,
) { ) {
(self.residuals, self.residual_uav_descs) (self.residuals, self.residual_barriers)
} }
} }
@ -153,7 +153,7 @@ impl D3D12MipmapGen {
) -> Result< ) -> Result<
( (
Vec<D3D12DescriptorHeapSlot<ResourceWorkHeap>>, Vec<D3D12DescriptorHeapSlot<ResourceWorkHeap>>,
Vec<D3D12_RESOURCE_UAV_BARRIER>, Vec<D3D12_RESOURCE_BARRIER>,
), ),
E, E,
> >
@ -188,7 +188,7 @@ impl D3D12MipmapGen {
work_heap: &mut D3D12DescriptorHeap<ResourceWorkHeap>, work_heap: &mut D3D12DescriptorHeap<ResourceWorkHeap>,
) -> error::Result<( ) -> error::Result<(
Vec<D3D12DescriptorHeapSlot<ResourceWorkHeap>>, Vec<D3D12DescriptorHeapSlot<ResourceWorkHeap>>,
Vec<D3D12_RESOURCE_UAV_BARRIER>, Vec<D3D12_RESOURCE_BARRIER>,
)> { )> {
// create views for mipmap generation // create views for mipmap generation
let srv = work_heap.alloc_slot()?; let srv = work_heap.alloc_slot()?;
@ -240,7 +240,7 @@ impl D3D12MipmapGen {
cmd.SetComputeRootDescriptorTable(0, *heap_slots[0].deref().as_ref()); cmd.SetComputeRootDescriptorTable(0, *heap_slots[0].deref().as_ref());
} }
let mut residual_uavs = Vec::new(); let mut residual_barriers = Vec::new();
for i in 1..miplevels as u32 { for i in 1..miplevels as u32 {
let scaled = size.scale_mipmap(i); let scaled = size.scale_mipmap(i);
let mipmap_params = MipConstants { let mipmap_params = MipConstants {
@ -267,6 +267,7 @@ impl D3D12MipmapGen {
unsafe { unsafe {
cmd.ResourceBarrier(&barriers); cmd.ResourceBarrier(&barriers);
residual_barriers.extend(barriers);
cmd.SetComputeRootDescriptorTable(1, *heap_slots[i as usize].deref().as_ref()); cmd.SetComputeRootDescriptorTable(1, *heap_slots[i as usize].deref().as_ref());
cmd.SetComputeRoot32BitConstants( cmd.SetComputeRoot32BitConstants(
@ -311,14 +312,9 @@ impl D3D12MipmapGen {
cmd.ResourceBarrier(&barriers); cmd.ResourceBarrier(&barriers);
} }
let uav = unsafe { residual_barriers.extend(barriers)
let [barrier, ..] = barriers;
barrier.Anonymous.UAV
};
residual_uavs.push(ManuallyDrop::into_inner(uav))
} }
Ok((heap_slots, residual_uavs)) Ok((heap_slots, residual_barriers))
} }
} }

View file

@ -180,22 +180,7 @@ pub fn dxc_validate_shader(
} }
} }
#[inline(always)] #[must_use = "Resource Barrier must be disposed"]
pub fn d3d12_resource_transition(
cmd: &ID3D12GraphicsCommandList,
resource: &ID3D12Resource,
before: D3D12_RESOURCE_STATES,
after: D3D12_RESOURCE_STATES,
) {
d3d12_resource_transition_subresource(
cmd,
resource,
before,
after,
D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
);
}
pub fn d3d12_get_resource_transition_subresource( pub fn d3d12_get_resource_transition_subresource(
resource: &ID3D12Resource, resource: &ID3D12Resource,
before: D3D12_RESOURCE_STATES, before: D3D12_RESOURCE_STATES,
@ -216,6 +201,24 @@ pub fn d3d12_get_resource_transition_subresource(
} }
} }
#[must_use = "Resource Barrier must be disposed"]
#[inline(always)]
pub fn d3d12_resource_transition(
cmd: &ID3D12GraphicsCommandList,
resource: &ID3D12Resource,
before: D3D12_RESOURCE_STATES,
after: D3D12_RESOURCE_STATES,
) -> [D3D12_RESOURCE_BARRIER; 1] {
d3d12_resource_transition_subresource(
cmd,
resource,
before,
after,
D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
)
}
#[must_use = "Resource Barrier must be disposed"]
#[inline(always)] #[inline(always)]
pub fn d3d12_resource_transition_subresource( pub fn d3d12_resource_transition_subresource(
cmd: &ID3D12GraphicsCommandList, cmd: &ID3D12GraphicsCommandList,
@ -223,7 +226,7 @@ pub fn d3d12_resource_transition_subresource(
before: D3D12_RESOURCE_STATES, before: D3D12_RESOURCE_STATES,
after: D3D12_RESOURCE_STATES, after: D3D12_RESOURCE_STATES,
subresource: u32, subresource: u32,
) { ) -> [D3D12_RESOURCE_BARRIER; 1] {
let barrier = [d3d12_get_resource_transition_subresource( let barrier = [d3d12_get_resource_transition_subresource(
resource, resource,
before, before,
@ -231,6 +234,7 @@ pub fn d3d12_resource_transition_subresource(
subresource, subresource,
)]; )];
unsafe { cmd.ResourceBarrier(&barrier) } unsafe { cmd.ResourceBarrier(&barrier) }
barrier
} }
pub(crate) fn d3d12_update_subresources( pub(crate) fn d3d12_update_subresources(

View file

@ -5,12 +5,12 @@ use crate::hello_triangle::{DXSample, SampleCommandLine};
#[test] #[test]
fn triangle_d3d12() { fn triangle_d3d12() {
let sample = hello_triangle::d3d12_hello_triangle::Sample::new( let sample = hello_triangle::d3d12_hello_triangle::Sample::new(
// "../test/shaders_slang/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp", "../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/basic.slangp",
// "../test/shaders_slang/handheld/console-border/gbc-lcd-grid-v2.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/Mega_Bezel_Packs/Duimon-Mega-Bezel/Presets/Advanced/Nintendo_GBA_SP/GBA_SP-[ADV]-[LCD-GRID]-[Night].slangp",
"../test/shaders_slang/test/feedback.slangp", // "../test/shaders_slang/test/feedback.slangp",
// "../test/shaders_slang/test/history.slangp", // "../test/shaders_slang/test/history.slangp",
// "../test/shaders_slang/crt/crt-royale.slangp", // "../test/shaders_slang/crt/crt-royale.slangp",
// "../test/slang-shaders/vhs/VHSPro.slangp", // "../test/slang-shaders/vhs/VHSPro.slangp",