d3d11: cleanup error and api
This commit is contained in:
parent
6519a78df2
commit
873814b03b
15 changed files with 316 additions and 240 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -4,3 +4,4 @@
|
|||
/target
|
||||
*.rdc
|
||||
*.cap
|
||||
/.vs/
|
||||
|
|
|
@ -84,8 +84,6 @@ fn from_int(input: Span) -> Result<i32, ParsePresetError> {
|
|||
col: input.get_column(),
|
||||
kind: ParseErrorKind::Int,
|
||||
})?;
|
||||
|
||||
eprintln!("falling back to float trunc {result}");
|
||||
Ok(result)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -23,3 +23,5 @@ pub enum FilterChainError {
|
|||
#[error("lut loading error")]
|
||||
LutLoadError(#[from] ImageError),
|
||||
}
|
||||
|
||||
pub type Result<T> = std::result::Result<T, FilterChainError>;
|
||||
|
|
|
@ -14,24 +14,26 @@ use librashader_reflect::reflect::semantics::{
|
|||
use librashader_reflect::reflect::ReflectShader;
|
||||
use rustc_hash::FxHashMap;
|
||||
use std::collections::VecDeque;
|
||||
use std::error::Error;
|
||||
|
||||
use std::path::Path;
|
||||
|
||||
use crate::error::FilterChainError;
|
||||
use crate::filter_pass::{ConstantBufferBinding, FilterPass};
|
||||
use crate::framebuffer::{OutputFramebuffer, OwnedFramebuffer};
|
||||
use crate::framebuffer::OwnedFramebuffer;
|
||||
use crate::options::{FilterChainOptions, FrameOptions};
|
||||
use crate::quad_render::DrawQuad;
|
||||
use crate::render_target::RenderTarget;
|
||||
use crate::samplers::SamplerSet;
|
||||
use crate::util;
|
||||
use crate::util::d3d11_compile_bound_shader;
|
||||
use crate::viewport::Viewport;
|
||||
use crate::{error, util};
|
||||
use librashader_runtime::uniforms::UniformStorage;
|
||||
use windows::Win32::Graphics::Direct3D11::{
|
||||
ID3D11Buffer, ID3D11Device, ID3D11DeviceContext, D3D11_BIND_CONSTANT_BUFFER, D3D11_BUFFER_DESC,
|
||||
D3D11_CPU_ACCESS_WRITE, D3D11_RESOURCE_MISC_FLAG, D3D11_RESOURCE_MISC_GENERATE_MIPS,
|
||||
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;
|
||||
use windows::Win32::Graphics::Dxgi::Common::DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
|
||||
pub struct FilterMutable {
|
||||
pub(crate) passes_enabled: usize,
|
||||
|
@ -48,18 +50,19 @@ type ShaderPassMeta = (
|
|||
);
|
||||
|
||||
pub struct FilterChain {
|
||||
pub common: FilterCommon,
|
||||
pub passes: Vec<FilterPass>,
|
||||
pub output_framebuffers: Box<[OwnedFramebuffer]>,
|
||||
pub feedback_framebuffers: Box<[OwnedFramebuffer]>,
|
||||
pub history_framebuffers: VecDeque<OwnedFramebuffer>,
|
||||
pub(crate) common: FilterCommon,
|
||||
pub(crate) passes: Vec<FilterPass>,
|
||||
pub(crate) output_framebuffers: Box<[OwnedFramebuffer]>,
|
||||
pub(crate) feedback_framebuffers: Box<[OwnedFramebuffer]>,
|
||||
pub(crate) history_framebuffers: VecDeque<OwnedFramebuffer>,
|
||||
pub(crate) draw_quad: DrawQuad,
|
||||
}
|
||||
|
||||
pub struct Direct3D11 {
|
||||
pub(crate) struct Direct3D11 {
|
||||
pub(crate) device: ID3D11Device,
|
||||
pub(crate) device_context: ID3D11DeviceContext,
|
||||
pub context_is_deferred: bool
|
||||
pub(crate) current_context: ID3D11DeviceContext,
|
||||
pub(crate) immediate_context: ID3D11DeviceContext,
|
||||
pub context_is_deferred: bool,
|
||||
}
|
||||
|
||||
pub struct FilterCommon {
|
||||
|
@ -69,11 +72,128 @@ pub struct FilterCommon {
|
|||
pub output_textures: Box<[Option<Texture>]>,
|
||||
pub feedback_textures: Box<[Option<Texture>]>,
|
||||
pub history_textures: Box<[Option<Texture>]>,
|
||||
pub config: FilterMutable
|
||||
pub config: FilterMutable,
|
||||
}
|
||||
|
||||
impl FilterChain {
|
||||
fn create_constant_buffer(device: &ID3D11Device, size: u32) -> util::Result<ID3D11Buffer> {
|
||||
/// Load the shader preset at the given path into a filter chain.
|
||||
pub fn load_from_path(
|
||||
device: &ID3D11Device,
|
||||
path: impl AsRef<Path>,
|
||||
options: Option<&FilterChainOptions>,
|
||||
) -> error::Result<FilterChain> {
|
||||
// load passes from preset
|
||||
let preset = ShaderPreset::try_parse(path)?;
|
||||
Self::load_from_preset(device, preset, options)
|
||||
}
|
||||
|
||||
/// Load a filter chain from a pre-parsed `ShaderPreset`.
|
||||
pub fn load_from_preset(
|
||||
device: &ID3D11Device,
|
||||
preset: ShaderPreset,
|
||||
options: Option<&FilterChainOptions>,
|
||||
) -> error::Result<FilterChain> {
|
||||
let (passes, semantics) = FilterChain::load_preset(preset.shaders, &preset.textures)?;
|
||||
|
||||
let use_deferred_context = options.map(|f| f.use_deferred_context).unwrap_or(false);
|
||||
|
||||
let samplers = SamplerSet::new(device)?;
|
||||
|
||||
// initialize passes
|
||||
let filters = FilterChain::init_passes(device, passes, &semantics)?;
|
||||
|
||||
let mut immediate_context = None;
|
||||
unsafe {
|
||||
device.GetImmediateContext(&mut immediate_context);
|
||||
}
|
||||
|
||||
let Some(immediate_context) = immediate_context else {
|
||||
return Err(FilterChainError::Direct3DContextError)
|
||||
};
|
||||
|
||||
let current_context = if use_deferred_context {
|
||||
unsafe { device.CreateDeferredContext(0)? }
|
||||
} else {
|
||||
immediate_context.clone()
|
||||
};
|
||||
|
||||
// initialize output framebuffers
|
||||
let mut output_framebuffers = Vec::new();
|
||||
output_framebuffers.resize_with(filters.len(), || {
|
||||
OwnedFramebuffer::new(
|
||||
device,
|
||||
Size::new(1, 1),
|
||||
ImageFormat::R8G8B8A8Unorm,
|
||||
)
|
||||
});
|
||||
|
||||
// resolve all results
|
||||
let output_framebuffers = output_framebuffers
|
||||
.into_iter()
|
||||
.collect::<error::Result<Vec<OwnedFramebuffer>>>()?;
|
||||
|
||||
let mut output_textures = Vec::new();
|
||||
output_textures.resize_with(filters.len(), || None);
|
||||
//
|
||||
// // initialize feedback framebuffers
|
||||
let mut feedback_framebuffers = Vec::new();
|
||||
feedback_framebuffers.resize_with(filters.len(), || {
|
||||
OwnedFramebuffer::new(
|
||||
device,
|
||||
Size::new(1, 1),
|
||||
ImageFormat::R8G8B8A8Unorm,
|
||||
)
|
||||
});
|
||||
// resolve all results
|
||||
let feedback_framebuffers = feedback_framebuffers
|
||||
.into_iter()
|
||||
.collect::<error::Result<Vec<OwnedFramebuffer>>>()?;
|
||||
|
||||
let mut feedback_textures = Vec::new();
|
||||
feedback_textures.resize_with(filters.len(), || None);
|
||||
|
||||
// load luts
|
||||
let luts = FilterChain::load_luts(device, ¤t_context, &preset.textures)?;
|
||||
|
||||
let (history_framebuffers, history_textures) =
|
||||
FilterChain::init_history(device, &filters)?;
|
||||
|
||||
let draw_quad = DrawQuad::new(device, ¤t_context)?;
|
||||
|
||||
// todo: make vbo: d3d11.c 1376
|
||||
Ok(FilterChain {
|
||||
passes: filters,
|
||||
output_framebuffers: output_framebuffers.into_boxed_slice(),
|
||||
feedback_framebuffers: feedback_framebuffers.into_boxed_slice(),
|
||||
history_framebuffers,
|
||||
draw_quad,
|
||||
common: FilterCommon {
|
||||
d3d11: Direct3D11 {
|
||||
device: device.clone(),
|
||||
current_context,
|
||||
immediate_context,
|
||||
context_is_deferred: use_deferred_context,
|
||||
},
|
||||
config: FilterMutable {
|
||||
passes_enabled: preset.shader_count as usize,
|
||||
parameters: preset
|
||||
.parameters
|
||||
.into_iter()
|
||||
.map(|param| (param.name, param.value))
|
||||
.collect(),
|
||||
},
|
||||
luts,
|
||||
samplers,
|
||||
output_textures: output_textures.into_boxed_slice(),
|
||||
feedback_textures: feedback_textures.into_boxed_slice(),
|
||||
history_textures,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl FilterChain {
|
||||
fn create_constant_buffer(device: &ID3D11Device, size: u32) -> error::Result<ID3D11Buffer> {
|
||||
unsafe {
|
||||
let buffer = device.CreateBuffer(
|
||||
&D3D11_BUFFER_DESC {
|
||||
|
@ -95,7 +215,7 @@ impl FilterChain {
|
|||
device: &ID3D11Device,
|
||||
passes: Vec<ShaderPassMeta>,
|
||||
semantics: &ReflectSemantics,
|
||||
) -> util::Result<Vec<FilterPass>> {
|
||||
) -> error::Result<Vec<FilterPass>> {
|
||||
// let mut filters = Vec::new();
|
||||
let mut filters = Vec::new();
|
||||
|
||||
|
@ -190,108 +310,11 @@ impl FilterChain {
|
|||
}
|
||||
Ok(filters)
|
||||
}
|
||||
/// Load a filter chain from a pre-parsed `ShaderPreset`.
|
||||
pub fn load_from_preset(
|
||||
device: &ID3D11Device,
|
||||
preset: ShaderPreset,
|
||||
) -> util::Result<FilterChain> {
|
||||
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)?;
|
||||
|
||||
let mut device_context = None;
|
||||
unsafe {
|
||||
device.GetImmediateContext(&mut device_context);
|
||||
}
|
||||
|
||||
let device_context = device_context.unwrap();
|
||||
|
||||
let device_context =
|
||||
unsafe {
|
||||
device.CreateDeferredContext(0)?
|
||||
};
|
||||
// initialize output framebuffers
|
||||
let mut output_framebuffers = Vec::new();
|
||||
output_framebuffers.resize_with(filters.len(), || {
|
||||
OwnedFramebuffer::new(
|
||||
device,
|
||||
&device_context,
|
||||
Size::new(1, 1),
|
||||
ImageFormat::R8G8B8A8Unorm,
|
||||
)
|
||||
});
|
||||
|
||||
// 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);
|
||||
//
|
||||
// // initialize feedback framebuffers
|
||||
let mut feedback_framebuffers = Vec::new();
|
||||
feedback_framebuffers.resize_with(filters.len(), || {
|
||||
OwnedFramebuffer::new(
|
||||
device,
|
||||
&device_context,
|
||||
Size::new(1, 1),
|
||||
ImageFormat::R8G8B8A8Unorm,
|
||||
)
|
||||
});
|
||||
// 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,
|
||||
&device_context, &preset.textures)?;
|
||||
|
||||
let (history_framebuffers, history_textures) =
|
||||
FilterChain::init_history(device, &device_context, &filters)?;
|
||||
|
||||
let draw_quad = DrawQuad::new(device, &device_context)?;
|
||||
|
||||
// todo: make vbo: d3d11.c 1376
|
||||
Ok(FilterChain {
|
||||
passes: filters,
|
||||
output_framebuffers: output_framebuffers.into_boxed_slice(),
|
||||
feedback_framebuffers: feedback_framebuffers.into_boxed_slice(),
|
||||
history_framebuffers,
|
||||
draw_quad,
|
||||
common: FilterCommon {
|
||||
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,
|
||||
output_textures: output_textures.into_boxed_slice(),
|
||||
feedback_textures: feedback_textures.into_boxed_slice(),
|
||||
history_textures,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
fn init_history(
|
||||
device: &ID3D11Device,
|
||||
context: &ID3D11DeviceContext,
|
||||
filters: &[FilterPass],
|
||||
) -> util::Result<(VecDeque<OwnedFramebuffer>, Box<[Option<Texture>]>)> {
|
||||
) -> error::Result<(VecDeque<OwnedFramebuffer>, Box<[Option<Texture>]>)> {
|
||||
let mut required_images = 0;
|
||||
|
||||
for pass in filters {
|
||||
|
@ -326,11 +349,12 @@ impl FilterChain {
|
|||
eprintln!("[history] using frame history with {required_images} images");
|
||||
let mut framebuffers = VecDeque::with_capacity(required_images);
|
||||
framebuffers.resize_with(required_images, || {
|
||||
OwnedFramebuffer::new(device, context, Size::new(1, 1), ImageFormat::R8G8B8A8Unorm)
|
||||
OwnedFramebuffer::new(device, Size::new(1, 1), ImageFormat::R8G8B8A8Unorm)
|
||||
});
|
||||
|
||||
let framebuffers = framebuffers
|
||||
.into_iter().collect::<util::Result<VecDeque<OwnedFramebuffer>>>()?;
|
||||
.into_iter()
|
||||
.collect::<error::Result<VecDeque<OwnedFramebuffer>>>()?;
|
||||
|
||||
let mut history_textures = Vec::new();
|
||||
history_textures.resize_with(required_images, || None);
|
||||
|
@ -338,9 +362,9 @@ impl FilterChain {
|
|||
Ok((framebuffers, history_textures.into_boxed_slice()))
|
||||
}
|
||||
|
||||
fn push_history(&mut self, input: &DxImageView) -> util::Result<()> {
|
||||
fn push_history(&mut self, input: &DxImageView) -> error::Result<()> {
|
||||
if let Some(mut back) = self.history_framebuffers.pop_back() {
|
||||
back.copy_from(&input)?;
|
||||
back.copy_from(input)?;
|
||||
self.history_framebuffers.push_front(back)
|
||||
}
|
||||
|
||||
|
@ -351,7 +375,7 @@ impl FilterChain {
|
|||
device: &ID3D11Device,
|
||||
context: &ID3D11DeviceContext,
|
||||
textures: &[TextureConfig],
|
||||
) -> util::Result<FxHashMap<usize, LutTexture>> {
|
||||
) -> error::Result<FxHashMap<usize, LutTexture>> {
|
||||
let mut luts = FxHashMap::default();
|
||||
|
||||
for (index, texture) in textures.iter().enumerate() {
|
||||
|
@ -369,26 +393,23 @@ impl FilterChain {
|
|||
..Default::default()
|
||||
};
|
||||
|
||||
let texture =
|
||||
LutTexture::new(device, context,&image, desc, texture.filter_mode, texture.wrap_mode)?;
|
||||
let texture = LutTexture::new(
|
||||
device,
|
||||
context,
|
||||
&image,
|
||||
desc,
|
||||
texture.filter_mode,
|
||||
texture.wrap_mode,
|
||||
)?;
|
||||
luts.insert(index, texture);
|
||||
}
|
||||
Ok(luts)
|
||||
}
|
||||
|
||||
/// Load the shader preset at the given path into a filter chain.
|
||||
pub fn load_from_path(
|
||||
device: &ID3D11Device,
|
||||
path: impl AsRef<Path>,
|
||||
) -> util::Result<FilterChain> {
|
||||
// load passes from preset
|
||||
let preset = ShaderPreset::try_parse(path)?;
|
||||
Self::load_from_preset(device, preset)
|
||||
}
|
||||
|
||||
fn load_preset( passes: Vec<ShaderPassConfig>,
|
||||
fn load_preset(
|
||||
passes: Vec<ShaderPassConfig>,
|
||||
textures: &[TextureConfig],
|
||||
) -> util::Result<(Vec<ShaderPassMeta>, ReflectSemantics)> {
|
||||
) -> error::Result<(Vec<ShaderPassMeta>, ReflectSemantics)> {
|
||||
let mut uniform_semantics: FxHashMap<String, UniformSemantic> = Default::default();
|
||||
let mut texture_semantics: FxHashMap<String, SemanticMap<TextureSemantics>> =
|
||||
Default::default();
|
||||
|
@ -414,7 +435,7 @@ impl FilterChain {
|
|||
Ok::<_, FilterChainError>((shader, source, reflect))
|
||||
})
|
||||
.into_iter()
|
||||
.collect::<util::Result<Vec<(ShaderPassConfig, ShaderSource, CompilerBackend<_>)>>>(
|
||||
.collect::<error::Result<Vec<(ShaderPassConfig, ShaderSource, CompilerBackend<_>)>>>(
|
||||
)?;
|
||||
|
||||
for details in &passes {
|
||||
|
@ -425,7 +446,7 @@ impl FilterChain {
|
|||
)
|
||||
}
|
||||
librashader_runtime::semantics::insert_lut_semantics(
|
||||
&textures,
|
||||
textures,
|
||||
&mut uniform_semantics,
|
||||
&mut texture_semantics,
|
||||
);
|
||||
|
@ -440,12 +461,19 @@ impl FilterChain {
|
|||
|
||||
pub fn frame(
|
||||
&mut self,
|
||||
count: usize,
|
||||
viewport: &Size<u32>,
|
||||
input: DxImageView,
|
||||
output: OutputFramebuffer,
|
||||
) -> util::Result<()> {
|
||||
let passes = &mut self.passes;
|
||||
viewport: &Viewport,
|
||||
frame_count: usize,
|
||||
options: Option<&FrameOptions>,
|
||||
) -> error::Result<()> {
|
||||
let passes = &mut self.passes[0..self.common.config.passes_enabled];
|
||||
if let Some(options) = options {
|
||||
if options.clear_history {
|
||||
for framebuffer in &mut self.history_framebuffers {
|
||||
framebuffer.init(Size::new(1, 1), ImageFormat::R8G8B8A8Unorm)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if passes.is_empty() {
|
||||
return Ok(());
|
||||
|
@ -469,7 +497,7 @@ impl FilterChain {
|
|||
self.output_framebuffers[index].scale(
|
||||
pass.config.scaling.clone(),
|
||||
pass.get_format(),
|
||||
viewport,
|
||||
&viewport.size,
|
||||
&original,
|
||||
&source,
|
||||
)?;
|
||||
|
@ -477,7 +505,7 @@ impl FilterChain {
|
|||
self.feedback_framebuffers[index].scale(
|
||||
pass.config.scaling.clone(),
|
||||
pass.get_format(),
|
||||
viewport,
|
||||
&viewport.size,
|
||||
&original,
|
||||
&source,
|
||||
)?;
|
||||
|
@ -494,9 +522,9 @@ impl FilterChain {
|
|||
index,
|
||||
&self.common,
|
||||
if pass.config.frame_count_mod > 0 {
|
||||
count % pass.config.frame_count_mod as usize
|
||||
frame_count % pass.config.frame_count_mod as usize
|
||||
} else {
|
||||
count
|
||||
frame_count
|
||||
} as u32,
|
||||
1,
|
||||
viewport,
|
||||
|
@ -523,15 +551,15 @@ impl FilterChain {
|
|||
passes_len - 1,
|
||||
&self.common,
|
||||
if pass.config.frame_count_mod > 0 {
|
||||
count % pass.config.frame_count_mod as usize
|
||||
frame_count % pass.config.frame_count_mod as usize
|
||||
} else {
|
||||
count
|
||||
frame_count
|
||||
} as u32,
|
||||
1,
|
||||
viewport,
|
||||
&original,
|
||||
&source,
|
||||
RenderTarget::new(output, None),
|
||||
viewport.into(),
|
||||
)?;
|
||||
|
||||
// diverge so we don't need to clone output.
|
||||
|
@ -549,12 +577,14 @@ impl FilterChain {
|
|||
|
||||
self.push_history(&input)?;
|
||||
|
||||
if self.common.d3d11.context_is_deferred {
|
||||
unsafe {
|
||||
let list = self.common.d3d11.device_context.FinishCommandList(false)?;
|
||||
let mut imm = None;
|
||||
self.common.d3d11.device.GetImmediateContext(&mut imm);
|
||||
let imm = imm.unwrap();
|
||||
imm.ExecuteCommandList(&list, true);
|
||||
let command_list = self.common.d3d11.current_context.FinishCommandList(false)?;
|
||||
self.common
|
||||
.d3d11
|
||||
.immediate_context
|
||||
.ExecuteCommandList(&command_list, true);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -10,17 +10,17 @@ use librashader_reflect::reflect::semantics::{
|
|||
};
|
||||
use librashader_reflect::reflect::ShaderReflection;
|
||||
use rustc_hash::FxHashMap;
|
||||
use std::error::Error;
|
||||
|
||||
use windows::Win32::Graphics::Direct3D11::{
|
||||
ID3D11Buffer, ID3D11InputLayout, ID3D11PixelShader, ID3D11SamplerState,
|
||||
ID3D11ShaderResourceView, ID3D11VertexShader, D3D11_MAP_WRITE_DISCARD,
|
||||
};
|
||||
|
||||
use crate::error;
|
||||
use crate::render_target::RenderTarget;
|
||||
use crate::samplers::SamplerSet;
|
||||
use crate::viewport::Viewport;
|
||||
use librashader_runtime::uniforms::UniformStorage;
|
||||
use crate::util;
|
||||
|
||||
pub struct ConstantBufferBinding {
|
||||
pub binding: u32,
|
||||
|
@ -301,8 +301,6 @@ impl FilterPass {
|
|||
{
|
||||
let id = id.as_str();
|
||||
|
||||
// todo: cache parameters.
|
||||
// presets override params
|
||||
let default = self
|
||||
.source
|
||||
.parameters
|
||||
|
@ -345,19 +343,19 @@ impl FilterPass {
|
|||
(textures, samplers)
|
||||
}
|
||||
|
||||
pub fn draw(
|
||||
pub(crate) fn draw(
|
||||
&mut self,
|
||||
pass_index: usize,
|
||||
parent: &FilterCommon,
|
||||
frame_count: u32,
|
||||
frame_direction: i32,
|
||||
viewport: &Size<u32>,
|
||||
viewport: &Viewport,
|
||||
original: &Texture,
|
||||
source: &Texture,
|
||||
output: RenderTarget,
|
||||
) -> util::Result<()> {
|
||||
) -> error::Result<()> {
|
||||
let _device = &parent.d3d11.device;
|
||||
let context = &parent.d3d11.device_context;
|
||||
let context = &parent.d3d11.current_context;
|
||||
unsafe {
|
||||
context.IASetInputLayout(&self.vertex_layout);
|
||||
context.VSSetShader(&self.vertex_shader, None);
|
||||
|
@ -371,7 +369,7 @@ impl FilterPass {
|
|||
frame_count,
|
||||
frame_direction,
|
||||
output.output.size,
|
||||
*viewport,
|
||||
viewport.size,
|
||||
original,
|
||||
source,
|
||||
);
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
use windows::core::Interface;
|
||||
use crate::error;
|
||||
use crate::texture::{DxImageView, Texture};
|
||||
use crate::util;
|
||||
use crate::util::d3d11_get_closest_format;
|
||||
use librashader_common::{ImageFormat, Size};
|
||||
use librashader_presets::Scale2D;
|
||||
use windows::core::Interface;
|
||||
use windows::Win32::Graphics::Direct3D::D3D_SRV_DIMENSION_TEXTURE2D;
|
||||
use windows::Win32::Graphics::Direct3D11::{
|
||||
ID3D11Device, ID3D11DeviceContext, ID3D11RenderTargetView, ID3D11Resource,
|
||||
ID3D11ShaderResourceView, ID3D11Texture2D, D3D11_BIND_RENDER_TARGET,
|
||||
D3D11_BIND_SHADER_RESOURCE, D3D11_BOX, D3D11_CPU_ACCESS_WRITE,
|
||||
ID3D11Device, ID3D11RenderTargetView, ID3D11ShaderResourceView,
|
||||
ID3D11Texture2D, D3D11_BIND_RENDER_TARGET, D3D11_BIND_SHADER_RESOURCE, D3D11_CPU_ACCESS_WRITE,
|
||||
D3D11_FORMAT_SUPPORT_RENDER_TARGET, D3D11_FORMAT_SUPPORT_SHADER_SAMPLE,
|
||||
D3D11_FORMAT_SUPPORT_TEXTURE2D, D3D11_RENDER_TARGET_VIEW_DESC, D3D11_RENDER_TARGET_VIEW_DESC_0,
|
||||
D3D11_RTV_DIMENSION_TEXTURE2D, D3D11_SHADER_RESOURCE_VIEW_DESC,
|
||||
|
@ -18,22 +17,20 @@ use windows::Win32::Graphics::Direct3D11::{
|
|||
use windows::Win32::Graphics::Dxgi::Common::{DXGI_FORMAT, DXGI_SAMPLE_DESC};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct OwnedFramebuffer {
|
||||
pub(crate) struct OwnedFramebuffer {
|
||||
pub texture: ID3D11Texture2D,
|
||||
pub size: Size<u32>,
|
||||
pub format: DXGI_FORMAT,
|
||||
device: ID3D11Device,
|
||||
context: ID3D11DeviceContext,
|
||||
is_raw: bool,
|
||||
}
|
||||
|
||||
impl OwnedFramebuffer {
|
||||
pub fn new(
|
||||
device: &ID3D11Device,
|
||||
context: &ID3D11DeviceContext,
|
||||
size: Size<u32>,
|
||||
format: ImageFormat,
|
||||
) -> util::Result<OwnedFramebuffer> {
|
||||
) -> error::Result<OwnedFramebuffer> {
|
||||
unsafe {
|
||||
let format = d3d11_get_closest_format(
|
||||
device,
|
||||
|
@ -50,7 +47,6 @@ impl OwnedFramebuffer {
|
|||
size,
|
||||
format,
|
||||
device: device.clone(),
|
||||
context: context.clone(),
|
||||
is_raw: false,
|
||||
})
|
||||
}
|
||||
|
@ -63,7 +59,7 @@ impl OwnedFramebuffer {
|
|||
viewport_size: &Size<u32>,
|
||||
_original: &Texture,
|
||||
source: &Texture,
|
||||
) -> util::Result<Size<u32>> {
|
||||
) -> error::Result<Size<u32>> {
|
||||
if self.is_raw {
|
||||
return Ok(self.size);
|
||||
}
|
||||
|
@ -85,7 +81,7 @@ impl OwnedFramebuffer {
|
|||
Ok(size)
|
||||
}
|
||||
|
||||
pub fn init(&mut self, size: Size<u32>, format: ImageFormat) -> util::Result<()> {
|
||||
pub fn init(&mut self, size: Size<u32>, format: ImageFormat) -> error::Result<()> {
|
||||
if self.is_raw {
|
||||
return Ok(());
|
||||
}
|
||||
|
@ -110,7 +106,7 @@ impl OwnedFramebuffer {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn create_shader_resource_view(&self) -> util::Result<ID3D11ShaderResourceView> {
|
||||
pub fn create_shader_resource_view(&self) -> error::Result<ID3D11ShaderResourceView> {
|
||||
unsafe {
|
||||
Ok(self.device.CreateShaderResourceView(
|
||||
&self.texture,
|
||||
|
@ -128,7 +124,7 @@ impl OwnedFramebuffer {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn create_render_target_view(&self) -> util::Result<ID3D11RenderTargetView> {
|
||||
pub fn create_render_target_view(&self) -> error::Result<ID3D11RenderTargetView> {
|
||||
unsafe {
|
||||
Ok(self.device.CreateRenderTargetView(
|
||||
&self.texture,
|
||||
|
@ -143,7 +139,7 @@ impl OwnedFramebuffer {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn as_output_framebuffer(&self) -> util::Result<OutputFramebuffer> {
|
||||
pub fn as_output_framebuffer(&self) -> error::Result<OutputFramebuffer> {
|
||||
Ok(OutputFramebuffer {
|
||||
rtv: self.create_render_target_view()?,
|
||||
size: self.size,
|
||||
|
@ -151,7 +147,7 @@ impl OwnedFramebuffer {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn copy_from(&mut self, image: &DxImageView) -> util::Result<()> {
|
||||
pub fn copy_from(&mut self, image: &DxImageView) -> error::Result<()> {
|
||||
let resource: ID3D11Texture2D = unsafe {
|
||||
let mut resource = None;
|
||||
image.handle.GetResource(&mut resource);
|
||||
|
@ -172,12 +168,12 @@ impl OwnedFramebuffer {
|
|||
self.init(image.size, ImageFormat::from(format))?;
|
||||
}
|
||||
|
||||
self.texture = resource.clone();
|
||||
self.texture = resource;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct OutputFramebuffer {
|
||||
pub(crate) struct OutputFramebuffer {
|
||||
pub rtv: ID3D11RenderTargetView,
|
||||
pub size: Size<u32>,
|
||||
pub viewport: D3D11_VIEWPORT,
|
||||
|
|
|
@ -225,14 +225,14 @@ pub mod d3d11_hello_triangle {
|
|||
use std::path::Path;
|
||||
|
||||
use crate::filter_chain::FilterChain;
|
||||
use crate::framebuffer::OutputFramebuffer;
|
||||
|
||||
use crate::options::FilterChainOptions;
|
||||
use crate::texture::DxImageView;
|
||||
use crate::viewport::Viewport;
|
||||
use librashader_common::Size;
|
||||
use std::slice;
|
||||
use std::time::Instant;
|
||||
|
||||
const FRAME_COUNT: u32 = 2;
|
||||
|
||||
pub struct Sample {
|
||||
pub dxgi_factory: IDXGIFactory4,
|
||||
pub device: ID3D11Device,
|
||||
|
@ -263,9 +263,12 @@ pub mod d3d11_hello_triangle {
|
|||
}
|
||||
|
||||
impl Sample {
|
||||
pub(crate) fn new(filter: impl AsRef<Path>) -> Result<Self> {
|
||||
pub(crate) fn new(
|
||||
filter: impl AsRef<Path>,
|
||||
filter_options: Option<&FilterChainOptions>,
|
||||
) -> Result<Self> {
|
||||
let (dxgi_factory, device, context) = create_device()?;
|
||||
let filter = FilterChain::load_from_path(&device, filter).unwrap();
|
||||
let filter = FilterChain::load_from_path(&device, filter, filter_options).unwrap();
|
||||
Ok(Sample {
|
||||
filter,
|
||||
dxgi_factory,
|
||||
|
@ -469,14 +472,25 @@ pub mod d3d11_hello_triangle {
|
|||
}),
|
||||
)?;
|
||||
|
||||
//
|
||||
// OutputFramebuffer {
|
||||
// rtv: resources.rtv.clone(),
|
||||
// // rtv,
|
||||
// size: Size {
|
||||
// width: tex2d_desc.Width,
|
||||
// height: tex2d_desc.Height,
|
||||
// },
|
||||
// viewport: resources.viewport, // 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,
|
||||
// // },
|
||||
// },
|
||||
|
||||
self.filter
|
||||
.frame(
|
||||
resources.frame_count,
|
||||
&Size {
|
||||
width: tex2d_desc.Width,
|
||||
height: tex2d_desc.Height,
|
||||
},
|
||||
DxImageView {
|
||||
handle: srv,
|
||||
size: Size {
|
||||
|
@ -484,22 +498,18 @@ pub mod d3d11_hello_triangle {
|
|||
height: tex2d_desc.Height,
|
||||
},
|
||||
},
|
||||
OutputFramebuffer {
|
||||
rtv: resources.rtv.clone(),
|
||||
// rtv,
|
||||
&Viewport {
|
||||
x: resources.viewport.TopLeftX,
|
||||
y: resources.viewport.TopLeftY,
|
||||
size: Size {
|
||||
width: tex2d_desc.Width,
|
||||
height: tex2d_desc.Height,
|
||||
},
|
||||
viewport: resources.viewport, // 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,
|
||||
// },
|
||||
output: resources.rtv.clone(),
|
||||
mvp: None,
|
||||
},
|
||||
resources.frame_count,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
@ -705,13 +715,7 @@ pub mod d3d11_hello_triangle {
|
|||
}
|
||||
}
|
||||
fn create_device() -> Result<(IDXGIFactory4, ID3D11Device, ID3D11DeviceContext)> {
|
||||
let dxgi_factory_flags = if cfg!(debug_assertions) {
|
||||
DXGI_CREATE_FACTORY_DEBUG
|
||||
} else {
|
||||
DXGI_CREATE_FACTORY_DEBUG
|
||||
};
|
||||
|
||||
let dxgi_factory: IDXGIFactory4 = unsafe { CreateDXGIFactory2(dxgi_factory_flags) }?;
|
||||
let dxgi_factory: IDXGIFactory4 = unsafe { CreateDXGIFactory2(DXGI_CREATE_FACTORY_DEBUG) }?;
|
||||
let feature_levels = vec![D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_11_1];
|
||||
|
||||
let mut out_device = None;
|
||||
|
|
|
@ -4,15 +4,17 @@
|
|||
#[cfg(test)]
|
||||
mod hello_triangle;
|
||||
|
||||
pub mod error;
|
||||
mod filter_chain;
|
||||
mod filter_pass;
|
||||
mod framebuffer;
|
||||
pub mod options;
|
||||
mod quad_render;
|
||||
mod render_target;
|
||||
mod samplers;
|
||||
mod texture;
|
||||
mod util;
|
||||
pub mod error;
|
||||
mod viewport;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
@ -21,11 +23,18 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn triangle_d3d11() {
|
||||
// let sample = hello_triangle::d3d11_hello_triangle::Sample::new("../test/slang-shaders/crt/crt-royale.slangp").unwrap();
|
||||
let sample = hello_triangle::d3d11_hello_triangle::Sample::new(
|
||||
"../test/slang-shaders/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp",
|
||||
"../test/slang-shaders/crt/crt-royale.slangp",
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
// let sample = hello_triangle::d3d11_hello_triangle::Sample::new(
|
||||
// "../test/slang-shaders/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp",
|
||||
// Some(&FilterChainOptions {
|
||||
// use_deferred_context: true,
|
||||
// })
|
||||
// )
|
||||
// .unwrap();
|
||||
|
||||
// let sample = hello_triangle::d3d11_hello_triangle::Sample::new("../test/basic.slangp").unwrap();
|
||||
|
||||
|
|
11
librashader-runtime-d3d11/src/options.rs
Normal file
11
librashader-runtime-d3d11/src/options.rs
Normal file
|
@ -0,0 +1,11 @@
|
|||
#[repr(C)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct FrameOptions {
|
||||
pub clear_history: bool,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct FilterChainOptions {
|
||||
pub use_deferred_context: bool,
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
use crate::util;
|
||||
use crate::error;
|
||||
use bytemuck::offset_of;
|
||||
use windows::core::PCSTR;
|
||||
use windows::Win32::Graphics::Direct3D::D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
|
||||
|
@ -50,7 +50,7 @@ pub(crate) struct DrawQuad {
|
|||
}
|
||||
|
||||
impl DrawQuad {
|
||||
pub fn new(device: &ID3D11Device, context: &ID3D11DeviceContext) -> util::Result<DrawQuad> {
|
||||
pub fn new(device: &ID3D11Device, context: &ID3D11DeviceContext) -> error::Result<DrawQuad> {
|
||||
unsafe {
|
||||
let buffer = device.CreateBuffer(
|
||||
&D3D11_BUFFER_DESC {
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
use crate::framebuffer::OutputFramebuffer;
|
||||
use crate::viewport::Viewport;
|
||||
use windows::Win32::Graphics::Direct3D11::D3D11_VIEWPORT;
|
||||
|
||||
#[rustfmt::skip]
|
||||
static DEFAULT_MVP: &[f32; 16] = &[
|
||||
|
@ -9,7 +11,7 @@ static DEFAULT_MVP: &[f32; 16] = &[
|
|||
];
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RenderTarget<'a> {
|
||||
pub(crate) struct RenderTarget<'a> {
|
||||
pub mvp: &'a [f32; 16],
|
||||
pub output: OutputFramebuffer,
|
||||
}
|
||||
|
@ -29,3 +31,23 @@ impl<'a> RenderTarget<'a> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&Viewport<'a>> for RenderTarget<'a> {
|
||||
fn from(value: &Viewport<'a>) -> Self {
|
||||
RenderTarget::new(
|
||||
OutputFramebuffer {
|
||||
rtv: value.output.clone(),
|
||||
size: value.size,
|
||||
viewport: D3D11_VIEWPORT {
|
||||
TopLeftX: value.x,
|
||||
TopLeftY: value.y,
|
||||
Width: value.size.width as f32,
|
||||
Height: value.size.height as f32,
|
||||
MinDepth: 0.0,
|
||||
MaxDepth: 1.0,
|
||||
},
|
||||
},
|
||||
value.mvp,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::util::Result;
|
||||
use crate::error::Result;
|
||||
use librashader_common::{FilterMode, WrapMode};
|
||||
use rustc_hash::FxHashMap;
|
||||
use windows::Win32::Graphics::Direct3D11::{
|
||||
|
|
|
@ -1,11 +1,16 @@
|
|||
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, ID3D11DeviceContext};
|
||||
use windows::Win32::Graphics::Direct3D11::{
|
||||
ID3D11Device, ID3D11DeviceContext, ID3D11ShaderResourceView, ID3D11Texture2D, D3D11_BIND_FLAG,
|
||||
D3D11_BIND_RENDER_TARGET, D3D11_BIND_SHADER_RESOURCE, D3D11_BOX, D3D11_CPU_ACCESS_FLAG,
|
||||
D3D11_CPU_ACCESS_WRITE, 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 crate::filter_chain::Direct3D11;
|
||||
|
||||
use crate::util::Result;
|
||||
use crate::error::Result;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DxImageView {
|
||||
|
@ -71,16 +76,8 @@ impl LutTexture {
|
|||
}
|
||||
}
|
||||
|
||||
// determine if format is supported.
|
||||
// bruh why does D3D11_FORMAT_SUPPORT not implement bitor???
|
||||
let mut format_support =
|
||||
D3D11_FORMAT_SUPPORT_TEXTURE2D.0 | D3D11_FORMAT_SUPPORT_SHADER_SAMPLE.0;
|
||||
if (desc.BindFlags & D3D11_BIND_RENDER_TARGET).0 != 0 {
|
||||
format_support |= D3D11_FORMAT_SUPPORT_RENDER_TARGET.0;
|
||||
}
|
||||
|
||||
// eprintln!("s {:?}, p {:?}, l {:?}", source.size, source.pitch, source.bytes.len());
|
||||
// eprintln!("{:#?}", desc);
|
||||
// Don't need to determine format support because LUTs are always DXGI_FORMAT_R8G8B8A8_UNORM
|
||||
// since we load them with the Image module.
|
||||
|
||||
unsafe {
|
||||
let handle = device.CreateTexture2D(&desc, None).unwrap();
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::error::Error;
|
||||
use crate::error;
|
||||
use std::slice;
|
||||
use windows::core::PCSTR;
|
||||
use windows::Win32::Graphics::Direct3D::Fxc::{
|
||||
|
@ -104,7 +104,7 @@ pub fn d3d11_get_closest_format(
|
|||
DXGI_FORMAT_UNKNOWN
|
||||
}
|
||||
|
||||
pub fn d3d_compile_shader(source: &[u8], entry: &[u8], version: &[u8]) -> Result<ID3DBlob> {
|
||||
pub fn d3d_compile_shader(source: &[u8], entry: &[u8], version: &[u8]) -> error::Result<ID3DBlob> {
|
||||
unsafe {
|
||||
let mut blob = None;
|
||||
D3DCompile(
|
||||
|
@ -115,7 +115,7 @@ pub fn d3d_compile_shader(source: &[u8], entry: &[u8], version: &[u8]) -> Result
|
|||
None,
|
||||
PCSTR(entry.as_ptr()),
|
||||
PCSTR(version.as_ptr()),
|
||||
if cfg!(debug_assertions) {
|
||||
if cfg!(feature = "debug-shader") {
|
||||
D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION
|
||||
} else {
|
||||
0
|
||||
|
@ -137,7 +137,7 @@ pub fn d3d11_compile_bound_shader<'a, T, L>(
|
|||
blob: &ID3DBlob,
|
||||
linkage: L,
|
||||
factory: ShaderFactory<'a, L, T>,
|
||||
) -> Result<T>
|
||||
) -> error::Result<T>
|
||||
where
|
||||
L: Into<windows::core::InParam<'a, ID3D11ClassLinkage>>,
|
||||
{
|
||||
|
@ -155,7 +155,7 @@ pub fn d3d11_create_input_layout(
|
|||
device: &ID3D11Device,
|
||||
desc: &[D3D11_INPUT_ELEMENT_DESC],
|
||||
blob: &ID3DBlob,
|
||||
) -> Result<ID3D11InputLayout> {
|
||||
) -> error::Result<ID3D11InputLayout> {
|
||||
unsafe {
|
||||
// SAFETY: slice as valid for as long as vs_blob is alive.
|
||||
let dxil =
|
||||
|
@ -165,6 +165,3 @@ pub fn d3d11_create_input_layout(
|
|||
Ok(compiled)
|
||||
}
|
||||
}
|
||||
|
||||
// todo: d3d11.c 2097
|
||||
pub type Result<T> = std::result::Result<T, crate::error::FilterChainError>;
|
||||
|
|
11
librashader-runtime-d3d11/src/viewport.rs
Normal file
11
librashader-runtime-d3d11/src/viewport.rs
Normal file
|
@ -0,0 +1,11 @@
|
|||
use librashader_common::Size;
|
||||
use windows::Win32::Graphics::Direct3D11::ID3D11RenderTargetView;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Viewport<'a> {
|
||||
pub x: f32,
|
||||
pub y: f32,
|
||||
pub size: Size<u32>,
|
||||
pub output: ID3D11RenderTargetView,
|
||||
pub mvp: Option<&'a [f32; 16]>,
|
||||
}
|
Loading…
Add table
Reference in a new issue