From 2c953d638fa9b4587d18ae67442250935217d208 Mon Sep 17 00:00:00 2001 From: chyyran Date: Mon, 28 Nov 2022 21:00:54 -0500 Subject: [PATCH] dx11: get single pass working --- librashader-runtime-d3d11/src/filter_chain.rs | 85 ++++++++------ librashader-runtime-d3d11/src/filter_pass.rs | 10 +- .../src/hello_triangle.rs | 82 ++++++++++++-- librashader-runtime-d3d11/src/lib.rs | 7 +- librashader-runtime-d3d11/src/quad_render.rs | 106 ++++++++++++++++++ librashader-runtime-d3d11/src/texture.rs | 12 +- librashader-runtime-gl/src/filter_chain.rs | 1 + 7 files changed, 248 insertions(+), 55 deletions(-) diff --git a/librashader-runtime-d3d11/src/filter_chain.rs b/librashader-runtime-d3d11/src/filter_chain.rs index ed158df..5675bd1 100644 --- a/librashader-runtime-d3d11/src/filter_chain.rs +++ b/librashader-runtime-d3d11/src/filter_chain.rs @@ -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, @@ -53,6 +49,7 @@ pub struct FilterCommon { pub(crate) preset: ShaderPreset, pub(crate) luts: FxHashMap, 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 { 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, 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(()) + + } } diff --git a/librashader-runtime-d3d11/src/filter_pass.rs b/librashader-runtime-d3d11/src/filter_pass.rs index 5264749..007c2a9 100644 --- a/librashader-runtime-d3d11/src/filter_pass.rs +++ b/librashader-runtime-d3d11/src/filter_pass.rs @@ -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, ); } } diff --git a/librashader-runtime-d3d11/src/hello_triangle.rs b/librashader-runtime-d3d11/src/hello_triangle.rs index ee9aea6..a94fadb 100644 --- a/librashader-runtime-d3d11/src/hello_triangle.rs +++ b/librashader-runtime-d3d11/src/hello_triangle.rs @@ -67,10 +67,6 @@ use gfx_maths::Mat4; use std::mem::transmute; pub trait DXSample { - fn new() -> Result - 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, + 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 } - impl DXSample for Sample { - fn new() -> Result { - let (dxgi_factory, device, context) = create_device()?; + impl Sample { + pub(crate) fn new(filter: impl AsRef) -> Result { + 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()?; } diff --git a/librashader-runtime-d3d11/src/lib.rs b/librashader-runtime-d3d11/src/lib.rs index 37d6867..ef5efa6 100644 --- a/librashader-runtime-d3d11/src/lib.rs +++ b/librashader-runtime-d3d11/src/lib.rs @@ -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(); } diff --git a/librashader-runtime-d3d11/src/quad_render.rs b/librashader-runtime-d3d11/src/quad_render.rs index e69de29..516ae4e 100644 --- a/librashader-runtime-d3d11/src/quad_render.rs +++ b/librashader-runtime-d3d11/src/quad_render.rs @@ -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 { + 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::() 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, + } + ] + } +} \ No newline at end of file diff --git a/librashader-runtime-d3d11/src/texture.rs b/librashader-runtime-d3d11/src/texture.rs index a33a17f..33c2091 100644 --- a/librashader-runtime-d3d11/src/texture.rs +++ b/librashader-runtime-d3d11/src/texture.rs @@ -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, // 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 } diff --git a/librashader-runtime-gl/src/filter_chain.rs b/librashader-runtime-gl/src/filter_chain.rs index e6971e0..e7c54fc 100644 --- a/librashader-runtime-gl/src/filter_chain.rs +++ b/librashader-runtime-gl/src/filter_chain.rs @@ -666,6 +666,7 @@ impl FilterChain { } else { count } as u32, + // todo: put this in options 1, viewport, &original,