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 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<impl CompileReflectShader<HLSL, GlslangCompilation>>;
@ -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<OutputTexture>,
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(())
}

View file

@ -136,7 +136,7 @@ impl FilterPass {
viewport: &Viewport<OutputTexture>,
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.

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 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<u32>,
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 {

View file

@ -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(),

View file

@ -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<CpuStagingHeap>
}
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,

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 {