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::{error, GLImage};
use gl::types::GLuint;
use librashader_common::Viewport;
use librashader_common::{FilterMode, Viewport, WrapMode};
use librashader_presets::{ShaderPassConfig, ShaderPreset, TextureConfig};
use librashader_reflect::back::glsl::GlslVersion;
@ -250,7 +250,7 @@ impl<T: GLInterface> FilterChainImpl<T> {
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)
}
@ -302,12 +302,17 @@ impl<T: GLInterface> FilterChainImpl<T> {
}
// shader_gl3: 2067
let original = InputTexture {
image: *input,
filter,
mip_filter: filter,
wrap_mode,
};
// let original = InputTexture {
// image: *input,
// filter,
// mip_filter: filter,
// 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;
@ -363,9 +368,19 @@ impl<T: GLInterface> FilterChainImpl<T> {
}
self.draw_quad.bind_vertices(QuadType::Final);
// try to hint the optimizer
assert_eq!(last.len(), 1);
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.mip_filter = pass.config.filter;
source.wrap_mode = pass.config.wrap_mode;
@ -378,11 +393,22 @@ impl<T: GLInterface> FilterChainImpl<T> {
viewport,
&original,
&source,
RenderTarget::viewport(viewport),
RenderTarget::viewport_with_output(&output, viewport),
);
self.common.output_textures[passes_len - 1] = viewport
.output
.as_texture(pass.config.filter, pass.config.wrap_mode);
self.common.output_textures[passes_len - 1] =
output.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
@ -392,7 +418,6 @@ impl<T: GLInterface> FilterChainImpl<T> {
);
self.push_history(input)?;
self.draw_quad.unbind_vertices();
Ok(())

View file

@ -67,8 +67,34 @@ impl GLFramebuffer {
)
}
pub(crate) fn copy_from<T: FramebufferInterface>(&mut self, image: &GLImage) -> Result<()> {
T::copy_from(self, image)
pub(crate) unsafe fn copy_from_unchecked<T: FramebufferInterface>(
&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 {

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 {
gl::BindFramebuffer(gl::FRAMEBUFFER, fb.fbo);
@ -112,9 +108,9 @@ impl FramebufferInterface for Gl3Framebuffer {
fb.size.width as GLint,
fb.size.height as GLint,
0,
0,
if flip_y { fb.size.height as GLint } else { 0 },
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::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.
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(fb, image.size, image.format)?;
}
unsafe {
// gl::NamedFramebufferDrawBuffer(fb.handle, gl::COLOR_ATTACHMENT1);
gl::NamedFramebufferReadBuffer(image.handle, gl::COLOR_ATTACHMENT0);
@ -101,9 +96,9 @@ impl FramebufferInterface for Gl46Framebuffer {
image.size.width as GLint,
image.size.height as GLint,
0,
0,
if flip_y { fb.size.height as GLint } else { 0 },
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::NEAREST,
);

View file

@ -95,7 +95,7 @@ pub(crate) trait FramebufferInterface {
mipmap: bool,
) -> Result<Size<u32>>;
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<()>;
}

View file

@ -9,7 +9,8 @@ fn triangle_gl() {
unsafe {
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 {
glsl_version: 0,
use_dsa: false,
@ -30,7 +31,7 @@ fn triangle_gl46() {
let mut filter = FilterChainGL::load_from_path(
// "../test/slang-shaders/vhs/VHSPro.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",
Some(&FilterChainOptionsGL {
glsl_version: 0,