d3d11: fix flickering when using feedback
This commit is contained in:
parent
acab02e401
commit
8fa38c564c
|
@ -65,7 +65,7 @@ pub(crate) struct Direct3D11 {
|
|||
pub context_is_deferred: bool,
|
||||
}
|
||||
|
||||
pub struct FilterCommon {
|
||||
pub(crate) struct FilterCommon {
|
||||
pub(crate) d3d11: Direct3D11,
|
||||
pub(crate) luts: FxHashMap<usize, LutTexture>,
|
||||
pub samplers: SamplerSet,
|
||||
|
@ -122,8 +122,8 @@ impl FilterChain {
|
|||
output_framebuffers.resize_with(filters.len(), || {
|
||||
OwnedFramebuffer::new(
|
||||
device,
|
||||
¤t_context,
|
||||
Size::new(1, 1),
|
||||
0,
|
||||
ImageFormat::R8G8B8A8Unorm,
|
||||
)
|
||||
});
|
||||
|
@ -141,8 +141,8 @@ impl FilterChain {
|
|||
feedback_framebuffers.resize_with(filters.len(), || {
|
||||
OwnedFramebuffer::new(
|
||||
device,
|
||||
¤t_context,
|
||||
Size::new(1, 1),
|
||||
1,
|
||||
ImageFormat::R8G8B8A8Unorm,
|
||||
)
|
||||
});
|
||||
|
@ -158,7 +158,9 @@ impl FilterChain {
|
|||
let luts = FilterChain::load_luts(device, ¤t_context, &preset.textures)?;
|
||||
|
||||
let (history_framebuffers, history_textures) =
|
||||
FilterChain::init_history(device, &filters)?;
|
||||
FilterChain::init_history(device,
|
||||
¤t_context,
|
||||
&filters)?;
|
||||
|
||||
let draw_quad = DrawQuad::new(device, ¤t_context)?;
|
||||
|
||||
|
@ -315,7 +317,8 @@ impl FilterChain {
|
|||
|
||||
fn init_history(
|
||||
device: &ID3D11Device,
|
||||
filters: &[FilterPass],
|
||||
context: &ID3D11DeviceContext,
|
||||
filters: &Vec<FilterPass>,
|
||||
) -> error::Result<(VecDeque<OwnedFramebuffer>, Box<[Option<Texture>]>)> {
|
||||
let mut required_images = 0;
|
||||
|
||||
|
@ -351,7 +354,7 @@ 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, Size::new(1, 1), 1, ImageFormat::R8G8B8A8Unorm)
|
||||
OwnedFramebuffer::new(device, context, Size::new(1, 1), ImageFormat::R8G8B8A8Unorm)
|
||||
});
|
||||
|
||||
let framebuffers = framebuffers
|
||||
|
@ -487,6 +490,25 @@ impl FilterChain {
|
|||
|
||||
self.draw_quad.bind_vertices();
|
||||
|
||||
for ((texture, fbo), pass) in self
|
||||
.common
|
||||
.feedback_textures
|
||||
.iter_mut()
|
||||
.zip(self.feedback_framebuffers.iter())
|
||||
.zip(passes.iter())
|
||||
{
|
||||
*texture = Some(Texture::from_framebuffer(fbo, pass.config.wrap_mode, pass.config.filter)?);
|
||||
}
|
||||
|
||||
for (texture, fbo) in self
|
||||
.common
|
||||
.history_textures
|
||||
.iter_mut()
|
||||
.zip(self.history_framebuffers.iter())
|
||||
{
|
||||
*texture = Some(Texture::from_framebuffer(fbo, wrap_mode, filter)?);
|
||||
}
|
||||
|
||||
let original = Texture {
|
||||
view: input.clone(),
|
||||
filter,
|
||||
|
@ -565,19 +587,11 @@ impl FilterChain {
|
|||
&source,
|
||||
viewport.into(),
|
||||
)?;
|
||||
|
||||
// diverge so we don't need to clone output.
|
||||
break;
|
||||
}
|
||||
|
||||
// swap feedback framebuffers with output
|
||||
for (output, feedback) in self
|
||||
.output_framebuffers
|
||||
.iter_mut()
|
||||
.zip(self.feedback_framebuffers.iter_mut())
|
||||
{
|
||||
std::mem::swap(output, feedback);
|
||||
}
|
||||
std::mem::swap(&mut self.output_framebuffers, &mut self.feedback_framebuffers);
|
||||
|
||||
self.push_history(&input)?;
|
||||
|
||||
|
|
|
@ -78,7 +78,7 @@ impl FilterPass {
|
|||
// framecount should be pre-modded
|
||||
fn build_semantics(
|
||||
&mut self,
|
||||
_pass_index: usize,
|
||||
pass_index: usize,
|
||||
parent: &FilterCommon,
|
||||
mvp: &[f32; 16],
|
||||
frame_count: u32,
|
||||
|
@ -205,6 +205,7 @@ impl FilterPass {
|
|||
|
||||
for (index, output) in parent.history_textures.iter().enumerate() {
|
||||
let Some(output) = output else {
|
||||
eprintln!("no history");
|
||||
continue;
|
||||
};
|
||||
if let Some(binding) = self
|
||||
|
@ -233,8 +234,10 @@ impl FilterPass {
|
|||
}
|
||||
|
||||
// PassOutput
|
||||
for (index, output) in parent.output_textures.iter().enumerate() {
|
||||
for (index, output) in parent.output_textures[0..pass_index].iter().enumerate() {
|
||||
let Some(output) = output else {
|
||||
eprintln!("no passoutput {index}");
|
||||
|
||||
continue;
|
||||
};
|
||||
if let Some(binding) = self
|
||||
|
@ -264,6 +267,7 @@ impl FilterPass {
|
|||
// PassFeedback
|
||||
for (index, feedback) in parent.feedback_textures.iter().enumerate() {
|
||||
let Some(feedback) = feedback else {
|
||||
eprintln!("no passfeedback {index}");
|
||||
continue;
|
||||
};
|
||||
if let Some(binding) = self
|
||||
|
@ -356,6 +360,12 @@ impl FilterPass {
|
|||
) -> error::Result<()> {
|
||||
let _device = &parent.d3d11.device;
|
||||
let context = &parent.d3d11.current_context;
|
||||
|
||||
if self.config.mipmap_input {
|
||||
unsafe {
|
||||
context.GenerateMips(&source.view.handle);
|
||||
}
|
||||
}
|
||||
unsafe {
|
||||
context.IASetInputLayout(&self.vertex_layout);
|
||||
context.VSSetShader(&self.vertex_shader, None);
|
||||
|
|
|
@ -5,15 +5,7 @@ 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, 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,
|
||||
D3D11_SHADER_RESOURCE_VIEW_DESC_0, D3D11_TEX2D_RTV, D3D11_TEX2D_SRV, D3D11_TEXTURE2D_DESC,
|
||||
D3D11_USAGE_DEFAULT, D3D11_VIEWPORT,
|
||||
};
|
||||
use windows::Win32::Graphics::Direct3D11::{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, D3D11_SHADER_RESOURCE_VIEW_DESC_0, D3D11_TEX2D_RTV, D3D11_TEX2D_SRV, D3D11_TEXTURE2D_DESC, D3D11_USAGE_DEFAULT, D3D11_VIEWPORT, D3D11_RESOURCE_MISC_GENERATE_MIPS, D3D11_BOX, ID3D11DeviceContext};
|
||||
use windows::Win32::Graphics::Dxgi::Common::{DXGI_FORMAT, DXGI_SAMPLE_DESC};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
@ -21,16 +13,16 @@ pub(crate) struct OwnedFramebuffer {
|
|||
pub texture: ID3D11Texture2D,
|
||||
pub size: Size<u32>,
|
||||
pub format: DXGI_FORMAT,
|
||||
pub max_levels: u32,
|
||||
device: ID3D11Device,
|
||||
context: ID3D11DeviceContext,
|
||||
is_raw: bool,
|
||||
}
|
||||
|
||||
impl OwnedFramebuffer {
|
||||
pub fn new(
|
||||
device: &ID3D11Device,
|
||||
context: &ID3D11DeviceContext,
|
||||
size: Size<u32>,
|
||||
mip_levels: u32,
|
||||
format: ImageFormat,
|
||||
) -> error::Result<OwnedFramebuffer> {
|
||||
unsafe {
|
||||
|
@ -41,7 +33,7 @@ impl OwnedFramebuffer {
|
|||
| D3D11_FORMAT_SUPPORT_SHADER_SAMPLE.0
|
||||
| D3D11_FORMAT_SUPPORT_RENDER_TARGET.0,
|
||||
);
|
||||
let desc = default_desc(size, format, mip_levels);
|
||||
let desc = default_desc(size, format, 1);
|
||||
let texture = device.CreateTexture2D(&desc, None)?;
|
||||
|
||||
Ok(OwnedFramebuffer {
|
||||
|
@ -49,7 +41,7 @@ impl OwnedFramebuffer {
|
|||
size,
|
||||
format,
|
||||
device: device.clone(),
|
||||
max_levels: mip_levels,
|
||||
context: context.clone(),
|
||||
is_raw: false,
|
||||
})
|
||||
}
|
||||
|
@ -98,7 +90,7 @@ impl OwnedFramebuffer {
|
|||
| D3D11_FORMAT_SUPPORT_RENDER_TARGET.0,
|
||||
);
|
||||
|
||||
let desc = default_desc(size, format, self.max_levels);
|
||||
let desc = default_desc(size, format, 1);
|
||||
unsafe {
|
||||
let mut texture = self.device.CreateTexture2D(&desc, None)?;
|
||||
std::mem::swap(&mut self.texture, &mut texture);
|
||||
|
@ -172,6 +164,26 @@ impl OwnedFramebuffer {
|
|||
self.init(image.size, ImageFormat::from(format))?;
|
||||
}
|
||||
|
||||
// unsafe {
|
||||
// self.context.CopySubresourceRegion(
|
||||
// &self.texture,
|
||||
// 0,
|
||||
// 0,
|
||||
// 0,
|
||||
// 0,
|
||||
// &resource,
|
||||
// 0,
|
||||
// Some(&D3D11_BOX {
|
||||
// left: 0,
|
||||
// top: 0,
|
||||
// front: 0,
|
||||
// right: self.size.width,
|
||||
// bottom: self.size.height,
|
||||
// back: 1,
|
||||
// }),
|
||||
// )
|
||||
// }
|
||||
//
|
||||
self.texture = resource;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -197,7 +209,7 @@ fn default_desc(size: Size<u32>, format: DXGI_FORMAT, mip_levels: u32) -> D3D11_
|
|||
Usage: D3D11_USAGE_DEFAULT,
|
||||
BindFlags: D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET,
|
||||
CPUAccessFlags: D3D11_CPU_ACCESS_WRITE,
|
||||
MiscFlags: Default::default(),
|
||||
MiscFlags: D3D11_RESOURCE_MISC_GENERATE_MIPS
|
||||
}
|
||||
}
|
||||
pub const fn default_viewport(size: Size<u32>) -> D3D11_VIEWPORT {
|
||||
|
|
|
@ -23,7 +23,7 @@ pub use texture::DxImageView;
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use crate::options::FilterChainOptions;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -11,6 +11,7 @@ use windows::Win32::Graphics::Direct3D11::{
|
|||
use windows::Win32::Graphics::Dxgi::Common::DXGI_SAMPLE_DESC;
|
||||
|
||||
use crate::error::Result;
|
||||
use crate::framebuffer::OwnedFramebuffer;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DxImageView {
|
||||
|
@ -18,14 +19,27 @@ pub struct DxImageView {
|
|||
pub size: Size<u32>,
|
||||
}
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Texture {
|
||||
pub(crate) struct Texture {
|
||||
pub view: DxImageView,
|
||||
pub filter: FilterMode,
|
||||
pub wrap_mode: WrapMode,
|
||||
}
|
||||
|
||||
impl Texture {
|
||||
pub fn from_framebuffer(fbo: &OwnedFramebuffer, wrap_mode: WrapMode, filter: FilterMode) -> Result<Self> {
|
||||
Ok(Texture {
|
||||
view: DxImageView {
|
||||
handle: fbo.create_shader_resource_view()?,
|
||||
size: fbo.size,
|
||||
},
|
||||
filter,
|
||||
wrap_mode
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct LutTexture {
|
||||
pub(crate) struct LutTexture {
|
||||
pub handle: ID3D11Texture2D,
|
||||
pub desc: D3D11_TEXTURE2D_DESC,
|
||||
pub image: Texture,
|
||||
|
|
|
@ -118,7 +118,8 @@ pub fn d3d_compile_shader(source: &[u8], entry: &[u8], version: &[u8]) -> error:
|
|||
if cfg!(feature = "debug-shader") {
|
||||
D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION
|
||||
} else {
|
||||
0
|
||||
D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION
|
||||
|
||||
},
|
||||
0,
|
||||
&mut blob,
|
||||
|
|
|
@ -535,16 +535,11 @@ impl<T: GLInterface> FilterChainImpl<T> {
|
|||
&source,
|
||||
viewport.into(),
|
||||
);
|
||||
self.common.output_textures[passes_len - 1] = viewport.output.as_texture(pass.config.filter, pass.config.wrap_mode);
|
||||
}
|
||||
|
||||
// swap feedback framebuffers with output
|
||||
for (output, feedback) in self
|
||||
.output_framebuffers
|
||||
.iter_mut()
|
||||
.zip(self.feedback_framebuffers.iter_mut())
|
||||
{
|
||||
std::mem::swap(output, feedback);
|
||||
}
|
||||
std::mem::swap(&mut self.output_framebuffers, &mut self.feedback_framebuffers);
|
||||
|
||||
self.push_history(input)?;
|
||||
|
||||
|
|
|
@ -45,6 +45,10 @@ impl<T: GLInterface> FilterPass<T> {
|
|||
) {
|
||||
let framebuffer = output.framebuffer;
|
||||
|
||||
if self.config.mipmap_input {
|
||||
T::BindTexture::gen_mipmaps(source);
|
||||
}
|
||||
|
||||
unsafe {
|
||||
gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer.handle);
|
||||
gl::UseProgram(self.program);
|
||||
|
@ -112,7 +116,7 @@ impl<T: GLInterface> FilterPass<T> {
|
|||
// framecount should be pre-modded
|
||||
fn build_semantics(
|
||||
&mut self,
|
||||
_pass_index: usize,
|
||||
pass_index: usize,
|
||||
parent: &FilterCommon,
|
||||
mvp: &[f32; 16],
|
||||
frame_count: u32,
|
||||
|
@ -243,7 +247,7 @@ impl<T: GLInterface> FilterPass<T> {
|
|||
}
|
||||
|
||||
// PassOutput
|
||||
for (index, output) in parent.output_textures.iter().enumerate() {
|
||||
for (index, output) in parent.output_textures[0..pass_index].iter().enumerate() {
|
||||
if !output.is_bound() {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -18,4 +18,12 @@ impl BindTexture for Gl3BindTexture {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn gen_mipmaps(texture: &Texture) {
|
||||
unsafe {
|
||||
gl::BindTexture(gl::TEXTURE_2D, texture.image.handle);
|
||||
gl::GenerateMipmap(gl::TEXTURE_2D);
|
||||
gl::BindTexture(gl::TEXTURE_2D, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,4 +16,10 @@ impl BindTexture for Gl46BindTexture {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn gen_mipmaps(texture: &Texture) {
|
||||
unsafe {
|
||||
gl::GenerateTextureMipmap(texture.image.handle)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,6 +60,7 @@ pub trait FramebufferInterface {
|
|||
|
||||
pub trait BindTexture {
|
||||
fn bind_texture(samplers: &SamplerSet, binding: &TextureBinding, texture: &Texture);
|
||||
fn gen_mipmaps(texture: &Texture);
|
||||
}
|
||||
|
||||
pub trait GLInterface {
|
||||
|
|
Loading…
Reference in a new issue