d3d12: render to intermediate buffers

This commit is contained in:
chyyran 2023-02-01 01:57:31 -05:00 committed by Ronny Chan
parent cbe087fa6c
commit c29cc51ed5
6 changed files with 121 additions and 18 deletions

View file

@ -1,5 +1,5 @@
use std::collections::VecDeque; use std::collections::VecDeque;
use crate::{error}; use crate::{error, util};
use crate::heap::{D3D12DescriptorHeap, CpuStagingHeap, ResourceWorkHeap, SamplerWorkHeap, RenderTargetHeap}; use crate::heap::{D3D12DescriptorHeap, CpuStagingHeap, ResourceWorkHeap, SamplerWorkHeap, RenderTargetHeap};
use crate::samplers::SamplerSet; use crate::samplers::SamplerSet;
use crate::luts::LutTexture; use crate::luts::LutTexture;
@ -14,7 +14,7 @@ use std::path::Path;
use windows::core::Interface; use windows::core::Interface;
use windows::w; use windows::w;
use windows::Win32::Foundation::CloseHandle; 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::Threading::{CreateEventA, ResetEvent, WaitForSingleObject};
use windows::Win32::System::WindowsProgramming::INFINITE; use windows::Win32::System::WindowsProgramming::INFINITE;
use librashader_common::{ImageFormat, Size, Viewport}; 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::ReflectShader;
use librashader_reflect::reflect::semantics::{MAX_BINDINGS_COUNT, ShaderSemantics, TextureSemantics, UniformBinding}; use librashader_reflect::reflect::semantics::{MAX_BINDINGS_COUNT, ShaderSemantics, TextureSemantics, UniformBinding};
use librashader_runtime::binding::TextureInput; use librashader_runtime::binding::TextureInput;
use librashader_runtime::quad::{IDENTITY_MVP, QuadType};
use librashader_runtime::uniforms::UniformStorage; use librashader_runtime::uniforms::UniformStorage;
use crate::buffer::{D3D12Buffer, D3D12ConstantBuffer}; use crate::buffer::{D3D12Buffer, D3D12ConstantBuffer};
use crate::filter_pass::FilterPass; use crate::filter_pass::FilterPass;
@ -29,6 +30,7 @@ use crate::framebuffer::OwnedImage;
use crate::graphics_pipeline::{D3D12GraphicsPipeline, D3D12RootSignature}; use crate::graphics_pipeline::{D3D12GraphicsPipeline, D3D12RootSignature};
use crate::mipmap::D3D12MipmapGen; use crate::mipmap::D3D12MipmapGen;
use crate::quad_render::DrawQuad; use crate::quad_render::DrawQuad;
use crate::render_target::RenderTarget;
use crate::texture::{InputTexture, OutputTexture}; use crate::texture::{InputTexture, OutputTexture};
type ShaderPassMeta = ShaderPassArtifact<impl CompileReflectShader<HLSL, GlslangCompilation>>; type ShaderPassMeta = ShaderPassArtifact<impl CompileReflectShader<HLSL, GlslangCompilation>>;
@ -443,7 +445,8 @@ impl FilterChainD3D12 {
/// Process a frame with the input image. /// Process a frame with the input image.
pub fn frame( pub fn frame(
&mut self, &mut self,
input: InputTexture, cmd: &ID3D12GraphicsCommandList,
mut input: InputTexture,
viewport: &Viewport<OutputTexture>, viewport: &Viewport<OutputTexture>,
frame_count: usize, frame_count: usize,
options: Option<&()>, options: Option<&()>,
@ -482,8 +485,8 @@ impl FilterChainD3D12 {
} }
let original = &input; let original = input;
let mut source = &input; let mut source = unsafe { original.cloned() };
// rescale render buffers to ensure all bindings are valid. // rescale render buffers to ensure all bindings are valid.
@ -512,8 +515,78 @@ impl FilterChainD3D12 {
)?; )?;
source_size = next_size; 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(()) Ok(())
} }

View file

@ -136,7 +136,7 @@ impl FilterPass {
viewport: &Viewport<OutputTexture>, viewport: &Viewport<OutputTexture>,
original: &InputTexture, original: &InputTexture,
source: &InputTexture, source: &InputTexture,
output: RenderTarget, output: &RenderTarget,
vbo_type: QuadType, vbo_type: QuadType,
) -> error::Result<()> { ) -> error::Result<()> {
@ -188,7 +188,7 @@ impl FilterPass {
unsafe { unsafe {
cmd.SetGraphicsRootDescriptorTable(0, *self.texture_heap[0].as_ref()); 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. // todo: check for non-renderpass.

View file

@ -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 windows::Win32::Graphics::Dxgi::Common::{DXGI_SAMPLE_DESC};
use librashader_common::{FilterMode, ImageFormat, Size, WrapMode}; use librashader_common::{FilterMode, ImageFormat, Size, WrapMode};
use librashader_presets::Scale2D; use librashader_presets::Scale2D;
@ -11,7 +11,7 @@ use crate::util::d3d12_get_closest_format;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(crate) struct OwnedImage { pub(crate) struct OwnedImage {
handle: ID3D12Resource, pub(crate)handle: ID3D12Resource,
pub(crate) size: Size<u32>, pub(crate) size: Size<u32>,
format: ImageFormat, format: ImageFormat,
device: ID3D12Device, device: ID3D12Device,
@ -41,7 +41,7 @@ impl OwnedImage {
Quality: 0, Quality: 0,
}, },
Layout: Default::default(), Layout: Default::default(),
Flags: Default::default(), Flags: D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET,
}; };
let mut format_support = D3D12_FEATURE_DATA_FORMAT_SUPPORT { let mut format_support = D3D12_FEATURE_DATA_FORMAT_SUPPORT {

View file

@ -79,7 +79,7 @@ const D3D12_SLANG_ROOT_SIGNATURE: &D3D12_ROOT_SIGNATURE_DESC = &D3D12_ROOT_SIGNA
}; };
pub struct D3D12RootSignature { pub struct D3D12RootSignature {
signature: ID3D12RootSignature pub(crate) handle: ID3D12RootSignature
} }
impl D3D12RootSignature { impl D3D12RootSignature {
@ -107,7 +107,7 @@ impl D3D12RootSignature {
}; };
Ok(D3D12RootSignature { Ok(D3D12RootSignature {
signature, handle: signature,
}) })
} }
} }
@ -129,7 +129,7 @@ impl D3D12GraphicsPipeline {
let pipeline_state: ID3D12PipelineState = unsafe { let pipeline_state: ID3D12PipelineState = unsafe {
let pipeline_desc = D3D12_GRAPHICS_PIPELINE_STATE_DESC { 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 { VS: D3D12_SHADER_BYTECODE {
pShaderBytecode: vertex_dxbc.GetBufferPointer(), pShaderBytecode: vertex_dxbc.GetBufferPointer(),
BytecodeLength: vertex_dxbc.GetBufferSize(), BytecodeLength: vertex_dxbc.GetBufferSize(),

View file

@ -241,6 +241,7 @@ pub mod d3d12_hello_triangle {
use crate::filter_chain::FilterChainD3D12; use crate::filter_chain::FilterChainD3D12;
use std::path::Path; use std::path::Path;
use librashader_common::{FilterMode, Size, Viewport, WrapMode}; use librashader_common::{FilterMode, Size, Viewport, WrapMode};
use crate::heap::{CpuStagingHeap, D3D12DescriptorHeap};
use crate::texture::{InputTexture, OutputTexture}; use crate::texture::{InputTexture, OutputTexture};
const FRAME_COUNT: u32 = 2; const FRAME_COUNT: u32 = 2;
@ -276,6 +277,7 @@ pub mod d3d12_hello_triangle {
fence: ID3D12Fence, fence: ID3D12Fence,
fence_value: u64, fence_value: u64,
fence_event: HANDLE, fence_event: HANDLE,
frambuffer_heap: D3D12DescriptorHeap<CpuStagingHeap>
} }
impl DXSample for Sample { impl DXSample for Sample {
@ -468,6 +470,7 @@ pub mod d3d12_hello_triangle {
fence, fence,
fence_value, fence_value,
fence_event, fence_event,
frambuffer_heap: D3D12DescriptorHeap::new(&self.device, 1024).unwrap(),
}); });
Ok(()) Ok(())
@ -483,7 +486,24 @@ pub mod d3d12_hello_triangle {
fn render(&mut self) { fn render(&mut self) {
if let Some(resources) = &mut self.resources { 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. // Execute the command list.
let command_list = ID3D12CommandList::from(&resources.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 list allocators can only be reset when the associated
// command lists have finished execution on the GPU; apps should use // command lists have finished execution on the GPU; apps should use
// fences to determine GPU execution progress. // fences to determine GPU execution progress.
@ -568,9 +591,9 @@ pub mod d3d12_hello_triangle {
)]); )]);
filter.frame( filter.frame(
InputTexture::new_from_raw(D3D12_CPU_DESCRIPTOR_HANDLE { command_list,
ptr: 0 InputTexture::new_from_raw(framebuffer,
}, Size::new(resources.viewport.Width as u32, resources.viewport.Height as u32), Size::new(resources.viewport.Width as u32, resources.viewport.Height as u32),
DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM,
WrapMode::ClampToEdge, WrapMode::ClampToEdge,
FilterMode::Linear, FilterMode::Linear,

View file

@ -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<InputTexture> for InputTexture { impl AsRef<InputTexture> for InputTexture {