From 30e8cf85f8b3abbbd73ac2210f7bc11b36e2715a Mon Sep 17 00:00:00 2001 From: Wito Wiala Date: Fri, 13 Feb 2026 14:16:22 +0000 Subject: [PATCH] Continuing fixing errors from thoughtless copying of shared code --- README.md | 3 +- shared/src/cameras/mod.rs | 2 +- shared/src/cameras/orthographic.rs | 2 +- shared/src/core/film.rs | 48 ++++++++++++++++++++++-------- shared/src/utils/mod.rs | 14 ++++++++- src/core/film.rs | 36 ++++++++++++---------- src/core/image/mod.rs | 25 +++++++--------- src/core/medium.rs | 4 +-- src/core/scene/builder.rs | 13 ++++---- src/core/scene/scene.rs | 19 ++++++------ src/core/texture.rs | 6 ++-- src/films/gbuffer.rs | 11 +++---- src/films/rgb.rs | 7 +++-- src/films/spectral.rs | 20 ++++--------- src/filters/triangle.rs | 1 + src/integrators/base.rs | 2 +- src/integrators/mod.rs | 5 ++-- src/integrators/path.rs | 3 +- src/integrators/pipeline.rs | 15 +++++----- src/lights/diffuse.rs | 7 ++--- src/lights/goniometric.rs | 2 +- src/lights/projection.rs | 2 +- src/shapes/bilinear.rs | 2 +- src/shapes/sphere.rs | 2 +- src/spectra/mod.rs | 10 +++---- src/textures/checkerboard.rs | 4 +-- src/textures/constant.rs | 2 +- src/textures/dots.rs | 2 +- src/textures/fbm.rs | 4 +-- src/textures/image.rs | 2 +- src/textures/mix.rs | 4 +-- src/textures/scaled.rs | 2 +- src/textures/windy.rs | 4 +-- src/textures/wrinkled.rs | 2 +- src/utils/arena.rs | 18 +++++------ src/utils/mipmap.rs | 2 +- src/utils/parser.rs | 12 ++++---- src/utils/sampling.rs | 2 +- 38 files changed, 174 insertions(+), 147 deletions(-) diff --git a/README.md b/README.md index d133a09..89ee873 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ To get a local copy up and running, follow these simple steps. 1. **Clone the repository:** ```sh - git clone + git clone cd pbrt ``` @@ -43,6 +43,7 @@ This project relies on the following external crates: * [**once_cell**](https://crates.io/crates/once_cell) * [**rand**](https://crates.io/crates/rand) * [**thiserror**](https://crates.io/crates/thiserror) +* TODO: Generate docs with cargo docs. There are a lot more crates. ## Help diff --git a/shared/src/cameras/mod.rs b/shared/src/cameras/mod.rs index 80822cf..f27a4e4 100644 --- a/shared/src/cameras/mod.rs +++ b/shared/src/cameras/mod.rs @@ -6,4 +6,4 @@ mod spherical; pub use orthographic::OrthographicCamera; pub use perspective::PerspectiveCamera; pub use realistic::RealisticCamera; -pub use spherical::{SphericalCamera, Mapping}; +pub use spherical::{Mapping, SphericalCamera}; diff --git a/shared/src/cameras/orthographic.rs b/shared/src/cameras/orthographic.rs index 51b7f4f..c60b8fd 100644 --- a/shared/src/cameras/orthographic.rs +++ b/shared/src/cameras/orthographic.rs @@ -96,7 +96,7 @@ impl CameraTrait for OrthographicCamera { p_camera, Vector3f::new(0., 0., 1.), Some(self.sample_time(sample.time)), - &*self.base().medium, + &self.base().medium, ); if self.lens_radius > 0. { let p_lens_vec = diff --git a/shared/src/core/film.rs b/shared/src/core/film.rs index 228fae1..a7bc018 100644 --- a/shared/src/core/film.rs +++ b/shared/src/core/film.rs @@ -21,7 +21,7 @@ use crate::utils::transform::AnimatedTransform; use crate::utils::{AtomicFloat, Ptr}; #[repr(C)] -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct RGBFilm { pub base: FilmBase, pub max_component_value: Float, @@ -32,7 +32,7 @@ pub struct RGBFilm { } #[repr(C)] -#[derive(Debug)] +#[derive(Debug, Clone, Default)] pub struct RGBPixel { rgb_sum: [AtomicFloat; 3], weight_sum: AtomicFloat, @@ -152,12 +152,12 @@ impl RGBFilm { } #[repr(C)] -#[derive(Debug, Default)] -#[cfg_attr(target_os = "cuda", derive(Copy, Clone))] +#[derive(Debug, Default, Clone)] +#[cfg_attr(target_os = "cuda", derive(Copy))] pub struct GBufferPixel { pub rgb_sum: [AtomicFloat; 3], pub weight_sum: AtomicFloat, - pub g_bugger_weight_sum: AtomicFloat, + pub g_buffer_weight_sum: AtomicFloat, pub rgb_splat: [AtomicFloat; 3], pub p_sum: Point3f, pub dz_dx_sum: AtomicFloat, @@ -170,8 +170,8 @@ pub struct GBufferPixel { } #[repr(C)] -#[derive(Debug)] -#[cfg_attr(target_os = "cuda", derive(Copy, Clone))] +#[derive(Debug, Clone)] +#[cfg_attr(target_os = "cuda", derive(Copy))] pub struct GBufferFilm { pub base: FilmBase, pub output_from_render: AnimatedTransform, @@ -206,7 +206,7 @@ impl GBufferFilm { } pub fn add_sample( - &mut self, + &self, _p_film: Point2i, _l: SampledSpectrum, _lambda: &SampledWavelengths, @@ -286,15 +286,37 @@ impl GBufferFilm { } #[repr(C)] -#[derive(Debug, Default)] -#[cfg_attr(target_os = "cuda", derive(Copy, Clone))] +#[derive(Debug)] +#[cfg_attr(target_os = "cuda", derive(Copy))] pub struct SpectralPixel { pub rgb_sum: [AtomicFloat; 3], - pub rgb_weigh_sum: AtomicFloat, + pub rgb_weight_sum: AtomicFloat, pub rgb_splat: [AtomicFloat; 3], pub bucket_offset: usize, } +impl Clone for SpectralPixel { + fn clone(&self) -> Self { + Self { + rgb_sum: std::array::from_fn(|i| AtomicFloat::new(self.rgb_sum[i].get())), + rgb_weight_sum: AtomicFloat::new(self.rgb_weight_sum.get()), + rgb_splat: std::array::from_fn(|i| AtomicFloat::new(self.rgb_splat[i].get())), + bucket_offset: self.bucket_offset, + } + } +} + +impl Default for SpectralPixel { + fn default() -> Self { + Self { + rgb_sum: std::array::from_fn(|_| AtomicFloat::new(0.0)), + rgb_weight_sum: AtomicFloat::new(0.0), + rgb_splat: std::array::from_fn(|_| AtomicFloat::new(0.0)), + bucket_offset: 0, + } + } +} + #[repr(C)] #[derive(Debug)] #[cfg_attr(target_os = "cuda", derive(Copy, Clone))] @@ -331,7 +353,7 @@ impl SpectralFilm { } pub fn add_sample( - &mut self, + &self, _p_film: Point2i, _l: SampledSpectrum, _lambda: &SampledWavelengths, @@ -469,7 +491,7 @@ impl Film { } pub fn add_sample( - &mut self, + &self, p_film: Point2i, l: SampledSpectrum, lambda: &SampledWavelengths, diff --git a/shared/src/utils/mod.rs b/shared/src/utils/mod.rs index 4c1c841..f4c62fc 100644 --- a/shared/src/utils/mod.rs +++ b/shared/src/utils/mod.rs @@ -59,11 +59,23 @@ where } #[repr(C)] -#[derive(Debug, Default)] +#[derive(Debug)] pub struct AtomicFloat { bits: AtomicU32, } +impl Default for AtomicFloat { + fn default() -> Self { + Self::new(0.) + } +} + +impl Clone for AtomicFloat { + fn clone(&self) -> Self { + Self::new(self.get()) + } +} + impl AtomicFloat { pub fn new(val: f32) -> Self { Self { diff --git a/src/core/film.rs b/src/core/film.rs index 2c685dc..7dbe804 100644 --- a/src/core/film.rs +++ b/src/core/film.rs @@ -3,6 +3,7 @@ use crate::core::image::{Image, ImageChannelDesc, ImageChannelValues, ImageIO, I use crate::films::*; use crate::spectra::{SRGB, data::get_named_spectrum}; use anyhow::{Result, anyhow}; +use rayon::iter::ParallelIterator; use rayon::prelude::IntoParallelIterator; use shared::Float; use shared::core::camera::CameraTransform; @@ -14,6 +15,7 @@ use shared::core::filter::{Filter, FilterTrait}; use shared::core::geometry::{Bounds2f, Bounds2i, Point2f, Point2i}; use shared::core::image::PixelFormat; use shared::core::spectrum::Spectrum; +use shared::spectra::cie::CIE_Y; use shared::spectra::{ DenselySampledSpectrum, PiecewiseLinearSpectrum, RGBColorSpace, cie::SWATCHES_RAW, }; @@ -21,7 +23,9 @@ use shared::utils::math::{SquareMatrix, linear_least_squares}; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::{Arc, LazyLock}; -use crate::spectra::{DenselySampledSpectrumBuffer, get_spectra_context}; +use crate::spectra::{ + CIE_X_DATA, CIE_Y_DATA, CIE_Z_DATA, DenselySampledSpectrumBuffer, get_spectra_context, +}; use crate::utils::{FileLoc, ParameterDictionary}; const N_SWATCH_REFLECTANCES: usize = 24; @@ -43,7 +47,7 @@ pub trait PixelSensorTrait { output_colorspace: Arc, exposure_time: Float, loc: &FileLoc, - ) -> Result { + ) -> Result { let iso = params.get_one_float("iso", 100.); let mut white_balance_temp = params.get_one_float("whitebalance", 0.); let sensor_name = params.get_one_string("sensor", "cie1931"); @@ -75,11 +79,11 @@ pub trait PixelSensorTrait { let g_opt = get_named_spectrum(&format!("{}_g", sensor_name)); let b_opt = get_named_spectrum(&format!("{}_b", sensor_name)); if r_opt.is_none() || g_opt.is_none() || b_opt.is_none() { - return Err(format!( + return anyhow!( "{}: unknown sensor type '{}' (missing RGB spectral data)", - loc, sensor_name - ) - .into()); + loc, + sensor_name + ); } let r = Arc::new(r_opt.unwrap()); @@ -114,9 +118,9 @@ pub trait PixelSensorTrait { None => &output_colorspace.illuminant, }; - let r_bar = DenselySampledSpectrum::from_spectrum(&r); - let g_bar = DenselySampledSpectrum::from_spectrum(&g); - let b_bar = DenselySampledSpectrum::from_spectrum(&b); + let r_bar = DenselySampledSpectrumBuffer::from_spectrum(&r).device(); + let g_bar = DenselySampledSpectrumBuffer::from_spectrum(&g).device(); + let b_bar = DenselySampledSpectrumBuffer::from_spectrum(&b).device(); let mut rgb_camera = [[0.; 3]; N_SWATCH_REFLECTANCES]; let swatches = Self::get_swatches(); @@ -125,9 +129,9 @@ pub trait PixelSensorTrait { let rgb = Self::project_reflectance::( &swatches[i], illum, - &Spectrum::Dense(r_bar.clone()), - &Spectrum::Dense(g_bar.clone()), - &Spectrum::Dense(b_bar.clone()), + &Spectrum::Dense(r_bar), + &Spectrum::Dense(g_bar), + &Spectrum::Dense(b_bar), ); for c in 0..3 { rgb_camera[i][c] = rgb[c]; @@ -170,13 +174,13 @@ pub trait PixelSensorTrait { imaging_ratio: Float, ) -> Self { let spectra = get_spectra_context(); - let r_bar = DenselySampledSpectrumBuffer::from_spectrum(spectra.x); - let g_bar = DenselySampledSpectrumBuffer::from_spectrum(spectra.y); - let b_bar = DenselySampledSpectrumBuffer::from_spectrum(spectra.z); + let r_bar = CIE_X_DATA.clone(); + let g_bar = CIE_Y_DATA.clone(); + let b_bar = CIE_Z_DATA.clone(); let xyz_from_sensor_rgb: SquareMatrix; if let Some(illum) = sensor_illum { - let source_white = illum.to_xyz(spectra).xy(); + let source_white = illum.to_xyz(&spectra).xy(); let target_white = output_colorspace.w; xyz_from_sensor_rgb = white_balance(source_white, target_white); } else { diff --git a/src/core/image/mod.rs b/src/core/image/mod.rs index 6eae312..d0950f6 100644 --- a/src/core/image/mod.rs +++ b/src/core/image/mod.rs @@ -102,8 +102,8 @@ impl PixelStorage { #[derive(Debug, Clone)] pub struct Image { - storage: PixelStorage, - channel_names: Vec, + pub pixels: PixelStorage, + pub channel_names: Vec, pub device: DeviceImage, } @@ -144,7 +144,7 @@ impl Image { }; Self { - storage, + pixels: storage, channel_names, device, } @@ -248,7 +248,7 @@ impl Image { } // Access - pub fn device_image(&self) -> &DeviceImage { + pub fn device(&self) -> &DeviceImage { &self.device } @@ -290,7 +290,7 @@ impl Image { let offset = self.pixel_offset(p) + c as usize; - match &self.storage { + match &self.pixels { PixelStorage::U8(data) => self.device.base.encoding.to_linear_scalar(data[offset]), PixelStorage::F16(data) => data[offset].to_f32(), PixelStorage::F32(data) => data[offset], @@ -314,7 +314,7 @@ impl Image { let nc = self.n_channels() as usize; let mut values = SmallVec::with_capacity(nc); - match &self.storage { + match &self.pixels { PixelStorage::U8(data) => { for i in 0..nc { values.push(self.device.base.encoding.to_linear_scalar(data[offset + i])); @@ -348,17 +348,14 @@ impl Image { let offset = self.pixel_offset(p) + c as usize; - match &mut self.storage { + match &mut self.pixels { PixelStorage::U8(data) => { - let data = Box::as_mut(data); data[offset] = self.device.base.encoding.from_linear_scalar(value); } PixelStorage::F16(data) => { - let data = Box::as_mut(data); data[offset] = f16::from_f32(value); } PixelStorage::F32(data) => { - let data = Box::as_mut(data); data[offset] = value; } } @@ -379,7 +376,7 @@ impl Image { let pixel_offset = self.pixel_offset(pp); let mut values = SmallVec::with_capacity(desc.offset.len()); - match &self.storage { + match &self.pixels { PixelStorage::U8(data) => { for &c in &desc.offset { let raw = data[pixel_offset + c]; @@ -410,7 +407,7 @@ impl Image { pub fn get_channel_desc( &self, - requested_channels: &[impl AsRef], + requested_channels: &[impl AsRef + std::fmt::Display], ) -> Result { let mut offset = Vec::with_capacity(requested_channels.len()); @@ -450,7 +447,7 @@ impl Image { let src_nc = self.n_channels() as usize; let dst_nc = desc.offset.len(); - let new_storage = match &self.storage { + let new_storage = match &self.pixels { PixelStorage::U8(src) => { let mut dst = vec![0u8; pixel_count * dst_nc]; for i in 0..pixel_count { @@ -580,7 +577,7 @@ impl Image { } pub fn update_view_pointers(&mut self) { - self.device.pixels = match &self.storage { + self.device.pixels = match &self.pixels { PixelStorage::U8(vec) => Pixels::U8(vec.as_ptr().into()), PixelStorage::F16(vec) => Pixels::F16((vec.as_ptr() as *const f16).into()), PixelStorage::F32(vec) => Pixels::F32(vec.as_ptr().into()), diff --git a/src/core/medium.rs b/src/core/medium.rs index 72a09c1..370b5f6 100644 --- a/src/core/medium.rs +++ b/src/core/medium.rs @@ -53,7 +53,7 @@ impl RGBGridMediumCreator for RGBGridMedium { le_grid: SampledGrid, le_scale: Float, ) -> Self { - let majorant_grid = MajorantGrid::new(*bounds, Point3i::new(16, 16, 16)); + let mut majorant_grid = MajorantGridHost::new(*bounds, Point3i::new(16, 16, 16)).device; for z in 0..majorant_grid.res.x() { for y in 0..majorant_grid.res.y() { for x in 0..majorant_grid.res.x() { @@ -117,7 +117,7 @@ impl GridMediumCreator for GridMedium { let le_spec = DenselySampledSpectrumBuffer::from_spectrum(le); - let mut majorant_grid = MajorantGrid::new(*bounds, Point3i::new(16, 16, 16)); + let mut majorant_grid = MajorantGridHost::new(*bounds, Point3i::new(16, 16, 16)).device; let is_emissive = if temperature_grid.is_some() { true } else { diff --git a/src/core/scene/builder.rs b/src/core/scene/builder.rs index b4b7236..1058b33 100644 --- a/src/core/scene/builder.rs +++ b/src/core/scene/builder.rs @@ -12,7 +12,8 @@ use shared::core::camera::CameraTransform; use shared::core::geometry::Vector3f; use shared::core::options::RenderingCoordinateSystem; use shared::spectra::RGBColorSpace; -use shared::utils::transform::{AnimatedTransform, Transform, look_at}; +use shared::utils::transform; +use shared::utils::transform::{self, AnimatedTransform, Transform}; use std::collections::{HashMap, HashSet}; use std::ops::{Index, IndexMut}; use std::sync::Arc; @@ -192,7 +193,7 @@ impl ParserTarget for BasicSceneBuilder { let stdcs = get_colorspace_device(); let _ = match stdcs.get_named(name) { Ok(cs) => { - self.graphics_state.color_space = Some(cs); + self.graphics_state.color_space = unsafe { Some(Arc::new(*cs.as_ref())) }; } Err(_) => { eprintln!("Error: Color space '{}' unknown at {}", name, loc); @@ -232,7 +233,7 @@ impl ParserTarget for BasicSceneBuilder { uz: Float, loc: FileLoc, ) { - let result = look_at((ex, ey, ez), (lx, ly, lz), (ux, uy, uz)); + let result = transform::look_at((ex, ey, ez), (lx, ly, lz), (ux, uy, uz)); match result { Ok(t) => { self.for_active_transforms(|cur| cur * &t); @@ -531,7 +532,7 @@ impl ParserTarget for BasicSceneBuilder { tex_name: &str, params: &ParsedParameterVector, loc: FileLoc, - arena: &mut Arena, + arena: Arc, ) { let name = normalize_utf8(orig_name); self.verify_world("Texture", &loc); @@ -588,9 +589,9 @@ impl ParserTarget for BasicSceneBuilder { let entity = SceneEntity { name: name.to_string(), loc, - parameters: ParameterDictionary::new(*params, None), + parameters: ParameterDictionary::new(params.clone(), None), }; - self.graphics_state.current_material_name = self.scene.add_material(entity); + self.graphics_state.current_material_name = self.scene.add_material(entity).to_string(); } fn make_named_material(&mut self, _name: &str, _params: &ParsedParameterVector, _loc: FileLoc) { todo!() diff --git a/src/core/scene/scene.rs b/src/core/scene/scene.rs index 71e44b7..77857c9 100644 --- a/src/core/scene/scene.rs +++ b/src/core/scene/scene.rs @@ -189,7 +189,7 @@ impl BasicScene { get_jobs: impl FnOnce(&mut TextureState) -> &mut HashMap>>, create_fn: F, ) where - T: Send + 'static, + T: Send + Sync + 'static, F: FnOnce(TextureSceneEntity) -> T + Send + 'static, { if texture.render_from_object.is_animated() { @@ -237,16 +237,15 @@ impl BasicScene { true } - pub fn add_float_texture(&self, name: String, texture: TextureSceneEntity, arena: &mut Arena) { + pub fn add_float_texture(&self, name: String, texture: TextureSceneEntity, arena: Arc) { let mut state = self.texture_state.lock(); - let arena = arena.clone(); self.add_texture_generic( name, texture, &mut state, |s| &mut s.serial_float_textures, |s| &mut s.float_texture_jobs, - |tex| { + move |tex| { let render_from_texture = tex.render_from_object.start_transform; let tex_dict = TextureParameterDictionary::new(tex.base.parameters.into(), None); FloatTexture::create( @@ -254,7 +253,7 @@ impl BasicScene { render_from_texture, tex_dict, tex.base.loc, - arena, + &arena, ) .expect("Could not create Float texture") }, @@ -265,7 +264,7 @@ impl BasicScene { &self, name: String, texture: TextureSceneEntity, - arena: &mut Arena, + arena: Arc, ) { let mut state = self.texture_state.lock(); self.add_texture_generic( @@ -274,7 +273,7 @@ impl BasicScene { &mut state, |s| &mut s.serial_spectrum_textures, |s| &mut s.spectrum_texture_jobs, - |tex| { + move |tex| { let render_from_texture = tex.render_from_object.start_transform; let tex_dict = TextureParameterDictionary::new(tex.base.parameters.into(), None); SpectrumTexture::create( @@ -283,7 +282,7 @@ impl BasicScene { tex_dict, SpectrumType::Albedo, tex.base.loc, - arena, + &arena, ) .expect("Could not create spectrum texture") }, @@ -378,8 +377,8 @@ impl BasicScene { ) -> (HashMap, Vec) { let mut state = self.material_state.lock(); - // Resolve normal map jobs - for (filename, job) in state.normal_map_jobs.drain() { + let finished: Vec<_> = state.normal_map_jobs.drain().collect(); + for (filename, job) in finished { state.normal_maps.insert(filename, job.wait()); } diff --git a/src/core/texture.rs b/src/core/texture.rs index 7d20824..f7ad55f 100644 --- a/src/core/texture.rs +++ b/src/core/texture.rs @@ -56,7 +56,7 @@ pub trait CreateFloatTexture { render_from_texture: Transform, params: TextureParameterDictionary, loc: FileLoc, - arena: &mut Arena, + arena: &Arena, ) -> Result; } @@ -66,7 +66,7 @@ impl FloatTexture { render_from_texture: Transform, params: TextureParameterDictionary, loc: FileLoc, - arena: &mut Arena, + arena: &Arena, ) -> Result { match name { "constant" => FloatConstantTexture::create(render_from_texture, params, loc, arena), @@ -122,7 +122,7 @@ impl SpectrumTexture { params: TextureParameterDictionary, spectrum_type: SpectrumType, loc: FileLoc, - _arena: &mut Arena, + _arena: &Arena, ) -> Result { match name { "constant" => { diff --git a/src/films/gbuffer.rs b/src/films/gbuffer.rs index 5684a59..d92aef0 100644 --- a/src/films/gbuffer.rs +++ b/src/films/gbuffer.rs @@ -1,6 +1,7 @@ use super::*; -use crate::core::film::{CreateFilmBase, PixelSensor, PixelSensorTrait}; +use crate::core::film::{CreateFilmBase, PixelSensor}; use crate::utils::containers::Array2D; +use anyhow::{Result, anyhow}; use shared::core::film::{DevicePixelSensor, FilmBase, GBufferFilm}; use shared::core::filter::FilterTrait; use shared::spectra::RGBColorSpace; @@ -25,7 +26,7 @@ impl GBufferFilmHost { if sensor_ptr.is_null() { panic!("Film must have a sensor"); } - let sensor = unsafe { &*sensor_ptr }; + let sensor = &*sensor_ptr; let output_rgbf_from_sensor_rgb = colorspace.rgb_from_xyz * sensor.xyz_from_sensor_rgb; let filter_integral = base.filter.integral(); let pixels = Array2D::new(base.pixel_bounds); @@ -64,13 +65,13 @@ impl CreateFilm for GBufferFilm { let filename = params.get_one_string("filename", "pbrt.exr"); if Path::new(&filename).extension() != Some("exr".as_ref()) { - return Err(format!("{}: EXR is the only format supported by GBufferFilm", loc).into()); + return Err(anyhow!("{}: EXR is the only format supported by GBufferFilm", loc).into()); } let coords_system = params.get_one_string("coordinatesystem", "camera"); let mut apply_inverse = false; - let camera_transform = camera_transform - .ok_or_else(|| "GBufferFilm requires a camera_transform".to_string())?; + let camera_transform = + camera_transform.ok_or_else(|| anyhow!("GBufferFilm requires a camera_transform"))?; let output_from_render = if coords_system == "camera" { apply_inverse = true; camera_transform.render_from_camera diff --git a/src/films/rgb.rs b/src/films/rgb.rs index 8951067..9671f26 100644 --- a/src/films/rgb.rs +++ b/src/films/rgb.rs @@ -2,6 +2,7 @@ use super::*; use crate::Arena; use crate::core::film::{CreateFilmBase, PixelSensorTrait}; use crate::utils::containers::Array2D; +use anyhow::Result; use shared::core::camera::CameraTransform; use shared::core::film::{DevicePixelSensor, Film, FilmBase, RGBFilm, RGBPixel}; use shared::core::filter::FilterTrait; @@ -64,10 +65,10 @@ impl CreateFilm for RGBFilm { params: &ParameterDictionary, exposure_time: Float, filter: Filter, - camera_transform: Option, + _camera_transform: Option, loc: &FileLoc, - arena: &mut Arena, - ) -> anyhow::Result { + _ arena: &Arena, + ) -> Result { let colorspace = params.color_space.as_ref().unwrap(); let max_component_value = params.get_one_float("maxcomponentvalue", Float::INFINITY); let write_fp16 = params.get_one_bool("savefp16", true); diff --git a/src/films/spectral.rs b/src/films/spectral.rs index 13f4d6d..2f50ece 100644 --- a/src/films/spectral.rs +++ b/src/films/spectral.rs @@ -2,6 +2,7 @@ use super::*; use crate::core::film::{CreateFilmBase, PixelSensorTrait}; use crate::utils::containers::Array2D; use crate::{Arena, FileLoc, ParameterDictionary}; +use anyhow::Result; use shared::Float; use shared::core::camera::CameraTransform; use shared::core::film::{ @@ -24,7 +25,7 @@ struct SpectralFilmStorage { pub struct SpectralFilmHost { pub device: SpectralFilm, - storage: Box, + storage: Arc, } impl SpectralFilmHost { @@ -56,20 +57,11 @@ impl SpectralFilmHost { for i in 0..n_pixels { let pixel = pixels.get_linear_mut(i); - pixel.bucket_offset = i * n_buckets; - - unsafe { - let offset = i * n_buckets; - - pixel.bucket_sums = p_sums_base.add(offset); - pixel.weight_sums = p_weights_base.add(offset); - pixel.bucket_splats = p_splats_base.add(offset); - } } - let storage = Box::new(SpectralFilmStorage { - pixels, + let storage = Arc::new(SpectralFilmStorage { + pixels: pixels.device, bucket_sums, weight_sums, bucket_splats, @@ -87,7 +79,7 @@ impl SpectralFilmHost { output_rgbf_from_sensor_rgb: SquareMatrix::identity(), pixels: DeviceArray2D { - values: Ptr::from(&storage.pixels), + values: storage.pixels.as_ptr(), extent: base.pixel_bounds, stride: base.pixel_bounds.p_max.x() - base.pixel_bounds.p_min.x(), }, @@ -97,7 +89,7 @@ impl SpectralFilmHost { bucket_splats: storage.bucket_splats.as_ptr() as *mut AtomicFloat, }; - Self { device, storage }; + Self { device, storage } } } diff --git a/src/filters/triangle.rs b/src/filters/triangle.rs index e69de29..8b13789 100644 --- a/src/filters/triangle.rs +++ b/src/filters/triangle.rs @@ -0,0 +1 @@ + diff --git a/src/integrators/base.rs b/src/integrators/base.rs index 6848eef..165dbc4 100644 --- a/src/integrators/base.rs +++ b/src/integrators/base.rs @@ -4,7 +4,7 @@ use shared::core::interaction::{Interaction, InteractionTrait}; use shared::core::light::{Light, LightTrait}; use shared::core::primitive::{Primitive, PrimitiveTrait}; use shared::core::shape::ShapeIntersection; -use shared::lights::sampler::LightSampler; +use shared::lights::sampler::{LightSampler, LightSamplerTrait}; use shared::spectra::SampledWavelengths; use shared::utils::sampling::power_heuristic; use shared::{Float, SHADOW_EPSILON}; diff --git a/src/integrators/mod.rs b/src/integrators/mod.rs index 6c61f94..dbf51ef 100644 --- a/src/integrators/mod.rs +++ b/src/integrators/mod.rs @@ -11,6 +11,7 @@ use shared::core::film::VisibleSurface; use shared::core::geometry::{Point2i, Ray}; use shared::core::sampler::Sampler; use shared::spectra::{SampledSpectrum, SampledWavelengths}; +use std::sync::Arc; pub trait IntegratorTrait { fn render(&self); @@ -22,7 +23,7 @@ pub trait RayIntegratorTrait { p_pixel: Point2i, sample_ind: usize, sampler: &mut Sampler, - arena: &mut Arena, + arena: &Arena, ); fn li( @@ -31,6 +32,6 @@ pub trait RayIntegratorTrait { lambda: &SampledWavelengths, sampler: &mut Sampler, visible_surface: bool, - arena: &mut Arena, + arena: &Arena, ) -> (SampledSpectrum, Option); } diff --git a/src/integrators/path.rs b/src/integrators/path.rs index fe61f4e..b382879 100644 --- a/src/integrators/path.rs +++ b/src/integrators/path.rs @@ -223,6 +223,7 @@ impl RayIntegratorTrait for PathIntegrator { break; }; + let t_hit = si.t_hit(); let isect = &mut si.intr; // Emission from hit surface @@ -244,7 +245,7 @@ impl RayIntegratorTrait for PathIntegrator { // Get BSDF let Some(mut bsdf) = isect.get_bsdf(&ray, lambda, &self.camera, sampler) else { state.specular_bounce = true; - isect.skip_intersection(&mut ray, si.t_hit()); + isect.skip_intersection(&mut ray, t_hit); continue; }; diff --git a/src/integrators/pipeline.rs b/src/integrators/pipeline.rs index 0b11f14..32b0e71 100644 --- a/src/integrators/pipeline.rs +++ b/src/integrators/pipeline.rs @@ -17,6 +17,7 @@ use shared::core::sampler::{Sampler, SamplerTrait}; use shared::spectra::SampledSpectrum; use std::io::Write; use std::path::Path; +use std::sync::Arc; struct PbrtProgress { bar: ProgressBar, @@ -78,9 +79,9 @@ pub fn render( _base: &IntegratorBase, camera: &Camera, sampler_prototype: &Sampler, - arena: &mut Arena, + arena: Arc, ) where - T: RayIntegratorTrait, + T: RayIntegratorTrait + Sync, { let options = get_options(); if let Some((p_pixel, sample_index)) = options.debug_start { @@ -95,7 +96,7 @@ pub fn render( &mut tile_sampler, p_pixel, s_index, - arena, + &arena, ); return; } @@ -168,7 +169,7 @@ pub fn render( &mut sampler, *p_pixel, sample_index.try_into().unwrap(), - arena, + &arena, ); } } @@ -206,7 +207,7 @@ pub fn render( let splat_scale = 1.0 / (wave_start as Float); let film_metadata = ImageMetadata::default(); - let film = *camera.get_film(); + let film = camera.get_film(); let film_image = film.get_image(&film_metadata, splat_scale); let (mse_values, _mse_debug_img) = @@ -230,7 +231,7 @@ pub fn evaluate_pixel_sample( sampler: &mut Sampler, pixel: Point2i, _sample_index: usize, - arena: &mut Arena, + arena: &Arena, ) { let mut lu = sampler.get1d(); if get_options().disable_wavelength_jitter { @@ -238,7 +239,7 @@ pub fn evaluate_pixel_sample( } let lambda = camera.get_film().sample_wavelengths(lu); - let mut film: &mut Film = camera.get_film(); + let film = camera.get_film(); let filter = film.get_filter(); let camera_sample = get_camera_sample(sampler, pixel, filter); if let Some(mut camera_ray) = camera.generate_ray_differential(camera_sample, &lambda) { diff --git a/src/lights/diffuse.rs b/src/lights/diffuse.rs index 7f9f6e8..b7c8e38 100644 --- a/src/lights/diffuse.rs +++ b/src/lights/diffuse.rs @@ -30,7 +30,6 @@ pub trait CreateDiffuseLight { image: Ptr, colorspace: Ptr, two_sided: bool, - fov: Float, ) -> Self; } @@ -42,10 +41,9 @@ impl CreateDiffuseLight for DiffuseAreaLight { scale: Float, shape: Ptr, alpha: Ptr, - image: Ptr, + image: Ptr, colorspace: Ptr, two_sided: bool, - fov: Float, ) -> Self { let is_constant_zero = match &*alpha { GPUFloatTexture::Constant(tex) => tex.evaluate(&TextureEvalContext::default()) == 0.0, @@ -93,7 +91,7 @@ impl CreateDiffuseLight for DiffuseAreaLight { Self { base, area: shape.area(), - image, + image: Ptr::from(image.device()), colorspace, shape, alpha: stored_alpha.expect("Could not retrieve texture"), @@ -203,7 +201,6 @@ impl CreateLight for DiffuseAreaLight { image.upload(arena), image_color_space.upload(arena), true, - shape.area(), ); Ok(Light::DiffuseArea(specific)) diff --git a/src/lights/goniometric.rs b/src/lights/goniometric.rs index 0d69f94..46b76b3 100644 --- a/src/lights/goniometric.rs +++ b/src/lights/goniometric.rs @@ -48,7 +48,7 @@ impl CreateGoniometricLight for GoniometricLight { base, iemit: Ptr::from(&iemit.device()), scale, - image: Ptr::from(image.device_image()), + image: Ptr::from(image.device()), distrib: Ptr::from(&distrib.device), } } diff --git a/src/lights/projection.rs b/src/lights/projection.rs index adf0fad..1f712b9 100644 --- a/src/lights/projection.rs +++ b/src/lights/projection.rs @@ -81,7 +81,7 @@ impl CreateProjectionLight for ProjectionLight { Self { base, - image: Ptr::from(image.device_image()), + image: Ptr::from(image.device()), image_color_space, distrib: Ptr::from(&distrib.device), screen_bounds, diff --git a/src/shapes/bilinear.rs b/src/shapes/bilinear.rs index 095acaf..22aa899 100644 --- a/src/shapes/bilinear.rs +++ b/src/shapes/bilinear.rs @@ -114,7 +114,7 @@ impl CreateShape for BilinearPatchShape { let host_arc = Arc::new(host); let mut global_store = ALL_BILINEAR_MESHES.lock(); - let mesh_index = global_store.len() as u32; + // let mesh_index = global_store.len() as u32; global_store.push(host_arc.clone()); drop(global_store); let n_patches = host_arc.device.n_patches; diff --git a/src/shapes/sphere.rs b/src/shapes/sphere.rs index ea58e98..1c595a2 100644 --- a/src/shapes/sphere.rs +++ b/src/shapes/sphere.rs @@ -16,7 +16,7 @@ impl CreateShape for SphereShape { parameters: ParameterDictionary, _float_textures: &HashMap>, _loc: FileLoc, - arena: &mut Arena, + arena: &Arena, ) -> Result> { let radius = parameters.get_one_float("radius", 1.); let zmin = parameters.get_one_float("zmin", -radius); diff --git a/src/spectra/mod.rs b/src/spectra/mod.rs index 415fb3e..47f25c4 100644 --- a/src/spectra/mod.rs +++ b/src/spectra/mod.rs @@ -17,17 +17,17 @@ pub mod piecewise; pub use dense::DenselySampledSpectrumBuffer; -static CIE_X_DATA: LazyLock = +pub static CIE_X_DATA: LazyLock = LazyLock::new(|| data::create_cie_buffer(&CIE_X)); -static CIE_Y_DATA: LazyLock = +pub static CIE_Y_DATA: LazyLock = LazyLock::new(|| data::create_cie_buffer(&CIE_Y)); -static CIE_Z_DATA: LazyLock = +pub static CIE_Z_DATA: LazyLock = LazyLock::new(|| data::create_cie_buffer(&CIE_Z)); -static CIE_D65_DATA: LazyLock = +pub static CIE_D65_DATA: LazyLock = LazyLock::new(|| data::create_cie_buffer(&CIE_D65)); fn get_d65_illuminant_buffer() -> Arc { - Arc::from(*&CIE_D65_DATA) + Arc::new(CIE_D65_DATA.clone()) } pub fn cie_x() -> Spectrum { diff --git a/src/textures/checkerboard.rs b/src/textures/checkerboard.rs index 2935ed8..632e9ec 100644 --- a/src/textures/checkerboard.rs +++ b/src/textures/checkerboard.rs @@ -1,5 +1,5 @@ -use anyhow::Result; use crate::Arena; +use anyhow::Result; use shared::{ core::texture::SpectrumType, textures::{FloatCheckerboardTexture, SpectrumCheckerboardTexture}, @@ -19,7 +19,7 @@ impl CreateFloatTexture for FloatCheckerboardTexture { _render_from_texture: Transform, _parameters: TextureParameterDictionary, _loc: FileLoc, - _arena: &mut Arena, + _arena: &Arena, ) -> Result { todo!() } diff --git a/src/textures/constant.rs b/src/textures/constant.rs index 389096f..e6114cf 100644 --- a/src/textures/constant.rs +++ b/src/textures/constant.rs @@ -19,7 +19,7 @@ impl CreateFloatTexture for FloatConstantTexture { _render_from_texture: Transform, _parameters: TextureParameterDictionary, _loc: FileLoc, - _arena: &mut Arena, + _arena: &Arena, ) -> Result { todo!() } diff --git a/src/textures/dots.rs b/src/textures/dots.rs index a880b82..641abb8 100644 --- a/src/textures/dots.rs +++ b/src/textures/dots.rs @@ -25,7 +25,7 @@ impl CreateFloatTexture for FloatDotsTexture { _render_from_texture: Transform, _parameters: TextureParameterDictionary, _loc: FileLoc, - _arena: &mut Arena, + _arena: &Arena, ) -> Result { todo!() } diff --git a/src/textures/fbm.rs b/src/textures/fbm.rs index 970614d..2dc8ce8 100644 --- a/src/textures/fbm.rs +++ b/src/textures/fbm.rs @@ -1,5 +1,5 @@ -use anyhow::Result; use crate::Arena; +use anyhow::Result; use shared::core::texture::TextureEvalContext; use shared::{textures::FBmTexture, utils::Transform}; @@ -13,7 +13,7 @@ impl CreateFloatTexture for FBmTexture { _render_from_texture: Transform, _parameters: TextureParameterDictionary, _loc: FileLoc, - _arena: &mut Arena, + _arena: &Arena, ) -> Result { todo!() } diff --git a/src/textures/image.rs b/src/textures/image.rs index a0ebeb2..7134c48 100644 --- a/src/textures/image.rs +++ b/src/textures/image.rs @@ -205,7 +205,7 @@ impl CreateFloatTexture for FloatImageTexture { _render_from_texture: Transform, _parameters: TextureParameterDictionary, _loc: FileLoc, - _arena: &mut Arena, + _arena: &Arena, ) -> Result { todo!() } diff --git a/src/textures/mix.rs b/src/textures/mix.rs index 78ef854..43b374b 100644 --- a/src/textures/mix.rs +++ b/src/textures/mix.rs @@ -31,7 +31,7 @@ impl FloatMixTexture { _render_from_texture: &Transform, params: &TextureParameterDictionary, _loc: &FileLoc, - _arena: &mut Arena, + _arena: &Arena, ) -> Result { let tex1 = params.get_float_texture("tex1", 0.); let tex2 = params.get_float_texture("tex2", 1.); @@ -72,7 +72,7 @@ impl FloatDirectionMixTexture { render_from_texture: &Transform, params: &TextureParameterDictionary, _loc: &FileLoc, - _arena: &mut Arena, + _arena: &Arena, ) -> Result { let dir_raw = params.get_one_vector3f("dir", Vector3f::new(0., 1., 0.)); let dir = render_from_texture.apply_to_vector(dir_raw).normalize(); diff --git a/src/textures/scaled.rs b/src/textures/scaled.rs index e5d0acd..fa2e217 100644 --- a/src/textures/scaled.rs +++ b/src/textures/scaled.rs @@ -24,7 +24,7 @@ impl FloatScaledTexture { _render_from_texture: &Transform, params: &TextureParameterDictionary, _loc: &FileLoc, - _arena: &mut Arena, + _arena: &Arena, ) -> Result { let mut tex = params.get_float_texture("tex", 1.); let mut scale = params.get_float_texture("scale", 1.); diff --git a/src/textures/windy.rs b/src/textures/windy.rs index 4bb3978..62762c5 100644 --- a/src/textures/windy.rs +++ b/src/textures/windy.rs @@ -1,5 +1,5 @@ -use anyhow::Result; use crate::Arena; +use anyhow::Result; use shared::{textures::WindyTexture, utils::Transform}; use crate::{ @@ -12,7 +12,7 @@ impl CreateFloatTexture for WindyTexture { _render_from_texture: Transform, _parameters: TextureParameterDictionary, _loc: FileLoc, - _arena: &mut Arena, + _arena: &Arena, ) -> Result { todo!() } diff --git a/src/textures/wrinkled.rs b/src/textures/wrinkled.rs index 37ef999..9929d08 100644 --- a/src/textures/wrinkled.rs +++ b/src/textures/wrinkled.rs @@ -12,7 +12,7 @@ impl CreateFloatTexture for WrinkledTexture { _render_from_texture: Transform, _parameters: TextureParameterDictionary, _loc: FileLoc, - _arena: &mut Arena, + _arena: &Arena, ) -> Result { todo!() } diff --git a/src/utils/arena.rs b/src/utils/arena.rs index 87b8725..4da0fb5 100644 --- a/src/utils/arena.rs +++ b/src/utils/arena.rs @@ -33,11 +33,6 @@ struct ArenaInner { texture_cache: HashMap, } -pub struct Arena { - buffer: Vec<(*mut u8, Layout)>, - texture_cache: HashMap, -} - impl Arena { pub fn new() -> Self { Self { @@ -101,7 +96,8 @@ impl Arena { #[cfg(not(feature = "cuda"))] unsafe fn alloc_unified(&self, layout: Layout) -> *mut u8 { let ptr = unsafe { std::alloc::alloc(layout) }; - self.buffer.push((ptr, layout)); + let mut inner = self.inner.lock(); + inner.buffer.push((ptr, layout)); ptr } @@ -119,7 +115,7 @@ impl Arena { #[cfg(not(feature = "cuda"))] let tex_obj = 0u64; - self.texture_cache.insert(key, tex_obj); + inner.texture_cache.insert(key, tex_obj); tex_obj } @@ -141,8 +137,8 @@ impl Arena { impl Drop for Arena { fn drop(&mut self) { - let inner = self.inner.get_mut().unwrap(); - for (ptr, layout) in self.buffer.drain(..) { + let inner = self.inner.get_mut(); + for (ptr, layout) in inner.buffer.drain(..) { unsafe { #[cfg(feature = "cuda")] { @@ -183,7 +179,7 @@ impl Upload for Light { impl Upload for Image { type Target = DeviceImage; fn upload(&self, arena: &Arena) -> Ptr { - arena.alloc(*self.device_image()) + arena.alloc(*self.device()) } } @@ -204,7 +200,7 @@ impl Upload for Material { impl Upload for DenselySampledSpectrumBuffer { type Target = DenselySampledSpectrum; fn upload(&self, arena: &Arena) -> Ptr { - arena.alloc(self.device()) + arena.alloc(*&self.device()) } } diff --git a/src/utils/mipmap.rs b/src/utils/mipmap.rs index 298536f..51a08bd 100644 --- a/src/utils/mipmap.rs +++ b/src/utils/mipmap.rs @@ -383,7 +383,7 @@ fn create_cuda_texture(pyramid: &[Image], wrap_mode: WrapMode) -> u64 { let mut array: cudaArray_t = std::ptr::null_mut(); cudaMallocArray(&mut array, &channel_desc, width, height, 0); - let pixels = base.as_slice(); // Assuming you have this method + let pixels = base.as_slice(); cudaMemcpy2DToArray( array, 0, diff --git a/src/utils/parser.rs b/src/utils/parser.rs index 5879aa4..cc25bc2 100644 --- a/src/utils/parser.rs +++ b/src/utils/parser.rs @@ -50,7 +50,7 @@ pub trait ParserTarget { fn medium_interface(&mut self, inside_name: &str, outside_name: &str, loc: FileLoc); fn sampler(&mut self, name: &str, params: &ParsedParameterVector, loc: FileLoc); - fn world_begin(&mut self, loc: FileLoc, arena: &mut Arena); + fn world_begin(&mut self, loc: FileLoc, arena: &Arena); fn attribute_begin(&mut self, loc: FileLoc); fn attribute_end(&mut self, loc: FileLoc); fn attribute(&mut self, target: &str, params: ParsedParameterVector, loc: FileLoc); @@ -62,7 +62,7 @@ pub trait ParserTarget { tex_name: &str, params: &ParsedParameterVector, loc: FileLoc, - arena: &mut Arena, + arena: &Arena, ); fn material(&mut self, name: &str, params: &ParsedParameterVector, loc: FileLoc); fn make_named_material(&mut self, name: &str, params: &ParsedParameterVector, loc: FileLoc); @@ -459,7 +459,7 @@ impl ParserTarget for FormattingParserTarget { println!("{}CoordSysTransform \"{}\"", self.indent(0), name); } - fn world_begin(&mut self, _loc: FileLoc, _arena: &mut Arena) { + fn world_begin(&mut self, _loc: FileLoc, _arena: &Arena) { println!("{}WorldBegin", self.indent(0)); self.cat_indent_count += 4; } @@ -744,7 +744,7 @@ impl<'a> SceneParser<'a> { } pub fn run(&mut self) -> Result<(), ParserError> { - let mut arena = Arena::new(); + let arena = Arc::new(Arena::new()); loop { let token = match self.next_token()? { Some(t) => t, @@ -1013,7 +1013,7 @@ impl<'a> SceneParser<'a> { let tex_name = self.expect_quoted_string()?; let params = self.parse_parameters()?; self.target - .texture(&name, &type_name, &tex_name, ¶ms, token.loc, arena); + .texture(&name, &type_name, &tex_name, ¶ms, token.loc, &arena); } _ => { return Err(ParserError::Generic( @@ -1024,7 +1024,7 @@ impl<'a> SceneParser<'a> { }, 'W' => match token.text.as_str() { - "WorldBegin" => self.target.world_begin(token.loc, &mut arena), + "WorldBegin" => self.target.world_begin(token.loc, &arena), "WorldEnd" => {} _ => { return Err(ParserError::Generic( diff --git a/src/utils/sampling.rs b/src/utils/sampling.rs index 42c098a..0beb9d1 100644 --- a/src/utils/sampling.rs +++ b/src/utils/sampling.rs @@ -23,7 +23,7 @@ impl PiecewiseConstant1D { Self::new_with_bounds(f.to_vec(), 0.0, 1.0) } - pub fn to_shared(&self, arena: &mut Arena) -> DevicePiecewiseConstant1D { + pub fn to_shared(&self, arena: &Arena) -> DevicePiecewiseConstant1D { let (func_ptr, _) = arena.alloc_slice(&self.func); let (cdf_ptr, _) = arena.alloc_slice(&self.cdf);