rt(d3d12): allow manually specifying the strategy to get a manuallydrop for luts

This commit is contained in:
chyyran 2024-09-28 21:05:27 -04:00 committed by Ronny Chan
parent dedde05c83
commit 7edff0ae35
6 changed files with 120 additions and 54 deletions

View file

@ -17,6 +17,7 @@ mod util;
pub mod error;
pub mod options;
mod resource;
use librashader_runtime::impl_filter_chain_parameters;
impl_filter_chain_parameters!(FilterChainD3D12);

View file

@ -1,7 +1,10 @@
use crate::descriptor_heap::CpuStagingHeap;
use crate::error;
use crate::error::assume_d3d12_init;
use crate::filter_chain::FrameResiduals;
use crate::mipmap::MipmapGenContext;
use crate::resource::OutlivesFrame;
use crate::resource::ResourceHandleStrategy;
use crate::texture::InputTexture;
use crate::util::{d3d12_get_closest_format, d3d12_resource_transition};
use d3d12_descriptor_heap::D3D12DescriptorHeap;
@ -15,19 +18,34 @@ use librashader_runtime::image::Image;
use librashader_runtime::scaling::MipmapSize;
use parking_lot::Mutex;
use std::mem::ManuallyDrop;
use std::ops::Deref;
use std::sync::Arc;
use windows::Win32::Graphics::Direct3D12::{ID3D12Device, ID3D12GraphicsCommandList, ID3D12Resource, D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING, D3D12_FEATURE_DATA_FORMAT_SUPPORT, D3D12_FORMAT_SUPPORT1_MIP, D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE, D3D12_FORMAT_SUPPORT1_TEXTURE2D, D3D12_MEMCPY_DEST, D3D12_PLACED_SUBRESOURCE_FOOTPRINT, D3D12_RESOURCE_DESC, D3D12_RESOURCE_DIMENSION_BUFFER, D3D12_RESOURCE_DIMENSION_TEXTURE2D, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_SHADER_RESOURCE_VIEW_DESC, D3D12_SHADER_RESOURCE_VIEW_DESC_0, D3D12_SRV_DIMENSION_TEXTURE2D, D3D12_SUBRESOURCE_DATA, D3D12_TEX2D_SRV, D3D12_TEXTURE_COPY_LOCATION, D3D12_TEXTURE_COPY_LOCATION_0, D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT, D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX, D3D12_TEXTURE_LAYOUT_ROW_MAJOR};
use windows::Win32::Graphics::Dxgi::Common::DXGI_SAMPLE_DESC;
use std::u64;
use crate::error::assume_d3d12_init;
use windows::Win32::Graphics::Direct3D12::{
ID3D12Device, ID3D12GraphicsCommandList, ID3D12Resource,
D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING, D3D12_FEATURE_DATA_FORMAT_SUPPORT,
D3D12_FORMAT_SUPPORT1_MIP, D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE,
D3D12_FORMAT_SUPPORT1_TEXTURE2D, D3D12_MEMCPY_DEST, D3D12_PLACED_SUBRESOURCE_FOOTPRINT,
D3D12_RESOURCE_DESC, D3D12_RESOURCE_DIMENSION_BUFFER, D3D12_RESOURCE_DIMENSION_TEXTURE2D,
D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_DEST,
D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
D3D12_SHADER_RESOURCE_VIEW_DESC, D3D12_SHADER_RESOURCE_VIEW_DESC_0,
D3D12_SRV_DIMENSION_TEXTURE2D, D3D12_SUBRESOURCE_DATA, D3D12_TEX2D_SRV,
D3D12_TEXTURE_COPY_LOCATION, D3D12_TEXTURE_COPY_LOCATION_0,
D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT, D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX,
D3D12_TEXTURE_LAYOUT_ROW_MAJOR,
};
use windows::Win32::Graphics::Dxgi::Common::DXGI_SAMPLE_DESC;
pub struct LutTexture {
resource: ManuallyDrop<Resource>,
allocator_resource: ManuallyDrop<Resource>,
resource: ManuallyDrop<ID3D12Resource>,
view: InputTexture,
miplevels: Option<u16>,
// Staging heap needs to be kept alive until the command list is submitted, which is
// really annoying. We could probably do better but it's safer to keep it around.
staging: ManuallyDrop<Resource>,
allocator_staging: ManuallyDrop<Resource>,
staging: ManuallyDrop<ID3D12Resource>,
allocator: Arc<Mutex<Allocator>>,
}
@ -75,7 +93,7 @@ impl LutTexture {
let descriptor = heap.allocate_descriptor()?;
// create handles on GPU
let resource = allocator.lock().create_resource(&ResourceCreateDesc {
let allocator_resource = allocator.lock().create_resource(&ResourceCreateDesc {
name: "lut alloc",
memory_location: MemoryLocation::GpuOnly,
resource_category: ResourceCategory::OtherTexture,
@ -102,7 +120,7 @@ impl LutTexture {
};
device.CreateShaderResourceView(
resource.resource(),
allocator_resource.resource(),
Some(&srv_desc),
*descriptor.as_ref(),
);
@ -136,7 +154,7 @@ impl LutTexture {
buffer_desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
}
let upload = allocator.lock().create_resource(&ResourceCreateDesc {
let allocator_upload = allocator.lock().create_resource(&ResourceCreateDesc {
name: "lut staging",
memory_location: MemoryLocation::CpuToGpu,
resource_category: ResourceCategory::Buffer,
@ -155,17 +173,20 @@ impl LutTexture {
SlicePitch: (4 * source.size.width * source.size.height) as isize,
}];
let resource = ManuallyDrop::new(allocator_resource.resource().clone());
let upload = ManuallyDrop::new(allocator_upload.resource().clone());
gc.dispose_barriers(d3d12_resource_transition(
cmd,
&resource.resource(),
&allocator_resource.resource(),
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
D3D12_RESOURCE_STATE_COPY_DEST,
));
d3d12_update_subresources(
d3d12_update_subresources::<OutlivesFrame>(
cmd,
&resource.resource(),
&upload.resource(),
&resource,
&upload,
0,
0,
1,
@ -175,32 +196,35 @@ impl LutTexture {
gc.dispose_barriers(d3d12_resource_transition(
cmd,
&resource.resource(),
&resource,
D3D12_RESOURCE_STATE_COPY_DEST,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
));
let view = InputTexture::new(
resource.resource().clone(),
allocator_resource.resource().clone(),
descriptor,
source.size,
ImageFormat::R8G8B8A8Unorm.into(),
filter,
wrap_mode,
);
Ok(LutTexture {
resource: ManuallyDrop::new(resource),
staging: ManuallyDrop::new(upload),
allocator_resource: ManuallyDrop::new(allocator_resource),
allocator_staging: ManuallyDrop::new(allocator_upload),
view,
miplevels: if mipmap { Some(miplevels) } else { None },
allocator: Arc::clone(&allocator),
resource,
staging: upload,
})
}
pub fn generate_mipmaps(&self, gen_mips: &mut MipmapGenContext) -> error::Result<()> {
if let Some(miplevels) = self.miplevels {
gen_mips.generate_mipmaps(
&self.resource.resource(),
&self.allocator_resource.resource(),
miplevels,
self.view.size,
ImageFormat::R8G8B8A8Unorm.into(),
@ -219,22 +243,29 @@ impl AsRef<InputTexture> for LutTexture {
impl Drop for LutTexture {
fn drop(&mut self) {
let resource = unsafe { ManuallyDrop::take(&mut self.resource) };
// drop view handles
unsafe {
ManuallyDrop::drop(&mut self.resource);
ManuallyDrop::drop(&mut self.staging)
};
// deallocate
let resource = unsafe { ManuallyDrop::take(&mut self.allocator_resource) };
if let Err(e) = self.allocator.lock().free_resource(resource) {
println!("librashader-runtime-d3d12: [warn] failed to deallocate lut buffer memory {e}")
}
let staging = unsafe { ManuallyDrop::take(&mut self.staging) };
let staging = unsafe { ManuallyDrop::take(&mut self.allocator_staging) };
if let Err(e) = self.allocator.lock().free_resource(staging) {
println!("librashader-runtime-d3d12: [warn] failed to deallocate lut staging buffer memory {e}")
}
}
}
fn d3d12_update_subresources(
fn d3d12_update_subresources<S: ResourceHandleStrategy<ManuallyDrop<ID3D12Resource>>>(
cmd: &ID3D12GraphicsCommandList,
destination_resource: &ID3D12Resource,
intermediate_resource: &ID3D12Resource,
destination_resource: &ManuallyDrop<ID3D12Resource>,
intermediate_resource: &ManuallyDrop<ID3D12Resource>,
intermediate_offset: u64,
first_subresouce: u32,
num_subresources: u32,
@ -269,7 +300,7 @@ fn d3d12_update_subresources(
Some(&mut required_size),
);
update_subresources(
update_subresources::<S>(
cmd,
destination_resource,
intermediate_resource,
@ -286,10 +317,10 @@ fn d3d12_update_subresources(
}
#[allow(clippy::too_many_arguments)]
fn update_subresources(
fn update_subresources<S: ResourceHandleStrategy<ManuallyDrop<ID3D12Resource>>>(
cmd: &ID3D12GraphicsCommandList,
destination_resource: &ID3D12Resource,
intermediate_resource: &ID3D12Resource,
destination_resource: &ManuallyDrop<ID3D12Resource>,
intermediate_resource: &ManuallyDrop<ID3D12Resource>,
first_subresouce: u32,
num_subresources: u32,
required_size: u64,
@ -327,16 +358,16 @@ fn update_subresources(
let destination_desc = destination_resource.GetDesc();
if destination_desc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER {
cmd.CopyBufferRegion(
destination_resource,
destination_resource.deref(),
0,
intermediate_resource,
intermediate_resource.deref(),
layouts[0].Offset,
layouts[0].Footprint.Width as u64,
);
} else {
for i in 0..num_subresources as usize {
let dest_location = D3D12_TEXTURE_COPY_LOCATION {
pResource: ManuallyDrop::new(Some(destination_resource.clone())),
pResource: S::obtain(&destination_resource),
Type: D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX,
Anonymous: D3D12_TEXTURE_COPY_LOCATION_0 {
SubresourceIndex: i as u32 + first_subresouce,
@ -344,7 +375,7 @@ fn update_subresources(
};
let source_location = D3D12_TEXTURE_COPY_LOCATION {
pResource: ManuallyDrop::new(Some(intermediate_resource.clone())),
pResource: S::obtain(&intermediate_resource),
Type: D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT,
Anonymous: D3D12_TEXTURE_COPY_LOCATION_0 {
PlacedFootprint: layouts[i],
@ -353,8 +384,8 @@ fn update_subresources(
cmd.CopyTextureRegion(&dest_location, 0, 0, 0, &source_location, None);
gc.dispose_resource(dest_location.pResource);
gc.dispose_resource(source_location.pResource);
S::cleanup(gc, dest_location.pResource);
S::cleanup(gc, source_location.pResource);
}
}
Ok(required_size)

View file

@ -0,0 +1,37 @@
use crate::filter_chain::FrameResiduals;
use std::mem::ManuallyDrop;
use std::ops::Deref;
use windows::Win32::Graphics::Direct3D12::ID3D12Resource;
pub trait ResourceHandleStrategy<H> {
unsafe fn obtain(handle: &H) -> ManuallyDrop<Option<ID3D12Resource>>;
unsafe fn cleanup(gc: &mut FrameResiduals, handle: ManuallyDrop<Option<ID3D12Resource>>);
}
pub struct IncrementRefcount;
impl ResourceHandleStrategy<ManuallyDrop<ID3D12Resource>> for IncrementRefcount {
unsafe fn obtain(
handle: &ManuallyDrop<ID3D12Resource>,
) -> ManuallyDrop<Option<ID3D12Resource>> {
ManuallyDrop::new(Some(handle.deref().clone()))
}
unsafe fn cleanup(gc: &mut FrameResiduals, handle: ManuallyDrop<Option<ID3D12Resource>>) {
gc.dispose_resource(handle);
}
}
pub struct OutlivesFrame;
impl ResourceHandleStrategy<ManuallyDrop<ID3D12Resource>> for OutlivesFrame {
unsafe fn obtain(
handle: &ManuallyDrop<ID3D12Resource>,
) -> ManuallyDrop<Option<ID3D12Resource>> {
unsafe { std::mem::transmute_copy(handle) }
}
unsafe fn cleanup(_gc: &mut FrameResiduals, _handle: ManuallyDrop<Option<ID3D12Resource>>) {
// Since the lifetime is ensured for the lifetime of the filter chain strategy, do nothing
}
}

View file

@ -9,12 +9,10 @@ use windows::Win32::Graphics::Direct3D::Dxc::{
use windows::Win32::Graphics::Direct3D12::{
ID3D12Device, ID3D12GraphicsCommandList, ID3D12Resource, D3D12_FEATURE_DATA_FORMAT_SUPPORT,
D3D12_FEATURE_FORMAT_SUPPORT,
D3D12_RESOURCE_BARRIER, D3D12_RESOURCE_BARRIER_0, D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
D3D12_RESOURCE_BARRIER_FLAG_NONE, D3D12_RESOURCE_BARRIER_TYPE_TRANSITION
, D3D12_RESOURCE_STATES, D3D12_RESOURCE_TRANSITION_BARRIER
,
D3D12_FEATURE_FORMAT_SUPPORT, D3D12_RESOURCE_BARRIER, D3D12_RESOURCE_BARRIER_0,
D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, D3D12_RESOURCE_BARRIER_FLAG_NONE,
D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, D3D12_RESOURCE_STATES,
D3D12_RESOURCE_TRANSITION_BARRIER,
};
use windows::Win32::Graphics::Dxgi::Common::*;
@ -232,4 +230,3 @@ pub fn d3d12_resource_transition_subresource(
unsafe { cmd.ResourceBarrier(&barrier) }
barrier
}

View file

@ -251,7 +251,7 @@ pub mod d3d12_hello_triangle {
command_queue: ID3D12CommandQueue,
swap_chain: IDXGISwapChain3,
frame_index: u32,
render_targets: [ID3D12Resource; FRAME_COUNT as usize],
render_targets: [ManuallyDrop<ID3D12Resource>; FRAME_COUNT as usize],
rtv_heap: ID3D12DescriptorHeap,
rtv_descriptor_size: usize,
viewport: D3D12_VIEWPORT,
@ -260,7 +260,7 @@ pub mod d3d12_hello_triangle {
root_signature: ID3D12RootSignature,
pso: ID3D12PipelineState,
command_list: ID3D12GraphicsCommandList,
framebuffer: ID3D12Resource,
framebuffer: ManuallyDrop<ID3D12Resource>,
// we need to keep this around to keep the reference alive, even though
// nothing reads from it
#[allow(dead_code)]
@ -377,8 +377,8 @@ pub mod d3d12_hello_triangle {
} as usize;
let rtv_handle = unsafe { rtv_heap.GetCPUDescriptorHandleForHeapStart() };
let render_targets: [ID3D12Resource; FRAME_COUNT as usize] =
array_init::try_array_init(|i: usize| -> Result<ID3D12Resource> {
let render_targets: [ManuallyDrop<ID3D12Resource>; FRAME_COUNT as usize] =
array_init::try_array_init(|i: usize| -> Result<ManuallyDrop<ID3D12Resource>> {
let render_target: ID3D12Resource = unsafe { swap_chain.GetBuffer(i as u32) }?;
unsafe {
self.device.CreateRenderTargetView(
@ -389,7 +389,7 @@ pub mod d3d12_hello_triangle {
},
)
};
Ok(render_target)
Ok(ManuallyDrop::new(render_target))
})?;
let framebuffer: ID3D12Resource = unsafe {
@ -475,7 +475,7 @@ pub mod d3d12_hello_triangle {
root_signature,
pso,
command_list,
framebuffer,
framebuffer: ManuallyDrop::new(framebuffer),
vertex_buffer,
vbv,
fence,
@ -501,7 +501,7 @@ pub mod d3d12_hello_triangle {
unsafe {
self.device.CreateShaderResourceView(
&resources.framebuffer,
resources.framebuffer.deref(),
Some(&D3D12_SHADER_RESOURCE_VIEW_DESC {
Format: DXGI_FORMAT_R8G8B8A8_UNORM,
ViewDimension: D3D12_SRV_DIMENSION_TEXTURE2D,
@ -601,8 +601,8 @@ pub mod d3d12_hello_triangle {
unsafe {
command_list.CopyResource(
&resources.framebuffer,
&resources.render_targets[resources.frame_index as usize],
&*resources.framebuffer,
&*resources.render_targets[resources.frame_index as usize],
);
command_list.ResourceBarrier(&[transition_barrier(
&resources.framebuffer,
@ -620,7 +620,7 @@ pub mod d3d12_hello_triangle {
.frame(
command_list,
D3D12InputImage {
resource: resources.framebuffer.clone(),
resource: ID3D12Resource::clone(&*resources.framebuffer),
descriptor: framebuffer,
},
&Viewport {
@ -656,7 +656,7 @@ pub mod d3d12_hello_triangle {
}
fn transition_barrier(
resource: &ID3D12Resource,
resource: &ManuallyDrop<ID3D12Resource>,
state_before: D3D12_RESOURCE_STATES,
state_after: D3D12_RESOURCE_STATES,
) -> D3D12_RESOURCE_BARRIER {
@ -665,7 +665,7 @@ pub mod d3d12_hello_triangle {
Flags: D3D12_RESOURCE_BARRIER_FLAG_NONE,
Anonymous: D3D12_RESOURCE_BARRIER_0 {
Transition: ManuallyDrop::new(D3D12_RESOURCE_TRANSITION_BARRIER {
pResource: ManuallyDrop::new(Some(resource.clone())),
pResource: unsafe { std::mem::transmute_copy(resource) },
StateBefore: state_before,
StateAfter: state_after,
Subresource: D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
@ -694,7 +694,7 @@ pub mod d3d12_hello_triangle {
}?;
let mut device: Option<ID3D12Device> = None;
unsafe { D3D12CreateDevice(&adapter, D3D_FEATURE_LEVEL_12_2, &mut device) }?;
unsafe { D3D12CreateDevice(&adapter, D3D_FEATURE_LEVEL_12_1, &mut device) }?;
Ok((dxgi_factory, device.unwrap()))
}

View file

@ -6,7 +6,7 @@ use crate::hello_triangle::{DXSample, SampleCommandLine};
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/crt/crt-lottes.slangp",
"../test/shaders_slang/crt/crt-royale.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",