#![deny(unsafe_op_in_unsafe_fn)]
use crate::metal::error::allocation_failed;
use concinnity_core::gfx::render_types;
use concinnity_core::render::error::RenderResult;
use concinnity_core::render::post::ssr::settings::SsrSettings;
use concinnity_core::render::post::ssr::{SsrInputs, SsrPass};
use objc2::rc::Retained;
use objc2::runtime::ProtocolObject;
use objc2_metal::{MTLDevice as _, MTLPixelFormat, MTLTexture, MTLTextureUsage};
use crate::metal::context::MtlContext;
use crate::metal::descriptors::TextureDesc;
use crate::metal::post::post_device::MtlPostPipeline;
use crate::metal::post::reflection_composite::MtlReflectionCompositePass;
pub(crate) type MtlSsrPass = SsrPass<MtlPostPipeline>;
pub(crate) struct SsrState {
pub settings: Option<SsrSettings>,
pub reflection: Option<Retained<ProtocolObject<dyn MTLTexture>>>,
pub resolve: Option<MtlSsrPass>,
pub composite: Option<MtlReflectionCompositePass>,
pub trace_scale: u32,
}
pub(crate) fn create_reflection_target(
device: &ProtocolObject<dyn objc2_metal::MTLDevice>,
width: u32,
height: u32,
trace_scale: u32,
) -> RenderResult<Retained<ProtocolObject<dyn MTLTexture>>> {
let s = trace_scale.max(1);
let desc = TextureDesc {
format: MTLPixelFormat::RGBA16Float,
width: (width / s).max(1) as usize,
height: (height / s).max(1) as usize,
usage: MTLTextureUsage(MTLTextureUsage::ShaderRead.0 | MTLTextureUsage::RenderTarget.0),
..Default::default()
}
.build();
device
.newTextureWithDescriptor(&desc)
.ok_or_else(|| allocation_failed("reflection texture"))
}
impl MtlContext {
pub(in crate::metal) fn encode_ssr_resolve(
&self,
cmd_buf: &ProtocolObject<dyn objc2_metal::MTLCommandBuffer>,
ssr_params: &render_types::SsrParams,
) -> RenderResult<u32> {
let (Some(reflection), Some(resolve), Some(normal_depth), Some(roughness)) = (
&self.ssr.reflection,
&self.ssr.resolve,
self.gbuffer_normal_depth(),
self.gbuffer_roughness(),
) else {
return Ok(0);
};
resolve.encode(
&self.post_device(),
cmd_buf,
SsrInputs {
target: reflection.as_ref(),
scene: self.targets.hdr.hdr_resolve.as_ref(),
normal_depth,
roughness,
prefilter: self.scene.env_map.prefilter.as_ref(),
},
ssr_params,
)?;
self.encode_reflection_composite(cmd_buf)?;
Ok(0)
}
}