rt(mtl): fix history buffer off-by-one by buffering the history read.

This commit is contained in:
chyyran 2024-09-13 17:06:52 -04:00 committed by Ronny Chan
parent 98d8d91c66
commit 02288554b9

View file

@ -66,6 +66,14 @@ pub struct FilterChainMetal {
output_framebuffers: Box<[OwnedTexture]>, output_framebuffers: Box<[OwnedTexture]>,
feedback_framebuffers: Box<[OwnedTexture]>, feedback_framebuffers: Box<[OwnedTexture]>,
history_framebuffers: VecDeque<OwnedTexture>, history_framebuffers: VecDeque<OwnedTexture>,
/// Metal does not allow us to push the input texture to history
/// before recording framebuffers, so we double-buffer it.
///
/// First we swap OriginalHistory1 with the contents of this buffer (which were written to
/// in the previous frame)
///
/// Then we blit the original to the buffer.
prev_frame_history_buffer: OwnedTexture,
disable_mipmaps: bool, disable_mipmaps: bool,
default_options: FrameOptionsMetal, default_options: FrameOptionsMetal,
} }
@ -206,7 +214,18 @@ impl FilterChainMetal {
cmd: &ProtocolObject<dyn MTLCommandBuffer>, cmd: &ProtocolObject<dyn MTLCommandBuffer>,
input: &ProtocolObject<dyn MTLTexture>, input: &ProtocolObject<dyn MTLTexture>,
) -> error::Result<()> { ) -> error::Result<()> {
if let Some(mut back) = self.history_framebuffers.pop_back() { // If there's no history, there's no need to do any of this.
let Some(mut back) = self.history_framebuffers.pop_back() else {
return Ok(());
};
// Push the previous frame as OriginalHistory1
std::mem::swap(&mut back, &mut self.prev_frame_history_buffer);
self.history_framebuffers.push_front(back);
// Copy the current frame into prev_frame_history_buffer, which will be
// pushed to OriginalHistory1 in the next frame.
let back = &mut self.prev_frame_history_buffer;
let mipmapper = cmd let mipmapper = cmd
.blitCommandEncoder() .blitCommandEncoder()
.ok_or(FilterChainError::FailedToCreateCommandBuffer)?; .ok_or(FilterChainError::FailedToCreateCommandBuffer)?;
@ -220,15 +239,13 @@ impl FilterChainMetal {
}; };
let _old_back = std::mem::replace( let _old_back = std::mem::replace(
&mut back, back,
OwnedTexture::new(&self.common.device, size, 1, input.pixelFormat())?, OwnedTexture::new(&self.common.device, size, 1, input.pixelFormat())?,
); );
} }
back.copy_from(&mipmapper, input)?; back.copy_from(&mipmapper, input)?;
mipmapper.endEncoding(); mipmapper.endEncoding();
self.history_framebuffers.push_front(back);
}
Ok(()) Ok(())
} }
@ -290,6 +307,8 @@ impl FilterChainMetal {
// initialize history // initialize history
let (history_framebuffers, history_textures) = framebuffer_init.init_history()?; let (history_framebuffers, history_textures) = framebuffer_init.init_history()?;
let history_buffer = framebuffer_gen()?;
let draw_quad = DrawQuad::new(&device)?; let draw_quad = DrawQuad::new(&device)?;
Ok(FilterChainMetal { Ok(FilterChainMetal {
common: FilterCommon { common: FilterCommon {
@ -306,6 +325,7 @@ impl FilterChainMetal {
output_framebuffers, output_framebuffers,
feedback_framebuffers, feedback_framebuffers,
history_framebuffers, history_framebuffers,
prev_frame_history_buffer: history_buffer,
disable_mipmaps: options.map(|f| f.force_no_mipmaps).unwrap_or(false), disable_mipmaps: options.map(|f| f.force_no_mipmaps).unwrap_or(false),
default_options: Default::default(), default_options: Default::default(),
}) })