dx11: get single pass working

This commit is contained in:
chyyran 2022-11-28 21:00:54 -05:00
parent 5078015605
commit 2c953d638f
7 changed files with 248 additions and 55 deletions

View file

@ -1,4 +1,4 @@
use crate::texture::OwnedTexture; use crate::texture::{DxImageView, OwnedTexture, Texture};
use librashader_common::image::Image; use librashader_common::image::Image;
use librashader_common::Size; use librashader_common::Size;
use librashader_preprocess::ShaderSource; use librashader_preprocess::ShaderSource;
@ -15,13 +15,17 @@ use std::path::Path;
use bytemuck::offset_of; use bytemuck::offset_of;
use windows::core::PCSTR; use windows::core::PCSTR;
use windows::s; use windows::s;
use windows::Win32::Graphics::Direct3D11::{D3D11_BIND_CONSTANT_BUFFER, D3D11_BIND_SHADER_RESOURCE, D3D11_BUFFER_DESC, D3D11_CPU_ACCESS_WRITE, D3D11_INPUT_ELEMENT_DESC, D3D11_INPUT_PER_VERTEX_DATA, D3D11_RESOURCE_MISC_FLAG, D3D11_RESOURCE_MISC_GENERATE_MIPS, D3D11_SAMPLER_DESC, D3D11_TEXTURE2D_DESC, D3D11_USAGE_DEFAULT, D3D11_USAGE_DYNAMIC, ID3D11Buffer, ID3D11Device, ID3D11DeviceContext}; use windows::Win32::Graphics::Direct3D11::{D3D11_BIND_CONSTANT_BUFFER, D3D11_BIND_SHADER_RESOURCE, D3D11_BUFFER_DESC, D3D11_CPU_ACCESS_WRITE, D3D11_INPUT_ELEMENT_DESC, D3D11_INPUT_PER_VERTEX_DATA, D3D11_RESOURCE_MISC_FLAG, D3D11_RESOURCE_MISC_GENERATE_MIPS, D3D11_SAMPLER_DESC, D3D11_TEXTURE2D_DESC, D3D11_USAGE_DEFAULT, D3D11_USAGE_DYNAMIC, ID3D11Buffer, ID3D11Device, ID3D11DeviceContext, ID3D11RenderTargetView, ID3D11ShaderResourceView};
use windows::Win32::Graphics::Dxgi::Common::{DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_SAMPLE_DESC}; use windows::Win32::Graphics::Dxgi::Common::{DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_SAMPLE_DESC};
use crate::filter_pass::{ConstantBuffer, ConstantBufferBinding, FilterPass}; use crate::filter_pass::{ConstantBuffer, ConstantBufferBinding, FilterPass};
use crate::framebuffer::OutputFramebuffer;
use crate::quad_render::DrawQuad;
use crate::render_target::RenderTarget;
use crate::samplers::SamplerSet; use crate::samplers::SamplerSet;
use crate::util; use crate::util;
use crate::util::d3d11_compile_bound_shader; use crate::util::d3d11_compile_bound_shader;
// todo: get rid of preset
type ShaderPassMeta<'a> = ( type ShaderPassMeta<'a> = (
&'a ShaderPassConfig, &'a ShaderPassConfig,
ShaderSource, ShaderSource,
@ -30,14 +34,6 @@ type ShaderPassMeta<'a> = (
>, >,
); );
#[repr(C)]
#[derive(Default)]
struct D3D11VertexLayout {
position: [f32; 2],
texcoord: [f32; 2],
color: [f32; 4],
}
pub struct FilterChain { pub struct FilterChain {
pub common: FilterCommon, pub common: FilterCommon,
pub passes: Vec<FilterPass>, pub passes: Vec<FilterPass>,
@ -53,6 +49,7 @@ pub struct FilterCommon {
pub(crate) preset: ShaderPreset, pub(crate) preset: ShaderPreset,
pub(crate) luts: FxHashMap<usize, OwnedTexture>, pub(crate) luts: FxHashMap<usize, OwnedTexture>,
pub samplers: SamplerSet, pub samplers: SamplerSet,
pub(crate) draw_quad: DrawQuad,
} }
impl FilterChain { impl FilterChain {
@ -108,7 +105,7 @@ impl FilterChain {
fn create_constant_buffer(device: &ID3D11Device, size: u32) -> util::Result<ID3D11Buffer> { fn create_constant_buffer(device: &ID3D11Device, size: u32) -> util::Result<ID3D11Buffer> {
eprintln!("{size}"); eprintln!("{size}");
unsafe { unsafe {
let buffer = device.CreateBuffer(&D3D11_BUFFER_DESC { let buffer = device.CreateBuffer(&D3D11_BUFFER_DESC {
ByteWidth: size, ByteWidth: size,
Usage: D3D11_USAGE_DYNAMIC, Usage: D3D11_USAGE_DYNAMIC,
BindFlags: D3D11_BIND_CONSTANT_BUFFER, BindFlags: D3D11_BIND_CONSTANT_BUFFER,
@ -142,27 +139,8 @@ impl FilterChain {
let vs = d3d11_compile_bound_shader(device, &vertex_dxil, None, let vs = d3d11_compile_bound_shader(device, &vertex_dxil, None,
ID3D11Device::CreateVertexShader)?; ID3D11Device::CreateVertexShader)?;
let ia_desc = [ let ia_desc = DrawQuad::get_spirv_cross_vbo_desc();
D3D11_INPUT_ELEMENT_DESC { let vao = util::d3d11_create_input_layout(device, &ia_desc, &vertex_dxil)?;
SemanticName: PCSTR(b"TEXCOORD\0".as_ptr()),
SemanticIndex: 0,
Format: DXGI_FORMAT_R32G32_FLOAT,
InputSlot: 0,
AlignedByteOffset: offset_of!(D3D11VertexLayout, position) as u32,
InputSlotClass: D3D11_INPUT_PER_VERTEX_DATA,
InstanceDataStepRate: 0,
},
D3D11_INPUT_ELEMENT_DESC {
SemanticName: PCSTR(b"TEXCOORD\0".as_ptr()),
SemanticIndex: 1,
Format: DXGI_FORMAT_R32G32_FLOAT,
InputSlot: 0,
AlignedByteOffset: offset_of!(D3D11VertexLayout, texcoord) as u32,
InputSlotClass: D3D11_INPUT_PER_VERTEX_DATA,
InstanceDataStepRate: 0,
}
];
let vertex_ia = util::d3d11_create_input_layout(device, &ia_desc, &vertex_dxil)?;
let fragment_dxil = util::d3d_compile_shader( let fragment_dxil = util::d3d_compile_shader(
hlsl.fragment.as_bytes(), hlsl.fragment.as_bytes(),
@ -223,7 +201,7 @@ impl FilterChain {
reflection, reflection,
compiled: hlsl, compiled: hlsl,
vertex_shader: vs, vertex_shader: vs,
vertex_layout: vertex_ia, vertex_layout: vao,
pixel_shader: ps, pixel_shader: ps,
uniform_bindings, uniform_bindings,
uniform_buffer: ConstantBuffer::new(ubo_cbuffer), uniform_buffer: ConstantBuffer::new(ubo_cbuffer),
@ -231,7 +209,6 @@ impl FilterChain {
source, source,
config: config.clone(), config: config.clone(),
}) })
} }
Ok(filters) Ok(filters)
} }
@ -273,6 +250,8 @@ impl FilterChain {
unsafe { unsafe {
device.GetImmediateContext(&mut device_context); device.GetImmediateContext(&mut device_context);
} }
let device_context = device_context.unwrap();
let draw_quad = DrawQuad::new(device, &device_context)?;
// todo: make vbo: d3d11.c 1376 // todo: make vbo: d3d11.c 1376
Ok(FilterChain { Ok(FilterChain {
@ -284,7 +263,7 @@ impl FilterChain {
common: FilterCommon { common: FilterCommon {
d3d11: Direct3D11 { d3d11: Direct3D11 {
device: device.clone(), device: device.clone(),
device_context: device_context.unwrap() device_context
}, },
luts, luts,
samplers, samplers,
@ -294,7 +273,7 @@ impl FilterChain {
// output_textures: output_textures.into_boxed_slice(), // output_textures: output_textures.into_boxed_slice(),
// feedback_textures: feedback_textures.into_boxed_slice(), // feedback_textures: feedback_textures.into_boxed_slice(),
// history_textures, // history_textures,
// draw_quad, draw_quad,
}, },
}) })
} }
@ -397,4 +376,38 @@ impl FilterChain {
Ok((passes, semantics)) Ok((passes, semantics))
} }
pub fn frame(&mut self, count: usize, viewport: &Size<u32>, input: DxImageView, output: OutputFramebuffer) -> util::Result<()> {
let passes = &mut self.passes;
if passes.is_empty() {
return Ok(());
}
let filter = passes[0].config.filter;
let wrap_mode = passes[0].config.wrap_mode;
self.common.draw_quad.bind_vertices();
let original = Texture {
view: input,
filter,
wrap_mode,
};
let mut source = original.clone();
for (index, pass) in passes.iter_mut().enumerate() {
pass.draw(index, &self.common, if pass.config.frame_count_mod > 0 {
count % pass.config.frame_count_mod as usize
} else {
count
} as u32, 1, viewport, &original, &source, RenderTarget::new(output.clone(), None))?;
}
Ok(())
}
} }

View file

@ -82,7 +82,7 @@ impl FilterPass {
binding: &TextureBinding, binding: &TextureBinding,
texture: &Texture, texture: &Texture,
) { ) {
texture_binding[binding.binding as usize] = Some(texture.handle.clone()); texture_binding[binding.binding as usize] = Some(texture.view.handle.clone());
sampler_binding[binding.binding as usize] = Some(samplers.get(texture.wrap_mode, texture.filter).clone()); sampler_binding[binding.binding as usize] = Some(samplers.get(texture.wrap_mode, texture.filter).clone());
} }
@ -180,7 +180,7 @@ impl FilterPass {
MemberOffset::Ubo(offset) => (&mut self.uniform_buffer.storage, *offset), MemberOffset::Ubo(offset) => (&mut self.uniform_buffer.storage, *offset),
MemberOffset::PushConstant(offset) => (&mut self.push_buffer.storage, *offset), MemberOffset::PushConstant(offset) => (&mut self.push_buffer.storage, *offset),
}; };
FilterPass::build_vec4(&mut buffer[offset..][..16], original.size); FilterPass::build_vec4(&mut buffer[offset..][..16], original.view.size);
} }
// bind Source sampler // bind Source sampler
@ -203,7 +203,7 @@ impl FilterPass {
MemberOffset::Ubo(offset) => (&mut self.uniform_buffer.storage, *offset), MemberOffset::Ubo(offset) => (&mut self.uniform_buffer.storage, *offset),
MemberOffset::PushConstant(offset) => (&mut self.push_buffer.storage, *offset), MemberOffset::PushConstant(offset) => (&mut self.push_buffer.storage, *offset),
}; };
FilterPass::build_vec4(&mut buffer[offset..][..16], source.size); FilterPass::build_vec4(&mut buffer[offset..][..16], source.view.size);
} }
if let Some(binding) = self if let Some(binding) = self
@ -223,7 +223,7 @@ impl FilterPass {
MemberOffset::Ubo(offset) => (&mut self.uniform_buffer.storage, *offset), MemberOffset::Ubo(offset) => (&mut self.uniform_buffer.storage, *offset),
MemberOffset::PushConstant(offset) => (&mut self.push_buffer.storage, *offset), MemberOffset::PushConstant(offset) => (&mut self.push_buffer.storage, *offset),
}; };
FilterPass::build_vec4(&mut buffer[offset..][..16], original.size); FilterPass::build_vec4(&mut buffer[offset..][..16], original.view.size);
} }
// for (index, output) in parent.history_textures.iter().enumerate() { // for (index, output) in parent.history_textures.iter().enumerate() {
@ -365,7 +365,7 @@ impl FilterPass {
}; };
FilterPass::build_vec4( FilterPass::build_vec4(
&mut buffer[offset..][..16], &mut buffer[offset..][..16],
lut.image.size, lut.image.view.size,
); );
} }
} }

View file

@ -67,10 +67,6 @@ use gfx_maths::Mat4;
use std::mem::transmute; use std::mem::transmute;
pub trait DXSample { pub trait DXSample {
fn new() -> Result<Self>
where
Self: Sized;
fn bind_to_window(&mut self, hwnd: &HWND) -> Result<()>; fn bind_to_window(&mut self, hwnd: &HWND) -> Result<()>;
fn update(&mut self) {} fn update(&mut self) {}
@ -228,10 +224,15 @@ struct TriangleUniforms {
} }
pub mod d3d11_hello_triangle { pub mod d3d11_hello_triangle {
use std::path::Path;
use super::*; use super::*;
use gfx_maths::{Quaternion, Vec3}; use gfx_maths::{Quaternion, Vec3};
use std::slice; use std::slice;
use std::time::Instant; use std::time::Instant;
use librashader_common::Size;
use crate::filter_chain::FilterChain;
use crate::framebuffer::OutputFramebuffer;
use crate::texture::DxImageView;
const FRAME_COUNT: u32 = 2; const FRAME_COUNT: u32 = 2;
@ -240,6 +241,7 @@ pub mod d3d11_hello_triangle {
pub device: ID3D11Device, pub device: ID3D11Device,
pub context: ID3D11DeviceContext, pub context: ID3D11DeviceContext,
pub resources: Option<Resources>, pub resources: Option<Resources>,
pub filter: FilterChain,
} }
pub struct Resources { pub struct Resources {
@ -259,18 +261,24 @@ pub mod d3d11_hello_triangle {
pub backbuffer: ID3D11Texture2D, pub backbuffer: ID3D11Texture2D,
pub rtv: ID3D11RenderTargetView, pub rtv: ID3D11RenderTargetView,
pub viewport: D3D11_VIEWPORT, pub viewport: D3D11_VIEWPORT,
pub shader_output: Option<ID3D11Texture2D>
} }
impl DXSample for Sample {
fn new() -> Result<Self> {
let (dxgi_factory, device, context) = create_device()?;
impl Sample {
pub(crate) fn new(filter: impl AsRef<Path>) -> Result<Self> {
let (dxgi_factory, device, context) = create_device()?;
let filter = FilterChain::load_from_path(&device, filter).unwrap();
Ok(Sample { Ok(Sample {
filter,
dxgi_factory, dxgi_factory,
device, device,
context, context,
resources: None, resources: None,
}) })
} }
}
impl DXSample for Sample {
fn bind_to_window(&mut self, hwnd: &HWND) -> Result<()> { fn bind_to_window(&mut self, hwnd: &HWND) -> Result<()> {
let swapchain = create_swapchain(&self.dxgi_factory, &self.device, *hwnd)?; let swapchain = create_swapchain(&self.dxgi_factory, &self.device, *hwnd)?;
@ -308,6 +316,7 @@ pub mod d3d11_hello_triangle {
self.context.RSSetState(&raster_state); self.context.RSSetState(&raster_state);
} }
self.resources = Some(Resources { self.resources = Some(Resources {
swapchain, swapchain,
rtv, rtv,
@ -332,6 +341,7 @@ pub mod d3d11_hello_triangle {
MinDepth: D3D11_MIN_DEPTH, MinDepth: D3D11_MIN_DEPTH,
MaxDepth: D3D11_MAX_DEPTH, MaxDepth: D3D11_MAX_DEPTH,
}, },
shader_output: None,
}); });
Ok(()) Ok(())
@ -422,6 +432,64 @@ pub mod d3d11_hello_triangle {
self.context.DrawIndexed(3, 0, 0); self.context.DrawIndexed(3, 0, 0);
} }
unsafe {
let mut tex2d_desc = Default::default();
resources.backbuffer.GetDesc(&mut tex2d_desc);
let backup = self.device.CreateTexture2D(&D3D11_TEXTURE2D_DESC {
BindFlags: D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET,
CPUAccessFlags: D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE,
..tex2d_desc
}, None)?;
self.context.CopyResource(&backup, &resources.backbuffer);
let srv = self.device.CreateShaderResourceView(&backup, Some(&D3D11_SHADER_RESOURCE_VIEW_DESC {
Format: tex2d_desc.Format,
ViewDimension: D3D_SRV_DIMENSION_TEXTURE2D,
Anonymous: D3D11_SHADER_RESOURCE_VIEW_DESC_0 {
Texture2D: D3D11_TEX2D_SRV {
MostDetailedMip: 0,
MipLevels: u32::MAX,
}
},
}))?;
let shader_out = self.device.CreateTexture2D(&tex2d_desc, None)?;
let rtv = self.device.CreateRenderTargetView(&shader_out, Some(&D3D11_RENDER_TARGET_VIEW_DESC {
Format: tex2d_desc.Format,
ViewDimension: D3D11_RTV_DIMENSION_TEXTURE2D,
Anonymous: D3D11_RENDER_TARGET_VIEW_DESC_0 {
Texture2D: D3D11_TEX2D_RTV {
MipSlice: 0,
}
}
}))?;
//
self.filter.frame(1, &Size {
width: tex2d_desc.Width,
height: tex2d_desc.Height,
}, DxImageView { handle: srv, size: Size {
width: tex2d_desc.Width,
height: tex2d_desc.Height,
} }, OutputFramebuffer {
rtv,
size: Size {
width: tex2d_desc.Width,
height: tex2d_desc.Height,
},
viewport: D3D11_VIEWPORT {
TopLeftX: 0.0,
TopLeftY: 0.0,
Width: tex2d_desc.Width as f32,
Height: tex2d_desc.Height as f32,
MinDepth: 0.0,
MaxDepth: 1.0,
},
}).unwrap();
}
unsafe { unsafe {
resources.swapchain.Present(0, 0).ok()?; resources.swapchain.Present(0, 0).ok()?;
} }

View file

@ -25,6 +25,7 @@ mod util;
mod samplers; mod samplers;
mod render_target; mod render_target;
mod framebuffer; mod framebuffer;
mod quad_render;
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
@ -33,10 +34,8 @@ mod tests {
#[test] #[test]
fn triangle_d3d11() { fn triangle_d3d11() {
let sample = hello_triangle::d3d11_hello_triangle::Sample::new().unwrap(); let sample = hello_triangle::d3d11_hello_triangle::Sample::new("../test/slang-shaders/crt/crt-royale.slangp").unwrap();
let device = sample.device.clone();
let chain = filter_chain::FilterChain::load_from_path(&device, "../test/slang-shaders/crt/crt-royale.slangp").unwrap();
std::mem::forget(chain);
hello_triangle::main(sample).unwrap(); hello_triangle::main(sample).unwrap();
} }

View file

@ -0,0 +1,106 @@
use bytemuck::offset_of;
use windows::core::PCSTR;
use windows::Win32::Graphics::Direct3D11::{D3D11_BIND_VERTEX_BUFFER, D3D11_BUFFER_DESC, D3D11_INPUT_ELEMENT_DESC, D3D11_INPUT_PER_VERTEX_DATA, D3D11_SUBRESOURCE_DATA, D3D11_USAGE_IMMUTABLE, ID3D11Buffer, ID3D11Device, ID3D11DeviceContext};
use windows::Win32::Graphics::Direct3D::D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
use windows::Win32::Graphics::Dxgi::Common::DXGI_FORMAT_R32G32_FLOAT;
use crate::util;
#[repr(C)]
#[derive(Debug, Copy, Clone, Default)]
struct D3D11Vertex {
position: [f32; 2],
texcoord: [f32; 2],
color: [f32; 4]
}
const CLEAR: [f32; 4] = [1.0, 1.0, 1.0, 1.0];
static QUAD_VBO_DATA: &'static [D3D11Vertex; 4] = &[
D3D11Vertex {
position: [0.0, 0.0],
texcoord: [0.0, 1.0],
color: CLEAR,
},
D3D11Vertex {
position: [0.0, 1.0],
texcoord: [0.0, 0.0],
color: CLEAR,
},
D3D11Vertex {
position: [1.0, 0.0],
texcoord: [1.0, 1.0],
color: CLEAR,
},
D3D11Vertex {
position: [1.0, 1.0],
texcoord: [1.0, 0.0],
color: CLEAR,
},
];
pub(crate) struct DrawQuad {
buffer: ID3D11Buffer,
context: ID3D11DeviceContext,
offset: u32,
stride: u32,
}
impl DrawQuad {
pub fn new(device: &ID3D11Device, context: &ID3D11DeviceContext) -> util::Result<DrawQuad> {
unsafe {
let buffer = device.CreateBuffer(&D3D11_BUFFER_DESC {
ByteWidth: std::mem::size_of::<[D3D11Vertex; 4]>() as u32,
Usage: D3D11_USAGE_IMMUTABLE,
BindFlags: D3D11_BIND_VERTEX_BUFFER,
CPUAccessFlags: Default::default(),
MiscFlags: Default::default(),
StructureByteStride: 0,
}, Some(&D3D11_SUBRESOURCE_DATA {
pSysMem: QUAD_VBO_DATA.as_ptr().cast(),
SysMemPitch: 0,
SysMemSlicePitch: 0,
}))?;
Ok(DrawQuad {
buffer,
context: context.clone(),
offset: 0,
stride: std::mem::size_of::<D3D11Vertex>() as u32
})
}
}
pub fn bind_vertices(&self) {
unsafe {
self.context.IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
self.context.IASetVertexBuffers(0, 1, Some(&Some(self.buffer.clone())),
Some(&self.stride), Some(&self.offset));
}
}
pub fn get_spirv_cross_vbo_desc() -> [D3D11_INPUT_ELEMENT_DESC; 2] {
[
D3D11_INPUT_ELEMENT_DESC {
SemanticName: PCSTR(b"TEXCOORD\0".as_ptr()),
SemanticIndex: 0,
Format: DXGI_FORMAT_R32G32_FLOAT,
InputSlot: 0,
AlignedByteOffset: offset_of!(D3D11Vertex, position) as u32,
InputSlotClass: D3D11_INPUT_PER_VERTEX_DATA,
InstanceDataStepRate: 0,
},
D3D11_INPUT_ELEMENT_DESC {
SemanticName: PCSTR(b"TEXCOORD\0".as_ptr()),
SemanticIndex: 1,
Format: DXGI_FORMAT_R32G32_FLOAT,
InputSlot: 0,
AlignedByteOffset: offset_of!(D3D11Vertex, texcoord) as u32,
InputSlotClass: D3D11_INPUT_PER_VERTEX_DATA,
InstanceDataStepRate: 0,
}
]
}
}

View file

@ -7,9 +7,13 @@ use crate::util::d3d11_get_closest_format;
use crate::util::Result; use crate::util::Result;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Texture { pub struct DxImageView {
pub handle: ID3D11ShaderResourceView, pub handle: ID3D11ShaderResourceView,
pub size: Size<u32>, // pub image: GlImage, pub size: Size<u32>, // pub image: GlImage,
}
#[derive(Debug, Clone)]
pub struct Texture {
pub view: DxImageView,
pub filter: FilterMode, pub filter: FilterMode,
pub wrap_mode: WrapMode, pub wrap_mode: WrapMode,
// pub mip_filter: FilterMode, // pub mip_filter: FilterMode,
@ -135,8 +139,10 @@ impl OwnedTexture {
// staging, // staging,
desc, desc,
image: Texture { image: Texture {
handle: srv, view: DxImageView {
size: source.size, handle: srv,
size: source.size,
},
filter, filter,
wrap_mode wrap_mode
} }

View file

@ -666,6 +666,7 @@ impl FilterChain {
} else { } else {
count count
} as u32, } as u32,
// todo: put this in options
1, 1,
viewport, viewport,
&original, &original,