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::Size;
use librashader_preprocess::ShaderSource;
@ -15,13 +15,17 @@ use std::path::Path;
use bytemuck::offset_of;
use windows::core::PCSTR;
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 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::util;
use crate::util::d3d11_compile_bound_shader;
// todo: get rid of preset
type ShaderPassMeta<'a> = (
&'a ShaderPassConfig,
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 common: FilterCommon,
pub passes: Vec<FilterPass>,
@ -53,6 +49,7 @@ pub struct FilterCommon {
pub(crate) preset: ShaderPreset,
pub(crate) luts: FxHashMap<usize, OwnedTexture>,
pub samplers: SamplerSet,
pub(crate) draw_quad: DrawQuad,
}
impl FilterChain {
@ -108,7 +105,7 @@ impl FilterChain {
fn create_constant_buffer(device: &ID3D11Device, size: u32) -> util::Result<ID3D11Buffer> {
eprintln!("{size}");
unsafe {
let buffer = device.CreateBuffer(&D3D11_BUFFER_DESC {
let buffer = device.CreateBuffer(&D3D11_BUFFER_DESC {
ByteWidth: size,
Usage: D3D11_USAGE_DYNAMIC,
BindFlags: D3D11_BIND_CONSTANT_BUFFER,
@ -142,27 +139,8 @@ impl FilterChain {
let vs = d3d11_compile_bound_shader(device, &vertex_dxil, None,
ID3D11Device::CreateVertexShader)?;
let ia_desc = [
D3D11_INPUT_ELEMENT_DESC {
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 ia_desc = DrawQuad::get_spirv_cross_vbo_desc();
let vao = util::d3d11_create_input_layout(device, &ia_desc, &vertex_dxil)?;
let fragment_dxil = util::d3d_compile_shader(
hlsl.fragment.as_bytes(),
@ -223,7 +201,7 @@ impl FilterChain {
reflection,
compiled: hlsl,
vertex_shader: vs,
vertex_layout: vertex_ia,
vertex_layout: vao,
pixel_shader: ps,
uniform_bindings,
uniform_buffer: ConstantBuffer::new(ubo_cbuffer),
@ -231,7 +209,6 @@ impl FilterChain {
source,
config: config.clone(),
})
}
Ok(filters)
}
@ -273,6 +250,8 @@ impl FilterChain {
unsafe {
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
Ok(FilterChain {
@ -284,7 +263,7 @@ impl FilterChain {
common: FilterCommon {
d3d11: Direct3D11 {
device: device.clone(),
device_context: device_context.unwrap()
device_context
},
luts,
samplers,
@ -294,7 +273,7 @@ impl FilterChain {
// output_textures: output_textures.into_boxed_slice(),
// feedback_textures: feedback_textures.into_boxed_slice(),
// history_textures,
// draw_quad,
draw_quad,
},
})
}
@ -397,4 +376,38 @@ impl FilterChain {
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,
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());
}
@ -180,7 +180,7 @@ impl FilterPass {
MemberOffset::Ubo(offset) => (&mut self.uniform_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
@ -203,7 +203,7 @@ impl FilterPass {
MemberOffset::Ubo(offset) => (&mut self.uniform_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
@ -223,7 +223,7 @@ impl FilterPass {
MemberOffset::Ubo(offset) => (&mut self.uniform_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() {
@ -365,7 +365,7 @@ impl FilterPass {
};
FilterPass::build_vec4(
&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;
pub trait DXSample {
fn new() -> Result<Self>
where
Self: Sized;
fn bind_to_window(&mut self, hwnd: &HWND) -> Result<()>;
fn update(&mut self) {}
@ -228,10 +224,15 @@ struct TriangleUniforms {
}
pub mod d3d11_hello_triangle {
use std::path::Path;
use super::*;
use gfx_maths::{Quaternion, Vec3};
use std::slice;
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;
@ -240,6 +241,7 @@ pub mod d3d11_hello_triangle {
pub device: ID3D11Device,
pub context: ID3D11DeviceContext,
pub resources: Option<Resources>,
pub filter: FilterChain,
}
pub struct Resources {
@ -259,18 +261,24 @@ pub mod d3d11_hello_triangle {
pub backbuffer: ID3D11Texture2D,
pub rtv: ID3D11RenderTargetView,
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 {
filter,
dxgi_factory,
device,
context,
resources: None,
})
}
}
impl DXSample for Sample {
fn bind_to_window(&mut self, hwnd: &HWND) -> Result<()> {
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.resources = Some(Resources {
swapchain,
rtv,
@ -332,6 +341,7 @@ pub mod d3d11_hello_triangle {
MinDepth: D3D11_MIN_DEPTH,
MaxDepth: D3D11_MAX_DEPTH,
},
shader_output: None,
});
Ok(())
@ -422,6 +432,64 @@ pub mod d3d11_hello_triangle {
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 {
resources.swapchain.Present(0, 0).ok()?;
}

View file

@ -25,6 +25,7 @@ mod util;
mod samplers;
mod render_target;
mod framebuffer;
mod quad_render;
#[cfg(test)]
mod tests {
@ -33,10 +34,8 @@ mod tests {
#[test]
fn triangle_d3d11() {
let sample = hello_triangle::d3d11_hello_triangle::Sample::new().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);
let sample = hello_triangle::d3d11_hello_triangle::Sample::new("../test/slang-shaders/crt/crt-royale.slangp").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;
#[derive(Debug, Clone)]
pub struct Texture {
pub struct DxImageView {
pub handle: ID3D11ShaderResourceView,
pub size: Size<u32>, // pub image: GlImage,
}
#[derive(Debug, Clone)]
pub struct Texture {
pub view: DxImageView,
pub filter: FilterMode,
pub wrap_mode: WrapMode,
// pub mip_filter: FilterMode,
@ -135,8 +139,10 @@ impl OwnedTexture {
// staging,
desc,
image: Texture {
handle: srv,
size: source.size,
view: DxImageView {
handle: srv,
size: source.size,
},
filter,
wrap_mode
}

View file

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