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-runtime",
"rustc-hash",
"spirv_cross",
"thiserror",
"windows",
]

View file

@ -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"

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::{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<String, f32>,
}
// todo: get rid of preset
type ShaderPassMeta<'a> = (
&'a ShaderPassConfig,
type ShaderPassMeta = (
ShaderPassConfig,
ShaderSource,
CompilerBackend<
impl CompileShader<HLSL, Options = Option<()>, 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<usize, OwnedTexture>,
pub(crate) luts: FxHashMap<usize, LutTexture>,
pub samplers: SamplerSet,
pub output_textures: Box<[Option<Texture>]>,
pub feedback_textures: Box<[Option<Texture>]>,
pub history_textures: Box<[Option<Texture>]>,
pub config: FilterMutable
}
impl FilterChain {
@ -188,17 +195,18 @@ impl FilterChain {
device: &ID3D11Device,
preset: ShaderPreset,
) -> 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)?;
// 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::<util::Result<Vec<OwnedFramebuffer>>>()?;
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::<util::Result<Vec<OwnedFramebuffer>>>()?;
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<OwnedFramebuffer>, Box<[Option<Texture>]>) {
) -> util::Result<(VecDeque<OwnedFramebuffer>, Box<[Option<Texture>]>)> {
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::<util::Result<VecDeque<OwnedFramebuffer>>>()?;
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<FxHashMap<usize, OwnedTexture>> {
) -> util::Result<FxHashMap<usize, LutTexture>> {
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<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 texture_semantics: FxHashMap<String, SemanticMap<TextureSemantics>> =
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<dyn Error>>((shader, source, reflect))
Ok::<_, FilterChainError>((shader, source, reflect))
})
.into_iter()
.collect::<util::Result<Vec<(&ShaderPassConfig, ShaderSource, CompilerBackend<_>)>>>(
.collect::<util::Result<Vec<(ShaderPassConfig, ShaderSource, CompilerBackend<_>)>>>(
)?;
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,

View file

@ -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<dyn Error>> {
) -> util::Result<()> {
let _device = &parent.d3d11.device;
let context = &parent.d3d11.device_context;
unsafe {

View file

@ -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 {

View file

@ -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 {

View file

@ -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<u32>, // pub image: GlImage,
pub size: Size<u32>,
}
#[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<OwnedTexture> {
) -> Result<LutTexture> {
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,

View file

@ -167,4 +167,4 @@ pub fn d3d11_create_input_layout(
}
// 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> {
// 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,

View file

@ -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(