Compare commits
2 commits
0b04d54346
...
b36105edc1
| Author | SHA1 | Date | |
|---|---|---|---|
| b36105edc1 | |||
| 8a92d7642d |
23 changed files with 487 additions and 369 deletions
|
|
@ -9,6 +9,8 @@ use_f64 = []
|
||||||
use_gpu = []
|
use_gpu = []
|
||||||
use_nvtx = []
|
use_nvtx = []
|
||||||
cuda = ["dep:cudarc", "dep:cust", "dep:cust_raw"]
|
cuda = ["dep:cudarc", "dep:cust", "dep:cust_raw"]
|
||||||
|
vulkan = ["ash", "gpu-allocator"]
|
||||||
|
ash = ["dep:ash"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.100"
|
anyhow = "1.0.100"
|
||||||
|
|
@ -33,12 +35,12 @@ wgpu = "27.0.1"
|
||||||
shared = { path = "shared" }
|
shared = { path = "shared" }
|
||||||
ptex-filter = { path = "crates/ptex-filter" }
|
ptex-filter = { path = "crates/ptex-filter" }
|
||||||
# kernels = { path = "kernels" }
|
# 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 }
|
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 = { 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 }
|
cust_raw = { git = "https://github.com/Rust-GPU/Rust-CUDA", branch = "main", default-features = false, optional = true }
|
||||||
ptex = "0.3.0"
|
ptex = "0.3.0"
|
||||||
# ptex-sys = "0.3.0"
|
|
||||||
slice = "0.0.4"
|
slice = "0.0.4"
|
||||||
crossbeam-channel = "0.5.15"
|
crossbeam-channel = "0.5.15"
|
||||||
num_cpus = "1.17.0"
|
num_cpus = "1.17.0"
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,4 @@ pub mod utils;
|
||||||
#[cfg(feature = "cuda")]
|
#[cfg(feature = "cuda")]
|
||||||
pub mod gpu;
|
pub mod gpu;
|
||||||
|
|
||||||
pub use utils::arena::Arena;
|
pub use utils::{Arena, FileLoc, ParameterDictionary};
|
||||||
pub use utils::error::FileLoc;
|
|
||||||
pub use utils::parameters::ParameterDictionary;
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use crate::core::material::CreateMaterial;
|
||||||
use crate::core::texture::SpectrumTexture;
|
use crate::core::texture::SpectrumTexture;
|
||||||
use crate::spectra::data::get_named_spectrum;
|
use crate::spectra::data::get_named_spectrum;
|
||||||
use crate::utils::{Arena, FileLoc, TextureParameterDictionary, Upload, parameters::error_exit};
|
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::material::Material;
|
||||||
use shared::core::spectrum::Spectrum;
|
use shared::core::spectrum::Spectrum;
|
||||||
use shared::core::texture::SpectrumType;
|
use shared::core::texture::SpectrumType;
|
||||||
|
|
@ -27,32 +27,32 @@ impl CreateMaterial for CoatedDiffuseMaterial {
|
||||||
SpectrumConstantTexture::new(Spectrum::Constant(ConstantSpectrum::new(0.5))),
|
SpectrumConstantTexture::new(Spectrum::Constant(ConstantSpectrum::new(0.5))),
|
||||||
)));
|
)));
|
||||||
|
|
||||||
let u_roughness = parameters
|
let u_roughness =
|
||||||
.get_float_texture_or_null("uroughness")
|
parameters.get_float_texture_with_fallback("uroughness", "roughness", 0.5)?;
|
||||||
.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 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
|
let eta = parameters
|
||||||
.get_float_array("eta")
|
.get_float_array("eta")?
|
||||||
.first()
|
.first()
|
||||||
.map(|&v| Spectrum::Constant(ConstantSpectrum::new(v)))
|
.map(|&v| Spectrum::Constant(ConstantSpectrum::new(v)))
|
||||||
.or_else(|| parameters.get_one_spectrum("eta", None, SpectrumType::Unbounded))
|
.or_else(|| parameters.get_one_spectrum("eta", None, SpectrumType::Unbounded))
|
||||||
.unwrap_or_else(|| Spectrum::Constant(ConstantSpectrum::new(1.5)));
|
.unwrap_or_else(|| Spectrum::Constant(ConstantSpectrum::new(1.5)));
|
||||||
|
|
||||||
let max_depth = parameters.get_one_int("maxdepth", 10);
|
let max_depth = parameters.get_one_int("maxdepth", 10)?;
|
||||||
let n_samples = parameters.get_one_int("nsamples", 1);
|
let n_samples = parameters.get_one_int("nsamples", 1)?;
|
||||||
let g = parameters.get_float_texture("g", 0.);
|
let g = parameters.get_float_texture("g", 0.)?;
|
||||||
let albedo = parameters
|
let albedo = parameters
|
||||||
.get_spectrum_texture("albedo", None, SpectrumType::Albedo)
|
.get_spectrum_texture("albedo", None, SpectrumType::Albedo)
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(|| {
|
||||||
let default_spectrum = Spectrum::Constant(ConstantSpectrum::new(0.));
|
let default_spectrum = Spectrum::Constant(ConstantSpectrum::new(0.));
|
||||||
SpectrumTexture::Constant(SpectrumConstantTexture::new(default_spectrum)).into()
|
SpectrumTexture::Constant(SpectrumConstantTexture::new(default_spectrum)).into()
|
||||||
});
|
});
|
||||||
let displacement = parameters.get_float_texture("displacement", 0.);
|
let displacement = parameters.get_float_texture("displacement", 0.)?;
|
||||||
let remap_roughness = parameters.get_one_bool("remaproughness", true);
|
let remap_roughness = parameters.get_one_bool("remaproughness", true)?;
|
||||||
|
|
||||||
let specific = CoatedDiffuseMaterial::new(
|
let specific = CoatedDiffuseMaterial::new(
|
||||||
reflectance.upload(arena),
|
reflectance.upload(arena),
|
||||||
u_roughness.upload(arena),
|
u_roughness.upload(arena),
|
||||||
|
|
@ -80,68 +80,76 @@ impl CreateMaterial for CoatedConductorMaterial {
|
||||||
loc: &FileLoc,
|
loc: &FileLoc,
|
||||||
arena: &Arena,
|
arena: &Arena,
|
||||||
) -> Result<Material> {
|
) -> Result<Material> {
|
||||||
let interface_u_roughness = parameters
|
let interface_u_roughness = parameters.get_float_texture_with_fallback(
|
||||||
.get_float_texture_or_null("interface.uroughness")
|
"interface.uroughness",
|
||||||
.unwrap_or_else(|| parameters.get_float_texture("interface.roughness", 0.));
|
"interface.roughness",
|
||||||
let interface_v_roughness = parameters
|
0.,
|
||||||
.get_float_texture_or_null("interface.vroughness")
|
)?;
|
||||||
.unwrap_or_else(|| parameters.get_float_texture("interface.vroughness", 0.));
|
let interface_v_roughness = parameters.get_float_texture_with_fallback(
|
||||||
let thickness = parameters.get_float_texture("interface.thickness", 0.01);
|
"interface.vroughness",
|
||||||
|
"interface.roughness",
|
||||||
|
0.,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let thickness = parameters.get_float_texture("interface.thickness", 0.01)?;
|
||||||
let interface_eta: Spectrum = parameters
|
let interface_eta: Spectrum = parameters
|
||||||
.get_float_array("interface.eta")
|
.get_float_array("interface.eta")?
|
||||||
.first()
|
.first()
|
||||||
.map(|&v| Spectrum::Constant(ConstantSpectrum::new(v)))
|
.map(|&v| Spectrum::Constant(ConstantSpectrum::new(v)))
|
||||||
.or_else(|| parameters.get_one_spectrum("interface.eta", None, SpectrumType::Unbounded))
|
.or_else(|| parameters.get_one_spectrum("interface.eta", None, SpectrumType::Unbounded))
|
||||||
.unwrap_or_else(|| Spectrum::Constant(ConstantSpectrum::new(1.5)));
|
.unwrap_or_else(|| Spectrum::Constant(ConstantSpectrum::new(1.5)));
|
||||||
let conductor_u_roughness = parameters
|
|
||||||
.get_float_texture_or_null("conductor.uroughness")
|
let conductor_u_roughness = parameters.get_float_texture_with_fallback(
|
||||||
.unwrap_or_else(|| parameters.get_float_texture("conductor.roughness", 0.));
|
"conductor.uroughness",
|
||||||
let conductor_v_roughness = parameters
|
"conductor.roughness",
|
||||||
.get_float_texture_or_null("conductor.vroughness")
|
0.,
|
||||||
.unwrap_or_else(|| parameters.get_float_texture("conductor.vroughness", 0.));
|
)?;
|
||||||
|
|
||||||
|
let conductor_v_roughness = parameters.get_float_texture_with_fallback(
|
||||||
|
"conductor.vroughness",
|
||||||
|
"conductor.roughness",
|
||||||
|
0.,
|
||||||
|
)?;
|
||||||
|
|
||||||
let reflectance =
|
let reflectance =
|
||||||
parameters.get_spectrum_texture_or_null("reflectance", SpectrumType::Albedo);
|
parameters.get_spectrum_texture_or_null("reflectance", SpectrumType::Albedo);
|
||||||
let conductor_eta =
|
let conductor_eta =
|
||||||
parameters.get_spectrum_texture_or_null("conductor.eta", SpectrumType::Unbounded);
|
parameters.get_spectrum_texture_or_null("conductor.eta", SpectrumType::Unbounded);
|
||||||
let k = parameters.get_spectrum_texture_or_null("conductor.k", SpectrumType::Unbounded);
|
let k = parameters.get_spectrum_texture_or_null("conductor.k", SpectrumType::Unbounded);
|
||||||
|
|
||||||
let (conductor_eta, k) = match (&reflectance, conductor_eta, k) {
|
let (conductor_eta, k) = if reflectance.is_some() {
|
||||||
(Some(_), Some(_), _) | (Some(_), _, Some(_)) => {
|
if conductor_eta.is_some() || k.is_some() {
|
||||||
return Err(error_exit(
|
bail!(
|
||||||
Some(loc),
|
"{}: For the coated conductor material, both \"reflectance\" \
|
||||||
"For the coated conductor material, both \"reflectance\" \
|
and \"eta\"/\"k\" cannot be provided simultaneously.",
|
||||||
and \"eta\" and \"k\" can't be provided.",
|
loc
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
|
(None, None)
|
||||||
(None, eta, k) => {
|
} else {
|
||||||
let final_eta = eta.unwrap_or_else(|| {
|
let eta = conductor_eta.unwrap_or_else(|| {
|
||||||
let s = get_named_spectrum("metal-Cu-eta").expect("Missing copper spectrum");
|
let s = get_named_spectrum("metal-Cu-eta").expect("Missing copper spectrum");
|
||||||
Arc::new(SpectrumTexture::Constant(SpectrumConstantTexture::new(s)))
|
Arc::new(SpectrumTexture::Constant(SpectrumConstantTexture::new(s)))
|
||||||
});
|
});
|
||||||
|
let k = k.unwrap_or_else(|| {
|
||||||
let final_k = k.unwrap_or_else(|| {
|
|
||||||
let s = get_named_spectrum("metal-Cu-k").expect("Missing copper spectrum");
|
let s = get_named_spectrum("metal-Cu-k").expect("Missing copper spectrum");
|
||||||
Arc::new(SpectrumTexture::Constant(SpectrumConstantTexture::new(s)))
|
Arc::new(SpectrumTexture::Constant(SpectrumConstantTexture::new(s)))
|
||||||
});
|
});
|
||||||
|
(Some(eta), Some(k))
|
||||||
(Some(final_eta), Some(final_k))
|
|
||||||
}
|
|
||||||
|
|
||||||
(Some(_), None, None) => (None, None),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let max_depth = parameters.get_one_int("maxdepth", 10);
|
let max_depth = parameters.get_one_int("maxdepth", 10)?;
|
||||||
let n_samples = parameters.get_one_int("nsamples", 1);
|
let n_samples = parameters.get_one_int("nsamples", 1)?;
|
||||||
let g = parameters.get_float_texture("g", 0.);
|
let g = parameters.get_float_texture("g", 0.)?;
|
||||||
let albedo = parameters
|
let albedo = parameters
|
||||||
.get_spectrum_texture("albedo", None, SpectrumType::Albedo)
|
.get_spectrum_texture("albedo", None, SpectrumType::Albedo)
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(|| {
|
||||||
let spectrum = Spectrum::Constant(ConstantSpectrum::new(0.));
|
let spectrum = Spectrum::Constant(ConstantSpectrum::new(0.));
|
||||||
SpectrumTexture::Constant(SpectrumConstantTexture::new(spectrum)).into()
|
SpectrumTexture::Constant(SpectrumConstantTexture::new(spectrum)).into()
|
||||||
});
|
});
|
||||||
let displacement = parameters.get_float_texture_or_null("displacement");
|
let displacement = parameters.get_float_texture_or_null("displacement")?;
|
||||||
let remap_roughness = parameters.get_one_bool("remaproughness", true);
|
let remap_roughness = parameters.get_one_bool("remaproughness", true)?;
|
||||||
|
|
||||||
let material = Self::new(
|
let material = Self::new(
|
||||||
normal_map.upload(arena),
|
normal_map.upload(arena),
|
||||||
displacement.upload(arena),
|
displacement.upload(arena),
|
||||||
|
|
|
||||||
|
|
@ -27,8 +27,8 @@ impl CreateMaterial for HairMaterial {
|
||||||
let reflectance = parameters
|
let reflectance = parameters
|
||||||
.get_spectrum_texture_or_null("reflectance", SpectrumType::Albedo)
|
.get_spectrum_texture_or_null("reflectance", SpectrumType::Albedo)
|
||||||
.or_else(|| parameters.get_spectrum_texture_or_null("color", SpectrumType::Albedo));
|
.or_else(|| parameters.get_spectrum_texture_or_null("color", SpectrumType::Albedo));
|
||||||
let eumelanin = parameters.get_float_texture_or_null("eumelanin");
|
let eumelanin = parameters.get_float_texture_or_null("eumelanin")?;
|
||||||
let pheomelanin = parameters.get_float_texture_or_null("pheomelanin");
|
let pheomelanin = parameters.get_float_texture_or_null("pheomelanin")?;
|
||||||
let has_melanin = eumelanin.is_some() || pheomelanin.is_some();
|
let has_melanin = eumelanin.is_some() || pheomelanin.is_some();
|
||||||
|
|
||||||
// Default distribution if nothing is spceified
|
// Default distribution if nothing is spceified
|
||||||
|
|
@ -42,10 +42,10 @@ impl CreateMaterial for HairMaterial {
|
||||||
sigma_a
|
sigma_a
|
||||||
};
|
};
|
||||||
|
|
||||||
let eta = parameters.get_float_texture("eta", 1.55);
|
let eta = parameters.get_float_texture("eta", 1.55)?;
|
||||||
let beta_m = parameters.get_float_texture("beta_m", 0.3);
|
let beta_m = parameters.get_float_texture("beta_m", 0.3)?;
|
||||||
let beta_n = parameters.get_float_texture("beta_n", 0.3);
|
let beta_n = parameters.get_float_texture("beta_n", 0.3)?;
|
||||||
let alpha = parameters.get_float_texture("alpha", 2.);
|
let alpha = parameters.get_float_texture("alpha", 2.)?;
|
||||||
let material = HairMaterial::new(
|
let material = HairMaterial::new(
|
||||||
sigma_a.upload(arena),
|
sigma_a.upload(arena),
|
||||||
reflectance.upload(arena),
|
reflectance.upload(arena),
|
||||||
|
|
|
||||||
|
|
@ -71,14 +71,15 @@ impl CreateSampler for HaltonSampler {
|
||||||
_arena: &Arena,
|
_arena: &Arena,
|
||||||
) -> Result<Sampler> {
|
) -> Result<Sampler> {
|
||||||
let options = get_options();
|
let options = get_options();
|
||||||
let nsamp = options
|
let nsamp = if let Some(n) = options.quick_render.then_some(1).or(options.pixel_samples) {
|
||||||
.quick_render
|
n
|
||||||
.then_some(1)
|
} else {
|
||||||
.or(options.pixel_samples)
|
params.get_one_int("pixelsamples", 16)?
|
||||||
.unwrap_or_else(|| params.get_one_int("pixelsamples", 16));
|
};
|
||||||
let seed = params.get_one_int("seed", options.seed);
|
|
||||||
|
let seed = params.get_one_int("seed", options.seed)?;
|
||||||
let s = match params
|
let s = match params
|
||||||
.get_one_string("randomization", "permutedigits")
|
.get_one_string("randomization", "permutedigits")?
|
||||||
.as_str()
|
.as_str()
|
||||||
{
|
{
|
||||||
"none" => RandomizeStrategy::None,
|
"none" => RandomizeStrategy::None,
|
||||||
|
|
|
||||||
|
|
@ -11,12 +11,14 @@ impl CreateSampler for IndependentSampler {
|
||||||
arena: &Arena,
|
arena: &Arena,
|
||||||
) -> Result<Sampler> {
|
) -> Result<Sampler> {
|
||||||
let options = get_options();
|
let options = get_options();
|
||||||
let nsamp = options
|
|
||||||
.quick_render
|
let nsamp = if let Some(n) = options.quick_render.then_some(1).or(options.pixel_samples) {
|
||||||
.then_some(1)
|
n
|
||||||
.or(options.pixel_samples)
|
} else {
|
||||||
.unwrap_or_else(|| params.get_one_int("pixelsamples", 16));
|
params.get_one_int("pixelsamples", 16)?
|
||||||
let seed = params.get_one_int("seed", options.seed);
|
};
|
||||||
|
|
||||||
|
let seed = params.get_one_int("seed", options.seed)?;
|
||||||
let sampler = Self::new(nsamp, seed as u64);
|
let sampler = Self::new(nsamp, seed as u64);
|
||||||
arena.alloc(sampler);
|
arena.alloc(sampler);
|
||||||
Ok(Sampler::Independent(sampler))
|
Ok(Sampler::Independent(sampler))
|
||||||
|
|
|
||||||
|
|
@ -12,13 +12,15 @@ impl CreateSampler for SobolSampler {
|
||||||
_arena: &Arena,
|
_arena: &Arena,
|
||||||
) -> Result<Sampler> {
|
) -> Result<Sampler> {
|
||||||
let options = get_options();
|
let options = get_options();
|
||||||
let nsamp = options
|
let nsamp = if let Some(n) = options.quick_render.then_some(1).or(options.pixel_samples) {
|
||||||
.quick_render
|
n
|
||||||
.then_some(1)
|
} else {
|
||||||
.or(options.pixel_samples)
|
params.get_one_int("pixelsamples", 16)?
|
||||||
.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 seed = params.get_one_int("seed", options.seed)?;
|
||||||
|
|
||||||
|
let s = match params.get_one_string("randomization", "fastowen")?.as_str() {
|
||||||
"none" => RandomizeStrategy::None,
|
"none" => RandomizeStrategy::None,
|
||||||
"permutedigits" => RandomizeStrategy::PermuteDigits,
|
"permutedigits" => RandomizeStrategy::PermuteDigits,
|
||||||
"fastowen" => RandomizeStrategy::FastOwen,
|
"fastowen" => RandomizeStrategy::FastOwen,
|
||||||
|
|
@ -42,13 +44,13 @@ impl CreateSampler for PaddedSobolSampler {
|
||||||
_arena: &Arena,
|
_arena: &Arena,
|
||||||
) -> Result<Sampler> {
|
) -> Result<Sampler> {
|
||||||
let options = get_options();
|
let options = get_options();
|
||||||
let nsamp = options
|
let nsamp = if let Some(n) = options.quick_render.then_some(1).or(options.pixel_samples) {
|
||||||
.quick_render
|
n
|
||||||
.then_some(1)
|
} else {
|
||||||
.or(options.pixel_samples)
|
params.get_one_int("pixelsamples", 16)?
|
||||||
.unwrap_or_else(|| params.get_one_int("pixelsamples", 16));
|
};
|
||||||
let seed = params.get_one_int("seed", options.seed);
|
let seed = params.get_one_int("seed", options.seed)?;
|
||||||
let s = match params.get_one_string("randomization", "fastowen").as_str() {
|
let s = match params.get_one_string("randomization", "fastowen")?.as_str() {
|
||||||
"none" => RandomizeStrategy::None,
|
"none" => RandomizeStrategy::None,
|
||||||
"permutedigits" => RandomizeStrategy::PermuteDigits,
|
"permutedigits" => RandomizeStrategy::PermuteDigits,
|
||||||
"fastowen" => RandomizeStrategy::FastOwen,
|
"fastowen" => RandomizeStrategy::FastOwen,
|
||||||
|
|
@ -75,13 +77,14 @@ impl CreateSampler for ZSobolSampler {
|
||||||
_arena: &Arena,
|
_arena: &Arena,
|
||||||
) -> Result<Sampler> {
|
) -> Result<Sampler> {
|
||||||
let options = get_options();
|
let options = get_options();
|
||||||
let nsamp = options
|
let nsamp = if let Some(n) = options.quick_render.then_some(1).or(options.pixel_samples) {
|
||||||
.quick_render
|
n
|
||||||
.then_some(1)
|
} else {
|
||||||
.or(options.pixel_samples)
|
params.get_one_int("pixelsamples", 16)?
|
||||||
.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 seed = params.get_one_int("seed", options.seed)?;
|
||||||
|
let s = match params.get_one_string("randomization", "fastowen")?.as_str() {
|
||||||
"none" => RandomizeStrategy::None,
|
"none" => RandomizeStrategy::None,
|
||||||
"permutedigits" => RandomizeStrategy::PermuteDigits,
|
"permutedigits" => RandomizeStrategy::PermuteDigits,
|
||||||
"fastowen" => RandomizeStrategy::FastOwen,
|
"fastowen" => RandomizeStrategy::FastOwen,
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ impl CreateSampler for StratifiedSampler {
|
||||||
_arena: &Arena,
|
_arena: &Arena,
|
||||||
) -> Result<Sampler> {
|
) -> Result<Sampler> {
|
||||||
let options = get_options();
|
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 {
|
let (x_samples, y_samples) = if options.quick_render {
|
||||||
(1, 1)
|
(1, 1)
|
||||||
} else if let Some(n) = options.pixel_samples {
|
} else if let Some(n) = options.pixel_samples {
|
||||||
|
|
@ -21,11 +21,11 @@ impl CreateSampler for StratifiedSampler {
|
||||||
(n / y, y)
|
(n / y, y)
|
||||||
} else {
|
} else {
|
||||||
(
|
(
|
||||||
params.get_one_int("xsamples", 4),
|
params.get_one_int("xsamples", 4)?,
|
||||||
params.get_one_int("ysamples", 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);
|
let sampler = Self::new(x_samples, y_samples, Some(seed as u64), jitter);
|
||||||
// arena.aloc(sampler);
|
// arena.aloc(sampler);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,11 +23,11 @@ impl CreateShape for BilinearPatchShape {
|
||||||
_loc: FileLoc,
|
_loc: FileLoc,
|
||||||
_arena: &Arena,
|
_arena: &Arena,
|
||||||
) -> Result<Vec<Shape>> {
|
) -> Result<Vec<Shape>> {
|
||||||
let mut vertex_indices = parameters.get_int_array("indices");
|
let mut vertex_indices = parameters.get_int_array("indices")?;
|
||||||
let p = parameters.get_point3f_array("P");
|
let p = parameters.get_point3f_array("P")?;
|
||||||
let mut uv = parameters.get_point2f_array("uv");
|
let mut uv = parameters.get_point2f_array("uv")?;
|
||||||
let mut n = parameters.get_normal3f_array("N");
|
let mut n = parameters.get_normal3f_array("N")?;
|
||||||
let mut face_indices = parameters.get_int_array("faceIndices");
|
let mut face_indices = parameters.get_int_array("faceIndices")?;
|
||||||
|
|
||||||
if vertex_indices.is_empty() {
|
if vertex_indices.is_empty() {
|
||||||
if p.len() == 4 {
|
if p.len() == 4 {
|
||||||
|
|
@ -84,7 +84,7 @@ impl CreateShape for BilinearPatchShape {
|
||||||
face_indices.clear();
|
face_indices.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
let filename = parameters.get_one_string("emissionfilename", "");
|
let filename = parameters.get_one_string("emissionfilename", "")?;
|
||||||
|
|
||||||
let image_dist = if !filename.is_empty() {
|
let image_dist = if !filename.is_empty() {
|
||||||
if !uv.is_empty() {
|
if !uv.is_empty() {
|
||||||
|
|
|
||||||
|
|
@ -66,11 +66,11 @@ impl CreateShape for CurveShape {
|
||||||
_loc: FileLoc,
|
_loc: FileLoc,
|
||||||
_arena: &Arena,
|
_arena: &Arena,
|
||||||
) -> Result<Vec<Shape>> {
|
) -> Result<Vec<Shape>> {
|
||||||
let width = parameters.get_one_float("width", 1.0);
|
let width = parameters.get_one_float("width", 1.0)?;
|
||||||
let width0 = parameters.get_one_float("width0", width);
|
let width0 = parameters.get_one_float("width0", width)?;
|
||||||
let width1 = parameters.get_one_float("width1", 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 {
|
if degree != 2 && degree != 3 {
|
||||||
return Err(anyhow!(
|
return Err(anyhow!(
|
||||||
"Invalid degree {}: only degree 2 and 3 curves are supported.",
|
"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" {
|
if basis != "bezier" && basis != "bspline" {
|
||||||
return Err(anyhow!(
|
return Err(anyhow!(
|
||||||
"Invalid basis \"{}\": only \"bezier\" and \"bspline\" are supported.",
|
"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;
|
let n_segments;
|
||||||
|
|
||||||
if basis == "bezier" {
|
if basis == "bezier" {
|
||||||
|
|
@ -114,7 +114,7 @@ impl CreateShape for CurveShape {
|
||||||
n_segments = cp.len() - degree as usize;
|
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() {
|
let curve_type = match curve_type_str.as_str() {
|
||||||
"flat" => CurveType::Flat,
|
"flat" => CurveType::Flat,
|
||||||
"ribbon" => CurveType::Ribbon,
|
"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 !n.is_empty() {
|
||||||
if curve_type != CurveType::Ribbon {
|
if curve_type != CurveType::Ribbon {
|
||||||
warn!("Curve normals are only used with \"ribbon\" type curves. Discarding.");
|
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 {
|
let split_depth = if use_gpu {
|
||||||
0
|
0
|
||||||
} else {
|
} else {
|
||||||
parameters.get_one_int("splitdepth", 3)
|
parameters.get_one_int("splitdepth", 3)?
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut curves: Vec<Shape> = Vec::new();
|
let mut curves: Vec<Shape> = Vec::new();
|
||||||
|
|
|
||||||
|
|
@ -18,10 +18,10 @@ impl CreateShape for CylinderShape {
|
||||||
_loc: FileLoc,
|
_loc: FileLoc,
|
||||||
arena: &Arena,
|
arena: &Arena,
|
||||||
) -> Result<Vec<Shape>> {
|
) -> Result<Vec<Shape>> {
|
||||||
let radius = parameters.get_one_float("radius", 1.);
|
let radius = parameters.get_one_float("radius", 1.)?;
|
||||||
let z_min = parameters.get_one_float("zmin", -1.);
|
let z_min = parameters.get_one_float("zmin", -1.)?;
|
||||||
let z_max = parameters.get_one_float("zmax", 1.);
|
let z_max = parameters.get_one_float("zmax", 1.)?;
|
||||||
let phi_max = parameters.get_one_float("phimax", 360.);
|
let phi_max = parameters.get_one_float("phimax", 360.)?;
|
||||||
let shape = CylinderShape::new(
|
let shape = CylinderShape::new(
|
||||||
render_from_object,
|
render_from_object,
|
||||||
object_from_render,
|
object_from_render,
|
||||||
|
|
|
||||||
|
|
@ -18,10 +18,10 @@ impl CreateShape for DiskShape {
|
||||||
_loc: FileLoc,
|
_loc: FileLoc,
|
||||||
arena: &Arena,
|
arena: &Arena,
|
||||||
) -> Result<Vec<Shape>> {
|
) -> Result<Vec<Shape>> {
|
||||||
let height = parameters.get_one_float("height", 0.);
|
let height = parameters.get_one_float("height", 0.)?;
|
||||||
let radius = parameters.get_one_float("radius", 1.);
|
let radius = parameters.get_one_float("radius", 1.)?;
|
||||||
let inner_radius = parameters.get_one_float("innerradius", 0.);
|
let inner_radius = parameters.get_one_float("innerradius", 0.)?;
|
||||||
let phi_max = parameters.get_one_float("phimax", 360.);
|
let phi_max = parameters.get_one_float("phimax", 360.)?;
|
||||||
let shape = DiskShape::new(
|
let shape = DiskShape::new(
|
||||||
radius,
|
radius,
|
||||||
inner_radius,
|
inner_radius,
|
||||||
|
|
|
||||||
|
|
@ -246,9 +246,7 @@ impl BilinearPatchMesh {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// PLY Helper Functions
|
// PLY Helper Functions
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
fn get_float(elem: &DefaultElement, key: &str) -> AnyResult<f32> {
|
fn get_float(elem: &DefaultElement, key: &str) -> AnyResult<f32> {
|
||||||
match elem.get(key) {
|
match elem.get(key) {
|
||||||
|
|
@ -290,9 +288,7 @@ fn get_list_uint(elem: &DefaultElement, key: &str) -> AnyResult<Vec<u32>> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// TriQuadMesh Implementation
|
// TriQuadMesh Implementation
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
impl TriQuadMesh {
|
impl TriQuadMesh {
|
||||||
pub fn read_ply<P: AsRef<Path>>(filename: P) -> AnyResult<Self> {
|
pub fn read_ply<P: AsRef<Path>>(filename: P) -> AnyResult<Self> {
|
||||||
|
|
@ -510,9 +506,7 @@ impl TriQuadMesh {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// Create from PLY directly
|
||||||
// Convenience: Create from PLY directly
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
impl TriangleMesh {
|
impl TriangleMesh {
|
||||||
pub fn from_ply<P: AsRef<Path>>(
|
pub fn from_ply<P: AsRef<Path>>(
|
||||||
|
|
|
||||||
|
|
@ -18,10 +18,10 @@ impl CreateShape for SphereShape {
|
||||||
_loc: FileLoc,
|
_loc: FileLoc,
|
||||||
arena: &Arena,
|
arena: &Arena,
|
||||||
) -> Result<Vec<Shape>> {
|
) -> Result<Vec<Shape>> {
|
||||||
let radius = parameters.get_one_float("radius", 1.);
|
let radius = parameters.get_one_float("radius", 1.)?;
|
||||||
let zmin = parameters.get_one_float("zmin", -radius);
|
let zmin = parameters.get_one_float("zmin", -radius)?;
|
||||||
let zmax = parameters.get_one_float("zmax", radius);
|
let zmax = parameters.get_one_float("zmax", radius)?;
|
||||||
let phimax = parameters.get_one_float("phimax", 360.);
|
let phimax = parameters.get_one_float("phimax", 360.)?;
|
||||||
let shape = SphereShape::new(
|
let shape = SphereShape::new(
|
||||||
render_from_object,
|
render_from_object,
|
||||||
object_from_render,
|
object_from_render,
|
||||||
|
|
|
||||||
|
|
@ -20,11 +20,11 @@ impl CreateShape for TriangleShape {
|
||||||
_loc: FileLoc,
|
_loc: FileLoc,
|
||||||
_arena: &Arena,
|
_arena: &Arena,
|
||||||
) -> Result<Vec<Shape>> {
|
) -> Result<Vec<Shape>> {
|
||||||
let mut vertex_indices = parameters.get_int_array("indices");
|
let mut vertex_indices = parameters.get_int_array("indices")?;
|
||||||
let p = parameters.get_point3f_array("P");
|
let p = parameters.get_point3f_array("P")?;
|
||||||
let mut uvs = parameters.get_point2f_array("uv");
|
let mut uvs = parameters.get_point2f_array("uv")?;
|
||||||
let mut s = parameters.get_vector3f_array("S");
|
let mut s = parameters.get_vector3f_array("S")?;
|
||||||
let mut n = parameters.get_normal3f_array("N");
|
let mut n = parameters.get_normal3f_array("N")?;
|
||||||
|
|
||||||
if vertex_indices.is_empty() {
|
if vertex_indices.is_empty() {
|
||||||
if p.len() == 3 {
|
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;
|
let n_triangles = vertex_indices.len() / 3;
|
||||||
|
|
||||||
if !face_indices.is_empty() && face_indices.len() != n_triangles {
|
if !face_indices.is_empty() && face_indices.len() != n_triangles {
|
||||||
|
|
|
||||||
|
|
@ -33,9 +33,9 @@ impl FloatMixTexture {
|
||||||
_loc: &FileLoc,
|
_loc: &FileLoc,
|
||||||
_arena: &Arena,
|
_arena: &Arena,
|
||||||
) -> Result<FloatTexture> {
|
) -> Result<FloatTexture> {
|
||||||
let tex1 = params.get_float_texture("tex1", 0.);
|
let tex1 = params.get_float_texture("tex1", 0.)?;
|
||||||
let tex2 = params.get_float_texture("tex2", 1.);
|
let tex2 = params.get_float_texture("tex2", 1.)?;
|
||||||
let amount = params.get_float_texture("amount", 0.5);
|
let amount = params.get_float_texture("amount", 0.5)?;
|
||||||
// arena.alloc(Self::new(tex1, tex2, amount));
|
// arena.alloc(Self::new(tex1, tex2, amount));
|
||||||
Ok(FloatTexture::Mix(Self::new(tex1, tex2, amount)))
|
Ok(FloatTexture::Mix(Self::new(tex1, tex2, amount)))
|
||||||
}
|
}
|
||||||
|
|
@ -74,10 +74,10 @@ impl FloatDirectionMixTexture {
|
||||||
_loc: &FileLoc,
|
_loc: &FileLoc,
|
||||||
_arena: &Arena,
|
_arena: &Arena,
|
||||||
) -> Result<FloatTexture> {
|
) -> 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 dir = render_from_texture.apply_to_vector(dir_raw).normalize();
|
||||||
let tex1 = params.get_float_texture("tex1", 0.);
|
let tex1 = params.get_float_texture("tex1", 0.)?;
|
||||||
let tex2 = params.get_float_texture("tex2", 1.);
|
let tex2 = params.get_float_texture("tex2", 1.)?;
|
||||||
// arena.alloc(Self::new(tex1, tex2, dir))
|
// arena.alloc(Self::new(tex1, tex2, dir))
|
||||||
Ok(FloatTexture::DirectionMix(Self::new(tex1, tex2, dir)))
|
Ok(FloatTexture::DirectionMix(Self::new(tex1, tex2, dir)))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,8 +26,8 @@ impl FloatScaledTexture {
|
||||||
_loc: &FileLoc,
|
_loc: &FileLoc,
|
||||||
_arena: &Arena,
|
_arena: &Arena,
|
||||||
) -> Result<FloatTexture> {
|
) -> Result<FloatTexture> {
|
||||||
let mut tex = params.get_float_texture("tex", 1.);
|
let mut tex = params.get_float_texture("tex", 1.)?;
|
||||||
let mut scale = params.get_float_texture("scale", 1.);
|
let mut scale = params.get_float_texture("scale", 1.)?;
|
||||||
|
|
||||||
for _ in 0..2 {
|
for _ in 0..2 {
|
||||||
if let FloatTexture::Constant(c_tex) = &*scale {
|
if let FloatTexture::Constant(c_tex) = &*scale {
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ use crate::core::image::Image;
|
||||||
use crate::core::texture::{FloatTexture, SpectrumTexture};
|
use crate::core::texture::{FloatTexture, SpectrumTexture};
|
||||||
use crate::shapes::{BilinearPatchMesh, TriangleMesh};
|
use crate::shapes::{BilinearPatchMesh, TriangleMesh};
|
||||||
use crate::spectra::DenselySampledSpectrumBuffer;
|
use crate::spectra::DenselySampledSpectrumBuffer;
|
||||||
|
use crate::utils::backend::GpuAllocator;
|
||||||
use crate::utils::mipmap::MIPMap;
|
use crate::utils::mipmap::MIPMap;
|
||||||
use crate::utils::sampling::{PiecewiseConstant2D, WindowedPiecewiseConstant2D};
|
use crate::utils::sampling::{PiecewiseConstant2D, WindowedPiecewiseConstant2D};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
|
|
@ -24,7 +25,8 @@ use std::collections::HashMap;
|
||||||
use std::slice::from_raw_parts;
|
use std::slice::from_raw_parts;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
pub struct Arena {
|
pub struct Arena<A: GpuAllocator> {
|
||||||
|
allocator: A,
|
||||||
inner: Mutex<ArenaInner>,
|
inner: Mutex<ArenaInner>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -33,9 +35,10 @@ struct ArenaInner {
|
||||||
texture_cache: HashMap<usize, u64>,
|
texture_cache: HashMap<usize, u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Arena {
|
impl<A: GpuAllocator> Arena<A> {
|
||||||
pub fn new() -> Self {
|
pub fn new(allocator: A) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
allocator,
|
||||||
inner: Mutex::new(ArenaInner {
|
inner: Mutex::new(ArenaInner {
|
||||||
buffer: Vec::new(),
|
buffer: Vec::new(),
|
||||||
texture_cache: HashMap::new(),
|
texture_cache: HashMap::new(),
|
||||||
|
|
@ -45,12 +48,10 @@ impl Arena {
|
||||||
|
|
||||||
pub fn alloc<T>(&self, value: T) -> Ptr<T> {
|
pub fn alloc<T>(&self, value: T) -> Ptr<T> {
|
||||||
let layout = Layout::new::<T>();
|
let layout = Layout::new::<T>();
|
||||||
let ptr = unsafe { self.alloc_unified(layout) } as *mut T;
|
let ptr = unsafe { self.allocator.alloc(layout) } as *mut T;
|
||||||
|
unsafe { ptr.write(value) };
|
||||||
unsafe {
|
|
||||||
ptr.write(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
self.inner.lock().buffer.push((ptr as *mut u8, layout));
|
||||||
Ptr::from_raw(ptr)
|
Ptr::from_raw(ptr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -67,44 +68,13 @@ impl Arena {
|
||||||
}
|
}
|
||||||
|
|
||||||
let layout = Layout::array::<T>(values.len()).unwrap();
|
let layout = Layout::array::<T>(values.len()).unwrap();
|
||||||
let ptr = unsafe { self.alloc_unified(layout) } as *mut T;
|
let ptr = unsafe { self.allocator.alloc(layout) } as *mut T;
|
||||||
|
unsafe { std::ptr::copy_nonoverlapping(values.as_ptr(), ptr, values.len()) };
|
||||||
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())
|
(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 {
|
pub fn get_texture_object(&self, mipmap: &Arc<MIPMap>) -> u64 {
|
||||||
let key = Arc::as_ptr(mipmap) as usize;
|
let key = Arc::as_ptr(mipmap) as usize;
|
||||||
let mut inner = self.inner.lock();
|
let mut inner = self.inner.lock();
|
||||||
|
|
@ -113,107 +83,85 @@ impl Arena {
|
||||||
return tex_obj;
|
return tex_obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "cuda")]
|
// TODO: Backend-specific texture object creation.
|
||||||
let tex_obj = self.create_cuda_texture(mipmap);
|
// CUDA: cudaCreateTextureObject
|
||||||
|
// Vulkan: VkImageView + VkSampler -> descriptor index
|
||||||
#[cfg(not(feature = "cuda"))]
|
|
||||||
let tex_obj = 0u64;
|
let tex_obj = 0u64;
|
||||||
|
|
||||||
inner.texture_cache.insert(key, tex_obj);
|
inner.texture_cache.insert(key, tex_obj);
|
||||||
tex_obj
|
tex_obj
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "cuda")]
|
impl<A: GpuAllocator + Default> Default for Arena<A> {
|
||||||
fn create_cuda_texture(&self, mipmap: &MIPMap) -> u64 {
|
fn default() -> Self {
|
||||||
// TODO: Implement with cudarc
|
Self::new(A::default())
|
||||||
// 1. Get image data from mipmap.base_image()
|
|
||||||
// 2. cudaMallocArray
|
|
||||||
// 3. cudaMemcpy2DToArray
|
|
||||||
// 4. cudaCreateTextureObject
|
|
||||||
// 5. Return handle
|
|
||||||
0
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for Arena {
|
impl<A: GpuAllocator> Drop for Arena<A> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
let inner = self.inner.get_mut();
|
let inner = self.inner.get_mut();
|
||||||
for (ptr, layout) in inner.buffer.drain(..) {
|
for (ptr, layout) in inner.buffer.drain(..) {
|
||||||
if layout.size() == 0 {
|
unsafe { self.allocator.dealloc(ptr, layout) };
|
||||||
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 impl Send for Arena {}
|
unsafe impl<A: GpuAllocator> Send for Arena<A> {}
|
||||||
unsafe impl Sync for Arena {}
|
unsafe impl<A: GpuAllocator> Sync for Arena<A> {}
|
||||||
|
|
||||||
pub trait Upload {
|
pub trait Upload {
|
||||||
type Target: Copy;
|
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 {
|
impl Upload for Shape {
|
||||||
type Target = 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())
|
arena.alloc(self.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Upload for Light {
|
impl Upload for Light {
|
||||||
type Target = 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())
|
arena.alloc(self.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Upload for Image {
|
impl Upload for Image {
|
||||||
type Target = DeviceImage;
|
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())
|
arena.alloc(*self.device())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Upload for Spectrum {
|
impl Upload for Spectrum {
|
||||||
type Target = 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())
|
arena.alloc(self.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Upload for Material {
|
impl Upload for Material {
|
||||||
type Target = 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())
|
arena.alloc(self.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Upload for DenselySampledSpectrumBuffer {
|
impl Upload for DenselySampledSpectrumBuffer {
|
||||||
type Target = DenselySampledSpectrum;
|
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())
|
arena.alloc(*&self.device())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Upload for SpectrumTexture {
|
impl Upload for SpectrumTexture {
|
||||||
type Target = GPUSpectrumTexture;
|
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 {
|
let gpu_variant = match self {
|
||||||
SpectrumTexture::Constant(tex) => GPUSpectrumTexture::Constant(tex.clone()),
|
SpectrumTexture::Constant(tex) => GPUSpectrumTexture::Constant(tex.clone()),
|
||||||
SpectrumTexture::Checkerboard(tex) => GPUSpectrumTexture::Checkerboard(tex.clone()),
|
SpectrumTexture::Checkerboard(tex) => GPUSpectrumTexture::Checkerboard(tex.clone()),
|
||||||
|
|
@ -241,15 +189,6 @@ impl Upload for SpectrumTexture {
|
||||||
};
|
};
|
||||||
GPUSpectrumTexture::Scaled(gpu_scaled)
|
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::Marble(tex) => GPUSpectrumTexture::Marble(tex.clone()),
|
||||||
SpectrumTexture::Mix(tex) => {
|
SpectrumTexture::Mix(tex) => {
|
||||||
let tex1_ptr = tex.tex1.upload(arena);
|
let tex1_ptr = tex.tex1.upload(arena);
|
||||||
|
|
@ -284,7 +223,7 @@ impl Upload for SpectrumTexture {
|
||||||
|
|
||||||
impl Upload for FloatTexture {
|
impl Upload for FloatTexture {
|
||||||
type Target = GPUFloatTexture;
|
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 {
|
let gpu_variant = match self {
|
||||||
FloatTexture::Constant(tex) => GPUFloatTexture::Constant(tex.clone()),
|
FloatTexture::Constant(tex) => GPUFloatTexture::Constant(tex.clone()),
|
||||||
FloatTexture::Checkerboard(tex) => GPUFloatTexture::Checkerboard(tex.clone()),
|
FloatTexture::Checkerboard(tex) => GPUFloatTexture::Checkerboard(tex.clone()),
|
||||||
|
|
@ -346,7 +285,7 @@ impl Upload for FloatTexture {
|
||||||
impl Upload for RGBToSpectrumTable {
|
impl Upload for RGBToSpectrumTable {
|
||||||
type Target = 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 n_nodes = self.n_nodes as usize;
|
||||||
let z_slice = unsafe { from_raw_parts(self.z_nodes.as_raw(), n_nodes) };
|
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) };
|
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 {
|
impl Upload for RGBColorSpace {
|
||||||
type Target = 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 table_ptr = self.rgb_to_spectrum_table.upload(arena);
|
||||||
|
|
||||||
let shared_space = RGBColorSpace {
|
let shared_space = RGBColorSpace {
|
||||||
|
|
@ -387,7 +326,7 @@ impl Upload for RGBColorSpace {
|
||||||
impl Upload for DeviceStandardColorSpaces {
|
impl Upload for DeviceStandardColorSpaces {
|
||||||
type Target = 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 srgb_ptr = self.srgb.upload(arena);
|
||||||
let dci_ptr = self.dci_p3.upload(arena);
|
let dci_ptr = self.dci_p3.upload(arena);
|
||||||
let rec_ptr = self.rec2020.upload(arena);
|
let rec_ptr = self.rec2020.upload(arena);
|
||||||
|
|
@ -407,7 +346,7 @@ impl Upload for DeviceStandardColorSpaces {
|
||||||
impl Upload for PiecewiseConstant2D {
|
impl Upload for PiecewiseConstant2D {
|
||||||
type Target = DevicePiecewiseConstant2D;
|
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 marginal_shared = self.marginal.to_shared(arena);
|
||||||
|
|
||||||
let conditionals_shared: Vec<DevicePiecewiseConstant1D> = self
|
let conditionals_shared: Vec<DevicePiecewiseConstant1D> = self
|
||||||
|
|
@ -430,7 +369,7 @@ impl Upload for PiecewiseConstant2D {
|
||||||
|
|
||||||
impl Upload for WindowedPiecewiseConstant2D {
|
impl Upload for WindowedPiecewiseConstant2D {
|
||||||
type Target = DeviceWindowedPiecewiseConstant2D;
|
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 {
|
let specific = DeviceWindowedPiecewiseConstant2D {
|
||||||
sat: self.sat,
|
sat: self.sat,
|
||||||
func: self.func,
|
func: self.func,
|
||||||
|
|
@ -442,7 +381,7 @@ impl Upload for WindowedPiecewiseConstant2D {
|
||||||
impl Upload for TriangleMesh {
|
impl Upload for TriangleMesh {
|
||||||
type Target = DeviceTriangleMesh;
|
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;
|
let storage = &self.storage;
|
||||||
|
|
||||||
// Upload all arrays to arena
|
// Upload all arrays to arena
|
||||||
|
|
@ -490,7 +429,7 @@ impl Upload for TriangleMesh {
|
||||||
impl Upload for BilinearPatchMesh {
|
impl Upload for BilinearPatchMesh {
|
||||||
type Target = DeviceBilinearPatchMesh;
|
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 storage = &self.storage;
|
||||||
|
|
||||||
let (vertex_indices_ptr, _) = arena.alloc_slice(&storage.vertex_indices);
|
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> {
|
impl<T: Upload> Upload for Option<T> {
|
||||||
type Target = T::Target;
|
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 {
|
match self {
|
||||||
Some(val) => val.upload(arena),
|
Some(val) => val.upload(arena),
|
||||||
None => Ptr::null(),
|
None => Ptr::null(),
|
||||||
|
|
@ -536,7 +475,7 @@ impl<T: Upload> Upload for Option<T> {
|
||||||
impl<T: Upload> Upload for Arc<T> {
|
impl<T: Upload> Upload for Arc<T> {
|
||||||
type Target = T::Target;
|
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)
|
(**self).upload(arena)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
147
src/utils/backend.rs
Normal file
147
src/utils/backend.rs
Normal file
|
|
@ -0,0 +1,147 @@
|
||||||
|
use std::alloc::Layout;
|
||||||
|
|
||||||
|
pub trait GpuAllocator: Send + Sync {
|
||||||
|
/// Allocate `size` bytes with given alignment.
|
||||||
|
/// Returns a host-mapped pointer.
|
||||||
|
unsafe fn alloc(&self, layout: Layout) -> *mut u8;
|
||||||
|
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// CPU fallback — standard system allocator.
|
||||||
|
pub struct SystemAllocator;
|
||||||
|
|
||||||
|
impl Default for SystemAllocator {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GpuAllocator for SystemAllocator {
|
||||||
|
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||||
|
if layout.size() == 0 {
|
||||||
|
return layout.align() as *mut u8;
|
||||||
|
}
|
||||||
|
unsafe { std::alloc::alloc(layout) }
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
|
||||||
|
if layout.size() > 0 {
|
||||||
|
unsafe {
|
||||||
|
std::alloc::dealloc(ptr, layout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// CUDA unified memory backend using CudaAllocator
|
||||||
|
#[cfg(feature = "cuda")]
|
||||||
|
pub struct CudaAllocator;
|
||||||
|
|
||||||
|
#[cfg(feature = "cuda")]
|
||||||
|
impl Default for CudaAllocator {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "cuda")]
|
||||||
|
impl GpuAllocator for CudaAllocator {
|
||||||
|
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||||
|
use cust::memory::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();
|
||||||
|
std::mem::forget(unified_ptr);
|
||||||
|
raw
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
|
||||||
|
use cust::memory::{UnifiedPointer, cuda_free_unified};
|
||||||
|
if layout.size() > 0 {
|
||||||
|
let _ = unsafe { cuda_free_unified(UnifiedPointer::wrap(ptr)) };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Vulkan backend using gpu-allocator.
|
||||||
|
#[cfg(feature = "vulkan")]
|
||||||
|
pub mod vulkan {
|
||||||
|
use super::GpuAllocator;
|
||||||
|
use ash::vk;
|
||||||
|
use gpu_allocator::MemoryLocation;
|
||||||
|
use gpu_allocator::vulkan::{Allocation, AllocationCreateDesc, AllocationScheme, Allocator};
|
||||||
|
use parking_lot::Mutex;
|
||||||
|
use std::alloc::Layout;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
pub struct VulkanAllocator {
|
||||||
|
allocator: Mutex<Allocator>,
|
||||||
|
/// Track pointer -> Allocation so we can free later.
|
||||||
|
allocations: Mutex<HashMap<usize, Allocation>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VulkanAllocator {
|
||||||
|
pub fn new(allocator: Allocator) -> Self {
|
||||||
|
Self {
|
||||||
|
allocator: Mutex::new(allocator),
|
||||||
|
allocations: Mutex::new(HashMap::new()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for VulkanAllocator {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GpuAllocator for VulkanAllocator {
|
||||||
|
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||||
|
let size = layout.size().max(layout.align());
|
||||||
|
if size == 0 {
|
||||||
|
return layout.align() as *mut u8;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut alloc = self.allocator.lock();
|
||||||
|
let allocation = alloc
|
||||||
|
.allocate(&AllocationCreateDesc {
|
||||||
|
name: "arena",
|
||||||
|
requirements: vk::MemoryRequirements {
|
||||||
|
size: size as u64,
|
||||||
|
alignment: layout.align() as u64,
|
||||||
|
memory_type_bits: u32::MAX,
|
||||||
|
},
|
||||||
|
location: MemoryLocation::CpuToGpu,
|
||||||
|
linear: true,
|
||||||
|
allocation_scheme: AllocationScheme::GpuAllocatorManaged,
|
||||||
|
})
|
||||||
|
.expect("Vulkan allocation failed");
|
||||||
|
|
||||||
|
let ptr = allocation
|
||||||
|
.mapped_ptr()
|
||||||
|
.expect("Vulkan allocation not host-mapped")
|
||||||
|
.as_ptr() as *mut u8;
|
||||||
|
|
||||||
|
self.allocations.lock().insert(ptr as usize, allocation);
|
||||||
|
ptr
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
|
||||||
|
if layout.size() == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if let Some(allocation) = self.allocations.lock().remove(&(ptr as usize)) {
|
||||||
|
self.allocator
|
||||||
|
.lock()
|
||||||
|
.free(allocation)
|
||||||
|
.expect("Vulkan free failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
pub mod arena;
|
pub mod arena;
|
||||||
|
pub mod backend;
|
||||||
pub mod containers;
|
pub mod containers;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod file;
|
pub mod file;
|
||||||
|
|
@ -11,10 +12,19 @@ pub mod parser;
|
||||||
pub mod sampling;
|
pub mod sampling;
|
||||||
pub mod strings;
|
pub mod strings;
|
||||||
|
|
||||||
pub use arena::{Arena, Upload};
|
pub use arena::Upload;
|
||||||
pub use error::FileLoc;
|
pub use error::FileLoc;
|
||||||
pub use file::{read_float_file, resolve_filename};
|
pub use file::{read_float_file, resolve_filename};
|
||||||
pub use parameters::{
|
pub use parameters::{
|
||||||
ParameterDictionary, ParsedParameter, ParsedParameterVector, TextureParameterDictionary,
|
ParameterDictionary, ParsedParameter, ParsedParameterVector, TextureParameterDictionary,
|
||||||
};
|
};
|
||||||
pub use strings::*;
|
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::data::get_named_spectrum;
|
||||||
use crate::spectra::piecewise::PiecewiseLinearSpectrumBuffer;
|
use crate::spectra::piecewise::PiecewiseLinearSpectrumBuffer;
|
||||||
use crate::utils::FileLoc;
|
use crate::utils::FileLoc;
|
||||||
|
use anyhow::{Result, bail};
|
||||||
use shared::Float;
|
use shared::Float;
|
||||||
use shared::core::color::RGB;
|
use shared::core::color::RGB;
|
||||||
use shared::core::geometry::{Normal3f, Point2f, Point3f, Vector2f, Vector3f};
|
use shared::core::geometry::{Normal3f, Point2f, Point3f, Vector2f, Vector3f};
|
||||||
|
|
@ -19,14 +20,12 @@ use std::sync::{
|
||||||
atomic::{AtomicBool, Ordering},
|
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 {
|
if let Some(l) = loc {
|
||||||
log::error!("Error: {}: {}", l, message);
|
format!("{}: {}", l, message)
|
||||||
} else {
|
} else {
|
||||||
log::error!("Error: {}", message);
|
message.to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
std::process::exit(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
@ -250,7 +249,10 @@ pub struct ParameterDictionary {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl 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();
|
let n_owned_params = params.len();
|
||||||
params.reverse();
|
params.reverse();
|
||||||
let dict = Self {
|
let dict = Self {
|
||||||
|
|
@ -258,15 +260,15 @@ impl ParameterDictionary {
|
||||||
color_space,
|
color_space,
|
||||||
n_owned_params,
|
n_owned_params,
|
||||||
};
|
};
|
||||||
dict.check_parameter_types();
|
dict.check_parameter_types()?;
|
||||||
dict
|
Ok(dict)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_array(
|
pub fn from_array(
|
||||||
mut p0: ParsedParameterVector,
|
mut p0: ParsedParameterVector,
|
||||||
params: &[ParsedParameter],
|
params: &[ParsedParameter],
|
||||||
color_space: Option<Arc<RGBColorSpace>>,
|
color_space: Option<Arc<RGBColorSpace>>,
|
||||||
) -> Self {
|
) -> Result<Self> {
|
||||||
let n_owned_params = params.len();
|
let n_owned_params = params.len();
|
||||||
p0.extend(params.iter().rev().cloned());
|
p0.extend(params.iter().rev().cloned());
|
||||||
|
|
||||||
|
|
@ -275,21 +277,19 @@ impl ParameterDictionary {
|
||||||
color_space,
|
color_space,
|
||||||
n_owned_params,
|
n_owned_params,
|
||||||
};
|
};
|
||||||
dict.check_parameter_types();
|
dict.check_parameter_types()?;
|
||||||
dict
|
Ok(dict)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_parameter_types(&self) {
|
fn check_parameter_types(&self) -> Result<()> {
|
||||||
for p in &self.params {
|
for p in &self.params {
|
||||||
match p.type_name.as_str() {
|
match p.type_name.as_str() {
|
||||||
bool::TYPE_NAME => {
|
bool::TYPE_NAME => {
|
||||||
if p.bools.is_empty() {
|
if p.bools.is_empty() {
|
||||||
error_exit(
|
bail!(
|
||||||
Some(&p.loc),
|
"{}: non-Boolean values provided for Boolean-valued parameter \"{}\"",
|
||||||
&format!(
|
&p.loc,
|
||||||
"\"{}\": non-Boolean values provided for Boolean-valued parameter",
|
|
||||||
p.name
|
p.name
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -304,51 +304,49 @@ impl ParameterDictionary {
|
||||||
| "rgb"
|
| "rgb"
|
||||||
| "blackbody" => {
|
| "blackbody" => {
|
||||||
if p.ints.is_empty() && p.floats.is_empty() {
|
if p.ints.is_empty() && p.floats.is_empty() {
|
||||||
error_exit(
|
bail!(
|
||||||
Some(&p.loc),
|
"{}: non-numeric values provided for numeric-valued parameter \"{}\"",
|
||||||
&format!(
|
&p.loc,
|
||||||
"\"{}\": non-numeric values provided for numeric-valued parameter",
|
|
||||||
p.name
|
p.name
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String::TYPE_NAME | "texture" => {
|
String::TYPE_NAME | "texture" => {
|
||||||
if p.strings.is_empty() {
|
if p.strings.is_empty() {
|
||||||
error_exit(
|
bail!(
|
||||||
Some(&p.loc),
|
"{}: non-string values provided for string-valued parameter \"{}\"",
|
||||||
&format!(
|
&p.loc,
|
||||||
"\"{}\": non-string values provided for string-valued parameter",
|
|
||||||
p.name
|
p.name
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
"spectrum" => {
|
"spectrum" => {
|
||||||
if p.strings.is_empty() && p.ints.is_empty() && p.floats.is_empty() {
|
if p.strings.is_empty() && p.ints.is_empty() && p.floats.is_empty() {
|
||||||
error_exit(
|
bail!(
|
||||||
Some(&p.loc),
|
"{}: expecting string or numeric-valued parameter for spectrum parameter \"{}\"",
|
||||||
&format!(
|
&p.loc,
|
||||||
"\"{}\": expecting string or numeric-valued parameter for spectrum parameter",
|
|
||||||
p.name
|
p.name
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unknown => {
|
unknown => {
|
||||||
error_exit(
|
bail!(
|
||||||
Some(&p.loc),
|
"{}: unknown parameter type \"{}\" '{}'",
|
||||||
&format!("\"{}\": unknown parameter type '{}'", p.name, unknown),
|
&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
|
where
|
||||||
T: PBRTParameter,
|
T: PBRTParameter,
|
||||||
{
|
{
|
||||||
|
|
@ -357,32 +355,31 @@ impl ParameterDictionary {
|
||||||
let values = T::get_values(¶m);
|
let values = T::get_values(¶m);
|
||||||
|
|
||||||
if values.is_empty() {
|
if values.is_empty() {
|
||||||
error_exit(
|
bail!(
|
||||||
Some(¶m.loc),
|
"{}: No values provided for parameter \"{}\".",
|
||||||
&format!("No values provided for parameter \"{}\".", name),
|
¶m.loc,
|
||||||
|
name
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if values.len() != T::N_PER_ITEM {
|
if values.len() != T::N_PER_ITEM {
|
||||||
error_exit(
|
bail!(
|
||||||
Some(¶m.loc),
|
"{}: Expected {} values for parameter \"{}\". Found {}.",
|
||||||
&format!(
|
¶m.loc,
|
||||||
"Expected {} values for parameter \"{}\". Found {}.",
|
|
||||||
T::N_PER_ITEM,
|
T::N_PER_ITEM,
|
||||||
name,
|
name,
|
||||||
values.len()
|
values.len()
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
param.looked_up.store(true, Ordering::Relaxed);
|
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
|
where
|
||||||
T: PBRTParameter,
|
T: PBRTParameter,
|
||||||
{
|
{
|
||||||
|
|
@ -391,92 +388,90 @@ impl ParameterDictionary {
|
||||||
let values = T::get_values(param);
|
let values = T::get_values(param);
|
||||||
|
|
||||||
if values.len() % T::N_PER_ITEM != 0 {
|
if values.len() % T::N_PER_ITEM != 0 {
|
||||||
error_exit(
|
bail!(
|
||||||
Some(¶m.loc),
|
"{}: Number of values for \"{}\" is not a multiple of {}",
|
||||||
&format!(
|
¶m.loc,
|
||||||
"Number of values for \"{}\" is not a multiple of {}",
|
|
||||||
name,
|
name,
|
||||||
T::N_PER_ITEM
|
T::N_PER_ITEM
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
param.looked_up.store(true, Ordering::Relaxed);
|
param.looked_up.store(true, Ordering::Relaxed);
|
||||||
|
|
||||||
return values
|
return Ok(values
|
||||||
.chunks(T::N_PER_ITEM)
|
.chunks(T::N_PER_ITEM)
|
||||||
.map(|chunk| T::convert(chunk))
|
.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)
|
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)
|
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)
|
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())
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
self.lookup_array(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -709,70 +704,73 @@ pub struct TextureParameterDictionary {
|
||||||
|
|
||||||
impl TextureParameterDictionary {
|
impl TextureParameterDictionary {
|
||||||
pub fn new(dict: Arc<ParameterDictionary>, textures: Option<&NamedTextures>) -> Self {
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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> {
|
pub fn get_float_texture(&self, name: &str, val: Float) -> Result<Arc<FloatTexture>> {
|
||||||
if let Some(tex) = self.get_float_texture_or_null(name) {
|
if let Some(tex) = self.get_float_texture_or_null(name)? {
|
||||||
return tex;
|
return Ok(tex);
|
||||||
} else {
|
} 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;
|
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 {
|
for p in &self.dict.params {
|
||||||
if p.name != name {
|
if p.name != name {
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -932,19 +944,19 @@ impl TextureParameterDictionary {
|
||||||
if let Some(nt) = &self.textures {
|
if let Some(nt) = &self.textures {
|
||||||
let map = &nt.float_textures;
|
let map = &nt.float_textures;
|
||||||
if let Some(tex) = map.get(tex_name) {
|
if let Some(tex) = map.get(tex_name) {
|
||||||
return Some(Arc::clone(tex));
|
return Ok(Some(Arc::clone(tex)));
|
||||||
}
|
}
|
||||||
panic!(
|
panic!(
|
||||||
"[{:?}] Couldn't find float texture named '{}'",
|
"[{:?}] Couldn't find float texture named '{}'",
|
||||||
p.loc, tex_name
|
p.loc, tex_name
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return None;
|
return Ok(None);
|
||||||
}
|
}
|
||||||
"float" => {
|
"float" => {
|
||||||
let v = self.get_one_float(name, 0.);
|
let v = self.get_one_float(name, 0.)?;
|
||||||
return Some(Arc::new(FloatTexture::Constant(FloatConstantTexture::new(
|
return Ok(Some(Arc::new(FloatTexture::Constant(
|
||||||
v,
|
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> {
|
pub fn run(&mut self) -> Result<(), ParserError> {
|
||||||
let arena = Arc::new(Arena::new());
|
let arena = Arc::new(Arena::default());
|
||||||
loop {
|
loop {
|
||||||
let token = match self.next_token()? {
|
let token = match self.next_token()? {
|
||||||
Some(t) => t,
|
Some(t) => t,
|
||||||
None => break, // EOF
|
// EOF
|
||||||
|
None => break,
|
||||||
};
|
};
|
||||||
|
|
||||||
let first_char = token.text.chars().next().unwrap();
|
let first_char = token.text.chars().next().unwrap();
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::core::image::Image;
|
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 crate::utils::containers::Array2D;
|
||||||
use shared::Float;
|
use shared::Float;
|
||||||
use shared::core::geometry::{Bounds2f, Point2i, Vector2f, Vector2i};
|
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)
|
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 (func_ptr, _) = arena.alloc_slice(&self.func);
|
||||||
let (cdf_ptr, _) = arena.alloc_slice(&self.cdf);
|
let (cdf_ptr, _) = arena.alloc_slice(&self.cdf);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue