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,
ID3D12GraphicsCommandList, ID3D12Resource, D3D12_COMMAND_LIST_TYPE_DIRECT,
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::System::Threading::{CreateEventA, WaitForSingleObject, INFINITE};
@ -104,6 +106,7 @@ pub(crate) struct FrameResiduals {
mipmaps: Vec<D3D12DescriptorHeapSlot<ResourceWorkHeap>>,
mipmap_luts: Vec<D3D12MipmapGen>,
resources: Vec<ManuallyDrop<Option<ID3D12Resource>>>,
resource_barriers: Vec<D3D12_RESOURCE_BARRIER>,
}
impl FrameResiduals {
@ -113,6 +116,7 @@ impl FrameResiduals {
mipmaps: Vec::new(),
mipmap_luts: Vec::new(),
resources: Vec::new(),
resource_barriers: Vec::new(),
}
}
@ -135,12 +139,30 @@ impl FrameResiduals {
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) {
self.outputs.clear();
self.mipmaps.clear();
for resource in self.resources.drain(..) {
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_gen(mipmap_gen);
for barrier in residual_barrier {
gc.dispose_resource(barrier.pResource)
}
gc.dispose_barriers(residual_barrier);
Ok(luts)
}
@ -640,7 +659,7 @@ impl FilterChainD3D12 {
if let Some(options) = options {
if options.clear_history {
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
.dispose_barriers(util::d3d12_resource_transition(
cmd,
&target.handle.resource(),
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
D3D12_RESOURCE_STATE_RENDER_TARGET,
);
));
let view = target.create_render_target_view(&mut self.rtv_heap)?;
let out = RenderTarget::identity(&view);
@ -775,15 +795,16 @@ impl FilterChainD3D12 {
QuadType::Offscreen,
)?;
util::d3d12_resource_transition(
self.residuals
.dispose_barriers(util::d3d12_resource_transition(
cmd,
&target.handle.resource(),
D3D12_RESOURCE_STATE_RENDER_TARGET,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
);
));
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,
&mut self.mipmap_heap,
|ctx| {
@ -798,9 +819,7 @@ impl FilterChainD3D12 {
)?;
self.residuals.dispose_mipmap_handles(residuals);
for uav in residual_uav {
self.residuals.dispose_resource(uav.pResource)
}
self.residuals.dispose_barriers(residual_barriers);
}
self.residuals.dispose_output(view.descriptor);

View file

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

View file

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

View file

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

View file

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

View file

@ -5,12 +5,12 @@ use crate::hello_triangle::{DXSample, SampleCommandLine};
#[test]
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/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.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/shaders_slang/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",