Changing error handling with scene file parsing
This commit is contained in:
parent
8a92d7642d
commit
b36105edc1
22 changed files with 340 additions and 369 deletions
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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>>(
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>;
|
||||
|
|
|
|||
|
|
@ -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(¶m);
|
||||
|
||||
if values.is_empty() {
|
||||
error_exit(
|
||||
Some(¶m.loc),
|
||||
&format!("No values provided for parameter \"{}\".", name),
|
||||
bail!(
|
||||
"{}: No values provided for parameter \"{}\".",
|
||||
¶m.loc,
|
||||
name
|
||||
);
|
||||
}
|
||||
|
||||
if values.len() != T::N_PER_ITEM {
|
||||
error_exit(
|
||||
Some(¶m.loc),
|
||||
&format!(
|
||||
"Expected {} values for parameter \"{}\". Found {}.",
|
||||
T::N_PER_ITEM,
|
||||
name,
|
||||
values.len()
|
||||
),
|
||||
bail!(
|
||||
"{}: Expected {} values for parameter \"{}\". Found {}.",
|
||||
¶m.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(¶m.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 {}",
|
||||
¶m.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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue