use concinnity_core::render::backend_init::{PostSettings, SceneData};
use concinnity_core::render::error::RenderResult;
use concinnity_core::render::post::rt_reflections::RtReflectionSettings;
use objc2::runtime::ProtocolObject;
use objc2_metal::MTLDevice;
use super::InitGpu;
use crate::metal::builtin_shaders::{RT_REFLECTIONS_FRAG, RT_REFLECTIONS_FRAG_TEXTURED};
use crate::metal::context::{GlassState, MtlSceneAssets};
use crate::metal::post::build_rt_reflection_pipeline;
use crate::metal::raytrace::{
RtGpu, RtPipelines, RtSceneGeometry, RtState, RtStaticGeometry, RtTextureCounts,
build_rt_accel, build_rt_skin_pipeline, raytracing_supported,
};
pub(super) struct RtInputs<'a> {
pub(super) world: &'a SceneData<'a>,
pub(super) scene: &'a MtlSceneAssets,
pub(super) glass: &'a GlassState,
pub(super) post: &'a PostSettings,
}
pub(super) fn build_ray_tracing(gpu: &InitGpu<'_>, inputs: RtInputs<'_>) -> RenderResult<RtState> {
let RtInputs {
world,
scene,
glass,
post,
} = inputs;
let device = &*gpu.hw.device;
let pipelines = build_rt_pipelines(device, &post.rt_reflections, gpu.hot_reload)?;
let seethrough_enabled =
!glass.seethrough_mesh_indices.is_empty() && glass.mesh_pipeline_rt.is_some();
let accel = if post.rt_reflections.is_some() && raytracing_supported(device) {
match build_rt_accel(
RtGpu {
device,
command_queue: &gpu.hw.command_queue,
frames_in_flight: gpu.frames_in_flight,
},
RtStaticGeometry {
vertex_buffer: &scene.vertex_buffer,
index_buffer: &scene.index_buffer,
},
RtSceneGeometry {
draw_objects: &world.draw_objects,
clusters: &world.instanced_clusters,
},
RtTextureCounts {
albedo_count: scene.textures.len(),
},
None,
seethrough_enabled,
)? {
Some(a) => {
tracing::info!(
"ray-traced reflections: built BVH over {} static objects",
a.blas().len()
);
Some(a)
}
None => {
tracing::warn!(
"ray-traced reflections requested but the scene has no static geometry to build a BVH from; reflections disabled"
);
None
}
}
} else {
if post.rt_reflections.is_some() {
tracing::warn!(
"ray-traced reflections requested but this GPU does not support hardware ray tracing; falling back (no RT reflections)"
);
}
None
};
if accel.is_some() {
tracing::info!(
"ray-traced reflections: dynamic transform mode = {:?}",
post.rt_dynamic
);
}
Ok(RtState {
settings: post.rt_reflections,
accel,
dynamic_mode: post.rt_dynamic,
skinned_geometry: post.rt_skinned_geometry,
update_streak: concinnity_core::render::rt_accel::FailureStreak::default(),
pipelines,
retired: concinnity_core::render::retire_pool::RetirePool::new(),
})
}
pub(in crate::metal) fn build_rt_pipelines(
device: &ProtocolObject<dyn MTLDevice>,
settings: &Option<RtReflectionSettings>,
hot_reload: bool,
) -> RenderResult<RtPipelines> {
let (resolve, resolve_textured) = if settings.is_some() {
(
Some(build_rt_reflection_pipeline(
device,
&RT_REFLECTIONS_FRAG,
hot_reload,
)?),
Some(build_rt_reflection_pipeline(
device,
&RT_REFLECTIONS_FRAG_TEXTURED,
hot_reload,
)?),
)
} else {
(None, None)
};
let skin = if settings.is_some() && raytracing_supported(device) {
Some(build_rt_skin_pipeline(device, hot_reload)?)
} else {
None
};
Ok(RtPipelines {
resolve,
resolve_textured,
skin,
})
}