use crate::alpha::AlphaMode;
use crate::error::{Error, Result};
use crate::format_kind::{FormatFamily, FormatKind, classify};
use crate::surface::{ColorSpace, Surface};
use super::alpha;
use super::buffer::Buffer;
use super::load_kernels as k;
fn srgb_eotf_scalar(c: f32) -> f32 {
if c <= 0.04045 {
c / 12.92
} else {
((c + 0.055) / 1.055).powf(2.4)
}
}
pub fn load_f32(surface: &Surface) -> Result<Buffer<f32>> {
profiling::scope!("load_f32");
let info = classify(surface.format, surface.color_space).ok_or_else(|| {
Error::UnsupportedFormat(format!(
"float pipeline: unsupported input format {:?}",
surface.format
))
})?;
if info.family.is_integer() {
return Err(Error::UnsupportedConversion(format!(
"cannot load integer format {:?} into float pipeline",
surface.format,
)));
}
let (mut buf, srgb_decoded_by_kernel) = match info.kind {
FormatKind::U8 => (k::load_u8_unorm_f32(surface, info.channels)?, false),
FormatKind::I8 => (k::load_i8_snorm_f32(surface, info.channels)?, false),
FormatKind::Srgb8 => (k::load_srgb8_f32(surface, info.channels)?, true),
FormatKind::Bgra8 => (k::load_bgra8_unorm_f32(surface)?, false),
FormatKind::Bgra8Srgb => (k::load_bgra8_srgb_f32(surface)?, true),
FormatKind::Bgr8 => (k::load_bgr8_unorm_f32(surface)?, false),
FormatKind::Bgr8Srgb => (k::load_bgr8_srgb_f32(surface)?, true),
FormatKind::U16 => (k::load_u16_unorm_f32(surface, info.channels)?, false),
FormatKind::I16 => (k::load_i16_snorm_f32(surface, info.channels)?, false),
FormatKind::F16 => (k::load_f16_f32(surface, info.channels)?, false),
FormatKind::F32 => (k::load_f32_f32(surface, info.channels)?, false),
other => {
return Err(Error::UnsupportedFormat(format!(
"float pipeline: unsupported format kind {other:?}"
)));
}
};
if !srgb_decoded_by_kernel && surface.color_space == ColorSpace::Srgb {
profiling::scope!("srgb_eotf_scalar_f32");
for p in buf.pixels.iter_mut() {
p[0] = srgb_eotf_scalar(p[0]);
p[1] = srgb_eotf_scalar(p[1]);
p[2] = srgb_eotf_scalar(p[2]);
}
}
if surface.alpha == AlphaMode::Straight {
alpha::premultiply_f32(&mut buf);
}
Ok(buf)
}
pub fn load_f64(surface: &Surface) -> Result<Buffer<f64>> {
profiling::scope!("load_f64");
let info = classify(surface.format, surface.color_space).ok_or_else(|| {
Error::UnsupportedFormat(format!(
"f64 pipeline: unsupported input format {:?}",
surface.format
))
})?;
if !matches!(info.family, FormatFamily::Float) {
return Err(Error::UnsupportedConversion(format!(
"f64 pipeline requires a float-family source, got {:?}",
surface.format,
)));
}
let mut buf = match info.kind {
FormatKind::F32 => k::load_f32_f64(surface, info.channels)?,
FormatKind::F64 => k::load_f64_f64(surface, info.channels)?,
other => {
return Err(Error::UnsupportedFormat(format!(
"f64 pipeline: unsupported format kind {other:?}"
)));
}
};
if surface.alpha == AlphaMode::Straight {
alpha::premultiply_f64(&mut buf);
}
Ok(buf)
}
pub fn load_u32(surface: &Surface) -> Result<Buffer<u32>> {
profiling::scope!("load_u32");
let info = classify(surface.format, surface.color_space).ok_or_else(|| {
Error::UnsupportedFormat(format!(
"u32 pipeline: unsupported input format {:?}",
surface.format
))
})?;
if !info.family.is_integer() {
return Err(Error::UnsupportedConversion(format!(
"u32 pipeline requires an integer-family source, got {:?}",
surface.format,
)));
}
match info.kind {
FormatKind::U8 => k::load_u8_uint_u32(surface, info.channels),
FormatKind::I8 => k::load_i8_sint_u32(surface, info.channels),
FormatKind::U16 => k::load_u16_uint_u32(surface, info.channels),
FormatKind::I16 => k::load_i16_sint_u32(surface, info.channels),
FormatKind::U32 => k::load_u32_uint_u32(surface, info.channels),
FormatKind::I32 => k::load_i32_sint_u32(surface, info.channels),
other => Err(Error::UnsupportedFormat(format!(
"u32 pipeline: unsupported format kind {other:?}"
))),
}
}
pub fn load_u64(surface: &Surface) -> Result<Buffer<u64>> {
profiling::scope!("load_u64");
let info = classify(surface.format, surface.color_space).ok_or_else(|| {
Error::UnsupportedFormat(format!(
"u64 pipeline: unsupported input format {:?}",
surface.format
))
})?;
if !info.family.is_integer() {
return Err(Error::UnsupportedConversion(format!(
"u64 pipeline requires an integer-family source, got {:?}",
surface.format,
)));
}
match info.kind {
FormatKind::U64 => k::load_u64_uint_u64(surface, info.channels),
FormatKind::I64 => k::load_i64_sint_u64(surface, info.channels),
other => Err(Error::UnsupportedFormat(format!(
"u64 pipeline: unsupported format kind {other:?}"
))),
}
}