167 lines
4.7 KiB
Rust
167 lines
4.7 KiB
Rust
use crate::core::image::Image;
|
|
use crate::spectra::DenselySampledSpectrumBuffer;
|
|
use crate::Arena;
|
|
use shared::core::color::RGBToSpectrumTable;
|
|
use shared::core::image::DeviceImage;
|
|
use shared::core::light::Light;
|
|
use shared::core::material::Material;
|
|
use shared::core::shape::Shape;
|
|
use shared::core::spectrum::Spectrum;
|
|
use shared::spectra::{DenselySampledSpectrum, DeviceStandardColorSpaces, RGBColorSpace};
|
|
use shared::Ptr;
|
|
use std::slice::from_raw_parts;
|
|
|
|
pub trait DeviceRepr {
|
|
/// The `#[repr(C)] Copy` device-side struct.
|
|
type Target: Copy;
|
|
|
|
/// Upload into the arena and return the device struct by value.
|
|
/// Use this when embedding the result inline in another device struct.
|
|
fn upload_value(&self, arena: &Arena) -> Self::Target;
|
|
|
|
/// Upload into the arena and return a Ptr to the device struct.
|
|
/// This is the common entry point — allocates the Target in the arena.
|
|
fn upload(&self, arena: &Arena) -> Ptr<Self::Target> {
|
|
let value = self.upload_value(arena);
|
|
arena.alloc(value)
|
|
}
|
|
}
|
|
|
|
impl<T: DeviceRepr> DeviceRepr for Option<T> {
|
|
type Target = T::Target;
|
|
|
|
fn upload_value(&self, arena: &Arena) -> Self::Target {
|
|
match self {
|
|
Some(val) => val.upload_value(arena),
|
|
None => panic!("Cannot upload_value on None — use upload() which returns Ptr::null()"),
|
|
}
|
|
}
|
|
|
|
fn upload(&self, arena: &Arena) -> Ptr<Self::Target> {
|
|
match self {
|
|
Some(val) => val.upload(arena),
|
|
None => Ptr::null(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<T: DeviceRepr> DeviceRepr for std::sync::Arc<T> {
|
|
type Target = T::Target;
|
|
|
|
fn upload_value(&self, arena: &Arena) -> Self::Target {
|
|
(**self).upload_value(arena)
|
|
}
|
|
|
|
fn upload(&self, arena: &Arena) -> Ptr<Self::Target> {
|
|
(**self).upload(arena)
|
|
}
|
|
}
|
|
|
|
impl<T: DeviceRepr> DeviceRepr for Box<T> {
|
|
type Target = T::Target;
|
|
|
|
fn upload_value(&self, arena: &Arena) -> Self::Target {
|
|
(**self).upload_value(arena)
|
|
}
|
|
|
|
fn upload(&self, arena: &Arena) -> Ptr<Self::Target> {
|
|
(**self).upload(arena)
|
|
}
|
|
}
|
|
|
|
impl DeviceRepr for Shape {
|
|
type Target = Shape;
|
|
fn upload_value(&self, _arena: &Arena) -> Shape {
|
|
self.clone()
|
|
}
|
|
}
|
|
|
|
impl DeviceRepr for Light {
|
|
type Target = Light;
|
|
fn upload_value(&self, _arena: &Arena) -> Light {
|
|
self.clone()
|
|
}
|
|
}
|
|
|
|
impl DeviceRepr for Spectrum {
|
|
type Target = Spectrum;
|
|
fn upload_value(&self, _arena: &Arena) -> Spectrum {
|
|
self.clone()
|
|
}
|
|
}
|
|
|
|
impl DeviceRepr for Material {
|
|
type Target = Material;
|
|
fn upload_value(&self, _arena: &Arena) -> Material {
|
|
self.clone()
|
|
}
|
|
}
|
|
|
|
impl DeviceRepr for Image {
|
|
type Target = DeviceImage;
|
|
fn upload_value(&self, _arena: &Arena) -> DeviceImage {
|
|
*self.device()
|
|
}
|
|
}
|
|
|
|
impl DeviceRepr for DenselySampledSpectrumBuffer {
|
|
type Target = DenselySampledSpectrum;
|
|
fn upload_value(&self, _arena: &Arena) -> DenselySampledSpectrum {
|
|
self.device()
|
|
}
|
|
}
|
|
|
|
impl DeviceRepr for RGBToSpectrumTable {
|
|
type Target = RGBToSpectrumTable;
|
|
|
|
fn upload_value(&self, arena: &Arena) -> RGBToSpectrumTable {
|
|
let n_nodes = self.n_nodes as usize;
|
|
|
|
// Safety: these Ptrs point into static or previously-uploaded data;
|
|
// we're copying the contents into the arena for a new lifetime.
|
|
let z_slice = unsafe { from_raw_parts(self.z_nodes.as_raw(), n_nodes) };
|
|
let (z_ptr, _) = arena.alloc_slice(z_slice);
|
|
|
|
let n_coeffs = 3 * n_nodes.pow(3);
|
|
let coeffs_slice = unsafe { from_raw_parts(self.coeffs.as_raw(), n_coeffs) };
|
|
let (c_ptr, _) = arena.alloc_slice(coeffs_slice);
|
|
|
|
RGBToSpectrumTable {
|
|
z_nodes: z_ptr,
|
|
coeffs: c_ptr,
|
|
n_nodes: self.n_nodes,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl DeviceRepr for RGBColorSpace {
|
|
type Target = RGBColorSpace;
|
|
|
|
fn upload_value(&self, arena: &Arena) -> RGBColorSpace {
|
|
let table_ptr = self.rgb_to_spectrum_table.upload(arena);
|
|
|
|
RGBColorSpace {
|
|
r: self.r,
|
|
g: self.g,
|
|
b: self.b,
|
|
w: self.w,
|
|
illuminant: self.illuminant.clone(),
|
|
rgb_to_spectrum_table: table_ptr,
|
|
xyz_from_rgb: self.xyz_from_rgb,
|
|
rgb_from_xyz: self.rgb_from_xyz,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl DeviceRepr for DeviceStandardColorSpaces {
|
|
type Target = DeviceStandardColorSpaces;
|
|
|
|
fn upload_value(&self, arena: &Arena) -> DeviceStandardColorSpaces {
|
|
DeviceStandardColorSpaces {
|
|
srgb: self.srgb.upload(arena),
|
|
dci_p3: self.dci_p3.upload(arena),
|
|
rec2020: self.rec2020.upload(arena),
|
|
aces2065_1: self.aces2065_1.upload(arena),
|
|
}
|
|
}
|
|
}
|