rt(mtl): draw final pass to output targets

This commit is contained in:
chyyran 2024-09-12 01:29:29 -04:00 committed by Ronny Chan
parent 22b2118e97
commit e24beede0b
5 changed files with 47 additions and 27 deletions

View file

@ -58,22 +58,6 @@ pub struct DrawQuad {
impl DrawQuad { impl DrawQuad {
pub fn new(device: &ProtocolObject<dyn MTLDevice>) -> Result<DrawQuad> { pub fn new(device: &ProtocolObject<dyn MTLDevice>) -> Result<DrawQuad> {
let vbo_data: &'static [u8] = bytemuck::cast_slice(&VBO_DATA); 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 { let buffer = unsafe {
device device
.newBufferWithBytes_length_options( .newBufferWithBytes_length_options(

View file

@ -27,7 +27,7 @@ use librashader_runtime::quad::QuadType;
use librashader_runtime::render_target::RenderTarget; use librashader_runtime::render_target::RenderTarget;
use librashader_runtime::scaling::ScaleFramebuffer; use librashader_runtime::scaling::ScaleFramebuffer;
use librashader_runtime::uniforms::UniformStorage; use librashader_runtime::uniforms::UniformStorage;
use objc2::rc::{Id, Retained}; use objc2::rc::Id;
use objc2::runtime::ProtocolObject; use objc2::runtime::ProtocolObject;
use objc2_foundation::NSString; use objc2_foundation::NSString;
use objc2_metal::{ use objc2_metal::{
@ -206,7 +206,6 @@ 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 let Some(mut back) = self.history_framebuffers.pop_back() {
let mipmapper = cmd let mipmapper = cmd
.blitCommandEncoder() .blitCommandEncoder()
@ -436,6 +435,8 @@ impl FilterChainMetal {
target.generate_mipmaps(&cmd)?; 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] source = self.common.output_textures[index]
.as_ref() .as_ref()
.map(InputTexture::try_clone) .map(InputTexture::try_clone)
@ -446,7 +447,10 @@ impl FilterChainMetal {
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() {
if pass.graphics_pipeline.render_pass_format != viewport.output.pixelFormat() { if !pass
.graphics_pipeline
.has_format(viewport.output.pixelFormat())
{
// need to recompile // need to recompile
pass.graphics_pipeline pass.graphics_pipeline
.recompile(&self.common.device, viewport.output.pixelFormat())?; .recompile(&self.common.device, viewport.output.pixelFormat())?;
@ -455,6 +459,24 @@ impl FilterChainMetal {
source.filter_mode = pass.config.filter; source.filter_mode = pass.config.filter;
source.wrap_mode = pass.config.wrap_mode; source.wrap_mode = pass.config.wrap_mode;
source.mip_filter = pass.config.filter; 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 output_image = viewport.output;
let out = RenderTarget::viewport_with_output(output_image, viewport); let out = RenderTarget::viewport_with_output(output_image, viewport);
pass.draw( pass.draw(

View file

@ -15,6 +15,7 @@ use objc2_metal::{
MTLVertexFormat, MTLVertexStepFunction, MTLViewport, MTLVertexFormat, MTLVertexStepFunction, MTLViewport,
}; };
use librashader_common::map::FastHashMap;
use objc2::rc::Retained; use objc2::rc::Retained;
use objc2::runtime::ProtocolObject; use objc2::runtime::ProtocolObject;
@ -23,8 +24,8 @@ pub const VERTEX_BUFFER_INDEX: usize = 4;
pub struct MetalGraphicsPipeline { pub struct MetalGraphicsPipeline {
pub layout: PipelineLayoutObjects, pub layout: PipelineLayoutObjects,
render_pipeline: Retained<ProtocolObject<dyn MTLRenderPipelineState>>, render_pipelines:
pub render_pass_format: MTLPixelFormat, FastHashMap<MTLPixelFormat, Retained<ProtocolObject<dyn MTLRenderPipelineState>>>,
} }
pub struct PipelineLayoutObjects { pub struct PipelineLayoutObjects {
@ -154,20 +155,25 @@ impl MetalGraphicsPipeline {
) -> Result<Self> { ) -> Result<Self> {
let layout = PipelineLayoutObjects::new(shader_assembly, device)?; let layout = PipelineLayoutObjects::new(shader_assembly, device)?;
let pipeline = layout.create_pipeline(device, render_pass_format)?; let pipeline = layout.create_pipeline(device, render_pass_format)?;
let mut pipelines = FastHashMap::default();
pipelines.insert(render_pass_format, pipeline);
Ok(Self { Ok(Self {
layout, layout,
render_pipeline: pipeline, render_pipelines: pipelines,
render_pass_format,
}) })
} }
pub fn has_format(&self, format: MTLPixelFormat) -> bool {
self.render_pipelines.contains_key(&format)
}
pub fn recompile( pub fn recompile(
&mut self, &mut self,
device: &ProtocolObject<dyn MTLDevice>, device: &ProtocolObject<dyn MTLDevice>,
format: MTLPixelFormat, format: MTLPixelFormat,
) -> Result<()> { ) -> Result<()> {
let render_pipeline = self.layout.create_pipeline(device, format)?; let render_pipeline = self.layout.create_pipeline(device, format)?;
self.render_pipeline = render_pipeline; self.render_pipelines.insert(format, render_pipeline);
Ok(()) Ok(())
} }
@ -177,6 +183,14 @@ impl MetalGraphicsPipeline {
buffer: &ProtocolObject<dyn MTLCommandBuffer>, buffer: &ProtocolObject<dyn MTLCommandBuffer>,
) -> Result<Retained<ProtocolObject<dyn MTLRenderCommandEncoder>>> { ) -> Result<Retained<ProtocolObject<dyn MTLRenderCommandEncoder>>> {
unsafe { 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 descriptor = MTLRenderPassDescriptor::new();
let ca = descriptor.colorAttachments().objectAtIndexedSubscript(0); let ca = descriptor.colorAttachments().objectAtIndexedSubscript(0);
ca.setLoadAction(MTLLoadAction::DontCare); ca.setLoadAction(MTLLoadAction::DontCare);
@ -188,7 +202,7 @@ impl MetalGraphicsPipeline {
.ok_or(FilterChainError::FailedToCreateRenderPass)?; .ok_or(FilterChainError::FailedToCreateRenderPass)?;
rpass.setLabel(Some(&*NSString::from_str("librashader rpass"))); rpass.setLabel(Some(&*NSString::from_str("librashader rpass")));
rpass.setRenderPipelineState(&self.render_pipeline); rpass.setRenderPipelineState(pipeline);
rpass.setScissorRect(MTLScissorRect { rpass.setScissorRect(MTLScissorRect {
x: output.x as usize, x: output.x as usize,

View file

@ -220,7 +220,7 @@ declare_class!(
.expect("Failed to create a pipeline state."); .expect("Failed to create a pipeline state.");
let preset = 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( let filter_chain = FilterChainMetal::load_from_preset(
preset, preset,