rt(gl): account for flipped coordinate space when blitting to output

This commit is contained in:
chyyran 2024-03-03 12:44:24 -05:00 committed by Ronny Chan
parent bacfbf0791
commit 623c6776f7
6 changed files with 76 additions and 33 deletions

View file

@ -10,7 +10,7 @@ use crate::texture::InputTexture;
use crate::util::{gl_get_version, gl_u16_to_version}; use crate::util::{gl_get_version, gl_u16_to_version};
use crate::{error, GLImage}; use crate::{error, GLImage};
use gl::types::GLuint; use gl::types::GLuint;
use librashader_common::Viewport; use librashader_common::{FilterMode, Viewport, WrapMode};
use librashader_presets::{ShaderPassConfig, ShaderPreset, TextureConfig}; use librashader_presets::{ShaderPassConfig, ShaderPreset, TextureConfig};
use librashader_reflect::back::glsl::GlslVersion; use librashader_reflect::back::glsl::GlslVersion;
@ -250,7 +250,7 @@ impl<T: GLInterface> FilterChainImpl<T> {
T::FramebufferInterface::init(&mut back, input.size, input.format)?; T::FramebufferInterface::init(&mut back, input.size, input.format)?;
} }
back.copy_from::<T::FramebufferInterface>(input)?; back.copy_from::<T::FramebufferInterface>(input, false)?;
self.history_framebuffers.push_front(back) self.history_framebuffers.push_front(back)
} }
@ -302,12 +302,17 @@ impl<T: GLInterface> FilterChainImpl<T> {
} }
// shader_gl3: 2067 // shader_gl3: 2067
let original = InputTexture { // let original = InputTexture {
image: *input, // image: *input,
filter, // filter,
mip_filter: filter, // mip_filter: filter,
wrap_mode, // wrap_mode,
}; // };
let mut flipped = T::FramebufferInterface::new(1);
flipped.copy_from::<T::FramebufferInterface>(&input, true)?;
let original = flipped.as_texture(filter, wrap_mode);
let mut source = original; let mut source = original;
@ -363,9 +368,19 @@ impl<T: GLInterface> FilterChainImpl<T> {
} }
self.draw_quad.bind_vertices(QuadType::Final); self.draw_quad.bind_vertices(QuadType::Final);
// try to hint the optimizer // try to hint the optimizer
assert_eq!(last.len(), 1); assert_eq!(last.len(), 1);
if let Some(pass) = last.iter_mut().next() { if let Some(pass) = last.iter_mut().next() {
// Need to flip the output, so we'll render to a backbuffer before blitting back to the viewport.
let mut output = T::FramebufferInterface::new(1);
output.right_size::<T::FramebufferInterface>(
&viewport
.output
.as_texture(FilterMode::Linear, WrapMode::ClampToEdge)
.image,
)?;
source.filter = pass.config.filter; source.filter = pass.config.filter;
source.mip_filter = pass.config.filter; source.mip_filter = pass.config.filter;
source.wrap_mode = pass.config.wrap_mode; source.wrap_mode = pass.config.wrap_mode;
@ -378,11 +393,22 @@ impl<T: GLInterface> FilterChainImpl<T> {
viewport, viewport,
&original, &original,
&source, &source,
RenderTarget::viewport(viewport), RenderTarget::viewport_with_output(&output, viewport),
); );
self.common.output_textures[passes_len - 1] = viewport self.common.output_textures[passes_len - 1] =
.output output.as_texture(pass.config.filter, pass.config.wrap_mode);
.as_texture(pass.config.filter, pass.config.wrap_mode);
// SAFETY: viewport should be the same size as output texture.
unsafe {
viewport
.output
.copy_from_unchecked::<T::FramebufferInterface>(
&output
.as_texture(pass.config.filter, pass.config.wrap_mode)
.image,
true,
)?;
}
} }
// swap feedback framebuffers with output // swap feedback framebuffers with output
@ -392,7 +418,6 @@ impl<T: GLInterface> FilterChainImpl<T> {
); );
self.push_history(input)?; self.push_history(input)?;
self.draw_quad.unbind_vertices(); self.draw_quad.unbind_vertices();
Ok(()) Ok(())

View file

@ -67,8 +67,34 @@ impl GLFramebuffer {
) )
} }
pub(crate) fn copy_from<T: FramebufferInterface>(&mut self, image: &GLImage) -> Result<()> { pub(crate) unsafe fn copy_from_unchecked<T: FramebufferInterface>(
T::copy_from(self, image) &self,
image: &GLImage,
flip_y: bool,
) -> Result<()> {
// SAFETY: checked size above.
unsafe { T::copy_from_unchecked(self, image, flip_y) }
}
pub(crate) fn right_size<T: FramebufferInterface>(&mut self, image: &GLImage) -> Result<()> {
if image.size != self.size || image.format != self.format {
T::init(self, image.size, image.format)?;
}
Ok(())
}
pub(crate) fn copy_from<T: FramebufferInterface>(
&mut self,
image: &GLImage,
flip_y: bool,
) -> Result<()> {
if image.size != self.size || image.format != self.format {
T::init(self, image.size, image.format)?;
}
// SAFETY: checked size above.
unsafe { self.copy_from_unchecked::<T>(image, flip_y) }
} }
pub(crate) fn as_texture(&self, filter: FilterMode, wrap_mode: WrapMode) -> InputTexture { pub(crate) fn as_texture(&self, filter: FilterMode, wrap_mode: WrapMode) -> InputTexture {

View file

@ -80,12 +80,8 @@ impl FramebufferInterface for Gl3Framebuffer {
} }
} }
} }
fn copy_from(fb: &mut GLFramebuffer, image: &GLImage) -> Result<()> {
// 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(fb, image.size, image.format)?;
}
unsafe fn copy_from_unchecked(fb: &GLFramebuffer, image: &GLImage, flip_y: bool) -> Result<()> {
unsafe { unsafe {
gl::BindFramebuffer(gl::FRAMEBUFFER, fb.fbo); gl::BindFramebuffer(gl::FRAMEBUFFER, fb.fbo);
@ -112,9 +108,9 @@ impl FramebufferInterface for Gl3Framebuffer {
fb.size.width as GLint, fb.size.width as GLint,
fb.size.height as GLint, fb.size.height as GLint,
0, 0,
0, if flip_y { fb.size.height as GLint } else { 0 },
fb.size.width as GLint, fb.size.width as GLint,
fb.size.height as GLint, if flip_y { 0 } else { fb.size.height as GLint },
gl::COLOR_BUFFER_BIT, gl::COLOR_BUFFER_BIT,
gl::NEAREST, gl::NEAREST,
); );

View file

@ -77,17 +77,12 @@ impl FramebufferInterface for Gl46Framebuffer {
); );
} }
} }
fn copy_from(fb: &mut GLFramebuffer, image: &GLImage) -> Result<()> { unsafe fn copy_from_unchecked(fb: &GLFramebuffer, image: &GLImage, flip_y: bool) -> Result<()> {
// todo: confirm this behaviour for unbound image. // todo: confirm this behaviour for unbound image.
if image.handle == 0 { if image.handle == 0 {
return Ok(()); 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(fb, image.size, image.format)?;
}
unsafe { unsafe {
// gl::NamedFramebufferDrawBuffer(fb.handle, gl::COLOR_ATTACHMENT1); // gl::NamedFramebufferDrawBuffer(fb.handle, gl::COLOR_ATTACHMENT1);
gl::NamedFramebufferReadBuffer(image.handle, gl::COLOR_ATTACHMENT0); gl::NamedFramebufferReadBuffer(image.handle, gl::COLOR_ATTACHMENT0);
@ -101,9 +96,9 @@ impl FramebufferInterface for Gl46Framebuffer {
image.size.width as GLint, image.size.width as GLint,
image.size.height as GLint, image.size.height as GLint,
0, 0,
0, if flip_y { fb.size.height as GLint } else { 0 },
fb.size.width as GLint, fb.size.width as GLint,
fb.size.height as GLint, if flip_y { 0 } else { fb.size.height as GLint },
gl::COLOR_BUFFER_BIT, gl::COLOR_BUFFER_BIT,
gl::NEAREST, gl::NEAREST,
); );

View file

@ -95,7 +95,7 @@ pub(crate) trait FramebufferInterface {
mipmap: bool, mipmap: bool,
) -> Result<Size<u32>>; ) -> Result<Size<u32>>;
fn clear<const REBIND: bool>(fb: &GLFramebuffer); fn clear<const REBIND: bool>(fb: &GLFramebuffer);
fn copy_from(fb: &mut GLFramebuffer, image: &GLImage) -> Result<()>; unsafe fn copy_from_unchecked(fb: &GLFramebuffer, image: &GLImage, flip_y: bool) -> Result<()>;
fn init(fb: &mut GLFramebuffer, size: Size<u32>, format: impl Into<GLenum>) -> Result<()>; fn init(fb: &mut GLFramebuffer, size: Size<u32>, format: impl Into<GLenum>) -> Result<()>;
} }

View file

@ -9,7 +9,8 @@ fn triangle_gl() {
unsafe { unsafe {
let mut filter = FilterChainGL::load_from_path( let mut filter = FilterChainGL::load_from_path(
"../test/shaders_slang/crt/crt-royale.slangp", "../test/shaders_slang/crt/crt-hyllian.slangp",
// "../test/shaders_slang/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp",
Some(&FilterChainOptionsGL { Some(&FilterChainOptionsGL {
glsl_version: 0, glsl_version: 0,
use_dsa: false, use_dsa: false,
@ -30,7 +31,7 @@ fn triangle_gl46() {
let mut filter = FilterChainGL::load_from_path( let mut filter = FilterChainGL::load_from_path(
// "../test/slang-shaders/vhs/VHSPro.slangp", // "../test/slang-shaders/vhs/VHSPro.slangp",
// "../test/slang-shaders/test/history.slangp", // "../test/slang-shaders/test/history.slangp",
"../test/shaders_slang/crt/crt-royale.slangp", "../test/shaders_slang/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp",
// "../test/shadersslang/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp", // "../test/shadersslang/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp",
Some(&FilterChainOptionsGL { Some(&FilterChainOptionsGL {
glsl_version: 0, glsl_version: 0,