Skip to content

Commit

Permalink
rt(d3d12): make images with OwnedFramebuffer provenance use ManuallyDrop
Browse files Browse the repository at this point in the history
  • Loading branch information
chyyran committed Sep 29, 2024
1 parent 7edff0a commit c57e502
Show file tree
Hide file tree
Showing 9 changed files with 233 additions and 138 deletions.
90 changes: 49 additions & 41 deletions librashader-runtime-d3d12/src/filter_chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,13 +131,18 @@ impl FrameResiduals {
self.mipmaps.extend(handles)
}

pub fn dispose_resource(&mut self, resource: ManuallyDrop<Option<ID3D12Resource>>) {
pub unsafe fn dispose_resource(&mut self, resource: ManuallyDrop<Option<ID3D12Resource>>) {
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>) {
/// Disposition only handles transition barriers.
///
/// **Safety:** It is only safe to dispose a barrier created with resource strategy IncrementRef.
///
pub unsafe fn dispose_barriers(
&mut self,
barrier: impl IntoIterator<Item = D3D12_RESOURCE_BARRIER>,
) {
self.resource_barriers.extend(barrier);
}

Expand Down Expand Up @@ -230,6 +235,7 @@ mod compile {
}
}

use crate::resource::OutlivesFrame;
use compile::{compile_passes_dxil, compile_passes_hlsl, DxilShaderPassMeta, HlslShaderPassMeta};
use librashader_runtime::parameters::RuntimeParameters;

Expand Down Expand Up @@ -321,7 +327,8 @@ impl FilterChainD3D12 {
let mut staging_heap = unsafe {
D3D12DescriptorHeap::new(
device,
(MAX_BINDINGS_COUNT as usize) * shader_count
// add one, because technically the input image doesn't need to count
(1 + MAX_BINDINGS_COUNT as usize) * shader_count
+ MIPMAP_RESERVED_WORKHEAP_DESCRIPTORS
+ lut_count,
)
Expand Down Expand Up @@ -391,7 +398,7 @@ impl FilterChainD3D12 {
common: FilterCommon {
d3d12: device.clone(),
samplers,
allocator: allocator,
allocator,
output_textures,
feedback_textures,
luts,
Expand Down Expand Up @@ -460,7 +467,10 @@ impl FilterChainD3D12 {

gc.dispose_mipmap_handles(residual_mipmap);
gc.dispose_mipmap_gen(mipmap_gen);
gc.dispose_barriers(residual_barrier);

unsafe {
gc.dispose_barriers(residual_barrier);
}

Ok(luts)
}
Expand Down Expand Up @@ -653,7 +663,7 @@ impl FilterChainD3D12 {
);
}
unsafe {
back.copy_from(cmd, input, &mut self.residuals)?;
back.copy_from(cmd, input)?;
}
self.history_framebuffers.push_front(back);
}
Expand All @@ -669,6 +679,8 @@ impl FilterChainD3D12 {
/// librashader **will not** create a resource barrier for the final pass. The output image will
/// remain in `D3D12_RESOURCE_STATE_RENDER_TARGET` after all shader passes. The caller must transition
/// the output image to the final resource state.
///
/// The input and output images must stay alive until the command list is submitted and work is complete.
pub unsafe fn frame(
&mut self,
cmd: &ID3D12GraphicsCommandList,
Expand All @@ -689,7 +701,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, &mut self.residuals)?;
framebuffer.clear(cmd, &mut self.rtv_heap)?;
}
}
}
Expand Down Expand Up @@ -787,13 +799,12 @@ impl FilterChainD3D12 {
)?;
}

self.residuals
.dispose_barriers(util::d3d12_resource_transition(
cmd,
&target.handle.resource(),
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
D3D12_RESOURCE_STATE_RENDER_TARGET,
));
util::d3d12_resource_transition::<OutlivesFrame, _>(
cmd,
&target.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)?;
Expand All @@ -811,21 +822,21 @@ impl FilterChainD3D12 {
QuadType::Offscreen,
)?;

self.residuals
.dispose_barriers(util::d3d12_resource_transition(
cmd,
&target.handle.resource(),
D3D12_RESOURCE_STATE_RENDER_TARGET,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
));
util::d3d12_resource_transition::<OutlivesFrame, _>(
cmd,
&target.resource,
D3D12_RESOURCE_STATE_RENDER_TARGET,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
);

if target.max_mipmap > 1 && !self.disable_mipmaps {
let (residuals, residual_barriers) = self.common.mipmap_gen.mipmapping_context(
// barriers don't get disposed because the context is OutlivesFrame
let (residuals, _residual_barriers) = self.common.mipmap_gen.mipmapping_context(
cmd,
&mut self.mipmap_heap,
|ctx| {
ctx.generate_mipmaps(
&target.handle.resource(),
ctx.generate_mipmaps::<OutlivesFrame, _>(
&target.resource,
target.max_mipmap,
target.size,
target.format.into(),
Expand All @@ -835,7 +846,6 @@ impl FilterChainD3D12 {
)?;

self.residuals.dispose_mipmap_handles(residuals);
self.residuals.dispose_barriers(residual_barriers);
}

self.residuals.dispose_output(view.descriptor);
Expand All @@ -862,13 +872,12 @@ impl FilterChainD3D12 {
)?;
}

self.residuals
.dispose_barriers(util::d3d12_resource_transition(
cmd,
&feedback_target.handle.resource(),
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
D3D12_RESOURCE_STATE_RENDER_TARGET,
));
util::d3d12_resource_transition::<OutlivesFrame, _>(
cmd,
&feedback_target.resource,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
D3D12_RESOURCE_STATE_RENDER_TARGET,
);

let view = feedback_target.create_render_target_view(&mut self.rtv_heap)?;
let out = RenderTarget::viewport_with_output(&view, viewport);
Expand All @@ -885,13 +894,12 @@ impl FilterChainD3D12 {
QuadType::Final,
)?;

self.residuals
.dispose_barriers(util::d3d12_resource_transition(
cmd,
&feedback_target.handle.resource(),
D3D12_RESOURCE_STATE_RENDER_TARGET,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
));
util::d3d12_resource_transition::<OutlivesFrame, _>(
cmd,
&feedback_target.resource,
D3D12_RESOURCE_STATE_RENDER_TARGET,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
);
}

if pass.pipeline.format != viewport.output.format {
Expand Down
84 changes: 43 additions & 41 deletions librashader-runtime-d3d12/src/framebuffer.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::descriptor_heap::{CpuStagingHeap, RenderTargetHeap};
use crate::error::FilterChainError;
use crate::filter_chain::FrameResiduals;
use crate::resource::{OutlivesFrame, ResourceHandleStrategy};
use crate::texture::{D3D12OutputView, InputTexture};
use crate::util::d3d12_get_closest_format;
use crate::{error, util};
Expand All @@ -17,12 +17,13 @@ use parking_lot::Mutex;
use std::mem::ManuallyDrop;
use std::sync::Arc;
use windows::Win32::Graphics::Direct3D12::{
ID3D12Device, ID3D12GraphicsCommandList, D3D12_BOX, D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING,
D3D12_FEATURE_DATA_FORMAT_SUPPORT, D3D12_FORMAT_SUPPORT1_MIP,
D3D12_FORMAT_SUPPORT1_RENDER_TARGET, D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE,
D3D12_FORMAT_SUPPORT1_TEXTURE2D, D3D12_FORMAT_SUPPORT2_UAV_TYPED_LOAD,
D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE, D3D12_RENDER_TARGET_VIEW_DESC,
D3D12_RENDER_TARGET_VIEW_DESC_0, D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, D3D12_RESOURCE_DESC,
ID3D12Device, ID3D12GraphicsCommandList, ID3D12Resource, D3D12_BOX,
D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING, D3D12_FEATURE_DATA_FORMAT_SUPPORT,
D3D12_FORMAT_SUPPORT1_MIP, D3D12_FORMAT_SUPPORT1_RENDER_TARGET,
D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE, D3D12_FORMAT_SUPPORT1_TEXTURE2D,
D3D12_FORMAT_SUPPORT2_UAV_TYPED_LOAD, D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE,
D3D12_RENDER_TARGET_VIEW_DESC, D3D12_RENDER_TARGET_VIEW_DESC_0,
D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, D3D12_RESOURCE_DESC,
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,
Expand All @@ -36,6 +37,7 @@ use windows::Win32::Graphics::Dxgi::Common::{DXGI_FORMAT, DXGI_SAMPLE_DESC};
#[derive(Debug)]
pub(crate) struct OwnedImage {
pub(crate) handle: ManuallyDrop<Resource>,
pub(crate) resource: ManuallyDrop<ID3D12Resource>,
pub(crate) size: Size<u32>,
pub(crate) format: DXGI_FORMAT,
pub(crate) max_mipmap: u16,
Expand Down Expand Up @@ -113,7 +115,7 @@ impl OwnedImage {

desc.Format = d3d12_get_closest_format(device, format_support);

let resource = allocator.lock().create_resource(&ResourceCreateDesc {
let allocator_resource = allocator.lock().create_resource(&ResourceCreateDesc {
name: "ownedimage",
memory_location: MemoryLocation::GpuOnly,
resource_category: ResourceCategory::RtvDsvTexture,
Expand Down Expand Up @@ -145,8 +147,10 @@ impl OwnedImage {
// }
// assume_d3d12_init!(resource, "CreateCommittedResource");

let resource = ManuallyDrop::new(allocator_resource.resource().clone());
Ok(OwnedImage {
handle: ManuallyDrop::new(resource),
handle: ManuallyDrop::new(allocator_resource),
resource,
size,
format: desc.Format,
device: device.clone(),
Expand All @@ -161,17 +165,16 @@ impl OwnedImage {
&self,
cmd: &ID3D12GraphicsCommandList,
input: &InputTexture,
gc: &mut FrameResiduals,
) -> error::Result<()> {
let barriers = [
util::d3d12_get_resource_transition_subresource(
util::d3d12_get_resource_transition_subresource::<OutlivesFrame, _>(
&input.resource,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
D3D12_RESOURCE_STATE_COPY_SOURCE,
D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
),
util::d3d12_get_resource_transition_subresource(
&self.handle.resource(),
util::d3d12_get_resource_transition_subresource::<OutlivesFrame, _>(
&self.resource,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
D3D12_RESOURCE_STATE_COPY_DEST,
D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
Expand All @@ -180,18 +183,17 @@ impl OwnedImage {

unsafe {
cmd.ResourceBarrier(&barriers);
gc.dispose_barriers(barriers);

let dst = D3D12_TEXTURE_COPY_LOCATION {
pResource: ManuallyDrop::new(Some(self.handle.resource().clone())),
pResource: OutlivesFrame::obtain(&self.resource),
Type: D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX,
Anonymous: D3D12_TEXTURE_COPY_LOCATION_0 {
SubresourceIndex: 0,
},
};

let src = D3D12_TEXTURE_COPY_LOCATION {
pResource: ManuallyDrop::new(Some(input.resource.clone())),
pResource: OutlivesFrame::obtain(&input.resource),
Type: D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX,
Anonymous: D3D12_TEXTURE_COPY_LOCATION_0 {
SubresourceIndex: 0,
Expand All @@ -213,20 +215,17 @@ impl OwnedImage {
back: 1,
}),
);

gc.dispose_resource(dst.pResource);
gc.dispose_resource(src.pResource);
}

let barriers = [
util::d3d12_get_resource_transition_subresource(
util::d3d12_get_resource_transition_subresource::<OutlivesFrame, _>(
&input.resource,
D3D12_RESOURCE_STATE_COPY_SOURCE,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
),
util::d3d12_get_resource_transition_subresource(
&self.handle.resource(),
util::d3d12_get_resource_transition_subresource::<OutlivesFrame, _>(
&self.resource,
D3D12_RESOURCE_STATE_COPY_DEST,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
Expand All @@ -237,34 +236,33 @@ impl OwnedImage {
cmd.ResourceBarrier(&barriers);
}

gc.dispose_barriers(barriers);

Ok(())
}

pub fn clear(
&self,
cmd: &ID3D12GraphicsCommandList,
heap: &mut D3D12DescriptorHeap<RenderTargetHeap>,
gc: &mut FrameResiduals,
) -> error::Result<()> {
gc.dispose_barriers(util::d3d12_resource_transition(
cmd,
&self.handle.resource(),
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
D3D12_RESOURCE_STATE_RENDER_TARGET,
));
unsafe {
util::d3d12_resource_transition::<OutlivesFrame, _>(
cmd,
&self.resource,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
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) }
cmd.ClearRenderTargetView(*rtv.descriptor.as_ref(), CLEAR, None);

gc.dispose_barriers(util::d3d12_resource_transition(
cmd,
&self.handle.resource(),
D3D12_RESOURCE_STATE_RENDER_TARGET,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
));
util::d3d12_resource_transition::<OutlivesFrame, _>(
cmd,
&self.resource,
D3D12_RESOURCE_STATE_RENDER_TARGET,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
);
}

Ok(())
}
Expand Down Expand Up @@ -297,8 +295,8 @@ impl OwnedImage {
);
}

Ok(InputTexture::new(
self.handle.resource().clone(),
Ok(InputTexture::new::<OutlivesFrame, _>(
&self.resource,
descriptor,
self.size,
self.format,
Expand Down Expand Up @@ -390,6 +388,10 @@ impl ScaleFramebuffer for OwnedImage {

impl Drop for OwnedImage {
fn drop(&mut self) {
// let go of the handle
unsafe {
ManuallyDrop::drop(&mut self.resource);
}
let resource = unsafe { ManuallyDrop::take(&mut self.handle) };
if let Err(e) = self.allocator.lock().free_resource(resource) {
println!("librashader-runtime-d3d12: [warn] failed to deallocate owned image buffer memory {e}")
Expand Down
Loading

0 comments on commit c57e502

Please sign in to comment.