From c29cc51ed5b8b7f1daa072a50fc4975ac89f6f4d Mon Sep 17 00:00:00 2001 From: chyyran Date: Wed, 1 Feb 2023 01:57:31 -0500 Subject: [PATCH] d3d12: render to intermediate buffers --- librashader-runtime-d3d12/src/filter_chain.rs | 83 +++++++++++++++++-- librashader-runtime-d3d12/src/filter_pass.rs | 4 +- librashader-runtime-d3d12/src/framebuffer.rs | 6 +- .../src/graphics_pipeline.rs | 6 +- .../src/hello_triangle.rs | 33 ++++++-- librashader-runtime-d3d12/src/texture.rs | 7 ++ 6 files changed, 121 insertions(+), 18 deletions(-) diff --git a/librashader-runtime-d3d12/src/filter_chain.rs b/librashader-runtime-d3d12/src/filter_chain.rs index 0b9f7c4..6d45d9b 100644 --- a/librashader-runtime-d3d12/src/filter_chain.rs +++ b/librashader-runtime-d3d12/src/filter_chain.rs @@ -1,5 +1,5 @@ use std::collections::VecDeque; -use crate::{error}; +use crate::{error, util}; use crate::heap::{D3D12DescriptorHeap, CpuStagingHeap, ResourceWorkHeap, SamplerWorkHeap, RenderTargetHeap}; use crate::samplers::SamplerSet; use crate::luts::LutTexture; @@ -14,7 +14,7 @@ use std::path::Path; use windows::core::Interface; use windows::w; use windows::Win32::Foundation::CloseHandle; -use windows::Win32::Graphics::Direct3D12::{ID3D12CommandAllocator, ID3D12CommandQueue, ID3D12Device, ID3D12Fence, ID3D12GraphicsCommandList, D3D12_COMMAND_LIST_TYPE_DIRECT, D3D12_COMMAND_QUEUE_DESC, D3D12_COMMAND_QUEUE_FLAG_NONE, D3D12_FENCE_FLAG_NONE, ID3D12DescriptorHeap}; +use windows::Win32::Graphics::Direct3D12::{ID3D12CommandAllocator, ID3D12CommandQueue, ID3D12Device, ID3D12Fence, ID3D12GraphicsCommandList, D3D12_COMMAND_LIST_TYPE_DIRECT, D3D12_COMMAND_QUEUE_DESC, D3D12_COMMAND_QUEUE_FLAG_NONE, D3D12_FENCE_FLAG_NONE, ID3D12DescriptorHeap, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET}; use windows::Win32::System::Threading::{CreateEventA, ResetEvent, WaitForSingleObject}; use windows::Win32::System::WindowsProgramming::INFINITE; use librashader_common::{ImageFormat, Size, Viewport}; @@ -22,6 +22,7 @@ use librashader_reflect::back::{CompileReflectShader, CompileShader}; use librashader_reflect::reflect::ReflectShader; use librashader_reflect::reflect::semantics::{MAX_BINDINGS_COUNT, ShaderSemantics, TextureSemantics, UniformBinding}; use librashader_runtime::binding::TextureInput; +use librashader_runtime::quad::{IDENTITY_MVP, QuadType}; use librashader_runtime::uniforms::UniformStorage; use crate::buffer::{D3D12Buffer, D3D12ConstantBuffer}; use crate::filter_pass::FilterPass; @@ -29,6 +30,7 @@ use crate::framebuffer::OwnedImage; use crate::graphics_pipeline::{D3D12GraphicsPipeline, D3D12RootSignature}; use crate::mipmap::D3D12MipmapGen; use crate::quad_render::DrawQuad; +use crate::render_target::RenderTarget; use crate::texture::{InputTexture, OutputTexture}; type ShaderPassMeta = ShaderPassArtifact>; @@ -443,7 +445,8 @@ impl FilterChainD3D12 { /// Process a frame with the input image. pub fn frame( &mut self, - input: InputTexture, + cmd: &ID3D12GraphicsCommandList, + mut input: InputTexture, viewport: &Viewport, frame_count: usize, options: Option<&()>, @@ -482,8 +485,8 @@ impl FilterChainD3D12 { } - let original = &input; - let mut source = &input; + let original = input; + let mut source = unsafe { original.cloned() }; // rescale render buffers to ensure all bindings are valid. @@ -512,8 +515,78 @@ impl FilterChainD3D12 { )?; source_size = next_size; + + // refresh inputs + self.common.feedback_textures[index] = Some( + self.feedback_framebuffers[index] + .create_shader_resource_view(&mut self.staging_heap, pass.config.filter, pass.config.wrap_mode)?, + ); + self.common.output_textures[index] = Some( + self.output_framebuffers[index] + .create_shader_resource_view(&mut self.staging_heap, pass.config.filter, pass.config.wrap_mode)?, + ); } + let passes_len = passes.len(); + let (pass, last) = passes.split_at_mut(passes_len - 1); + + let mut residuals = Vec::new(); + + unsafe { + let heaps = [self.texture_heap.clone(), self.sampler_heap.clone()]; + cmd.SetDescriptorHeaps(&heaps); + cmd.SetGraphicsRootSignature(&self.common.root_signature.handle); + } + for (index, pass) in pass.iter_mut().enumerate() { + + source.filter = pass.config.filter; + source.wrap_mode = pass.config.wrap_mode; + let target = &self.output_framebuffers[index]; + util::d3d12_resource_transition(&cmd, + &target.handle, + D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, + D3D12_RESOURCE_STATE_RENDER_TARGET); + let size = target.size; + let view = target.create_render_target_view(&mut self.rtv_heap)?; + + let out = RenderTarget { + x: 0.0, + y: 0.0, + mvp:IDENTITY_MVP, + output: OutputTexture { descriptor: view.descriptor, size }, + }; + + pass.draw( + cmd, + index, + &self.common, + if pass.config.frame_count_mod > 0 { + frame_count % pass.config.frame_count_mod as usize + } else { + frame_count + } as u32, + 1, + viewport, + &original, + &source, + &out, + QuadType::Offscreen + )?; + + util::d3d12_resource_transition(&cmd, + &target.handle, + D3D12_RESOURCE_STATE_RENDER_TARGET, + D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); + // let target_handle = target.create_shader_resource_view( + // &mut self.staging_heap, + // pass.config.filter, + // pass.config.wrap_mode, + // )?; + residuals.push(out.output.descriptor); + source = self.common.output_textures[index].as_ref().unwrap().cloned() + } + + Ok(()) } diff --git a/librashader-runtime-d3d12/src/filter_pass.rs b/librashader-runtime-d3d12/src/filter_pass.rs index c156dcf..2099dac 100644 --- a/librashader-runtime-d3d12/src/filter_pass.rs +++ b/librashader-runtime-d3d12/src/filter_pass.rs @@ -136,7 +136,7 @@ impl FilterPass { viewport: &Viewport, original: &InputTexture, source: &InputTexture, - output: RenderTarget, + output: &RenderTarget, vbo_type: QuadType, ) -> error::Result<()> { @@ -188,7 +188,7 @@ impl FilterPass { unsafe { cmd.SetGraphicsRootDescriptorTable(0, *self.texture_heap[0].as_ref()); - cmd.SetGraphicsRootDescriptorTable(0, *self.sampler_heap[0].as_ref()); + cmd.SetGraphicsRootDescriptorTable(1, *self.sampler_heap[0].as_ref()); } // todo: check for non-renderpass. diff --git a/librashader-runtime-d3d12/src/framebuffer.rs b/librashader-runtime-d3d12/src/framebuffer.rs index ffd5830..b5f6d2a 100644 --- a/librashader-runtime-d3d12/src/framebuffer.rs +++ b/librashader-runtime-d3d12/src/framebuffer.rs @@ -1,4 +1,4 @@ -use windows::Win32::Graphics::Direct3D12::{D3D12_CPU_PAGE_PROPERTY_UNKNOWN, 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_STORE, D3D12_HEAP_FLAG_NONE, D3D12_HEAP_PROPERTIES, D3D12_HEAP_TYPE_DEFAULT, D3D12_MEMORY_POOL_UNKNOWN, D3D12_RENDER_TARGET_VIEW_DESC, D3D12_RENDER_TARGET_VIEW_DESC_0, D3D12_RESOURCE_DESC, D3D12_RESOURCE_DIMENSION_TEXTURE2D, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, 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, ID3D12Device, ID3D12Resource}; +use windows::Win32::Graphics::Direct3D12::{D3D12_CPU_PAGE_PROPERTY_UNKNOWN, 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_STORE, D3D12_HEAP_FLAG_NONE, D3D12_HEAP_PROPERTIES, D3D12_HEAP_TYPE_DEFAULT, D3D12_MEMORY_POOL_UNKNOWN, D3D12_RENDER_TARGET_VIEW_DESC, D3D12_RENDER_TARGET_VIEW_DESC_0, D3D12_RESOURCE_DESC, D3D12_RESOURCE_DIMENSION_TEXTURE2D, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, 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, ID3D12Device, ID3D12Resource}; use windows::Win32::Graphics::Dxgi::Common::{DXGI_SAMPLE_DESC}; use librashader_common::{FilterMode, ImageFormat, Size, WrapMode}; use librashader_presets::Scale2D; @@ -11,7 +11,7 @@ use crate::util::d3d12_get_closest_format; #[derive(Debug, Clone)] pub(crate) struct OwnedImage { - handle: ID3D12Resource, + pub(crate)handle: ID3D12Resource, pub(crate) size: Size, format: ImageFormat, device: ID3D12Device, @@ -41,7 +41,7 @@ impl OwnedImage { Quality: 0, }, Layout: Default::default(), - Flags: Default::default(), + Flags: D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET, }; let mut format_support = D3D12_FEATURE_DATA_FORMAT_SUPPORT { diff --git a/librashader-runtime-d3d12/src/graphics_pipeline.rs b/librashader-runtime-d3d12/src/graphics_pipeline.rs index 367b554..64b98a8 100644 --- a/librashader-runtime-d3d12/src/graphics_pipeline.rs +++ b/librashader-runtime-d3d12/src/graphics_pipeline.rs @@ -79,7 +79,7 @@ const D3D12_SLANG_ROOT_SIGNATURE: &D3D12_ROOT_SIGNATURE_DESC = &D3D12_ROOT_SIGNA }; pub struct D3D12RootSignature { - signature: ID3D12RootSignature + pub(crate) handle: ID3D12RootSignature } impl D3D12RootSignature { @@ -107,7 +107,7 @@ impl D3D12RootSignature { }; Ok(D3D12RootSignature { - signature, + handle: signature, }) } } @@ -129,7 +129,7 @@ impl D3D12GraphicsPipeline { let pipeline_state: ID3D12PipelineState = unsafe { let pipeline_desc = D3D12_GRAPHICS_PIPELINE_STATE_DESC { - pRootSignature: windows::core::ManuallyDrop::new(&root_signature.signature), + pRootSignature: windows::core::ManuallyDrop::new(&root_signature.handle), VS: D3D12_SHADER_BYTECODE { pShaderBytecode: vertex_dxbc.GetBufferPointer(), BytecodeLength: vertex_dxbc.GetBufferSize(), diff --git a/librashader-runtime-d3d12/src/hello_triangle.rs b/librashader-runtime-d3d12/src/hello_triangle.rs index f96d0f5..1e2a664 100644 --- a/librashader-runtime-d3d12/src/hello_triangle.rs +++ b/librashader-runtime-d3d12/src/hello_triangle.rs @@ -241,6 +241,7 @@ pub mod d3d12_hello_triangle { use crate::filter_chain::FilterChainD3D12; use std::path::Path; use librashader_common::{FilterMode, Size, Viewport, WrapMode}; + use crate::heap::{CpuStagingHeap, D3D12DescriptorHeap}; use crate::texture::{InputTexture, OutputTexture}; const FRAME_COUNT: u32 = 2; @@ -276,6 +277,7 @@ pub mod d3d12_hello_triangle { fence: ID3D12Fence, fence_value: u64, fence_event: HANDLE, + frambuffer_heap: D3D12DescriptorHeap } impl DXSample for Sample { @@ -468,6 +470,7 @@ pub mod d3d12_hello_triangle { fence, fence_value, fence_event, + frambuffer_heap: D3D12DescriptorHeap::new(&self.device, 1024).unwrap(), }); Ok(()) @@ -483,7 +486,24 @@ pub mod d3d12_hello_triangle { fn render(&mut self) { if let Some(resources) = &mut self.resources { - populate_command_list(resources, &mut self.filter, self.framecount).unwrap(); + let srv = resources.frambuffer_heap.alloc_slot() + .unwrap(); + + unsafe { + self.device.CreateShaderResourceView(&resources.framebuffer, Some(&D3D12_SHADER_RESOURCE_VIEW_DESC { + Format: DXGI_FORMAT_R8G8B8A8_UNORM, + ViewDimension: D3D12_SRV_DIMENSION_TEXTURE2D, + Shader4ComponentMapping: D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING, + Anonymous: D3D12_SHADER_RESOURCE_VIEW_DESC_0 { + Texture2D: D3D12_TEX2D_SRV { + MipLevels: u32::MAX, + ..Default::default() + } + }, + }), *srv.as_ref()) + } + + populate_command_list(resources, &mut self.filter, self.framecount, *srv.as_ref()).unwrap(); // Execute the command list. let command_list = ID3D12CommandList::from(&resources.command_list); @@ -498,7 +518,10 @@ pub mod d3d12_hello_triangle { } } - fn populate_command_list(resources: &Resources, filter: &mut FilterChainD3D12, frame_count: usize) -> Result<()> { + fn populate_command_list(resources: &mut Resources, filter: &mut FilterChainD3D12, + frame_count: usize, + framebuffer: D3D12_CPU_DESCRIPTOR_HANDLE, + ) -> Result<()> { // Command list allocators can only be reset when the associated // command lists have finished execution on the GPU; apps should use // fences to determine GPU execution progress. @@ -568,9 +591,9 @@ pub mod d3d12_hello_triangle { )]); filter.frame( - InputTexture::new_from_raw(D3D12_CPU_DESCRIPTOR_HANDLE { - ptr: 0 - }, Size::new(resources.viewport.Width as u32, resources.viewport.Height as u32), + command_list, + InputTexture::new_from_raw(framebuffer, + Size::new(resources.viewport.Width as u32, resources.viewport.Height as u32), DXGI_FORMAT_R8G8B8A8_UNORM, WrapMode::ClampToEdge, FilterMode::Linear, diff --git a/librashader-runtime-d3d12/src/texture.rs b/librashader-runtime-d3d12/src/texture.rs index 4b25580..3e1cea1 100644 --- a/librashader-runtime-d3d12/src/texture.rs +++ b/librashader-runtime-d3d12/src/texture.rs @@ -100,6 +100,13 @@ impl InputTexture { } } + // parent descriptor has to stay alive. + pub fn cloned(&self) -> InputTexture { + unsafe { + Self::new_from_raw(*self.descriptor.as_ref(), + self.size, self.format, self.wrap_mode, self.filter) + } + } } impl AsRef for InputTexture {