Continuing cleanup

This commit is contained in:
Wito Wiala 2026-05-28 06:39:05 +01:00
parent 0c62fbc3b5
commit e6d1850785
13 changed files with 177 additions and 183 deletions

View file

@ -1,7 +1,7 @@
use super::{Normal3f, Point3f, Point3fi, Vector3f, VectorLike};
use crate::core::medium::Medium;
use crate::utils::math::{next_float_down, next_float_up};
use crate::{gvec_with_capacity, Float, GVec, Ptr, SOA};
use crate::{gvec_with_capacity, Float, GVec, Ptr};
#[repr(C)]
#[derive(Clone, Copy, Debug)]
@ -123,56 +123,3 @@ pub struct RayDifferential {
pub rx_direction: Vector3f,
pub ry_direction: Vector3f,
}
#[derive(Clone)]
pub struct RaySoA {
pub o: GVec<Point3f>,
pub d: GVec<Vector3f>,
pub time: GVec<Float>,
pub medium: GVec<Ptr<Medium>>,
pub has_differentials: GVec<bool>,
pub differential: GVec<RayDifferential>,
}
impl SoA for RaySoA {
type Item = Ray;
fn with_capacity(n: usize) -> Self {
Self {
o: gvec_with_capacity(n),
d: gvec_with_capacity(n),
time: gvec_with_capacity(n),
medium: gvec_with_capacity(n),
has_differentials: gvec_with_capacity(n),
differential: gvec_with_capacity(n),
}
}
fn len(&self) -> usize {
self.o.len()
}
unsafe fn get_unchecked(&self, i: usize) -> Ray {
Ray {
o: *self.o.get_unchecked(i),
d: *self.d.get_unchecked(i),
time: *self.time.get_unchecked(i),
medium: *self.medium.get_unchecked(i),
has_differentials: *self.has_differentials.get_unchecked(i),
differential: *self.differential.get_unchecked(i),
}
}
unsafe fn set_unchecked(&mut self, i: usize, v: Ray) {
*self.o.get_unchecked_mut(i) = v.o;
*self.d.get_unchecked_mut(i) = v.d;
*self.time.get_unchecked_mut(i) = v.time;
*self.medium.get_unchecked_mut(i) = v.medium;
*self.has_differentials.get_unchecked_mut(i) = v.has_differentials;
*self.differential.get_unchecked_mut(i) = v.differential;
}
}
impl SoAElement for Ray {
type SoA = RaySoA;
}

View file

@ -178,6 +178,7 @@ pub trait MaterialTrait {
fn has_subsurface_scattering(&self) -> bool;
}
#[repr(C)]
#[derive(Clone, Copy, Debug)]
#[enum_dispatch(MaterialTrait)]
pub enum Material {

View file

@ -68,9 +68,6 @@ impl PrimitiveTrait for GeometricPrimitive {
}
}
if r.medium.is_null() {
return None;
}
si.set_intersection_properties(
self.material,
self.area_light,

View file

@ -20,5 +20,6 @@ pub mod wavefront;
pub use core::pbrt::*;
pub use utils::alloc::{gbox, gvec, gvec_from_slice, gvec_with_capacity, leak, GBox, GVec};
pub use utils::{Array2D, PBRTOptions, Ptr, Transform, SOA};
pub use wavefront::{WavefrontAggregate, WorkQueue};
pub use utils::{Array2D, PBRTOptions, Ptr, Transform};
pub use utils::soa::WorkQueue;
pub use wavefront::{WavefrontAggregate};

View file

@ -334,7 +334,7 @@ impl MaterialTrait for CoatedConductorMaterial {
}
fn get_normal_map(&self) -> Option<&Image> {
Some(&*self.normal_map)
self.normal_map.get()
}
fn get_displacement(&self) -> Ptr<GPUFloatTexture> {

View file

@ -544,7 +544,7 @@ pub fn next_float_up(v: Float) -> Float {
if v >= 0.0 {
ui = ui.wrapping_add(1);
} else {
ui = ui.wrapping_sub(1);
ui.wrapping_sub(1);
}
bits_to_float(ui)
}

View file

@ -1,4 +1,5 @@
pub mod alloc;
pub mod atomic;
pub mod complex;
pub mod containers;
pub mod hash;
@ -10,18 +11,18 @@ pub mod ptr;
pub mod quaternion;
pub mod rng;
pub mod sampling;
pub mod soa;
pub mod sobol;
pub mod splines;
pub mod transform;
pub use atomic::{AtomicFloat, AtomicU32};
pub use containers::Array2D;
pub use options::PBRTOptions;
pub use ptr::Ptr;
pub use transform::{AnimatedTransform, Transform, TransformGeneric};
pub use containers::Array2D;
pub use soa::SOA:
use crate::Float;
use core::sync::atomic::{AtomicU32, Ordering};
#[inline]
pub fn find_interval<F>(sz: u32, pred: F) -> u32
@ -62,61 +63,6 @@ where
i
}
#[repr(C)]
#[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 {
bits: AtomicU32::new(val.to_bits()),
}
}
pub fn get(&self) -> Float {
Float::from_bits(self.bits.load(Ordering::Relaxed))
}
pub fn set(&self, val: Float) {
self.bits.store(val.to_bits(), Ordering::Relaxed);
}
/// Atomically adds `val` to the current value.
/// Compare-And-Swap loop.
pub fn add(&self, val: f32) {
let mut current_bits = self.bits.load(Ordering::Relaxed);
loop {
let current_val = f32::from_bits(current_bits);
let new_val = current_val + val;
let new_bits = new_val.to_bits();
match self.bits.compare_exchange_weak(
current_bits,
new_bits,
Ordering::Relaxed,
Ordering::Relaxed,
) {
Ok(_) => break,
Err(x) => current_bits = x,
}
}
}
}
#[inline(always)]
pub fn gpu_array_from_fn<T, const N: usize>(mut f: impl FnMut(usize) -> T) -> [T; N] {
unsafe {
@ -130,4 +76,3 @@ pub fn gpu_array_from_fn<T, const N: usize>(mut f: impl FnMut(usize) -> T) -> [T
arr.assume_init()
}
}

View file

@ -1,15 +1,120 @@
pub trait SoA: Clone {
use crate::utils::AtomicU32;
use crate::{Float, Ptr};
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct SoABuffer<T: Copy> {
pub ptr: Ptr<T>,
pub capacity: u32,
}
impl<T: Copy> SoABuffer<T> {
pub fn null() -> Self {
Self {
ptr: Ptr::null(),
capacity: 0,
}
}
#[inline(always)]
pub fn get(&self, i: usize) -> T {
debug_assert!(i < self.capacity as usize);
unsafe { *self.ptr.as_raw().add(i) }
}
#[inline(always)]
pub fn set(&self, i: usize, val: T) {
debug_assert!(i < self.capacity as usize);
unsafe {
let p = self.ptr.as_raw() as *mut T;
*p.add(i) = val;
}
}
}
pub trait SoA {
type Item: Copy;
fn with_capacity(n: usize) -> Self;
fn len(&self) -> usize;
fn is_empty(&self) -> bool {
self.len() == 0
fn allocate(n: u32, alloc: &dyn SoAAllocator) -> Self;
/// Read one element by scattering across all buffers.
unsafe fn get(&self, i: usize) -> Self::Item;
/// Write one element by scattering across all buffers.
/// Takes &self for GPU concurrent write (disjoint indices).
unsafe fn set(&self, i: usize, v: Self::Item);
}
unsafe fn get_unchecked(&self, i: usize) -> Self::Item;
unsafe fn set_unchecked(&mut self, i: usize, v: Self::Item);
pub trait SoAAllocator {
fn alloc_raw(&self, layout: core::alloc::Layout) -> *mut u8;
}
pub trait SoAElement: Copy {
type SoA: SoA<Item = Self>;
pub fn alloc_soa_buffer<T: Copy>(n: u32, alloc: &dyn SoAAllocator) -> SoABuffer<T> {
if n == 0 {
return SoABuffer::null();
}
let layout = core::alloc::Layout::array::<T>(n as usize).unwrap();
let raw = alloc.alloc_raw(layout);
SoABuffer {
ptr: Ptr::from_raw(raw as *mut T),
capacity: n,
}
}
#[repr(C)]
pub struct WorkQueue<S: SoA> {
pub storage: S,
pub count: AtomicU32,
pub capacity: u32,
}
impl<S: SoA> WorkQueue<S> {
pub fn new(storage: S, capacity: u32) -> Self {
Self {
storage,
count: AtomicU32::new(0),
capacity,
}
}
/// Number of items currently in the queue.
#[inline(always)]
pub fn size(&self) -> u32 {
self.count.load()
}
/// Reset the queue to empty. Call from host between kernel launches.
#[inline(always)]
pub fn reset(&self) {
self.count.store(0);
}
/// Push an item, returning its index. Returns None if the queue is full.
/// The atomic increment guarantees each thread gets a unique slot.
#[inline(always)]
pub fn push(&self, item: S::Item) -> Option<u32> {
let slot = self.count.fetch_add(1);
if slot >= self.capacity {
// Queue overflow — this shouldn't happen if capacity is
// sized correctly. In debug builds we want to know about it.
debug_assert!(false, "WorkQueue overflow: {} >= {}", slot, self.capacity);
return None;
}
unsafe {
self.storage.set(slot as usize, item);
}
Some(slot)
}
/// Read an item at the given index. Used by consumer kernels.
#[inline(always)]
pub unsafe fn get(&self, i: usize) -> S::Item {
debug_assert!(
(i as u32) < self.size(),
"WorkQueue::get out of bounds: {} >= {}",
i,
self.size()
);
self.storage.get(i)
}
}

View file

@ -14,4 +14,4 @@ pub mod utils;
pub mod wavefront;
pub use utils::{Arena, FileLoc, ParameterDictionary, Upload, ArenaUpload};
pub const MAX_TAGS = 16;
pub const MAX_TAGS: u32 = 16;

View file

@ -1,6 +1,7 @@
use crate::utils::backend::GpuAllocator;
use crate::utils::mipmap::MIPMap;
use parking_lot::Mutex;
use shared::utils::soa::SoAAllocator;
use shared::Ptr;
use std::alloc::Layout;
use std::collections::HashMap;
@ -161,6 +162,11 @@ impl<A: GpuAllocator> Arena<A> {
(Ptr::from_raw(ptr), len)
}
pub fn alloc_layout(&self, layout: Layout) -> *mut u8 {
let mut bump = self.bump.lock();
bump.alloc_layout(layout)
}
pub fn get_texture_object(&self, mipmap: &Arc<MIPMap>) -> u64 {
let key = Arc::as_ptr(mipmap) as usize;
let mut cache = self.texture_cache.lock();
@ -178,3 +184,9 @@ impl<A: GpuAllocator + Default> Default for Arena<A> {
Self::new(A::default())
}
}
impl<A: GpuAllocator> SoAAllocator for Arena<A> {
fn alloc_raw(&self, layout: core::alloc::Layout) -> *mut u8 {
self.alloc_layout(layout)
}
}

View file

@ -1,11 +0,0 @@
use shared::core::geometry::Bounds3f;
use super::{RayQueue, EscapedRayQueue, HitAreaLightQueue, MaterialEvalQueue, MediumSampleQueue, SubsurfaceScatterQueue};
#[derive(Clone, Debug)]
pub trait WavefrontAggregate {
fn bounds(&self) -> Bounds3f;
fn intersect_closest(max_rays: usize, ray_q: &mut RayQueue, hit_area_light_q: &mut HitAreaLightQueue, basic_mlt_q: &mut MaterialEvalQueue, universal_mtl_q: &mut MaterialEvalQueue, medium_sample_q: &mut MediumSampleQueue);
fn intersect_shadow(max_rays: usize, shadow_ray_q: &mut ShadowRayQueue, pixel_sample_state: &mut SOA<PixelSampleState>);
fn intersect_shadow_tr(max_rays: usize, shadow_ray_q: &mut ShadowRayQueue, pixel_sample_state: &mut SOA<PixelSampleState>);
fn intersect_one_random(max_rays: usize, subsurface_scatte_q: &mut SubsurfaceScatterQueue);
}

View file

@ -1,38 +1,38 @@
use crate::MAX_TAGS;
use shared::{Ptr, GVec};
use shared::core::film::Film;
use shared::core::color::RGB;
use shared::core::filter::Filter;
use shared::core::light::Light;
use shared::core::sampler::Filter;
use shared::wavefront::{WavefrontAggregate, RayQueue, MediumSampleQueue, EscapedRayQueue, HitAreaLightQueue, MaterialEvalQueue, ShadowRayQueue, GetBSSRDFAndProbeRayQueue, SubsurfaceScatterQueue};
pub struct WavefrontPathIntegrator {
pub init_visible_surface: bool,
pub have_subsurface: bool,
pub have_media: bool,
pub have_basic_eval_material: [bool; MAX_TAGS + 1],
pub have_universal_eval_material: [bool; MAX_TAGS + 1],
pub filter: Filter,
pub film: Film,
pub sampler: Sampler,
pub camera: Camera,
pub infinite_lights: GVec<Light>,
pub max_depth: usize,
pub sampler_per_pixel: usize,
pub regularize: bool,
pub scanlines_per_pixel: usize,
pub max_queue_size: usize,
pub medium_sample_queue: Ptr<MediumSampleQueue>,
pub medium_scatter_queue: Ptr<MediumScatterQueue>,
pub escaped_ray_queue: Ptr<EscapedRayQueue>,
pub hit_area_light_queue: Ptr<HitAreaLightQueue>,
pub basic_eval_material_queue: Ptr<MaterialEvalQueue>,
pub universal_eval_material_queue: Ptr<MaterialEvalQueue>,
pub shadow_ray_queue: Ptr<ShadowRayQueue>,
pub bssrdf_eval_queue: PTr<GetBSSRDFAndProbeRayQueue>,
pub subsurface_scatter_queue: Ptr<SubsurfaceScatterQueue>,
pub display_rgb: Ptr<RGB>,
pub display_rgb_host: Ptr<RGB,
}
// use crate::MAX_TAGS;
// use shared::{Ptr, GVec};
// use shared::core::film::Film;
// use shared::core::color::RGB;
// use shared::core::filter::Filter;
// use shared::core::light::Light;
// use shared::core::sampler::Sampler;
// use shared::wavefront::{WavefrontAggregate, RayQueue, MediumSampleQueue, EscapedRayQueue, HitAreaLightQueue, MaterialEvalQueue, ShadowRayQueue, GetBSSRDFAndProbeRayQueue, SubsurfaceScatterQueue};
//
// pub struct WavefrontPathIntegrator {
// pub init_visible_surface: bool,
// pub have_subsurface: bool,
// pub have_media: bool,
// pub have_basic_eval_material: [bool; MAX_TAGS + 1],
// pub have_universal_eval_material: [bool; MAX_TAGS + 1],
// pub filter: Filter,
// pub film: Film,
// pub sampler: Sampler,
// pub camera: Camera,
// pub infinite_lights: GVec<Light>,
// pub max_depth: usize,
// pub sampler_per_pixel: usize,
// pub regularize: bool,
// pub scanlines_per_pixel: usize,
// pub max_queue_size: usize,
// pub medium_sample_queue: Ptr<MediumSampleQueue>,
// pub medium_scatter_queue: Ptr<MediumScatterQueue>,
// pub escaped_ray_queue: Ptr<EscapedRayQueue>,
// pub hit_area_light_queue: Ptr<HitAreaLightQueue>,
// pub basic_eval_material_queue: Ptr<MaterialEvalQueue>,
// pub universal_eval_material_queue: Ptr<MaterialEvalQueue>,
// pub shadow_ray_queue: Ptr<ShadowRayQueue>,
// pub bssrdf_eval_queue: PTr<GetBSSRDFAndProbeRayQueue>,
// pub subsurface_scatter_queue: Ptr<SubsurfaceScatterQueue>,
// pub display_rgb: Ptr<RGB>,
// pub display_rgb_host: Ptr<RGB>,
//
// }

View file

@ -1,4 +1 @@
pub mod integrator;
pub mod aggregate;
pub use aggregate::WavefrontAggregate;