d3d11: fix flickering when using feedback

This commit is contained in:
chyyran 2022-12-01 00:11:41 -05:00
parent acab02e401
commit 8fa38c564c
11 changed files with 110 additions and 45 deletions

View file

@ -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,
&current_context,
Size::new(1, 1),
0,
ImageFormat::R8G8B8A8Unorm,
)
});
@ -141,8 +141,8 @@ impl FilterChain {
feedback_framebuffers.resize_with(filters.len(), || {
OwnedFramebuffer::new(
device,
&current_context,
Size::new(1, 1),
1,
ImageFormat::R8G8B8A8Unorm,
)
});
@ -158,7 +158,9 @@ impl FilterChain {
let luts = FilterChain::load_luts(device, &current_context, &preset.textures)?;
let (history_framebuffers, history_textures) =
FilterChain::init_history(device, &filters)?;
FilterChain::init_history(device,
&current_context,
&filters)?;
let draw_quad = DrawQuad::new(device, &current_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)?;

View file

@ -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);

View file

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

View file

@ -23,7 +23,7 @@ pub use texture::DxImageView;
#[cfg(test)]
mod tests {
use crate::options::FilterChainOptions;
use super::*;
#[test]

View file

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

View file

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

View file

@ -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)?;

View file

@ -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;
}

View file

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

View file

@ -16,4 +16,10 @@ impl BindTexture for Gl46BindTexture {
);
}
}
fn gen_mipmaps(texture: &Texture) {
unsafe {
gl::GenerateTextureMipmap(texture.image.handle)
}
}
}

View file

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