Changing error handling with scene file parsing

This commit is contained in:
Wito Wiala 2026-02-19 15:41:24 +00:00
parent 8a92d7642d
commit b36105edc1
22 changed files with 340 additions and 369 deletions

View file

@ -9,6 +9,8 @@ use_f64 = []
use_gpu = []
use_nvtx = []
cuda = ["dep:cudarc", "dep:cust", "dep:cust_raw"]
vulkan = ["ash", "gpu-allocator"]
ash = ["dep:ash"]
[dependencies]
anyhow = "1.0.100"
@ -33,12 +35,12 @@ wgpu = "27.0.1"
shared = { path = "shared" }
ptex-filter = { path = "crates/ptex-filter" }
# kernels = { path = "kernels" }
ash = { version = "0.38", optional = true }
gpu-allocator = { version = "0.28", features = ["vulkan"], optional = true }
cuda_std = { git = "https://github.com/Rust-GPU/Rust-CUDA", branch = "main", default-features = false, optional = true }
cust = { git = "https://github.com/Rust-GPU/Rust-CUDA", branch = "main", default-features = false, features = ["glam"], optional = true }
cust_raw = { git = "https://github.com/Rust-GPU/Rust-CUDA", branch = "main", default-features = false, optional = true }
ptex = "0.3.0"
# ptex-sys = "0.3.0"
slice = "0.0.4"
crossbeam-channel = "0.5.15"
num_cpus = "1.17.0"

View file

@ -15,6 +15,4 @@ pub mod utils;
#[cfg(feature = "cuda")]
pub mod gpu;
pub use utils::arena::Arena;
pub use utils::error::FileLoc;
pub use utils::parameters::ParameterDictionary;
pub use utils::{Arena, FileLoc, ParameterDictionary};

View file

@ -3,7 +3,7 @@ use crate::core::material::CreateMaterial;
use crate::core::texture::SpectrumTexture;
use crate::spectra::data::get_named_spectrum;
use crate::utils::{Arena, FileLoc, TextureParameterDictionary, Upload, parameters::error_exit};
use anyhow::Result;
use anyhow::{Result, bail};
use shared::core::material::Material;
use shared::core::spectrum::Spectrum;
use shared::core::texture::SpectrumType;
@ -27,32 +27,32 @@ impl CreateMaterial for CoatedDiffuseMaterial {
SpectrumConstantTexture::new(Spectrum::Constant(ConstantSpectrum::new(0.5))),
)));
let u_roughness = parameters
.get_float_texture_or_null("uroughness")
.unwrap_or_else(|| parameters.get_float_texture("roughness", 0.5));
let v_roughness = parameters
.get_float_texture_or_null("vroughness")
.unwrap_or_else(|| parameters.get_float_texture("roughness", 0.5));
let u_roughness =
parameters.get_float_texture_with_fallback("uroughness", "roughness", 0.5)?;
let thickness = parameters.get_float_texture("thickness", 0.01);
let v_roughness =
parameters.get_float_texture_with_fallback("vroughness", "roughness", 0.5)?;
let thickness = parameters.get_float_texture("thickness", 0.01)?;
let eta = parameters
.get_float_array("eta")
.get_float_array("eta")?
.first()
.map(|&v| Spectrum::Constant(ConstantSpectrum::new(v)))
.or_else(|| parameters.get_one_spectrum("eta", None, SpectrumType::Unbounded))
.unwrap_or_else(|| Spectrum::Constant(ConstantSpectrum::new(1.5)));
let max_depth = parameters.get_one_int("maxdepth", 10);
let n_samples = parameters.get_one_int("nsamples", 1);
let g = parameters.get_float_texture("g", 0.);
let max_depth = parameters.get_one_int("maxdepth", 10)?;
let n_samples = parameters.get_one_int("nsamples", 1)?;
let g = parameters.get_float_texture("g", 0.)?;
let albedo = parameters
.get_spectrum_texture("albedo", None, SpectrumType::Albedo)
.unwrap_or_else(|| {
let default_spectrum = Spectrum::Constant(ConstantSpectrum::new(0.));
SpectrumTexture::Constant(SpectrumConstantTexture::new(default_spectrum)).into()
});
let displacement = parameters.get_float_texture("displacement", 0.);
let remap_roughness = parameters.get_one_bool("remaproughness", true);
let displacement = parameters.get_float_texture("displacement", 0.)?;
let remap_roughness = parameters.get_one_bool("remaproughness", true)?;
let specific = CoatedDiffuseMaterial::new(
reflectance.upload(arena),
u_roughness.upload(arena),
@ -80,68 +80,76 @@ impl CreateMaterial for CoatedConductorMaterial {
loc: &FileLoc,
arena: &Arena,
) -> Result<Material> {
let interface_u_roughness = parameters
.get_float_texture_or_null("interface.uroughness")
.unwrap_or_else(|| parameters.get_float_texture("interface.roughness", 0.));
let interface_v_roughness = parameters
.get_float_texture_or_null("interface.vroughness")
.unwrap_or_else(|| parameters.get_float_texture("interface.vroughness", 0.));
let thickness = parameters.get_float_texture("interface.thickness", 0.01);
let interface_u_roughness = parameters.get_float_texture_with_fallback(
"interface.uroughness",
"interface.roughness",
0.,
)?;
let interface_v_roughness = parameters.get_float_texture_with_fallback(
"interface.vroughness",
"interface.roughness",
0.,
)?;
let thickness = parameters.get_float_texture("interface.thickness", 0.01)?;
let interface_eta: Spectrum = parameters
.get_float_array("interface.eta")
.get_float_array("interface.eta")?
.first()
.map(|&v| Spectrum::Constant(ConstantSpectrum::new(v)))
.or_else(|| parameters.get_one_spectrum("interface.eta", None, SpectrumType::Unbounded))
.unwrap_or_else(|| Spectrum::Constant(ConstantSpectrum::new(1.5)));
let conductor_u_roughness = parameters
.get_float_texture_or_null("conductor.uroughness")
.unwrap_or_else(|| parameters.get_float_texture("conductor.roughness", 0.));
let conductor_v_roughness = parameters
.get_float_texture_or_null("conductor.vroughness")
.unwrap_or_else(|| parameters.get_float_texture("conductor.vroughness", 0.));
let conductor_u_roughness = parameters.get_float_texture_with_fallback(
"conductor.uroughness",
"conductor.roughness",
0.,
)?;
let conductor_v_roughness = parameters.get_float_texture_with_fallback(
"conductor.vroughness",
"conductor.roughness",
0.,
)?;
let reflectance =
parameters.get_spectrum_texture_or_null("reflectance", SpectrumType::Albedo);
let conductor_eta =
parameters.get_spectrum_texture_or_null("conductor.eta", SpectrumType::Unbounded);
let k = parameters.get_spectrum_texture_or_null("conductor.k", SpectrumType::Unbounded);
let (conductor_eta, k) = match (&reflectance, conductor_eta, k) {
(Some(_), Some(_), _) | (Some(_), _, Some(_)) => {
return Err(error_exit(
Some(loc),
"For the coated conductor material, both \"reflectance\" \
and \"eta\" and \"k\" can't be provided.",
));
let (conductor_eta, k) = if reflectance.is_some() {
if conductor_eta.is_some() || k.is_some() {
bail!(
"{}: For the coated conductor material, both \"reflectance\" \
and \"eta\"/\"k\" cannot be provided simultaneously.",
loc
);
}
(None, eta, k) => {
let final_eta = eta.unwrap_or_else(|| {
let s = get_named_spectrum("metal-Cu-eta").expect("Missing copper spectrum");
Arc::new(SpectrumTexture::Constant(SpectrumConstantTexture::new(s)))
});
let final_k = k.unwrap_or_else(|| {
let s = get_named_spectrum("metal-Cu-k").expect("Missing copper spectrum");
Arc::new(SpectrumTexture::Constant(SpectrumConstantTexture::new(s)))
});
(Some(final_eta), Some(final_k))
}
(Some(_), None, None) => (None, None),
(None, None)
} else {
let eta = conductor_eta.unwrap_or_else(|| {
let s = get_named_spectrum("metal-Cu-eta").expect("Missing copper spectrum");
Arc::new(SpectrumTexture::Constant(SpectrumConstantTexture::new(s)))
});
let k = k.unwrap_or_else(|| {
let s = get_named_spectrum("metal-Cu-k").expect("Missing copper spectrum");
Arc::new(SpectrumTexture::Constant(SpectrumConstantTexture::new(s)))
});
(Some(eta), Some(k))
};
let max_depth = parameters.get_one_int("maxdepth", 10);
let n_samples = parameters.get_one_int("nsamples", 1);
let g = parameters.get_float_texture("g", 0.);
let max_depth = parameters.get_one_int("maxdepth", 10)?;
let n_samples = parameters.get_one_int("nsamples", 1)?;
let g = parameters.get_float_texture("g", 0.)?;
let albedo = parameters
.get_spectrum_texture("albedo", None, SpectrumType::Albedo)
.unwrap_or_else(|| {
let spectrum = Spectrum::Constant(ConstantSpectrum::new(0.));
SpectrumTexture::Constant(SpectrumConstantTexture::new(spectrum)).into()
});
let displacement = parameters.get_float_texture_or_null("displacement");
let remap_roughness = parameters.get_one_bool("remaproughness", true);
let displacement = parameters.get_float_texture_or_null("displacement")?;
let remap_roughness = parameters.get_one_bool("remaproughness", true)?;
let material = Self::new(
normal_map.upload(arena),
displacement.upload(arena),

View file

@ -27,8 +27,8 @@ impl CreateMaterial for HairMaterial {
let reflectance = parameters
.get_spectrum_texture_or_null("reflectance", SpectrumType::Albedo)
.or_else(|| parameters.get_spectrum_texture_or_null("color", SpectrumType::Albedo));
let eumelanin = parameters.get_float_texture_or_null("eumelanin");
let pheomelanin = parameters.get_float_texture_or_null("pheomelanin");
let eumelanin = parameters.get_float_texture_or_null("eumelanin")?;
let pheomelanin = parameters.get_float_texture_or_null("pheomelanin")?;
let has_melanin = eumelanin.is_some() || pheomelanin.is_some();
// Default distribution if nothing is spceified
@ -42,10 +42,10 @@ impl CreateMaterial for HairMaterial {
sigma_a
};
let eta = parameters.get_float_texture("eta", 1.55);
let beta_m = parameters.get_float_texture("beta_m", 0.3);
let beta_n = parameters.get_float_texture("beta_n", 0.3);
let alpha = parameters.get_float_texture("alpha", 2.);
let eta = parameters.get_float_texture("eta", 1.55)?;
let beta_m = parameters.get_float_texture("beta_m", 0.3)?;
let beta_n = parameters.get_float_texture("beta_n", 0.3)?;
let alpha = parameters.get_float_texture("alpha", 2.)?;
let material = HairMaterial::new(
sigma_a.upload(arena),
reflectance.upload(arena),

View file

@ -71,14 +71,15 @@ impl CreateSampler for HaltonSampler {
_arena: &Arena,
) -> Result<Sampler> {
let options = get_options();
let nsamp = options
.quick_render
.then_some(1)
.or(options.pixel_samples)
.unwrap_or_else(|| params.get_one_int("pixelsamples", 16));
let seed = params.get_one_int("seed", options.seed);
let nsamp = if let Some(n) = options.quick_render.then_some(1).or(options.pixel_samples) {
n
} else {
params.get_one_int("pixelsamples", 16)?
};
let seed = params.get_one_int("seed", options.seed)?;
let s = match params
.get_one_string("randomization", "permutedigits")
.get_one_string("randomization", "permutedigits")?
.as_str()
{
"none" => RandomizeStrategy::None,

View file

@ -11,12 +11,14 @@ impl CreateSampler for IndependentSampler {
arena: &Arena,
) -> Result<Sampler> {
let options = get_options();
let nsamp = options
.quick_render
.then_some(1)
.or(options.pixel_samples)
.unwrap_or_else(|| params.get_one_int("pixelsamples", 16));
let seed = params.get_one_int("seed", options.seed);
let nsamp = if let Some(n) = options.quick_render.then_some(1).or(options.pixel_samples) {
n
} else {
params.get_one_int("pixelsamples", 16)?
};
let seed = params.get_one_int("seed", options.seed)?;
let sampler = Self::new(nsamp, seed as u64);
arena.alloc(sampler);
Ok(Sampler::Independent(sampler))

View file

@ -12,13 +12,15 @@ impl CreateSampler for SobolSampler {
_arena: &Arena,
) -> Result<Sampler> {
let options = get_options();
let nsamp = options
.quick_render
.then_some(1)
.or(options.pixel_samples)
.unwrap_or_else(|| params.get_one_int("pixelsamples", 16));
let seed = params.get_one_int("seed", options.seed);
let s = match params.get_one_string("randomization", "fastowen").as_str() {
let nsamp = if let Some(n) = options.quick_render.then_some(1).or(options.pixel_samples) {
n
} else {
params.get_one_int("pixelsamples", 16)?
};
let seed = params.get_one_int("seed", options.seed)?;
let s = match params.get_one_string("randomization", "fastowen")?.as_str() {
"none" => RandomizeStrategy::None,
"permutedigits" => RandomizeStrategy::PermuteDigits,
"fastowen" => RandomizeStrategy::FastOwen,
@ -42,13 +44,13 @@ impl CreateSampler for PaddedSobolSampler {
_arena: &Arena,
) -> Result<Sampler> {
let options = get_options();
let nsamp = options
.quick_render
.then_some(1)
.or(options.pixel_samples)
.unwrap_or_else(|| params.get_one_int("pixelsamples", 16));
let seed = params.get_one_int("seed", options.seed);
let s = match params.get_one_string("randomization", "fastowen").as_str() {
let nsamp = if let Some(n) = options.quick_render.then_some(1).or(options.pixel_samples) {
n
} else {
params.get_one_int("pixelsamples", 16)?
};
let seed = params.get_one_int("seed", options.seed)?;
let s = match params.get_one_string("randomization", "fastowen")?.as_str() {
"none" => RandomizeStrategy::None,
"permutedigits" => RandomizeStrategy::PermuteDigits,
"fastowen" => RandomizeStrategy::FastOwen,
@ -75,13 +77,14 @@ impl CreateSampler for ZSobolSampler {
_arena: &Arena,
) -> Result<Sampler> {
let options = get_options();
let nsamp = options
.quick_render
.then_some(1)
.or(options.pixel_samples)
.unwrap_or_else(|| params.get_one_int("pixelsamples", 16));
let seed = params.get_one_int("seed", options.seed);
let s = match params.get_one_string("randomization", "fastowen").as_str() {
let nsamp = if let Some(n) = options.quick_render.then_some(1).or(options.pixel_samples) {
n
} else {
params.get_one_int("pixelsamples", 16)?
};
let seed = params.get_one_int("seed", options.seed)?;
let s = match params.get_one_string("randomization", "fastowen")?.as_str() {
"none" => RandomizeStrategy::None,
"permutedigits" => RandomizeStrategy::PermuteDigits,
"fastowen" => RandomizeStrategy::FastOwen,

View file

@ -11,7 +11,7 @@ impl CreateSampler for StratifiedSampler {
_arena: &Arena,
) -> Result<Sampler> {
let options = get_options();
let jitter = params.get_one_bool("jitter", true);
let jitter = params.get_one_bool("jitter", true)?;
let (x_samples, y_samples) = if options.quick_render {
(1, 1)
} else if let Some(n) = options.pixel_samples {
@ -21,11 +21,11 @@ impl CreateSampler for StratifiedSampler {
(n / y, y)
} else {
(
params.get_one_int("xsamples", 4),
params.get_one_int("ysamples", 4),
params.get_one_int("xsamples", 4)?,
params.get_one_int("ysamples", 4)?,
)
};
let seed = params.get_one_int("seed", options.seed);
let seed = params.get_one_int("seed", options.seed)?;
let sampler = Self::new(x_samples, y_samples, Some(seed as u64), jitter);
// arena.aloc(sampler);

View file

@ -23,11 +23,11 @@ impl CreateShape for BilinearPatchShape {
_loc: FileLoc,
_arena: &Arena,
) -> Result<Vec<Shape>> {
let mut vertex_indices = parameters.get_int_array("indices");
let p = parameters.get_point3f_array("P");
let mut uv = parameters.get_point2f_array("uv");
let mut n = parameters.get_normal3f_array("N");
let mut face_indices = parameters.get_int_array("faceIndices");
let mut vertex_indices = parameters.get_int_array("indices")?;
let p = parameters.get_point3f_array("P")?;
let mut uv = parameters.get_point2f_array("uv")?;
let mut n = parameters.get_normal3f_array("N")?;
let mut face_indices = parameters.get_int_array("faceIndices")?;
if vertex_indices.is_empty() {
if p.len() == 4 {
@ -84,7 +84,7 @@ impl CreateShape for BilinearPatchShape {
face_indices.clear();
}
let filename = parameters.get_one_string("emissionfilename", "");
let filename = parameters.get_one_string("emissionfilename", "")?;
let image_dist = if !filename.is_empty() {
if !uv.is_empty() {

View file

@ -66,11 +66,11 @@ impl CreateShape for CurveShape {
_loc: FileLoc,
_arena: &Arena,
) -> Result<Vec<Shape>> {
let width = parameters.get_one_float("width", 1.0);
let width0 = parameters.get_one_float("width0", width);
let width1 = parameters.get_one_float("width1", width);
let width = parameters.get_one_float("width", 1.0)?;
let width0 = parameters.get_one_float("width0", width)?;
let width1 = parameters.get_one_float("width1", width)?;
let degree = parameters.get_one_int("degree", 3);
let degree = parameters.get_one_int("degree", 3)?;
if degree != 2 && degree != 3 {
return Err(anyhow!(
"Invalid degree {}: only degree 2 and 3 curves are supported.",
@ -78,7 +78,7 @@ impl CreateShape for CurveShape {
));
}
let basis = parameters.get_one_string("basis", "bezier");
let basis = parameters.get_one_string("basis", "bezier")?;
if basis != "bezier" && basis != "bspline" {
return Err(anyhow!(
"Invalid basis \"{}\": only \"bezier\" and \"bspline\" are supported.",
@ -86,7 +86,7 @@ impl CreateShape for CurveShape {
));
}
let cp = parameters.get_point3f_array("P");
let cp = parameters.get_point3f_array("P")?;
let n_segments;
if basis == "bezier" {
@ -114,7 +114,7 @@ impl CreateShape for CurveShape {
n_segments = cp.len() - degree as usize;
}
let curve_type_str = parameters.get_one_string("type", "flat");
let curve_type_str = parameters.get_one_string("type", "flat")?;
let curve_type = match curve_type_str.as_str() {
"flat" => CurveType::Flat,
"ribbon" => CurveType::Ribbon,
@ -124,7 +124,7 @@ impl CreateShape for CurveShape {
}
};
let mut n = parameters.get_normal3f_array("N");
let mut n = parameters.get_normal3f_array("N")?;
if !n.is_empty() {
if curve_type != CurveType::Ribbon {
warn!("Curve normals are only used with \"ribbon\" type curves. Discarding.");
@ -147,7 +147,7 @@ impl CreateShape for CurveShape {
let split_depth = if use_gpu {
0
} else {
parameters.get_one_int("splitdepth", 3)
parameters.get_one_int("splitdepth", 3)?
};
let mut curves: Vec<Shape> = Vec::new();

View file

@ -18,10 +18,10 @@ impl CreateShape for CylinderShape {
_loc: FileLoc,
arena: &Arena,
) -> Result<Vec<Shape>> {
let radius = parameters.get_one_float("radius", 1.);
let z_min = parameters.get_one_float("zmin", -1.);
let z_max = parameters.get_one_float("zmax", 1.);
let phi_max = parameters.get_one_float("phimax", 360.);
let radius = parameters.get_one_float("radius", 1.)?;
let z_min = parameters.get_one_float("zmin", -1.)?;
let z_max = parameters.get_one_float("zmax", 1.)?;
let phi_max = parameters.get_one_float("phimax", 360.)?;
let shape = CylinderShape::new(
render_from_object,
object_from_render,

View file

@ -18,10 +18,10 @@ impl CreateShape for DiskShape {
_loc: FileLoc,
arena: &Arena,
) -> Result<Vec<Shape>> {
let height = parameters.get_one_float("height", 0.);
let radius = parameters.get_one_float("radius", 1.);
let inner_radius = parameters.get_one_float("innerradius", 0.);
let phi_max = parameters.get_one_float("phimax", 360.);
let height = parameters.get_one_float("height", 0.)?;
let radius = parameters.get_one_float("radius", 1.)?;
let inner_radius = parameters.get_one_float("innerradius", 0.)?;
let phi_max = parameters.get_one_float("phimax", 360.)?;
let shape = DiskShape::new(
radius,
inner_radius,

View file

@ -246,9 +246,7 @@ impl BilinearPatchMesh {
}
}
// ============================================================================
// PLY Helper Functions
// ============================================================================
fn get_float(elem: &DefaultElement, key: &str) -> AnyResult<f32> {
match elem.get(key) {
@ -290,9 +288,7 @@ fn get_list_uint(elem: &DefaultElement, key: &str) -> AnyResult<Vec<u32>> {
}
}
// ============================================================================
// TriQuadMesh Implementation
// ============================================================================
impl TriQuadMesh {
pub fn read_ply<P: AsRef<Path>>(filename: P) -> AnyResult<Self> {
@ -510,9 +506,7 @@ impl TriQuadMesh {
}
}
// ============================================================================
// Convenience: Create from PLY directly
// ============================================================================
// Create from PLY directly
impl TriangleMesh {
pub fn from_ply<P: AsRef<Path>>(

View file

@ -18,10 +18,10 @@ impl CreateShape for SphereShape {
_loc: FileLoc,
arena: &Arena,
) -> Result<Vec<Shape>> {
let radius = parameters.get_one_float("radius", 1.);
let zmin = parameters.get_one_float("zmin", -radius);
let zmax = parameters.get_one_float("zmax", radius);
let phimax = parameters.get_one_float("phimax", 360.);
let radius = parameters.get_one_float("radius", 1.)?;
let zmin = parameters.get_one_float("zmin", -radius)?;
let zmax = parameters.get_one_float("zmax", radius)?;
let phimax = parameters.get_one_float("phimax", 360.)?;
let shape = SphereShape::new(
render_from_object,
object_from_render,

View file

@ -20,11 +20,11 @@ impl CreateShape for TriangleShape {
_loc: FileLoc,
_arena: &Arena,
) -> Result<Vec<Shape>> {
let mut vertex_indices = parameters.get_int_array("indices");
let p = parameters.get_point3f_array("P");
let mut uvs = parameters.get_point2f_array("uv");
let mut s = parameters.get_vector3f_array("S");
let mut n = parameters.get_normal3f_array("N");
let mut vertex_indices = parameters.get_int_array("indices")?;
let p = parameters.get_point3f_array("P")?;
let mut uvs = parameters.get_point2f_array("uv")?;
let mut s = parameters.get_vector3f_array("S")?;
let mut n = parameters.get_normal3f_array("N")?;
if vertex_indices.is_empty() {
if p.len() == 3 {
@ -76,7 +76,7 @@ impl CreateShape for TriangleShape {
}
}
let mut face_indices = parameters.get_int_array("faceIndices");
let mut face_indices = parameters.get_int_array("faceIndices")?;
let n_triangles = vertex_indices.len() / 3;
if !face_indices.is_empty() && face_indices.len() != n_triangles {

View file

@ -33,9 +33,9 @@ impl FloatMixTexture {
_loc: &FileLoc,
_arena: &Arena,
) -> Result<FloatTexture> {
let tex1 = params.get_float_texture("tex1", 0.);
let tex2 = params.get_float_texture("tex2", 1.);
let amount = params.get_float_texture("amount", 0.5);
let tex1 = params.get_float_texture("tex1", 0.)?;
let tex2 = params.get_float_texture("tex2", 1.)?;
let amount = params.get_float_texture("amount", 0.5)?;
// arena.alloc(Self::new(tex1, tex2, amount));
Ok(FloatTexture::Mix(Self::new(tex1, tex2, amount)))
}
@ -74,10 +74,10 @@ impl FloatDirectionMixTexture {
_loc: &FileLoc,
_arena: &Arena,
) -> Result<FloatTexture> {
let dir_raw = params.get_one_vector3f("dir", Vector3f::new(0., 1., 0.));
let dir_raw = params.get_one_vector3f("dir", Vector3f::new(0., 1., 0.))?;
let dir = render_from_texture.apply_to_vector(dir_raw).normalize();
let tex1 = params.get_float_texture("tex1", 0.);
let tex2 = params.get_float_texture("tex2", 1.);
let tex1 = params.get_float_texture("tex1", 0.)?;
let tex2 = params.get_float_texture("tex2", 1.)?;
// arena.alloc(Self::new(tex1, tex2, dir))
Ok(FloatTexture::DirectionMix(Self::new(tex1, tex2, dir)))
}

View file

@ -26,8 +26,8 @@ impl FloatScaledTexture {
_loc: &FileLoc,
_arena: &Arena,
) -> Result<FloatTexture> {
let mut tex = params.get_float_texture("tex", 1.);
let mut scale = params.get_float_texture("scale", 1.);
let mut tex = params.get_float_texture("tex", 1.)?;
let mut scale = params.get_float_texture("scale", 1.)?;
for _ in 0..2 {
if let FloatTexture::Constant(c_tex) = &*scale {

View file

@ -2,6 +2,7 @@ use crate::core::image::Image;
use crate::core::texture::{FloatTexture, SpectrumTexture};
use crate::shapes::{BilinearPatchMesh, TriangleMesh};
use crate::spectra::DenselySampledSpectrumBuffer;
use crate::utils::backend::GpuAllocator;
use crate::utils::mipmap::MIPMap;
use crate::utils::sampling::{PiecewiseConstant2D, WindowedPiecewiseConstant2D};
use parking_lot::Mutex;
@ -24,7 +25,8 @@ use std::collections::HashMap;
use std::slice::from_raw_parts;
use std::sync::Arc;
pub struct Arena {
pub struct Arena<A: GpuAllocator> {
allocator: A,
inner: Mutex<ArenaInner>,
}
@ -33,9 +35,10 @@ struct ArenaInner {
texture_cache: HashMap<usize, u64>,
}
impl Arena {
pub fn new() -> Self {
impl<A: GpuAllocator> Arena<A> {
pub fn new(allocator: A) -> Self {
Self {
allocator,
inner: Mutex::new(ArenaInner {
buffer: Vec::new(),
texture_cache: HashMap::new(),
@ -45,12 +48,10 @@ impl Arena {
pub fn alloc<T>(&self, value: T) -> Ptr<T> {
let layout = Layout::new::<T>();
let ptr = unsafe { self.alloc_unified(layout) } as *mut T;
unsafe {
ptr.write(value);
}
let ptr = unsafe { self.allocator.alloc(layout) } as *mut T;
unsafe { ptr.write(value) };
self.inner.lock().buffer.push((ptr as *mut u8, layout));
Ptr::from_raw(ptr)
}
@ -67,44 +68,13 @@ impl Arena {
}
let layout = Layout::array::<T>(values.len()).unwrap();
let ptr = unsafe { self.alloc_unified(layout) } as *mut T;
unsafe {
std::ptr::copy_nonoverlapping(values.as_ptr(), ptr, values.len());
}
let ptr = unsafe { self.allocator.alloc(layout) } as *mut T;
unsafe { std::ptr::copy_nonoverlapping(values.as_ptr(), ptr, values.len()) };
self.inner.lock().buffer.push((ptr as *mut u8, layout));
(Ptr::from_raw(ptr), values.len())
}
#[cfg(feature = "cuda")]
unsafe fn alloc_unified(&self, layout: Layout) -> *mut u8 {
use cust::memory::{UnifiedPointer, cuda_free_unified, cuda_malloc_unified};
let size = layout.size().max(layout.align());
if size == 0 {
return layout.align() as *mut u8;
}
let mut unified_ptr =
unsafe { cuda_malloc_unified::<u8>(size).expect("cuda_malloc_unified failed") };
let raw = unified_ptr.as_raw_mut();
let mut inner = self.inner.lock();
inner.buffer.push((raw, layout));
raw
}
#[cfg(not(feature = "cuda"))]
unsafe fn alloc_unified(&self, layout: Layout) -> *mut u8 {
if layout.size() == 0 {
return layout.align() as *mut u8;
}
let ptr = unsafe { std::alloc::alloc(layout) };
let mut inner = self.inner.lock();
inner.buffer.push((ptr, layout));
ptr
}
pub fn get_texture_object(&self, mipmap: &Arc<MIPMap>) -> u64 {
let key = Arc::as_ptr(mipmap) as usize;
let mut inner = self.inner.lock();
@ -113,107 +83,85 @@ impl Arena {
return tex_obj;
}
#[cfg(feature = "cuda")]
let tex_obj = self.create_cuda_texture(mipmap);
#[cfg(not(feature = "cuda"))]
// TODO: Backend-specific texture object creation.
// CUDA: cudaCreateTextureObject
// Vulkan: VkImageView + VkSampler -> descriptor index
let tex_obj = 0u64;
inner.texture_cache.insert(key, tex_obj);
tex_obj
}
}
#[cfg(feature = "cuda")]
fn create_cuda_texture(&self, mipmap: &MIPMap) -> u64 {
// TODO: Implement with cudarc
// 1. Get image data from mipmap.base_image()
// 2. cudaMallocArray
// 3. cudaMemcpy2DToArray
// 4. cudaCreateTextureObject
// 5. Return handle
0
impl<A: GpuAllocator + Default> Default for Arena<A> {
fn default() -> Self {
Self::new(A::default())
}
}
impl Drop for Arena {
impl<A: GpuAllocator> Drop for Arena<A> {
fn drop(&mut self) {
let inner = self.inner.get_mut();
for (ptr, layout) in inner.buffer.drain(..) {
if layout.size() == 0 {
continue;
}
unsafe {
#[cfg(feature = "cuda")]
{
use cust::memory::{UnifiedPointer, cuda_free_unified};
if layout.size() > 0 {
let _ = cuda_free_unified(UnifiedPointer::wrap(ptr as *mut u8));
}
}
#[cfg(not(feature = "cuda"))]
{
std::alloc::dealloc(ptr, layout);
}
}
unsafe { self.allocator.dealloc(ptr, layout) };
}
}
}
unsafe impl Send for Arena {}
unsafe impl Sync for Arena {}
unsafe impl<A: GpuAllocator> Send for Arena<A> {}
unsafe impl<A: GpuAllocator> Sync for Arena<A> {}
pub trait Upload {
type Target: Copy;
fn upload(&self, arena: &Arena) -> Ptr<Self::Target>;
fn upload<A: GpuAllocator>(&self, arena: &Arena<A>) -> Ptr<Self::Target>;
}
impl Upload for Shape {
type Target = Shape;
fn upload(&self, arena: &Arena) -> Ptr<Self::Target> {
fn upload<A: GpuAllocator>(&self, arena: &Arena<A>) -> Ptr<Self::Target> {
arena.alloc(self.clone())
}
}
impl Upload for Light {
type Target = Light;
fn upload(&self, arena: &Arena) -> Ptr<Self::Target> {
fn upload<A: GpuAllocator>(&self, arena: &Arena<A>) -> Ptr<Self::Target> {
arena.alloc(self.clone())
}
}
impl Upload for Image {
type Target = DeviceImage;
fn upload(&self, arena: &Arena) -> Ptr<Self::Target> {
fn upload<A: GpuAllocator>(&self, arena: &Arena<A>) -> Ptr<Self::Target> {
arena.alloc(*self.device())
}
}
impl Upload for Spectrum {
type Target = Spectrum;
fn upload(&self, arena: &Arena) -> Ptr<Self::Target> {
fn upload<A: GpuAllocator>(&self, arena: &Arena<A>) -> Ptr<Self::Target> {
arena.alloc(self.clone())
}
}
impl Upload for Material {
type Target = Material;
fn upload(&self, arena: &Arena) -> Ptr<Self::Target> {
fn upload<A: GpuAllocator>(&self, arena: &Arena<A>) -> Ptr<Self::Target> {
arena.alloc(self.clone())
}
}
impl Upload for DenselySampledSpectrumBuffer {
type Target = DenselySampledSpectrum;
fn upload(&self, arena: &Arena) -> Ptr<Self::Target> {
fn upload<A: GpuAllocator>(&self, arena: &Arena<A>) -> Ptr<Self::Target> {
arena.alloc(*&self.device())
}
}
impl Upload for SpectrumTexture {
type Target = GPUSpectrumTexture;
fn upload(&self, arena: &Arena) -> Ptr<Self::Target> {
fn upload<A: GpuAllocator>(&self, arena: &Arena<A>) -> Ptr<Self::Target> {
let gpu_variant = match self {
SpectrumTexture::Constant(tex) => GPUSpectrumTexture::Constant(tex.clone()),
SpectrumTexture::Checkerboard(tex) => GPUSpectrumTexture::Checkerboard(tex.clone()),
@ -241,15 +189,6 @@ impl Upload for SpectrumTexture {
};
GPUSpectrumTexture::Scaled(gpu_scaled)
}
// SpectrumTexture::Ptex(tex) => {
// let gpu_ptex = GPUSpectrumPtexTexture::new(
// tex.base.filename,
// tex.base.encoding,
// tex.base.scale,
// tex.spectrum_type,
// );
// GPUSpectrumTexture::Ptex(gpu_ptex)
// }
SpectrumTexture::Marble(tex) => GPUSpectrumTexture::Marble(tex.clone()),
SpectrumTexture::Mix(tex) => {
let tex1_ptr = tex.tex1.upload(arena);
@ -284,7 +223,7 @@ impl Upload for SpectrumTexture {
impl Upload for FloatTexture {
type Target = GPUFloatTexture;
fn upload(&self, arena: &Arena) -> Ptr<Self::Target> {
fn upload<A: GpuAllocator>(&self, arena: &Arena<A>) -> Ptr<Self::Target> {
let gpu_variant = match self {
FloatTexture::Constant(tex) => GPUFloatTexture::Constant(tex.clone()),
FloatTexture::Checkerboard(tex) => GPUFloatTexture::Checkerboard(tex.clone()),
@ -346,7 +285,7 @@ impl Upload for FloatTexture {
impl Upload for RGBToSpectrumTable {
type Target = RGBToSpectrumTable;
fn upload(&self, arena: &Arena) -> Ptr<Self::Target> {
fn upload<A: GpuAllocator>(&self, arena: &Arena<A>) -> Ptr<Self::Target> {
let n_nodes = self.n_nodes as usize;
let z_slice = unsafe { from_raw_parts(self.z_nodes.as_raw(), n_nodes) };
let coeffs_slice = unsafe { from_raw_parts(self.coeffs.as_raw(), n_nodes) };
@ -366,7 +305,7 @@ impl Upload for RGBToSpectrumTable {
impl Upload for RGBColorSpace {
type Target = RGBColorSpace;
fn upload(&self, arena: &Arena) -> Ptr<Self::Target> {
fn upload<A: GpuAllocator>(&self, arena: &Arena<A>) -> Ptr<Self::Target> {
let table_ptr = self.rgb_to_spectrum_table.upload(arena);
let shared_space = RGBColorSpace {
@ -387,7 +326,7 @@ impl Upload for RGBColorSpace {
impl Upload for DeviceStandardColorSpaces {
type Target = DeviceStandardColorSpaces;
fn upload(&self, arena: &Arena) -> Ptr<Self::Target> {
fn upload<A: GpuAllocator>(&self, arena: &Arena<A>) -> Ptr<Self::Target> {
let srgb_ptr = self.srgb.upload(arena);
let dci_ptr = self.dci_p3.upload(arena);
let rec_ptr = self.rec2020.upload(arena);
@ -407,7 +346,7 @@ impl Upload for DeviceStandardColorSpaces {
impl Upload for PiecewiseConstant2D {
type Target = DevicePiecewiseConstant2D;
fn upload(&self, arena: &Arena) -> Ptr<Self::Target> {
fn upload<A: GpuAllocator>(&self, arena: &Arena<A>) -> Ptr<Self::Target> {
let marginal_shared = self.marginal.to_shared(arena);
let conditionals_shared: Vec<DevicePiecewiseConstant1D> = self
@ -430,7 +369,7 @@ impl Upload for PiecewiseConstant2D {
impl Upload for WindowedPiecewiseConstant2D {
type Target = DeviceWindowedPiecewiseConstant2D;
fn upload(&self, arena: &Arena) -> Ptr<Self::Target> {
fn upload<A: GpuAllocator>(&self, arena: &Arena<A>) -> Ptr<Self::Target> {
let specific = DeviceWindowedPiecewiseConstant2D {
sat: self.sat,
func: self.func,
@ -442,7 +381,7 @@ impl Upload for WindowedPiecewiseConstant2D {
impl Upload for TriangleMesh {
type Target = DeviceTriangleMesh;
fn upload(&self, arena: &Arena) -> Ptr<Self::Target> {
fn upload<A: GpuAllocator>(&self, arena: &Arena<A>) -> Ptr<Self::Target> {
let storage = &self.storage;
// Upload all arrays to arena
@ -490,7 +429,7 @@ impl Upload for TriangleMesh {
impl Upload for BilinearPatchMesh {
type Target = DeviceBilinearPatchMesh;
fn upload(&self, arena: &Arena) -> Ptr<Self::Target> {
fn upload<A: GpuAllocator>(&self, arena: &Arena<A>) -> Ptr<Self::Target> {
let storage = &self.storage;
let (vertex_indices_ptr, _) = arena.alloc_slice(&storage.vertex_indices);
@ -525,7 +464,7 @@ impl Upload for BilinearPatchMesh {
impl<T: Upload> Upload for Option<T> {
type Target = T::Target;
fn upload(&self, arena: &Arena) -> Ptr<Self::Target> {
fn upload<A: GpuAllocator>(&self, arena: &Arena<A>) -> Ptr<Self::Target> {
match self {
Some(val) => val.upload(arena),
None => Ptr::null(),
@ -536,7 +475,7 @@ impl<T: Upload> Upload for Option<T> {
impl<T: Upload> Upload for Arc<T> {
type Target = T::Target;
fn upload(&self, arena: &Arena) -> Ptr<Self::Target> {
fn upload<A: GpuAllocator>(&self, arena: &Arena<A>) -> Ptr<Self::Target> {
(**self).upload(arena)
}
}

View file

@ -1,4 +1,5 @@
pub mod arena;
pub mod backend;
pub mod containers;
pub mod error;
pub mod file;
@ -11,10 +12,19 @@ pub mod parser;
pub mod sampling;
pub mod strings;
pub use arena::{Arena, Upload};
pub use arena::Upload;
pub use error::FileLoc;
pub use file::{read_float_file, resolve_filename};
pub use parameters::{
ParameterDictionary, ParsedParameter, ParsedParameterVector, TextureParameterDictionary,
};
pub use strings::*;
#[cfg(feature = "vulkan")]
pub type Arena = arena::Arena<backend::vulkan::VulkanAllocator>;
#[cfg(all(feature = "cuda", not(feature = "vulkan")))]
pub type Arena = arena::Arena<backend::CudaAllocator>;
#[cfg(not(any(feature = "cuda", feature = "vulkan")))]
pub type Arena = arena::Arena<backend::SystemAllocator>;

View file

@ -3,6 +3,7 @@ use crate::core::texture::{FloatTexture, SpectrumTexture};
use crate::spectra::data::get_named_spectrum;
use crate::spectra::piecewise::PiecewiseLinearSpectrumBuffer;
use crate::utils::FileLoc;
use anyhow::{Result, bail};
use shared::Float;
use shared::core::color::RGB;
use shared::core::geometry::{Normal3f, Point2f, Point3f, Vector2f, Vector3f};
@ -19,14 +20,12 @@ use std::sync::{
atomic::{AtomicBool, Ordering},
};
pub fn error_exit(loc: Option<&FileLoc>, message: &str) -> ! {
pub fn error_exit(loc: Option<&FileLoc>, message: &str) -> String {
if let Some(l) = loc {
log::error!("Error: {}: {}", l, message);
format!("{}: {}", l, message)
} else {
log::error!("Error: {}", message);
message.to_string()
}
std::process::exit(1);
}
#[derive(Debug)]
@ -250,7 +249,10 @@ pub struct ParameterDictionary {
}
impl ParameterDictionary {
pub fn new(mut params: ParsedParameterVector, color_space: Option<Arc<RGBColorSpace>>) -> Self {
pub fn new(
mut params: ParsedParameterVector,
color_space: Option<Arc<RGBColorSpace>>,
) -> Result<Self> {
let n_owned_params = params.len();
params.reverse();
let dict = Self {
@ -258,15 +260,15 @@ impl ParameterDictionary {
color_space,
n_owned_params,
};
dict.check_parameter_types();
dict
dict.check_parameter_types()?;
Ok(dict)
}
pub fn from_array(
mut p0: ParsedParameterVector,
params: &[ParsedParameter],
color_space: Option<Arc<RGBColorSpace>>,
) -> Self {
) -> Result<Self> {
let n_owned_params = params.len();
p0.extend(params.iter().rev().cloned());
@ -275,21 +277,19 @@ impl ParameterDictionary {
color_space,
n_owned_params,
};
dict.check_parameter_types();
dict
dict.check_parameter_types()?;
Ok(dict)
}
fn check_parameter_types(&self) {
fn check_parameter_types(&self) -> Result<()> {
for p in &self.params {
match p.type_name.as_str() {
bool::TYPE_NAME => {
if p.bools.is_empty() {
error_exit(
Some(&p.loc),
&format!(
"\"{}\": non-Boolean values provided for Boolean-valued parameter",
p.name
),
bail!(
"{}: non-Boolean values provided for Boolean-valued parameter \"{}\"",
&p.loc,
p.name
);
}
}
@ -304,51 +304,49 @@ impl ParameterDictionary {
| "rgb"
| "blackbody" => {
if p.ints.is_empty() && p.floats.is_empty() {
error_exit(
Some(&p.loc),
&format!(
"\"{}\": non-numeric values provided for numeric-valued parameter",
p.name
),
bail!(
"{}: non-numeric values provided for numeric-valued parameter \"{}\"",
&p.loc,
p.name
);
}
}
String::TYPE_NAME | "texture" => {
if p.strings.is_empty() {
error_exit(
Some(&p.loc),
&format!(
"\"{}\": non-string values provided for string-valued parameter",
p.name
),
bail!(
"{}: non-string values provided for string-valued parameter \"{}\"",
&p.loc,
p.name
);
}
}
"spectrum" => {
if p.strings.is_empty() && p.ints.is_empty() && p.floats.is_empty() {
error_exit(
Some(&p.loc),
&format!(
"\"{}\": expecting string or numeric-valued parameter for spectrum parameter",
p.name
),
bail!(
"{}: expecting string or numeric-valued parameter for spectrum parameter \"{}\"",
&p.loc,
p.name
);
}
}
unknown => {
error_exit(
Some(&p.loc),
&format!("\"{}\": unknown parameter type '{}'", p.name, unknown),
bail!(
"{}: unknown parameter type \"{}\" '{}'",
&p.loc,
p.name,
unknown,
);
}
}
}
Ok(())
}
fn lookup_single<T>(&self, name: &str, default_val: T) -> T
fn lookup_single<T>(&self, name: &str, default_val: T) -> Result<T>
where
T: PBRTParameter,
{
@ -357,32 +355,31 @@ impl ParameterDictionary {
let values = T::get_values(&param);
if values.is_empty() {
error_exit(
Some(&param.loc),
&format!("No values provided for parameter \"{}\".", name),
bail!(
"{}: No values provided for parameter \"{}\".",
&param.loc,
name
);
}
if values.len() != T::N_PER_ITEM {
error_exit(
Some(&param.loc),
&format!(
"Expected {} values for parameter \"{}\". Found {}.",
T::N_PER_ITEM,
name,
values.len()
),
bail!(
"{}: Expected {} values for parameter \"{}\". Found {}.",
&param.loc,
T::N_PER_ITEM,
name,
values.len()
);
}
param.looked_up.store(true, Ordering::Relaxed);
return T::convert(values);
return Ok(T::convert(values));
}
default_val
Ok(default_val)
}
pub fn lookup_array<T>(&self, name: &str) -> Vec<T>
pub fn lookup_array<T>(&self, name: &str) -> Result<Vec<T>>
where
T: PBRTParameter,
{
@ -391,92 +388,90 @@ impl ParameterDictionary {
let values = T::get_values(param);
if values.len() % T::N_PER_ITEM != 0 {
error_exit(
Some(&param.loc),
&format!(
"Number of values for \"{}\" is not a multiple of {}",
name,
T::N_PER_ITEM
),
bail!(
"{}: Number of values for \"{}\" is not a multiple of {}",
&param.loc,
name,
T::N_PER_ITEM
);
}
param.looked_up.store(true, Ordering::Relaxed);
return values
return Ok(values
.chunks(T::N_PER_ITEM)
.map(|chunk| T::convert(chunk))
.collect();
.collect());
}
}
Vec::new()
Ok(Vec::new())
}
pub fn get_one_float(&self, name: &str, def: Float) -> Float {
pub fn get_one_float(&self, name: &str, def: Float) -> Result<Float> {
self.lookup_single(name, def)
}
pub fn get_one_int(&self, name: &str, def: i32) -> i32 {
pub fn get_one_int(&self, name: &str, def: i32) -> Result<i32> {
self.lookup_single(name, def)
}
pub fn get_one_bool(&self, name: &str, def: bool) -> bool {
pub fn get_one_bool(&self, name: &str, def: bool) -> Result<bool> {
self.lookup_single(name, def)
}
pub fn get_one_string(&self, name: &str, def: &str) -> String {
pub fn get_one_string(&self, name: &str, def: &str) -> Result<String> {
self.lookup_single(name, def.to_string())
}
pub fn get_one_point2f(&self, name: &str, def: Point2f) -> Point2f {
pub fn get_one_point2f(&self, name: &str, def: Point2f) -> Result<Point2f> {
self.lookup_single(name, def)
}
pub fn get_one_point3f(&self, name: &str, def: Point3f) -> Point3f {
pub fn get_one_point3f(&self, name: &str, def: Point3f) -> Result<Point3f> {
self.lookup_single(name, def)
}
pub fn get_one_vector2f(&self, name: &str, def: Vector2f) -> Vector2f {
pub fn get_one_vector2f(&self, name: &str, def: Vector2f) -> Result<Vector2f> {
self.lookup_single(name, def)
}
pub fn get_one_vector3f(&self, name: &str, def: Vector3f) -> Vector3f {
pub fn get_one_vector3f(&self, name: &str, def: Vector3f) -> Result<Vector3f> {
self.lookup_single(name, def)
}
pub fn get_one_normal3f(&self, name: &str, def: Normal3f) -> Normal3f {
pub fn get_one_normal3f(&self, name: &str, def: Normal3f) -> Result<Normal3f> {
self.lookup_single(name, def)
}
pub fn get_float_array(&self, name: &str) -> Vec<Float> {
pub fn get_float_array(&self, name: &str) -> Result<Vec<Float>> {
self.lookup_array(name)
}
pub fn get_int_array(&self, name: &str) -> Vec<i32> {
pub fn get_int_array(&self, name: &str) -> Result<Vec<i32>> {
self.lookup_array(name)
}
pub fn get_bool_array(&self, name: &str) -> Vec<bool> {
pub fn get_bool_array(&self, name: &str) -> Result<Vec<bool>> {
self.lookup_array(name)
}
pub fn get_string_array(&self, name: &str) -> Vec<String> {
pub fn get_string_array(&self, name: &str) -> Result<Vec<String>> {
self.lookup_array(name)
}
pub fn get_point2f_array(&self, name: &str) -> Vec<Point2f> {
pub fn get_point2f_array(&self, name: &str) -> Result<Vec<Point2f>> {
self.lookup_array(name)
}
pub fn get_point3f_array(&self, name: &str) -> Vec<Point3f> {
pub fn get_point3f_array(&self, name: &str) -> Result<Vec<Point3f>> {
self.lookup_array(name)
}
pub fn get_vector3f_array(&self, name: &str) -> Vec<Vector3f> {
pub fn get_vector3f_array(&self, name: &str) -> Result<Vec<Vector3f>> {
self.lookup_array(name)
}
pub fn get_normal3f_array(&self, name: &str) -> Vec<Normal3f> {
pub fn get_normal3f_array(&self, name: &str) -> Result<Vec<Normal3f>> {
self.lookup_array(name)
}
@ -709,70 +704,73 @@ pub struct TextureParameterDictionary {
impl TextureParameterDictionary {
pub fn new(dict: Arc<ParameterDictionary>, textures: Option<&NamedTextures>) -> Self {
Self { dict, textures: textures.cloned() }
Self {
dict,
textures: textures.cloned(),
}
}
pub fn get_one_float(&self, name: &str, def: Float) -> Float {
pub fn get_one_float(&self, name: &str, def: Float) -> Result<Float> {
self.dict.get_one_float(name, def)
}
pub fn get_one_int(&self, name: &str, def: i32) -> i32 {
pub fn get_one_int(&self, name: &str, def: i32) -> Result<i32> {
self.dict.get_one_int(name, def)
}
pub fn get_one_bool(&self, name: &str, def: bool) -> bool {
pub fn get_one_bool(&self, name: &str, def: bool) -> Result<bool> {
self.dict.get_one_bool(name, def)
}
pub fn get_one_string(&self, name: &str, def: &str) -> String {
pub fn get_one_string(&self, name: &str, def: &str) -> Result<String> {
self.dict.get_one_string(name, def)
}
pub fn get_float_array(&self, name: &str) -> Vec<Float> {
pub fn get_float_array(&self, name: &str) -> Result<Vec<Float>> {
self.dict.get_float_array(name)
}
pub fn get_int_array(&self, name: &str) -> Vec<i32> {
pub fn get_int_array(&self, name: &str) -> Result<Vec<i32>> {
self.dict.get_int_array(name)
}
pub fn get_bool_array(&self, name: &str) -> Vec<bool> {
pub fn get_bool_array(&self, name: &str) -> Result<Vec<bool>> {
self.dict.get_bool_array(name)
}
pub fn get_string_array(&self, name: &str) -> Vec<String> {
pub fn get_string_array(&self, name: &str) -> Result<Vec<String>> {
self.dict.get_string_array(name)
}
pub fn get_one_point3f(&self, name: &str, def: Point3f) -> Point3f {
pub fn get_one_point3f(&self, name: &str, def: Point3f) -> Result<Point3f> {
self.dict.get_one_point3f(name, def)
}
pub fn get_one_vector3f(&self, name: &str, def: Vector3f) -> Vector3f {
pub fn get_one_vector3f(&self, name: &str, def: Vector3f) -> Result<Vector3f> {
self.dict.get_one_vector3f(name, def)
}
pub fn get_one_normal3f(&self, name: &str, def: Normal3f) -> Normal3f {
pub fn get_one_normal3f(&self, name: &str, def: Normal3f) -> Result<Normal3f> {
self.dict.get_one_normal3f(name, def)
}
pub fn get_point3f_array(&self, name: &str) -> Vec<Point3f> {
pub fn get_point3f_array(&self, name: &str) -> Result<Vec<Point3f>> {
self.dict.get_point3f_array(name)
}
pub fn get_vector3f_array(&self, name: &str) -> Vec<Vector3f> {
pub fn get_vector3f_array(&self, name: &str) -> Result<Vec<Vector3f>> {
self.dict.get_vector3f_array(name)
}
pub fn get_normal3f_array(&self, name: &str) -> Vec<Normal3f> {
pub fn get_normal3f_array(&self, name: &str) -> Result<Vec<Normal3f>> {
self.dict.get_normal3f_array(name)
}
pub fn get_one_point2f(&self, name: &str, def: Point2f) -> Point2f {
pub fn get_one_point2f(&self, name: &str, def: Point2f) -> Result<Point2f> {
self.dict.get_one_point2f(name, def)
}
pub fn get_one_vector2f(&self, name: &str, def: Vector2f) -> Vector2f {
pub fn get_one_vector2f(&self, name: &str, def: Vector2f) -> Result<Vector2f> {
self.dict.get_one_vector2f(name, def)
}
@ -815,11 +813,25 @@ impl TextureParameterDictionary {
}
}
pub fn get_float_texture(&self, name: &str, val: Float) -> Arc<FloatTexture> {
if let Some(tex) = self.get_float_texture_or_null(name) {
return tex;
pub fn get_float_texture(&self, name: &str, val: Float) -> Result<Arc<FloatTexture>> {
if let Some(tex) = self.get_float_texture_or_null(name)? {
return Ok(tex);
} else {
return Arc::new(FloatTexture::Constant(FloatConstantTexture::new(val)));
return Ok(Arc::new(FloatTexture::Constant(FloatConstantTexture::new(
val,
))));
}
}
pub fn get_float_texture_with_fallback(
&self,
primary: &str,
fallback: &str,
default: Float,
) -> Result<Arc<FloatTexture>> {
match self.get_float_texture_or_null(primary)? {
Some(tex) => Ok(tex),
None => self.get_float_texture(fallback, default),
}
}
@ -909,7 +921,7 @@ impl TextureParameterDictionary {
return None;
}
pub fn get_float_texture_or_null(&self, name: &str) -> Option<Arc<FloatTexture>> {
pub fn get_float_texture_or_null(&self, name: &str) -> Result<Option<Arc<FloatTexture>>> {
for p in &self.dict.params {
if p.name != name {
continue;
@ -932,19 +944,19 @@ impl TextureParameterDictionary {
if let Some(nt) = &self.textures {
let map = &nt.float_textures;
if let Some(tex) = map.get(tex_name) {
return Some(Arc::clone(tex));
return Ok(Some(Arc::clone(tex)));
}
panic!(
"[{:?}] Couldn't find float texture named '{}'",
p.loc, tex_name
);
}
return None;
return Ok(None);
}
"float" => {
let v = self.get_one_float(name, 0.);
return Some(Arc::new(FloatTexture::Constant(FloatConstantTexture::new(
v,
let v = self.get_one_float(name, 0.)?;
return Ok(Some(Arc::new(FloatTexture::Constant(
FloatConstantTexture::new(v),
))));
}
_ => {
@ -952,6 +964,6 @@ impl TextureParameterDictionary {
}
}
}
return None;
Ok(None)
}
}

View file

@ -744,11 +744,12 @@ impl<'a> SceneParser<'a> {
}
pub fn run(&mut self) -> Result<(), ParserError> {
let arena = Arc::new(Arena::new());
let arena = Arc::new(Arena::default());
loop {
let token = match self.next_token()? {
Some(t) => t,
None => break, // EOF
// EOF
None => break,
};
let first_char = token.text.chars().next().unwrap();

View file

@ -1,5 +1,6 @@
use crate::core::image::Image;
use crate::utils::Arena;
use crate::utils::arena::Arena;
use crate::utils::backend::GpuAllocator;
use crate::utils::containers::Array2D;
use shared::Float;
use shared::core::geometry::{Bounds2f, Point2i, Vector2f, Vector2i};
@ -23,7 +24,7 @@ impl PiecewiseConstant1D {
Self::new_with_bounds(f.to_vec(), 0.0, 1.0)
}
pub fn to_shared(&self, arena: &Arena) -> DevicePiecewiseConstant1D {
pub fn to_shared<A: GpuAllocator>(&self, arena: &Arena<A>) -> DevicePiecewiseConstant1D {
let (func_ptr, _) = arena.alloc_slice(&self.func);
let (cdf_ptr, _) = arena.alloc_slice(&self.cdf);