From e24beede0b7de69f0315f5da873f72d3355f80eb Mon Sep 17 00:00:00 2001 From: chyyran Date: Thu, 12 Sep 2024 01:29:29 -0400 Subject: [PATCH] rt(mtl): draw final pass to output targets --- librashader-runtime-mtl/src/draw_quad.rs | 16 ----------- librashader-runtime-mtl/src/filter_chain.rs | 28 +++++++++++++++++-- .../src/graphics_pipeline.rs | 26 +++++++++++++---- .../tests/hello_triangle/main.rs | 2 +- librashader-runtime-mtl/tests/main.rs | 2 +- 5 files changed, 47 insertions(+), 27 deletions(-) diff --git a/librashader-runtime-mtl/src/draw_quad.rs b/librashader-runtime-mtl/src/draw_quad.rs index 422d30e..15dbd01 100644 --- a/librashader-runtime-mtl/src/draw_quad.rs +++ b/librashader-runtime-mtl/src/draw_quad.rs @@ -58,22 +58,6 @@ pub struct DrawQuad { impl DrawQuad { pub fn new(device: &ProtocolObject) -> Result { let vbo_data: &'static [u8] = bytemuck::cast_slice(&VBO_DATA); - // let buffer = unsafe { - // device - // .newBufferWithBytes_length_options( - // // SAFETY: this pointer is const. - // // https://developer.apple.com/documentation/metal/mtldevice/1433429-newbufferwithbytes - // NonNull::new_unchecked(vbo_data.as_ptr() as *mut c_void), - // vbo_data.len(), - // if cfg!(target_os = "ios") { - // MTLResourceStorageModeShared - // } else { - // MTLResourceStorageModeManaged - // }, - // ) - // .ok_or(FilterChainError::BufferError)? - // }; - let buffer = unsafe { device .newBufferWithBytes_length_options( diff --git a/librashader-runtime-mtl/src/filter_chain.rs b/librashader-runtime-mtl/src/filter_chain.rs index 2dad5ff..d646db7 100644 --- a/librashader-runtime-mtl/src/filter_chain.rs +++ b/librashader-runtime-mtl/src/filter_chain.rs @@ -27,7 +27,7 @@ use librashader_runtime::quad::QuadType; use librashader_runtime::render_target::RenderTarget; use librashader_runtime::scaling::ScaleFramebuffer; use librashader_runtime::uniforms::UniformStorage; -use objc2::rc::{Id, Retained}; +use objc2::rc::Id; use objc2::runtime::ProtocolObject; use objc2_foundation::NSString; use objc2_metal::{ @@ -206,7 +206,6 @@ impl FilterChainMetal { cmd: &ProtocolObject, input: &ProtocolObject, ) -> error::Result<()> { - if let Some(mut back) = self.history_framebuffers.pop_back() { let mipmapper = cmd .blitCommandEncoder() @@ -436,6 +435,8 @@ impl FilterChainMetal { target.generate_mipmaps(&cmd)?; } + self.common.output_textures[index] = + Some(target.as_input(pass.config.filter, pass.config.wrap_mode)?); source = self.common.output_textures[index] .as_ref() .map(InputTexture::try_clone) @@ -446,7 +447,10 @@ impl FilterChainMetal { assert_eq!(last.len(), 1); if let Some(pass) = last.iter_mut().next() { - if pass.graphics_pipeline.render_pass_format != viewport.output.pixelFormat() { + if !pass + .graphics_pipeline + .has_format(viewport.output.pixelFormat()) + { // need to recompile pass.graphics_pipeline .recompile(&self.common.device, viewport.output.pixelFormat())?; @@ -455,6 +459,24 @@ impl FilterChainMetal { source.filter_mode = pass.config.filter; source.wrap_mode = pass.config.wrap_mode; source.mip_filter = pass.config.filter; + let index = passes_len - 1; + + let output_image = &self.output_framebuffers[index].texture; + + let out = RenderTarget::viewport_with_output(output_image.as_ref(), viewport); + pass.draw( + &cmd, + passes_len - 1, + &self.common, + pass.config.get_frame_count(frame_count), + options, + viewport, + &original, + &source, + &out, + QuadType::Final, + )?; + let output_image = viewport.output; let out = RenderTarget::viewport_with_output(output_image, viewport); pass.draw( diff --git a/librashader-runtime-mtl/src/graphics_pipeline.rs b/librashader-runtime-mtl/src/graphics_pipeline.rs index 465bae2..bf560dd 100644 --- a/librashader-runtime-mtl/src/graphics_pipeline.rs +++ b/librashader-runtime-mtl/src/graphics_pipeline.rs @@ -15,6 +15,7 @@ use objc2_metal::{ MTLVertexFormat, MTLVertexStepFunction, MTLViewport, }; +use librashader_common::map::FastHashMap; use objc2::rc::Retained; use objc2::runtime::ProtocolObject; @@ -23,8 +24,8 @@ pub const VERTEX_BUFFER_INDEX: usize = 4; pub struct MetalGraphicsPipeline { pub layout: PipelineLayoutObjects, - render_pipeline: Retained>, - pub render_pass_format: MTLPixelFormat, + render_pipelines: + FastHashMap>>, } pub struct PipelineLayoutObjects { @@ -154,20 +155,25 @@ impl MetalGraphicsPipeline { ) -> Result { let layout = PipelineLayoutObjects::new(shader_assembly, device)?; let pipeline = layout.create_pipeline(device, render_pass_format)?; + let mut pipelines = FastHashMap::default(); + pipelines.insert(render_pass_format, pipeline); Ok(Self { layout, - render_pipeline: pipeline, - render_pass_format, + render_pipelines: pipelines, }) } + pub fn has_format(&self, format: MTLPixelFormat) -> bool { + self.render_pipelines.contains_key(&format) + } + pub fn recompile( &mut self, device: &ProtocolObject, format: MTLPixelFormat, ) -> Result<()> { let render_pipeline = self.layout.create_pipeline(device, format)?; - self.render_pipeline = render_pipeline; + self.render_pipelines.insert(format, render_pipeline); Ok(()) } @@ -177,6 +183,14 @@ impl MetalGraphicsPipeline { buffer: &ProtocolObject, ) -> Result>> { unsafe { + let Some(pipeline) = self + .render_pipelines + .get(&output.output.pixelFormat()) + .or_else(|| self.render_pipelines.values().next()) + else { + panic!("No render available pipeline found"); + }; + let descriptor = MTLRenderPassDescriptor::new(); let ca = descriptor.colorAttachments().objectAtIndexedSubscript(0); ca.setLoadAction(MTLLoadAction::DontCare); @@ -188,7 +202,7 @@ impl MetalGraphicsPipeline { .ok_or(FilterChainError::FailedToCreateRenderPass)?; rpass.setLabel(Some(&*NSString::from_str("librashader rpass"))); - rpass.setRenderPipelineState(&self.render_pipeline); + rpass.setRenderPipelineState(pipeline); rpass.setScissorRect(MTLScissorRect { x: output.x as usize, diff --git a/librashader-runtime-mtl/tests/hello_triangle/main.rs b/librashader-runtime-mtl/tests/hello_triangle/main.rs index 319326c..60265b3 100644 --- a/librashader-runtime-mtl/tests/hello_triangle/main.rs +++ b/librashader-runtime-mtl/tests/hello_triangle/main.rs @@ -220,7 +220,7 @@ declare_class!( .expect("Failed to create a pipeline state."); let preset = - ShaderPreset::try_parse("../test/shaders_slang/crt/crt-royale.slangp").unwrap(); + ShaderPreset::try_parse("../test/shaders_slang/test/feedback.slangp").unwrap(); let filter_chain = FilterChainMetal::load_from_preset( preset, diff --git a/librashader-runtime-mtl/tests/main.rs b/librashader-runtime-mtl/tests/main.rs index 5b49ac1..796729d 100644 --- a/librashader-runtime-mtl/tests/main.rs +++ b/librashader-runtime-mtl/tests/main.rs @@ -3,4 +3,4 @@ include!("./hello_triangle/main.rs"); #[test] fn test_mtl() { main() -} \ No newline at end of file +}