Plowing straight ahead

This commit is contained in:
Wito Wiala 2026-05-19 22:54:27 +01:00
parent 050698c1d0
commit 44099dffa9
14 changed files with 87 additions and 126 deletions

View file

@ -1045,7 +1045,7 @@ const SRGB_TO_LINEAR_LUT: [Float; 256] = [
pub const RES: u32 = 64;
#[repr(C)]
#[derive(Clone, Copy, Debug, Default)]
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Coeffs {
pub c0: Float,
pub c1: Float,
@ -1099,10 +1099,10 @@ impl Mul<Float> for Coeffs {
}
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq)]
#[derive(Clone, Debug, PartialEq)]
pub struct RGBToSpectrumTable {
pub z_nodes: Ptr<Float>,
pub coeffs: Ptr<Coeffs>,
pub z_nodes: GVec<Float>,
pub coeffs: GVec<Coeffs>,
pub n_nodes: u32,
}
@ -1113,7 +1113,7 @@ impl RGBToSpectrumTable {
#[inline(always)]
fn get_coeffs(&self, bucket: u32, z: u32, y: u32, x: u32) -> Coeffs {
let offset = bucket * (RES * RES * RES) + z * (RES * RES) + y * (RES) + x;
unsafe { *self.coeffs.add(offset as usize) }
unsafe { *self.coeffs.as_ptr().add(offset as usize) }
}
pub fn evaluate(&self, rgb: RGB) -> RGBSigmoidPolynomial {
@ -1153,7 +1153,7 @@ impl RGBToSpectrumTable {
let x = coord_a / z;
let y = coord_b / z;
let z_nodes = unsafe { core::slice::from_raw_parts(self.z_nodes.as_raw(), RES as usize) };
let z_nodes = &self.z_nodes;
let zi = find_interval(RES, |i| z_nodes[i as usize] < z) as usize;
let dz = (z - z_nodes[zi]) / (z_nodes[zi + 1] - z_nodes[zi]);
let x_float = x * (RES - 1) as Float;

View file

@ -18,5 +18,5 @@ pub mod textures;
pub mod utils;
pub use core::pbrt::*;
pub use utils::alloc::{gbox, gvec, gvec_from_slice, gvec_with_capacity, GVec, GBox};
pub use utils::alloc::{gbox, gvec, gvec_from_slice, gvec_with_capacity, leak, GBox, GVec};
pub use utils::{Array2D, PBRTOptions, Ptr, Transform};

View file

@ -62,7 +62,7 @@ impl ColorSpaceId {
}
#[repr(C)]
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Copy)]
pub struct RGBColorSpace {
pub r: Point2f,
pub g: Point2f,
@ -71,7 +71,7 @@ pub struct RGBColorSpace {
pub xyz_from_rgb: SquareMatrix3f,
pub rgb_from_xyz: SquareMatrix3f,
pub illuminant: Ptr<DenselySampledSpectrum>,
pub rgb_to_spectrum_table: RGBToSpectrumTable,
pub rgb_to_spectrum_table: Ptr<RGBToSpectrumTable>,
}
unsafe impl Send for RGBColorSpace {}

View file

@ -1,8 +1,9 @@
extern crate alloc;
use crate::utils::ptr::Ptr;
use alloc::alloc::Global;
use alloc::vec::Vec;
use alloc::boxed::Box;
use alloc::vec::Vec;
use core::alloc::{AllocError, Allocator, Layout};
use core::ptr::NonNull;
@ -200,3 +201,9 @@ pub fn gvec_from_slice<T: Clone>(slice: &[T]) -> GVec<T> {
pub fn gbox<T>(value: T) -> GBox<T> {
Box::new_in(value, GpuAlloc::default())
}
pub fn leak<T: 'static>(val: T) -> Ptr<T> {
let b = gbox(val);
let leaked: &'static T = Box::leak(b);
Ptr::from(leaked)
}

View file

@ -827,6 +827,12 @@ impl DigitPermutation {
}
}
pub fn compute_radical_inverse_permutations(seed: u64) -> GVec<DigitPermutation> {
let mut result = gvec();
result.extend(PRIMES.iter().map(|&base| DigitPermutation::new(base as i32, seed)));
result
}
pub fn scrambled_radical_inverse(base_index: u32, mut a: u64, perm: &DigitPermutation) -> Float {
let base = PRIMES[base_index as usize] as u64;

View file

@ -40,6 +40,7 @@ pub enum FloatTexture {
Mix(FloatMixTexture),
DirectionMix(FloatDirectionMixTexture),
// #[device(custom = "upload_image", variant_type = "GPUFloatImageTexture")]
Scaled(FloatScaledTexture)
Image(FloatImageTexture),
Bilerp(FloatBilerpTexture),
}
@ -105,6 +106,7 @@ impl FloatTexture {
}
}
#[derive(Clone, Debug)]
pub enum SpectrumTexture {
Constant(SpectrumConstantTexture),
Checkerboard(SpectrumCheckerboardTexture),

View file

@ -1,6 +1,6 @@
use super::*;
use crate::globals::get_options;
use crate::utils::math::compute_radical_inverse_permutations;
use shared::utils::math::compute_radical_inverse_permutations;
use anyhow::{Result, anyhow};
use shared::core::geometry::Point2i;
use shared::core::sampler::{HaltonSampler, MAX_HALTON_RESOLUTION, RandomizeStrategy};

View file

@ -258,12 +258,12 @@ impl TriQuadMesh {
TriangleMesh::new(
render_from_object,
reverse_orientation,
self.tri_indices,
self.p,
self.n,
Vec::new(),
self.uv,
self.face_indices,
&self.tri_indices,
&self.p,
&self.n,
&Vec::new(),
&self.uv,
&self.face_indices,
)
}
}

View file

@ -12,8 +12,8 @@ pub trait CreateRGBColorSpace {
r: Point2f,
g: Point2f,
b: Point2f,
illuminant: Arc<DenselySampledSpectrum>,
rgb_to_spectrum_table: Ptr<RGBToSpectrumTable>,
illuminant: &DenselySampledSpectrum,
rgb_to_spectrum_table: &RGBToSpectrumTable,
) -> Self;
}
@ -22,11 +22,12 @@ impl CreateRGBColorSpace for RGBColorSpace {
r: Point2f,
g: Point2f,
b: Point2f,
illuminant: Arc<DenselySampledSpectrum>,
rgb_to_spectrum_table: Ptr<RGBToSpectrumTable>,
illuminant: &DenselySampledSpectrum,
rgb_to_spectrum_table: &RGBToSpectrumTable,
) -> Self {
let stdspec = get_spectra_context();
let illum_spectrum = Spectrum::Dense(illuminant.as_ref().clone());
let illum_ptr = Ptr::from(illuminant);
let illum_spectrum = Spectrum::Dense(illuminant);
let w_xyz: XYZ = illum_spectrum.to_xyz(&stdspec);
let w = w_xyz.xy();
@ -49,8 +50,8 @@ impl CreateRGBColorSpace for RGBColorSpace {
g,
b,
w,
illuminant: Ptr::from(illuminant.as_ref()),
rgb_to_spectrum_table,
illuminant: illum_ptr,
rgb_to_spectrum_table: Ptr::from(rgb_to_spectrum_table),
xyz_from_rgb,
rgb_from_xyz,
}

View file

@ -1,7 +1,7 @@
use shared::Float;
use shared::core::spectrum::Spectrum;
use shared::spectra::cie::*;
use shared::spectra::{PiecewiseLinearSpectrum, DenselySampledSpectrum};
use shared::spectra::{DenselySampledSpectrum, PiecewiseLinearSpectrum};
use shared::{gbox, leak, Float, Ptr};
use std::collections::HashMap;
use std::sync::LazyLock;
@ -17,7 +17,7 @@ pub fn create_cie(data: &[Float]) -> DenselySampledSpectrum {
.collect();
let buffer = PiecewiseLinearSpectrum::new(lambdas, data.to_vec());
let spec = Spectrum::Piecewise(buffer);
let spec = Spectrum::Piecewise(Ptr::from(&*buffer));
DenselySampledSpectrum::from_spectrum(&spec)
}
@ -27,7 +27,7 @@ pub static NAMED_SPECTRA: LazyLock<HashMap<String, Spectrum>> = LazyLock::new(||
macro_rules! add {
($name:expr, $data:expr, $norm:expr) => {
let buffer = PiecewiseLinearSpectrum::from_interleaved($data, $norm);
let spectrum = Spectrum::Piecewise(buffer);
let spectrum = Spectrum::Piecewise(leak(buffer));
m.insert($name.to_string(), spectrum);
};
}
@ -49,7 +49,6 @@ pub static NAMED_SPECTRA: LazyLock<HashMap<String, Spectrum>> = LazyLock::new(||
add!("stdillum-F12", &CIE_ILLUM_F12, true);
add!("illum-acesD60", &ACES_ILLUM_D60, true);
// --- Glasses ---
add!("glass-BK7", &GLASS_BK7_ETA, false);
add!("glass-BAF10", &GLASS_BAF10_ETA, false);
add!("glass-FK51A", &GLASS_FK51A_ETA, false);
@ -58,7 +57,6 @@ pub static NAMED_SPECTRA: LazyLock<HashMap<String, Spectrum>> = LazyLock::new(||
add!("glass-F10", &GLASS_SF10_ETA, false);
add!("glass-F11", &GLASS_SF11_ETA, false);
// --- Metals ---
add!("metal-Ag-eta", &AG_ETA, false);
add!("metal-Ag-k", &AG_K, false);
add!("metal-Al-eta", &AL_ETA, false);
@ -74,87 +72,70 @@ pub static NAMED_SPECTRA: LazyLock<HashMap<String, Spectrum>> = LazyLock::new(||
add!("metal-TiO2-eta", &TIO2_ETA, false);
add!("metal-TiO2-k", &TIO2_K, false);
// --- Canon EOS 100D ---
add!("canon_eos_100d_r", &CANON_EOS_100D_R, false);
add!("canon_eos_100d_g", &CANON_EOS_100D_G, false);
add!("canon_eos_100d_b", &CANON_EOS_100D_B, false);
// --- Canon EOS 1DX MkII ---
add!("canon_eos_1dx_mkii_r", &CANON_EOS_1DX_MKII_R, false);
add!("canon_eos_1dx_mkii_g", &CANON_EOS_1DX_MKII_G, false);
add!("canon_eos_1dx_mkii_b", &CANON_EOS_1DX_MKII_B, false);
// --- Canon EOS 200D ---
add!("canon_eos_200d_r", &CANON_EOS_200D_R, false);
add!("canon_eos_200d_g", &CANON_EOS_200D_G, false);
add!("canon_eos_200d_b", &CANON_EOS_200D_B, false);
// --- Canon EOS 200D MkII ---
add!("canon_eos_200d_mkii_r", &CANON_EOS_200D_MKII_R, false);
add!("canon_eos_200d_mkii_g", &CANON_EOS_200D_MKII_G, false);
add!("canon_eos_200d_mkii_b", &CANON_EOS_200D_MKII_B, false);
// --- Canon EOS 5D ---
add!("canon_eos_5d_r", &CANON_EOS_5D_R, false);
add!("canon_eos_5d_g", &CANON_EOS_5D_G, false);
add!("canon_eos_5d_b", &CANON_EOS_5D_B, false);
// --- Canon EOS 5D MkII ---
add!("canon_eos_5d_mkii_r", &CANON_EOS_5D_MKII_R, false);
add!("canon_eos_5d_mkii_g", &CANON_EOS_5D_MKII_G, false);
add!("canon_eos_5d_mkii_b", &CANON_EOS_5D_MKII_B, false);
// --- Canon EOS 5D MkIII ---
add!("canon_eos_5d_mkiii_r", &CANON_EOS_5D_MKIII_R, false);
add!("canon_eos_5d_mkiii_g", &CANON_EOS_5D_MKIII_G, false);
add!("canon_eos_5d_mkiii_b", &CANON_EOS_5D_MKIII_B, false);
// --- Canon EOS 5D MkIV ---
add!("canon_eos_5d_mkiv_r", &CANON_EOS_5D_MKIV_R, false);
add!("canon_eos_5d_mkiv_g", &CANON_EOS_5D_MKIV_G, false);
add!("canon_eos_5d_mkiv_b", &CANON_EOS_5D_MKIV_B, false);
// --- Canon EOS 5DS ---
add!("canon_eos_5ds_r", &CANON_EOS_5DS_R, false);
add!("canon_eos_5ds_g", &CANON_EOS_5DS_G, false);
add!("canon_eos_5ds_b", &CANON_EOS_5DS_B, false);
// --- Canon EOS M ---
add!("canon_eos_m_r", &CANON_EOS_M_R, false);
add!("canon_eos_m_g", &CANON_EOS_M_G, false);
add!("canon_eos_m_b", &CANON_EOS_M_B, false);
// --- Hasselblad L1D 20C ---
add!("hasselblad_l1d_20c_r", &HASSELBLAD_L1D_20C_R, false);
add!("hasselblad_l1d_20c_g", &HASSELBLAD_L1D_20C_G, false);
add!("hasselblad_l1d_20c_b", &HASSELBLAD_L1D_20C_B, false);
// --- Nikon D810 ---
add!("nikon_d810_r", &NIKON_D810_R, false);
add!("nikon_d810_g", &NIKON_D810_G, false);
add!("nikon_d810_b", &NIKON_D810_B, false);
// --- Nikon D850 ---
add!("nikon_d850_r", &NIKON_D850_R, false);
add!("nikon_d850_g", &NIKON_D850_G, false);
add!("nikon_d850_b", &NIKON_D850_B, false);
// --- Sony ILCE 6400 ---
add!("sony_ilce_6400_r", &SONY_ILCE_6400_R, false);
add!("sony_ilce_6400_g", &SONY_ILCE_6400_G, false);
add!("sony_ilce_6400_b", &SONY_ILCE_6400_B, false);
// --- Sony ILCE 7M3 ---
add!("sony_ilce_7m3_r", &SONY_ILCE_7M3_R, false);
add!("sony_ilce_7m3_g", &SONY_ILCE_7M3_G, false);
add!("sony_ilce_7m3_b", &SONY_ILCE_7M3_B, false);
// --- Sony ILCE 7RM3 ---
add!("sony_ilce_7rm3_r", &SONY_ILCE_7RM3_R, false);
add!("sony_ilce_7rm3_g", &SONY_ILCE_7RM3_G, false);
add!("sony_ilce_7rm3_b", &SONY_ILCE_7RM3_B, false);
// --- Sony ILCE 9 ---
add!("sony_ilce_9_r", &SONY_ILCE_9_R, false);
add!("sony_ilce_9_g", &SONY_ILCE_9_G, false);
add!("sony_ilce_9_b", &SONY_ILCE_9_B, false);

View file

@ -28,19 +28,16 @@ fn get_d65_illuminant_buffer() -> Arc<DenselySampledSpectrum> {
}
pub fn cie_x() -> Spectrum {
Spectrum::Dense(CIE_X_DATA)
Spectrum::Dense(Ptr::from(&*CIE_X_DATA))
}
pub fn cie_y() -> Spectrum {
Spectrum::Dense(CIE_Y_DATA)
Spectrum::Dense(Ptr::from(&*CIE_Y_DATA))
}
pub fn cie_z() -> Spectrum {
Spectrum::Dense(CIE_Z_DATA)
Spectrum::Dense(Ptr::from(&*CIE_Z_DATA))
}
pub fn cie_d65() -> Spectrum {
Spectrum::Dense(CIE_D65_DATA)
Spectrum::Dense(Ptr::from(&*CIE_D65_DATA))
}
pub fn get_spectra_context() -> StandardSpectra {
@ -52,6 +49,7 @@ pub fn get_spectra_context() -> StandardSpectra {
}
}
pub static SRGB: LazyLock<Arc<RGBColorSpace>> = LazyLock::new(|| {
let illum = get_d65_illuminant_buffer();
let r = Point2f::new(0.64, 0.33);
@ -85,7 +83,7 @@ pub static ACES: LazyLock<Arc<RGBColorSpaceData>> = LazyLock::new(|| {
let r = Point2f::new(0.7347, 0.2653);
let g = Point2f::new(0.0000, 1.0000);
let b = Point2f::new(0.0001, -0.0770);
let table_ptr = Ptr::from(&ACES_TABLE.view);
let table_ptr = Ptr::from(&ACES_TABLE);
Arc::new(RGBColorSpace::new(r, g, b, illum, table_ptr))
});
@ -120,10 +118,10 @@ pub fn get_colorspace_context() -> StandardColorSpaces {
pub fn get_colorspace_device() -> DeviceStandardColorSpaces {
DeviceStandardColorSpaces {
srgb: Ptr::from(&*SRGB),
dci_p3: Ptr::from(&*DCI_P3),
rec2020: Ptr::from(&*REC2020),
aces2065_1: Ptr::from(&*ACES),
srgb: Ptr::from(&**SRGB),
dci_p3: Ptr::from(&**DCI_P3),
rec2020: Ptr::from(&**REC2020),
aces2065_1: Ptr::from(&**ACES),
}
}

View file

@ -1,59 +0,0 @@
use half::f16;
use shared::utils::hash::hash_buffer;
use shared::utils::math::{permutation_element, DigitPermutation, PRIMES};
use shared::Float;
#[inline(always)]
pub fn f16_to_f32(bits: u16) -> f32 {
#[cfg(feature = "cuda")]
{
// Use hardware intrinsic on CUDA
// Cast bits to cuda_f16, then cast to f32
let half_val = unsafe { core::mem::transmute::<u16, cuda_std::f16>(bits) };
half_val.to_f32()
}
#[cfg(feature = "vulkan")]
{
// Use shared logic or spirv-std intrinsics if available.
// Sadly, f16 support in rust-gpu is still maturing.
// A manual bit-conversion function is often safest here.
f16_to_f32_software(bits)
}
#[cfg(not(any(feature = "cuda", feature = "vulkan")))]
{
f16::from_bits(bits).to_f32()
}
}
pub fn compute_radical_inverse_permutations(seed: u64) -> (Vec<u16>, Vec<DigitPermutation>) {
let temp_data: Vec<Vec<u16>> = PRIMES
.iter()
.map(|&base| DigitPermutation::new(base as i32, seed).permutations)
.collect();
let mut storage: Vec<u16> = Vec::with_capacity(temp_data.iter().map(|v| v.len()).sum());
for vec in &temp_data {
storage.extend_from_slice(vec);
}
let mut views = Vec::with_capacity(PRIMES.len());
// let mut current_offset = 0;
// let storage_base_ptr = storage.as_ptr();
for (i, &base) in PRIMES.iter().enumerate() {
let len = temp_data[i].len();
let n_digits = len as u32 / base as u32;
// let ptr_to_data = storage_base_ptr.add(current_offset);
views.push(DigitPermutation::new(base as i32, n_digits as u64));
// current_offset += len;
}
(storage, views)
}

View file

@ -28,3 +28,28 @@ pub type Arena = arena::Arena<backend::cuda::CudaAllocator>;
#[cfg(not(any(feature = "cuda", feature = "vulkan")))]
pub type Arena = arena::Arena<backend::SystemAllocator>;
use half::f16;
#[inline(always)]
pub fn f16_to_f32(bits: u16) -> f32 {
#[cfg(feature = "cuda")]
{
// Use hardware intrinsic on CUDA
// Cast bits to cuda_f16, then cast to f32
let half_val = unsafe { core::mem::transmute::<u16, cuda_std::f16>(bits) };
half_val.to_f32()
}
#[cfg(feature = "vulkan")]
{
// Use shared logic or spirv-std intrinsics if available.
// Keep an eye on rust-gpu
f16_to_f32_software(bits)
}
#[cfg(not(any(feature = "cuda", feature = "vulkan")))]
{
f16::from_bits(bits).to_f32()
}
}

View file

@ -1,7 +1,7 @@
use crate::core::spectrum::SPECTRUM_FILE_CACHE;
use crate::spectra::piecewise::ReadFromFile;
use crate::core::texture::{FloatTexture, SpectrumTexture};
use crate::spectra::data::get_named_spectrum;
use crate::spectra::piecewise::ReadFromFile;
use crate::utils::FileLoc;
use anyhow::{bail, Result};
use shared::core::color::RGB;
@ -655,11 +655,11 @@ impl ParameterDictionary {
})
.unzip();
vec![Spectrum::Piecewise(PiecewiseLinearSpectrum {
lambdas: lambdas.as_ptr().into(),
values: values.as_ptr().into(),
vec![Spectrum::Piecewise(leak(PiecewiseLinearSpectrum {
lambdas: gvec_from_slice(lambdas),
values: gvec_from_slice(values),
count: lambdas.len() as u32,
})]
}))]
}
fn extract_file_spectrum(&self, param: &ParsedParameter) -> Vec<Spectrum> {
@ -681,18 +681,18 @@ fn read_spectrum_from_file(filename: &str) -> Result<Spectrum, String> {
{
let cache = SPECTRUM_FILE_CACHE.lock();
if let Some(s) = cache.get(&fn_key) {
return Ok(s.clone());
return Ok(*s); // Spectrum is Copy, so just copy it
}
}
let pls = PiecewiseLinearSpectrum::read(&fn_key)
.ok_or_else(|| format!("unable to read or parse spectrum file '{}'", fn_key))?;
let spectrum = Spectrum::Piecewise(*pls);
let spectrum = Spectrum::Piecewise(leak(pls));
{
let mut cache = SPECTRUM_FILE_CACHE.lock();
cache.insert(fn_key, spectrum.clone());
cache.insert(fn_key, spectrum);
}
Ok(spectrum)