diff --git a/Cargo.lock b/Cargo.lock index da66abe..8a91bd0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -491,6 +491,8 @@ dependencies = [ "librashader-reflect", "librashader-runtime", "rustc-hash", + "spirv_cross", + "thiserror", "windows", ] diff --git a/librashader-runtime-d3d11/Cargo.toml b/librashader-runtime-d3d11/Cargo.toml index 2b49630..c8830b1 100644 --- a/librashader-runtime-d3d11/Cargo.toml +++ b/librashader-runtime-d3d11/Cargo.toml @@ -11,9 +11,10 @@ librashader-presets = { path = "../librashader-presets" } librashader-preprocess = { path = "../librashader-preprocess" } librashader-reflect = { path = "../librashader-reflect" } librashader-runtime = { path = "../librashader-runtime" } +thiserror = "1.0.37" +spirv_cross = "0.23.1" rustc-hash = "1.1.0" -gfx-maths = "0.2.8" bytemuck = "1.12.3" [dependencies.windows] @@ -33,3 +34,4 @@ features = [ ] [dev-dependencies] +gfx-maths = "0.2.8" diff --git a/librashader-runtime-d3d11/src/error.rs b/librashader-runtime-d3d11/src/error.rs new file mode 100644 index 0000000..3db0aab --- /dev/null +++ b/librashader-runtime-d3d11/src/error.rs @@ -0,0 +1,25 @@ +use librashader_common::image::ImageError; +use librashader_preprocess::PreprocessError; +use librashader_presets::ParsePresetError; +use librashader_reflect::error::{ShaderCompileError, ShaderReflectError}; +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum FilterChainError { + #[error("unable to get direct3d context")] + Direct3DContextError, + #[error("direct3d driver error")] + Direct3DError(#[from] windows::core::Error), + #[error("SPIRV reflection error")] + SpirvCrossReflectError(#[from] spirv_cross::ErrorCode), + #[error("shader preset parse error")] + ShaderPresetError(#[from] ParsePresetError), + #[error("shader preprocess error")] + ShaderPreprocessError(#[from] PreprocessError), + #[error("shader compile error")] + ShaderCompileError(#[from] ShaderCompileError), + #[error("shader reflect error")] + ShaderReflectError(#[from] ShaderReflectError), + #[error("lut loading error")] + LutLoadError(#[from] ImageError), +} diff --git a/librashader-runtime-d3d11/src/filter_chain.rs b/librashader-runtime-d3d11/src/filter_chain.rs index 142b32d..d8d796a 100644 --- a/librashader-runtime-d3d11/src/filter_chain.rs +++ b/librashader-runtime-d3d11/src/filter_chain.rs @@ -1,4 +1,4 @@ -use crate::texture::{DxImageView, OwnedTexture, Texture}; +use crate::texture::{DxImageView, LutTexture, Texture}; use librashader_common::image::Image; use librashader_common::{ImageFormat, Size}; use librashader_preprocess::ShaderSource; @@ -31,10 +31,16 @@ use windows::Win32::Graphics::Direct3D11::{ D3D11_TEXTURE2D_DESC, D3D11_USAGE_DEFAULT, D3D11_USAGE_DYNAMIC, }; use windows::Win32::Graphics::Dxgi::Common::{DXGI_FORMAT, DXGI_FORMAT_R8G8B8A8_UNORM}; +use crate::error::FilterChainError; + +pub struct FilterMutable { + pub(crate) passes_enabled: usize, + pub(crate) parameters: FxHashMap, +} // todo: get rid of preset -type ShaderPassMeta<'a> = ( - &'a ShaderPassConfig, +type ShaderPassMeta = ( + ShaderPassConfig, ShaderSource, CompilerBackend< impl CompileShader, Context = GlslangHlslContext> + ReflectShader, @@ -53,16 +59,17 @@ pub struct FilterChain { pub struct Direct3D11 { pub(crate) device: ID3D11Device, pub(crate) device_context: ID3D11DeviceContext, + pub context_is_deferred: bool } pub struct FilterCommon { pub(crate) d3d11: Direct3D11, - pub(crate) preset: ShaderPreset, - pub(crate) luts: FxHashMap, + pub(crate) luts: FxHashMap, pub samplers: SamplerSet, pub output_textures: Box<[Option]>, pub feedback_textures: Box<[Option]>, pub history_textures: Box<[Option]>, + pub config: FilterMutable } impl FilterChain { @@ -188,17 +195,18 @@ impl FilterChain { device: &ID3D11Device, preset: ShaderPreset, ) -> util::Result { - let (passes, semantics) = FilterChain::load_preset(&preset)?; + let (passes, semantics) = FilterChain::load_preset(preset.shaders, &preset.textures)?; let samplers = SamplerSet::new(device)?; // initialize passes - let filters = FilterChain::init_passes(device, passes, &semantics).unwrap(); + let filters = FilterChain::init_passes(device, passes, &semantics)?; let mut device_context = None; unsafe { device.GetImmediateContext(&mut device_context); } + let device_context = device_context.unwrap(); let device_context = @@ -214,8 +222,12 @@ impl FilterChain { Size::new(1, 1), ImageFormat::R8G8B8A8Unorm, ) - .unwrap() }); + + // resolve all results + let output_framebuffers = output_framebuffers + .into_iter().collect::>>()?; + let mut output_textures = Vec::new(); output_textures.resize_with(filters.len(), || None); // @@ -228,16 +240,20 @@ impl FilterChain { Size::new(1, 1), ImageFormat::R8G8B8A8Unorm, ) - .unwrap() }); + // resolve all results + let feedback_framebuffers = feedback_framebuffers + .into_iter().collect::>>()?; + let mut feedback_textures = Vec::new(); feedback_textures.resize_with(filters.len(), || None); // load luts - let luts = FilterChain::load_luts(device, &preset.textures)?; + let luts = FilterChain::load_luts(device, + &device_context, &preset.textures)?; let (history_framebuffers, history_textures) = - FilterChain::init_history(device, &device_context, &filters); + FilterChain::init_history(device, &device_context, &filters)?; let draw_quad = DrawQuad::new(device, &device_context)?; @@ -252,12 +268,18 @@ impl FilterChain { d3d11: Direct3D11 { device: device.clone(), device_context, + context_is_deferred: false + }, + config: FilterMutable { + passes_enabled: preset.shader_count as usize, + parameters: preset + .parameters + .into_iter() + .map(|param| (param.name, param.value)) + .collect(), }, luts, samplers, - // we don't need the reflect semantics once all locations have been bound per pass. - // semantics, - preset, output_textures: output_textures.into_boxed_slice(), feedback_textures: feedback_textures.into_boxed_slice(), history_textures, @@ -269,7 +291,7 @@ impl FilterChain { device: &ID3D11Device, context: &ID3D11DeviceContext, filters: &[FilterPass], - ) -> (VecDeque, Box<[Option]>) { + ) -> util::Result<(VecDeque, Box<[Option]>)> { let mut required_images = 0; for pass in filters { @@ -296,7 +318,7 @@ impl FilterChain { // not using frame history; if required_images <= 1 { println!("[history] not using frame history"); - return (VecDeque::new(), Box::new([])); + return Ok((VecDeque::new(), Box::new([]))); } // history0 is aliased with the original @@ -305,13 +327,15 @@ impl FilterChain { let mut framebuffers = VecDeque::with_capacity(required_images); framebuffers.resize_with(required_images, || { OwnedFramebuffer::new(device, context, Size::new(1, 1), ImageFormat::R8G8B8A8Unorm) - .unwrap() }); + let framebuffers = framebuffers + .into_iter().collect::>>()?; + let mut history_textures = Vec::new(); history_textures.resize_with(required_images, || None); - (framebuffers, history_textures.into_boxed_slice()) + Ok((framebuffers, history_textures.into_boxed_slice())) } fn push_history(&mut self, input: &DxImageView) -> util::Result<()> { @@ -325,8 +349,9 @@ impl FilterChain { fn load_luts( device: &ID3D11Device, + context: &ID3D11DeviceContext, textures: &[TextureConfig], - ) -> util::Result> { + ) -> util::Result> { let mut luts = FxHashMap::default(); for (index, texture) in textures.iter().enumerate() { @@ -345,7 +370,7 @@ impl FilterChain { }; let texture = - OwnedTexture::new(device, &image, desc, texture.filter_mode, texture.wrap_mode)?; + LutTexture::new(device, context,&image, desc, texture.filter_mode, texture.wrap_mode)?; luts.insert(index, texture); } Ok(luts) @@ -361,14 +386,15 @@ impl FilterChain { Self::load_from_preset(device, preset) } - fn load_preset(preset: &ShaderPreset) -> util::Result<(Vec, ReflectSemantics)> { + fn load_preset( passes: Vec, + textures: &[TextureConfig], + ) -> util::Result<(Vec, ReflectSemantics)> { let mut uniform_semantics: FxHashMap = Default::default(); let mut texture_semantics: FxHashMap> = Default::default(); - let passes = preset - .shaders - .iter() + let passes = passes + .into_iter() .map(|shader| { eprintln!("[dx11] loading {}", &shader.name.display()); let source: ShaderSource = ShaderSource::load(&shader.name)?; @@ -385,21 +411,21 @@ impl FilterChain { }), ); } - Ok::<_, Box>((shader, source, reflect)) + Ok::<_, FilterChainError>((shader, source, reflect)) }) .into_iter() - .collect::)>>>( + .collect::)>>>( )?; for details in &passes { librashader_runtime::semantics::insert_pass_semantics( &mut uniform_semantics, &mut texture_semantics, - details.0, + &details.0, ) } librashader_runtime::semantics::insert_lut_semantics( - &preset.textures, + &textures, &mut uniform_semantics, &mut texture_semantics, ); @@ -476,12 +502,12 @@ impl FilterChain { viewport, &original, &source, - RenderTarget::new(target.as_output_framebuffer().unwrap(), None), + RenderTarget::new(target.as_output_framebuffer()?, None), )?; source = Texture { view: DxImageView { - handle: target.create_shader_resource_view().unwrap(), + handle: target.create_shader_resource_view()?, size, }, filter, diff --git a/librashader-runtime-d3d11/src/filter_pass.rs b/librashader-runtime-d3d11/src/filter_pass.rs index 4230c06..f6b29ac 100644 --- a/librashader-runtime-d3d11/src/filter_pass.rs +++ b/librashader-runtime-d3d11/src/filter_pass.rs @@ -20,6 +20,7 @@ use windows::Win32::Graphics::Direct3D11::{ use crate::render_target::RenderTarget; use crate::samplers::SamplerSet; use librashader_runtime::uniforms::UniformStorage; +use crate::util; pub struct ConstantBufferBinding { pub binding: u32, @@ -310,13 +311,7 @@ impl FilterPass { .map(|f| f.initial) .unwrap_or(0f32); - let value = parent - .preset - .parameters - .iter() - .find(|&p| p.name == id) - .map(|p| p.value) - .unwrap_or(default); + let value = *parent.config.parameters.get(id).unwrap_or(&default); self.uniform_storage.bind_scalar(*offset, value, None); } @@ -360,7 +355,7 @@ impl FilterPass { original: &Texture, source: &Texture, output: RenderTarget, - ) -> std::result::Result<(), Box> { + ) -> util::Result<()> { let _device = &parent.d3d11.device; let context = &parent.d3d11.device_context; unsafe { diff --git a/librashader-runtime-d3d11/src/framebuffer.rs b/librashader-runtime-d3d11/src/framebuffer.rs index 21a3014..9e1682e 100644 --- a/librashader-runtime-d3d11/src/framebuffer.rs +++ b/librashader-runtime-d3d11/src/framebuffer.rs @@ -155,9 +155,10 @@ impl OwnedFramebuffer { let resource: ID3D11Texture2D = unsafe { let mut resource = None; image.handle.GetResource(&mut resource); - - // todo: make panic-free - resource.unwrap().cast()? + let Some(resource) = resource else { + return Ok(()) + }; + resource.cast()? }; let format = unsafe { diff --git a/librashader-runtime-d3d11/src/lib.rs b/librashader-runtime-d3d11/src/lib.rs index cb4f5e6..54e105a 100644 --- a/librashader-runtime-d3d11/src/lib.rs +++ b/librashader-runtime-d3d11/src/lib.rs @@ -1,17 +1,18 @@ #![feature(type_alias_impl_trait)] #![feature(let_chains)] -mod filter_chain; - -mod filter_pass; -mod framebuffer; #[cfg(test)] mod hello_triangle; + +mod filter_chain; +mod filter_pass; +mod framebuffer; mod quad_render; mod render_target; mod samplers; mod texture; mod util; +pub mod error; #[cfg(test)] mod tests { diff --git a/librashader-runtime-d3d11/src/texture.rs b/librashader-runtime-d3d11/src/texture.rs index d29873d..edf8122 100644 --- a/librashader-runtime-d3d11/src/texture.rs +++ b/librashader-runtime-d3d11/src/texture.rs @@ -1,48 +1,40 @@ use librashader_common::image::Image; use librashader_common::{FilterMode, Size, WrapMode}; use windows::Win32::Graphics::Direct3D::D3D_SRV_DIMENSION_TEXTURE2D; -use windows::Win32::Graphics::Direct3D11::{ - ID3D11Device, ID3D11ShaderResourceView, ID3D11Texture2D, D3D11_BIND_FLAG, - D3D11_BIND_RENDER_TARGET, D3D11_BIND_SHADER_RESOURCE, D3D11_BOX, D3D11_CPU_ACCESS_FLAG, - D3D11_CPU_ACCESS_WRITE, D3D11_FORMAT_SUPPORT_RENDER_TARGET, D3D11_FORMAT_SUPPORT_SHADER_SAMPLE, - D3D11_FORMAT_SUPPORT_TEXTURE2D, D3D11_RESOURCE_MISC_FLAG, D3D11_RESOURCE_MISC_GENERATE_MIPS, - D3D11_SHADER_RESOURCE_VIEW_DESC, D3D11_SHADER_RESOURCE_VIEW_DESC_0, D3D11_SUBRESOURCE_DATA, - D3D11_TEX2D_SRV, D3D11_TEXTURE2D_DESC, D3D11_USAGE_DYNAMIC, D3D11_USAGE_STAGING, -}; +use windows::Win32::Graphics::Direct3D11::{ID3D11Device, ID3D11ShaderResourceView, ID3D11Texture2D, D3D11_BIND_FLAG, D3D11_BIND_RENDER_TARGET, D3D11_BIND_SHADER_RESOURCE, D3D11_BOX, D3D11_CPU_ACCESS_FLAG, D3D11_CPU_ACCESS_WRITE, D3D11_FORMAT_SUPPORT_RENDER_TARGET, D3D11_FORMAT_SUPPORT_SHADER_SAMPLE, D3D11_FORMAT_SUPPORT_TEXTURE2D, D3D11_RESOURCE_MISC_FLAG, D3D11_RESOURCE_MISC_GENERATE_MIPS, D3D11_SHADER_RESOURCE_VIEW_DESC, D3D11_SHADER_RESOURCE_VIEW_DESC_0, D3D11_SUBRESOURCE_DATA, D3D11_TEX2D_SRV, D3D11_TEXTURE2D_DESC, D3D11_USAGE_DYNAMIC, D3D11_USAGE_STAGING, ID3D11DeviceContext}; use windows::Win32::Graphics::Dxgi::Common::DXGI_SAMPLE_DESC; +use crate::filter_chain::Direct3D11; use crate::util::Result; #[derive(Debug, Clone)] pub struct DxImageView { pub handle: ID3D11ShaderResourceView, - pub size: Size, // pub image: GlImage, + pub size: Size, } #[derive(Debug, Clone)] pub struct Texture { pub view: DxImageView, pub filter: FilterMode, pub wrap_mode: WrapMode, - // pub mip_filter: FilterMode, - // pub wrap_mode: WrapMode, } #[derive(Debug, Clone)] -pub struct OwnedTexture { +pub struct LutTexture { pub handle: ID3D11Texture2D, - // pub staging: ID3D11Texture2D, pub desc: D3D11_TEXTURE2D_DESC, pub image: Texture, } -impl OwnedTexture { +impl LutTexture { pub fn new( device: &ID3D11Device, + context: &ID3D11DeviceContext, source: &Image, desc: D3D11_TEXTURE2D_DESC, filter: FilterMode, wrap_mode: WrapMode, - ) -> Result { + ) -> Result { let mut desc = D3D11_TEXTURE2D_DESC { Width: source.size.width, Height: source.size.height, @@ -107,12 +99,6 @@ impl OwnedTexture { }), )?; - let mut context = None; - device.GetImmediateContext(&mut context); - - // todo: make this fallible - let context = context.unwrap(); - // need a staging texture to defer mipmap generation let staging = device.CreateTexture2D( &D3D11_TEXTURE2D_DESC { @@ -158,7 +144,7 @@ impl OwnedTexture { // let mut subresource = context.Map(staging, 0, D3D11_MAP_WRITE, 0)?; // staging.Upd - Ok(OwnedTexture { + Ok(LutTexture { handle, // staging, desc, diff --git a/librashader-runtime-d3d11/src/util.rs b/librashader-runtime-d3d11/src/util.rs index e0daaf3..355329c 100644 --- a/librashader-runtime-d3d11/src/util.rs +++ b/librashader-runtime-d3d11/src/util.rs @@ -167,4 +167,4 @@ pub fn d3d11_create_input_layout( } // todo: d3d11.c 2097 -pub type Result = std::result::Result>; +pub type Result = std::result::Result; diff --git a/librashader-runtime-gl/src/filter_pass.rs b/librashader-runtime-gl/src/filter_pass.rs index 14cafc6..89802c7 100644 --- a/librashader-runtime-gl/src/filter_pass.rs +++ b/librashader-runtime-gl/src/filter_pass.rs @@ -32,7 +32,6 @@ pub struct FilterPass { } impl FilterPass { - // todo: fix rendertargets (i.e. non-final pass is internal, final pass is user provided fbo) pub(crate) fn draw( &mut self, pass_index: usize, diff --git a/librashader-runtime-gl/src/gl/gl46/framebuffer.rs b/librashader-runtime-gl/src/gl/gl46/framebuffer.rs index a16a65c..9e54e8c 100644 --- a/librashader-runtime-gl/src/gl/gl46/framebuffer.rs +++ b/librashader-runtime-gl/src/gl/gl46/framebuffer.rs @@ -89,6 +89,11 @@ impl FramebufferInterface for Gl46Framebuffer { } } fn copy_from(fb: &mut Framebuffer, image: &GLImage) -> Result<()> { + // todo: confirm this behaviour for unbound image. + if image.handle == 0 { + return Ok(()) + } + // todo: may want to use a shader and draw a quad to be faster. if image.size != fb.size || image.format != fb.format { Self::init(