d3d11: make error unboxed

This commit is contained in:
chyyran 2022-11-30 17:59:55 -05:00
parent 759cd4bc28
commit 6519a78df2
11 changed files with 112 additions and 70 deletions

2
Cargo.lock generated
View file

@ -491,6 +491,8 @@ dependencies = [
"librashader-reflect", "librashader-reflect",
"librashader-runtime", "librashader-runtime",
"rustc-hash", "rustc-hash",
"spirv_cross",
"thiserror",
"windows", "windows",
] ]

View file

@ -11,9 +11,10 @@ librashader-presets = { path = "../librashader-presets" }
librashader-preprocess = { path = "../librashader-preprocess" } librashader-preprocess = { path = "../librashader-preprocess" }
librashader-reflect = { path = "../librashader-reflect" } librashader-reflect = { path = "../librashader-reflect" }
librashader-runtime = { path = "../librashader-runtime" } librashader-runtime = { path = "../librashader-runtime" }
thiserror = "1.0.37"
spirv_cross = "0.23.1"
rustc-hash = "1.1.0" rustc-hash = "1.1.0"
gfx-maths = "0.2.8"
bytemuck = "1.12.3" bytemuck = "1.12.3"
[dependencies.windows] [dependencies.windows]
@ -33,3 +34,4 @@ features = [
] ]
[dev-dependencies] [dev-dependencies]
gfx-maths = "0.2.8"

View file

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

View file

@ -1,4 +1,4 @@
use crate::texture::{DxImageView, OwnedTexture, Texture}; use crate::texture::{DxImageView, LutTexture, Texture};
use librashader_common::image::Image; use librashader_common::image::Image;
use librashader_common::{ImageFormat, Size}; use librashader_common::{ImageFormat, Size};
use librashader_preprocess::ShaderSource; use librashader_preprocess::ShaderSource;
@ -31,10 +31,16 @@ use windows::Win32::Graphics::Direct3D11::{
D3D11_TEXTURE2D_DESC, D3D11_USAGE_DEFAULT, D3D11_USAGE_DYNAMIC, D3D11_TEXTURE2D_DESC, D3D11_USAGE_DEFAULT, D3D11_USAGE_DYNAMIC,
}; };
use windows::Win32::Graphics::Dxgi::Common::{DXGI_FORMAT, DXGI_FORMAT_R8G8B8A8_UNORM}; 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<String, f32>,
}
// todo: get rid of preset // todo: get rid of preset
type ShaderPassMeta<'a> = ( type ShaderPassMeta = (
&'a ShaderPassConfig, ShaderPassConfig,
ShaderSource, ShaderSource,
CompilerBackend< CompilerBackend<
impl CompileShader<HLSL, Options = Option<()>, Context = GlslangHlslContext> + ReflectShader, impl CompileShader<HLSL, Options = Option<()>, Context = GlslangHlslContext> + ReflectShader,
@ -53,16 +59,17 @@ pub struct FilterChain {
pub struct Direct3D11 { pub struct Direct3D11 {
pub(crate) device: ID3D11Device, pub(crate) device: ID3D11Device,
pub(crate) device_context: ID3D11DeviceContext, pub(crate) device_context: ID3D11DeviceContext,
pub context_is_deferred: bool
} }
pub struct FilterCommon { pub struct FilterCommon {
pub(crate) d3d11: Direct3D11, pub(crate) d3d11: Direct3D11,
pub(crate) preset: ShaderPreset, pub(crate) luts: FxHashMap<usize, LutTexture>,
pub(crate) luts: FxHashMap<usize, OwnedTexture>,
pub samplers: SamplerSet, pub samplers: SamplerSet,
pub output_textures: Box<[Option<Texture>]>, pub output_textures: Box<[Option<Texture>]>,
pub feedback_textures: Box<[Option<Texture>]>, pub feedback_textures: Box<[Option<Texture>]>,
pub history_textures: Box<[Option<Texture>]>, pub history_textures: Box<[Option<Texture>]>,
pub config: FilterMutable
} }
impl FilterChain { impl FilterChain {
@ -188,17 +195,18 @@ impl FilterChain {
device: &ID3D11Device, device: &ID3D11Device,
preset: ShaderPreset, preset: ShaderPreset,
) -> util::Result<FilterChain> { ) -> util::Result<FilterChain> {
let (passes, semantics) = FilterChain::load_preset(&preset)?; let (passes, semantics) = FilterChain::load_preset(preset.shaders, &preset.textures)?;
let samplers = SamplerSet::new(device)?; let samplers = SamplerSet::new(device)?;
// initialize passes // initialize passes
let filters = FilterChain::init_passes(device, passes, &semantics).unwrap(); let filters = FilterChain::init_passes(device, passes, &semantics)?;
let mut device_context = None; let mut device_context = None;
unsafe { unsafe {
device.GetImmediateContext(&mut device_context); device.GetImmediateContext(&mut device_context);
} }
let device_context = device_context.unwrap(); let device_context = device_context.unwrap();
let device_context = let device_context =
@ -214,8 +222,12 @@ impl FilterChain {
Size::new(1, 1), Size::new(1, 1),
ImageFormat::R8G8B8A8Unorm, ImageFormat::R8G8B8A8Unorm,
) )
.unwrap()
}); });
// resolve all results
let output_framebuffers = output_framebuffers
.into_iter().collect::<util::Result<Vec<OwnedFramebuffer>>>()?;
let mut output_textures = Vec::new(); let mut output_textures = Vec::new();
output_textures.resize_with(filters.len(), || None); output_textures.resize_with(filters.len(), || None);
// //
@ -228,16 +240,20 @@ impl FilterChain {
Size::new(1, 1), Size::new(1, 1),
ImageFormat::R8G8B8A8Unorm, ImageFormat::R8G8B8A8Unorm,
) )
.unwrap()
}); });
// resolve all results
let feedback_framebuffers = feedback_framebuffers
.into_iter().collect::<util::Result<Vec<OwnedFramebuffer>>>()?;
let mut feedback_textures = Vec::new(); let mut feedback_textures = Vec::new();
feedback_textures.resize_with(filters.len(), || None); feedback_textures.resize_with(filters.len(), || None);
// load luts // 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) = 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)?; let draw_quad = DrawQuad::new(device, &device_context)?;
@ -252,12 +268,18 @@ impl FilterChain {
d3d11: Direct3D11 { d3d11: Direct3D11 {
device: device.clone(), device: device.clone(),
device_context, 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, luts,
samplers, 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(), 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,
@ -269,7 +291,7 @@ impl FilterChain {
device: &ID3D11Device, device: &ID3D11Device,
context: &ID3D11DeviceContext, context: &ID3D11DeviceContext,
filters: &[FilterPass], filters: &[FilterPass],
) -> (VecDeque<OwnedFramebuffer>, Box<[Option<Texture>]>) { ) -> util::Result<(VecDeque<OwnedFramebuffer>, Box<[Option<Texture>]>)> {
let mut required_images = 0; let mut required_images = 0;
for pass in filters { for pass in filters {
@ -296,7 +318,7 @@ impl FilterChain {
// not using frame history; // not using frame history;
if required_images <= 1 { if required_images <= 1 {
println!("[history] not using frame history"); println!("[history] not using frame history");
return (VecDeque::new(), Box::new([])); return Ok((VecDeque::new(), Box::new([])));
} }
// history0 is aliased with the original // history0 is aliased with the original
@ -305,13 +327,15 @@ impl FilterChain {
let mut framebuffers = VecDeque::with_capacity(required_images); let mut framebuffers = VecDeque::with_capacity(required_images);
framebuffers.resize_with(required_images, || { framebuffers.resize_with(required_images, || {
OwnedFramebuffer::new(device, context, Size::new(1, 1), ImageFormat::R8G8B8A8Unorm) OwnedFramebuffer::new(device, context, Size::new(1, 1), ImageFormat::R8G8B8A8Unorm)
.unwrap()
}); });
let framebuffers = framebuffers
.into_iter().collect::<util::Result<VecDeque<OwnedFramebuffer>>>()?;
let mut history_textures = Vec::new(); let mut history_textures = Vec::new();
history_textures.resize_with(required_images, || None); 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<()> { fn push_history(&mut self, input: &DxImageView) -> util::Result<()> {
@ -325,8 +349,9 @@ impl FilterChain {
fn load_luts( fn load_luts(
device: &ID3D11Device, device: &ID3D11Device,
context: &ID3D11DeviceContext,
textures: &[TextureConfig], textures: &[TextureConfig],
) -> util::Result<FxHashMap<usize, OwnedTexture>> { ) -> util::Result<FxHashMap<usize, LutTexture>> {
let mut luts = FxHashMap::default(); let mut luts = FxHashMap::default();
for (index, texture) in textures.iter().enumerate() { for (index, texture) in textures.iter().enumerate() {
@ -345,7 +370,7 @@ impl FilterChain {
}; };
let texture = 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); luts.insert(index, texture);
} }
Ok(luts) Ok(luts)
@ -361,14 +386,15 @@ impl FilterChain {
Self::load_from_preset(device, preset) Self::load_from_preset(device, preset)
} }
fn load_preset(preset: &ShaderPreset) -> util::Result<(Vec<ShaderPassMeta>, ReflectSemantics)> { fn load_preset( passes: Vec<ShaderPassConfig>,
textures: &[TextureConfig],
) -> util::Result<(Vec<ShaderPassMeta>, ReflectSemantics)> {
let mut uniform_semantics: FxHashMap<String, UniformSemantic> = Default::default(); let mut uniform_semantics: FxHashMap<String, UniformSemantic> = Default::default();
let mut texture_semantics: FxHashMap<String, SemanticMap<TextureSemantics>> = let mut texture_semantics: FxHashMap<String, SemanticMap<TextureSemantics>> =
Default::default(); Default::default();
let passes = preset let passes = passes
.shaders .into_iter()
.iter()
.map(|shader| { .map(|shader| {
eprintln!("[dx11] loading {}", &shader.name.display()); eprintln!("[dx11] loading {}", &shader.name.display());
let source: ShaderSource = ShaderSource::load(&shader.name)?; let source: ShaderSource = ShaderSource::load(&shader.name)?;
@ -385,21 +411,21 @@ impl FilterChain {
}), }),
); );
} }
Ok::<_, Box<dyn Error>>((shader, source, reflect)) Ok::<_, FilterChainError>((shader, source, reflect))
}) })
.into_iter() .into_iter()
.collect::<util::Result<Vec<(&ShaderPassConfig, ShaderSource, CompilerBackend<_>)>>>( .collect::<util::Result<Vec<(ShaderPassConfig, ShaderSource, CompilerBackend<_>)>>>(
)?; )?;
for details in &passes { for details in &passes {
librashader_runtime::semantics::insert_pass_semantics( librashader_runtime::semantics::insert_pass_semantics(
&mut uniform_semantics, &mut uniform_semantics,
&mut texture_semantics, &mut texture_semantics,
details.0, &details.0,
) )
} }
librashader_runtime::semantics::insert_lut_semantics( librashader_runtime::semantics::insert_lut_semantics(
&preset.textures, &textures,
&mut uniform_semantics, &mut uniform_semantics,
&mut texture_semantics, &mut texture_semantics,
); );
@ -476,12 +502,12 @@ impl FilterChain {
viewport, viewport,
&original, &original,
&source, &source,
RenderTarget::new(target.as_output_framebuffer().unwrap(), None), RenderTarget::new(target.as_output_framebuffer()?, None),
)?; )?;
source = Texture { source = Texture {
view: DxImageView { view: DxImageView {
handle: target.create_shader_resource_view().unwrap(), handle: target.create_shader_resource_view()?,
size, size,
}, },
filter, filter,

View file

@ -20,6 +20,7 @@ use windows::Win32::Graphics::Direct3D11::{
use crate::render_target::RenderTarget; use crate::render_target::RenderTarget;
use crate::samplers::SamplerSet; use crate::samplers::SamplerSet;
use librashader_runtime::uniforms::UniformStorage; use librashader_runtime::uniforms::UniformStorage;
use crate::util;
pub struct ConstantBufferBinding { pub struct ConstantBufferBinding {
pub binding: u32, pub binding: u32,
@ -310,13 +311,7 @@ impl FilterPass {
.map(|f| f.initial) .map(|f| f.initial)
.unwrap_or(0f32); .unwrap_or(0f32);
let value = parent let value = *parent.config.parameters.get(id).unwrap_or(&default);
.preset
.parameters
.iter()
.find(|&p| p.name == id)
.map(|p| p.value)
.unwrap_or(default);
self.uniform_storage.bind_scalar(*offset, value, None); self.uniform_storage.bind_scalar(*offset, value, None);
} }
@ -360,7 +355,7 @@ impl FilterPass {
original: &Texture, original: &Texture,
source: &Texture, source: &Texture,
output: RenderTarget, output: RenderTarget,
) -> std::result::Result<(), Box<dyn Error>> { ) -> util::Result<()> {
let _device = &parent.d3d11.device; let _device = &parent.d3d11.device;
let context = &parent.d3d11.device_context; let context = &parent.d3d11.device_context;
unsafe { unsafe {

View file

@ -155,9 +155,10 @@ impl OwnedFramebuffer {
let resource: ID3D11Texture2D = unsafe { let resource: ID3D11Texture2D = unsafe {
let mut resource = None; let mut resource = None;
image.handle.GetResource(&mut resource); image.handle.GetResource(&mut resource);
let Some(resource) = resource else {
// todo: make panic-free return Ok(())
resource.unwrap().cast()? };
resource.cast()?
}; };
let format = unsafe { let format = unsafe {

View file

@ -1,17 +1,18 @@
#![feature(type_alias_impl_trait)] #![feature(type_alias_impl_trait)]
#![feature(let_chains)] #![feature(let_chains)]
mod filter_chain;
mod filter_pass;
mod framebuffer;
#[cfg(test)] #[cfg(test)]
mod hello_triangle; mod hello_triangle;
mod filter_chain;
mod filter_pass;
mod framebuffer;
mod quad_render; mod quad_render;
mod render_target; mod render_target;
mod samplers; mod samplers;
mod texture; mod texture;
mod util; mod util;
pub mod error;
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {

View file

@ -1,48 +1,40 @@
use librashader_common::image::Image; use librashader_common::image::Image;
use librashader_common::{FilterMode, Size, WrapMode}; use librashader_common::{FilterMode, Size, WrapMode};
use windows::Win32::Graphics::Direct3D::D3D_SRV_DIMENSION_TEXTURE2D; use windows::Win32::Graphics::Direct3D::D3D_SRV_DIMENSION_TEXTURE2D;
use windows::Win32::Graphics::Direct3D11::{ 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};
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::Dxgi::Common::DXGI_SAMPLE_DESC; use windows::Win32::Graphics::Dxgi::Common::DXGI_SAMPLE_DESC;
use crate::filter_chain::Direct3D11;
use crate::util::Result; use crate::util::Result;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct DxImageView { pub struct DxImageView {
pub handle: ID3D11ShaderResourceView, pub handle: ID3D11ShaderResourceView,
pub size: Size<u32>, // pub image: GlImage, pub size: Size<u32>,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Texture { pub struct Texture {
pub view: DxImageView, pub view: DxImageView,
pub filter: FilterMode, pub filter: FilterMode,
pub wrap_mode: WrapMode, pub wrap_mode: WrapMode,
// pub mip_filter: FilterMode,
// pub wrap_mode: WrapMode,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct OwnedTexture { pub struct LutTexture {
pub handle: ID3D11Texture2D, pub handle: ID3D11Texture2D,
// pub staging: ID3D11Texture2D,
pub desc: D3D11_TEXTURE2D_DESC, pub desc: D3D11_TEXTURE2D_DESC,
pub image: Texture, pub image: Texture,
} }
impl OwnedTexture { impl LutTexture {
pub fn new( pub fn new(
device: &ID3D11Device, device: &ID3D11Device,
context: &ID3D11DeviceContext,
source: &Image, source: &Image,
desc: D3D11_TEXTURE2D_DESC, desc: D3D11_TEXTURE2D_DESC,
filter: FilterMode, filter: FilterMode,
wrap_mode: WrapMode, wrap_mode: WrapMode,
) -> Result<OwnedTexture> { ) -> Result<LutTexture> {
let mut desc = D3D11_TEXTURE2D_DESC { let mut desc = D3D11_TEXTURE2D_DESC {
Width: source.size.width, Width: source.size.width,
Height: source.size.height, 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 // need a staging texture to defer mipmap generation
let staging = device.CreateTexture2D( let staging = device.CreateTexture2D(
&D3D11_TEXTURE2D_DESC { &D3D11_TEXTURE2D_DESC {
@ -158,7 +144,7 @@ impl OwnedTexture {
// let mut subresource = context.Map(staging, 0, D3D11_MAP_WRITE, 0)?; // let mut subresource = context.Map(staging, 0, D3D11_MAP_WRITE, 0)?;
// staging.Upd // staging.Upd
Ok(OwnedTexture { Ok(LutTexture {
handle, handle,
// staging, // staging,
desc, desc,

View file

@ -167,4 +167,4 @@ pub fn d3d11_create_input_layout(
} }
// todo: d3d11.c 2097 // todo: d3d11.c 2097
pub type Result<T> = std::result::Result<T, Box<dyn Error>>; pub type Result<T> = std::result::Result<T, crate::error::FilterChainError>;

View file

@ -32,7 +32,6 @@ pub struct FilterPass<T: GLInterface> {
} }
impl<T: GLInterface> FilterPass<T> { impl<T: GLInterface> FilterPass<T> {
// todo: fix rendertargets (i.e. non-final pass is internal, final pass is user provided fbo)
pub(crate) fn draw( pub(crate) fn draw(
&mut self, &mut self,
pass_index: usize, pass_index: usize,

View file

@ -89,6 +89,11 @@ impl FramebufferInterface for Gl46Framebuffer {
} }
} }
fn copy_from(fb: &mut Framebuffer, image: &GLImage) -> Result<()> { 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. // todo: may want to use a shader and draw a quad to be faster.
if image.size != fb.size || image.format != fb.format { if image.size != fb.size || image.format != fb.format {
Self::init( Self::init(