use std::sync::OnceLock;
type RenderExec = Box<dyn Fn(ArenaRenderArgs) + Send + Sync>;
type RenderBwdExec = Box<dyn Fn(ArenaRenderBwdArgs) + Send + Sync>;
type PrepareExec = Box<dyn Fn(ArenaPrepareArgs) + Send + Sync>;
type RasterizeExec = Box<dyn Fn(ArenaRasterizeArgs) + Send + Sync>;
type HostRenderExec = Box<dyn Fn(HostRenderArgs) -> Vec<f32> + Send + Sync>;
type HostBackwardExec = Box<dyn Fn(HostBackwardArgs) -> Vec<f32> + Send + Sync>;
static RENDER: OnceLock<RenderExec> = OnceLock::new();
static RENDER_BWD: OnceLock<RenderBwdExec> = OnceLock::new();
static PREPARE: OnceLock<PrepareExec> = OnceLock::new();
static RASTERIZE: OnceLock<RasterizeExec> = OnceLock::new();
static HOST_RENDER: OnceLock<HostRenderExec> = OnceLock::new();
static HOST_BACKWARD: OnceLock<HostBackwardExec> = OnceLock::new();
#[allow(clippy::struct_excessive_bools)]
pub struct ArenaRenderArgs {
pub positions_off: usize,
pub positions_len: usize,
pub scales_off: usize,
pub scales_len: usize,
pub rotations_off: usize,
pub rotations_len: usize,
pub opacities_off: usize,
pub opacities_len: usize,
pub colors_off: usize,
pub colors_len: usize,
pub sh_coeffs_off: usize,
pub sh_coeffs_len: usize,
pub meta_off: usize,
pub dst_off: usize,
pub dst_len: usize,
pub width: u32,
pub height: u32,
pub tile_size: u32,
pub radius_scale: f32,
pub alpha_cutoff: f32,
pub max_splat_steps: u32,
pub transmittance_threshold: f32,
pub max_list_entries: u32,
pub base: *mut u8,
}
pub struct ArenaPrepareArgs {
pub positions_off: usize,
pub positions_len: usize,
pub scales_off: usize,
pub scales_len: usize,
pub rotations_off: usize,
pub rotations_len: usize,
pub opacities_off: usize,
pub opacities_len: usize,
pub colors_off: usize,
pub colors_len: usize,
pub sh_coeffs_off: usize,
pub sh_coeffs_len: usize,
pub meta_off: usize,
pub meta_len: usize,
pub prep_off: usize,
pub prep_len: usize,
pub width: u32,
pub height: u32,
pub tile_size: u32,
pub radius_scale: f32,
pub alpha_cutoff: f32,
pub max_splat_steps: u32,
pub transmittance_threshold: f32,
pub max_list_entries: u32,
pub base: *mut u8,
}
pub struct ArenaRasterizeArgs {
pub prep_off: usize,
pub prep_len: usize,
pub meta_off: usize,
pub meta_len: usize,
pub dst_off: usize,
pub dst_len: usize,
pub count: usize,
pub width: u32,
pub height: u32,
pub tile_size: u32,
pub alpha_cutoff: f32,
pub max_splat_steps: u32,
pub transmittance_threshold: f32,
pub max_list_entries: u32,
pub base: *mut u8,
}
pub struct ArenaRenderBwdArgs {
pub positions_off: usize,
pub positions_len: usize,
pub scales_off: usize,
pub scales_len: usize,
pub rotations_off: usize,
pub rotations_len: usize,
pub opacities_off: usize,
pub opacities_len: usize,
pub colors_off: usize,
pub colors_len: usize,
pub sh_coeffs_off: usize,
pub sh_coeffs_len: usize,
pub meta_off: usize,
pub d_loss_off: usize,
pub d_loss_len: usize,
pub packed_off: usize,
pub packed_len: usize,
pub width: u32,
pub height: u32,
pub tile_size: u32,
pub radius_scale: f32,
pub alpha_cutoff: f32,
pub max_splat_steps: u32,
pub transmittance_threshold: f32,
pub max_list_entries: u32,
pub loss_grad_clip: f32,
pub sh_band: u32,
pub max_anisotropy: f32,
pub base: *mut u8,
}
pub struct HostRenderArgs {
pub positions: Vec<f32>,
pub scales: Vec<f32>,
pub rotations: Vec<f32>,
pub opacities: Vec<f32>,
pub colors: Vec<f32>,
pub sh_coeffs: Vec<f32>,
pub meta: Vec<f32>,
pub width: u32,
pub height: u32,
pub tile_size: u32,
pub radius_scale: f32,
pub alpha_cutoff: f32,
pub max_splat_steps: u32,
pub transmittance_threshold: f32,
pub max_list_entries: u32,
}
pub struct HostBackwardArgs {
pub positions: Vec<f32>,
pub scales: Vec<f32>,
pub rotations: Vec<f32>,
pub opacities: Vec<f32>,
pub colors: Vec<f32>,
pub sh_coeffs: Vec<f32>,
pub meta: Vec<f32>,
pub d_loss_rgba: Vec<f32>,
pub width: u32,
pub height: u32,
pub tile_size: u32,
pub radius_scale: f32,
pub alpha_cutoff: f32,
pub max_splat_steps: u32,
pub transmittance_threshold: f32,
pub max_list_entries: u32,
pub loss_grad_clip: f32,
pub sh_band: u32,
pub max_anisotropy: f32,
}
pub fn register_splat_executors(
render: RenderExec,
backward: RenderBwdExec,
prepare: PrepareExec,
rasterize: RasterizeExec,
host_render: HostRenderExec,
host_backward: HostBackwardExec,
) {
let _ = RENDER.set(render);
let _ = RENDER_BWD.set(backward);
let _ = PREPARE.set(prepare);
let _ = RASTERIZE.set(rasterize);
let _ = HOST_RENDER.set(host_render);
let _ = HOST_BACKWARD.set(host_backward);
}
#[allow(clippy::too_many_arguments)]
pub fn render_host_slices(
positions: &[f32],
scales: &[f32],
rotations: &[f32],
opacities: &[f32],
colors: &[f32],
sh_coeffs: &[f32],
meta: &[f32],
width: u32,
height: u32,
tile_size: u32,
radius_scale: f32,
alpha_cutoff: f32,
max_splat_steps: u32,
transmittance_threshold: f32,
max_list_entries: u32,
) -> Vec<f32> {
HOST_RENDER
.get()
.expect("call `rlx_splat::register()` before host splat render")(HostRenderArgs {
positions: positions.to_vec(),
scales: scales.to_vec(),
rotations: rotations.to_vec(),
opacities: opacities.to_vec(),
colors: colors.to_vec(),
sh_coeffs: sh_coeffs.to_vec(),
meta: meta.to_vec(),
width,
height,
tile_size,
radius_scale,
alpha_cutoff,
max_splat_steps,
transmittance_threshold,
max_list_entries,
})
}
#[allow(clippy::too_many_arguments)]
pub fn backward_host_slices(
positions: &[f32],
scales: &[f32],
rotations: &[f32],
opacities: &[f32],
colors: &[f32],
sh_coeffs: &[f32],
meta: &[f32],
d_loss_rgba: &[f32],
width: u32,
height: u32,
tile_size: u32,
radius_scale: f32,
alpha_cutoff: f32,
max_splat_steps: u32,
transmittance_threshold: f32,
max_list_entries: u32,
loss_grad_clip: f32,
sh_band: u32,
max_anisotropy: f32,
) -> Vec<f32> {
HOST_BACKWARD
.get()
.expect("call `rlx_splat::register()` before host splat backward")(HostBackwardArgs {
positions: positions.to_vec(),
scales: scales.to_vec(),
rotations: rotations.to_vec(),
opacities: opacities.to_vec(),
colors: colors.to_vec(),
sh_coeffs: sh_coeffs.to_vec(),
meta: meta.to_vec(),
d_loss_rgba: d_loss_rgba.to_vec(),
width,
height,
tile_size,
radius_scale,
alpha_cutoff,
max_splat_steps,
transmittance_threshold,
max_list_entries,
loss_grad_clip,
sh_band,
max_anisotropy,
})
}
#[allow(unsafe_op_in_unsafe_fn, clippy::too_many_arguments)]
pub unsafe fn execute_gaussian_splat_prepare(
positions_off: usize,
positions_len: usize,
scales_off: usize,
scales_len: usize,
rotations_off: usize,
rotations_len: usize,
opacities_off: usize,
opacities_len: usize,
colors_off: usize,
colors_len: usize,
sh_coeffs_off: usize,
sh_coeffs_len: usize,
meta_off: usize,
meta_len: usize,
prep_off: usize,
prep_len: usize,
width: u32,
height: u32,
tile_size: u32,
radius_scale: f32,
alpha_cutoff: f32,
max_splat_steps: u32,
transmittance_threshold: f32,
max_list_entries: u32,
base: *mut u8,
) {
PREPARE
.get()
.expect("call `rlx_splat::register()` before GaussianSplatPrepare")(ArenaPrepareArgs {
positions_off,
positions_len,
scales_off,
scales_len,
rotations_off,
rotations_len,
opacities_off,
opacities_len,
colors_off,
colors_len,
sh_coeffs_off,
sh_coeffs_len,
meta_off,
meta_len,
prep_off,
prep_len,
width,
height,
tile_size,
radius_scale,
alpha_cutoff,
max_splat_steps,
transmittance_threshold,
max_list_entries,
base,
});
}
#[allow(unsafe_op_in_unsafe_fn, clippy::too_many_arguments)]
pub unsafe fn execute_gaussian_splat_rasterize(
prep_off: usize,
prep_len: usize,
meta_off: usize,
meta_len: usize,
dst_off: usize,
dst_len: usize,
count: usize,
width: u32,
height: u32,
tile_size: u32,
alpha_cutoff: f32,
max_splat_steps: u32,
transmittance_threshold: f32,
max_list_entries: u32,
base: *mut u8,
) {
RASTERIZE
.get()
.expect("call `rlx_splat::register()` before GaussianSplatRasterize")(
ArenaRasterizeArgs {
prep_off,
prep_len,
meta_off,
meta_len,
dst_off,
dst_len,
count,
width,
height,
tile_size,
alpha_cutoff,
max_splat_steps,
transmittance_threshold,
max_list_entries,
base,
},
);
}
#[allow(unsafe_op_in_unsafe_fn, clippy::too_many_arguments)]
pub unsafe fn execute_gaussian_splat_render(
positions_off: usize,
positions_len: usize,
scales_off: usize,
scales_len: usize,
rotations_off: usize,
rotations_len: usize,
opacities_off: usize,
opacities_len: usize,
colors_off: usize,
colors_len: usize,
sh_coeffs_off: usize,
sh_coeffs_len: usize,
meta_off: usize,
dst_off: usize,
dst_len: usize,
width: u32,
height: u32,
tile_size: u32,
radius_scale: f32,
alpha_cutoff: f32,
max_splat_steps: u32,
transmittance_threshold: f32,
max_list_entries: u32,
base: *mut u8,
) {
RENDER
.get()
.expect("call `rlx_splat::register()` before GaussianSplatRender")(ArenaRenderArgs {
positions_off,
positions_len,
scales_off,
scales_len,
rotations_off,
rotations_len,
opacities_off,
opacities_len,
colors_off,
colors_len,
sh_coeffs_off,
sh_coeffs_len,
meta_off,
dst_off,
dst_len,
width,
height,
tile_size,
radius_scale,
alpha_cutoff,
max_splat_steps,
transmittance_threshold,
max_list_entries,
base,
});
}
#[allow(unsafe_op_in_unsafe_fn, clippy::too_many_arguments)]
pub unsafe fn execute_gaussian_splat_render_backward(
positions_off: usize,
positions_len: usize,
scales_off: usize,
scales_len: usize,
rotations_off: usize,
rotations_len: usize,
opacities_off: usize,
opacities_len: usize,
colors_off: usize,
colors_len: usize,
sh_coeffs_off: usize,
sh_coeffs_len: usize,
meta_off: usize,
d_loss_off: usize,
d_loss_len: usize,
packed_off: usize,
packed_len: usize,
width: u32,
height: u32,
tile_size: u32,
radius_scale: f32,
alpha_cutoff: f32,
max_splat_steps: u32,
transmittance_threshold: f32,
max_list_entries: u32,
loss_grad_clip: f32,
sh_band: u32,
max_anisotropy: f32,
base: *mut u8,
) {
RENDER_BWD
.get()
.expect("call `rlx_splat::register()` before GaussianSplatRenderBackward")(
ArenaRenderBwdArgs {
positions_off,
positions_len,
scales_off,
scales_len,
rotations_off,
rotations_len,
opacities_off,
opacities_len,
colors_off,
colors_len,
sh_coeffs_off,
sh_coeffs_len,
meta_off,
d_loss_off,
d_loss_len,
packed_off,
packed_len,
width,
height,
tile_size,
radius_scale,
alpha_cutoff,
max_splat_steps,
transmittance_threshold,
max_list_entries,
loss_grad_clip,
sh_band,
max_anisotropy,
base,
},
);
}