use crate::{
primitives::{
images::{ImageInputError, ImageOutputError},
pixels, ImgOps, PixelInfo,
},
GpuConstImage, GpuImage,
};
use image::ImageBuffer;
pub trait ImageToGpgpu {
type GpgpuPixel: PixelInfo + GpgpuToImage;
type NormGpgpuPixel: PixelInfo + GpgpuToImage;
}
pub trait GpgpuToImage {
type ImgPixel: ::image::Pixel + 'static;
}
macro_rules! image_to_gpgpu_impl {
($($img_pixel:ty, $pixel:ty, $norm:ty);+) => {
$(
impl ImageToGpgpu for $img_pixel {
type GpgpuPixel = $pixel;
type NormGpgpuPixel = $norm;
}
)+
}
}
macro_rules! gpgpu_to_image_impl {
($($pixel:ty, $($gpgpu_pixel:ty),+);+) => {
$(
$(
impl GpgpuToImage for $gpgpu_pixel {
type ImgPixel = $pixel;
}
)+
)+
}
}
gpgpu_to_image_impl! {
::image::Rgba<u8>, pixels::Rgba8Uint, pixels::Rgba8UintNorm;
::image::Rgba<i8>, pixels::Rgba8Sint, pixels::Rgba8SintNorm
}
image_to_gpgpu_impl! {
::image::Rgba<u8>, pixels::Rgba8Uint, pixels::Rgba8UintNorm;
::image::Rgba<i8>, pixels::Rgba8Sint, pixels::Rgba8SintNorm
}
type PixelContainer<P> = Vec<<<P as GpgpuToImage>::ImgPixel as image::Pixel>::Subpixel>;
impl<'fw, Pixel> GpuImage<'fw, Pixel>
where
Pixel: image::Pixel + ImageToGpgpu + 'static,
Pixel::Subpixel: bytemuck::Pod,
{
pub fn from_image_buffer<Container>(
fw: &'fw crate::Framework,
img: &ImageBuffer<Pixel, Container>,
) -> GpuImage<'fw, Pixel::GpgpuPixel>
where
Container: std::ops::Deref<Target = [Pixel::Subpixel]>,
{
let (width, height) = img.dimensions();
GpuImage::from_bytes(
fw,
bytemuck::cast_slice(img),
width * Pixel::GpgpuPixel::byte_size() as u32,
height,
)
}
pub fn from_image_buffer_normalised<Container>(
fw: &'fw crate::Framework,
img: &ImageBuffer<Pixel, Container>,
) -> GpuImage<'fw, Pixel::NormGpgpuPixel>
where
Container: std::ops::Deref<Target = [Pixel::Subpixel]>,
{
let (width, height) = img.dimensions();
GpuImage::from_bytes(
fw,
bytemuck::cast_slice(img),
width * Pixel::GpgpuPixel::byte_size() as u32,
height,
)
}
}
impl<'fw, Pixel> GpuConstImage<'fw, Pixel>
where
Pixel: image::Pixel + ImageToGpgpu + 'static,
Pixel::Subpixel: bytemuck::Pod,
{
pub fn from_image_buffer<Container>(
fw: &'fw crate::Framework,
img: &ImageBuffer<Pixel, Container>,
) -> GpuConstImage<'fw, Pixel::GpgpuPixel>
where
Container: std::ops::Deref<Target = [Pixel::Subpixel]>,
{
let (width, height) = img.dimensions();
GpuConstImage::from_bytes(
fw,
bytemuck::cast_slice(img),
width * Pixel::GpgpuPixel::byte_size() as u32,
height,
)
}
pub fn from_image_buffer_normalised<Container>(
fw: &'fw crate::Framework,
img: &ImageBuffer<Pixel, Container>,
) -> GpuConstImage<'fw, Pixel::NormGpgpuPixel>
where
Container: std::ops::Deref<Target = [Pixel::Subpixel]>,
{
let (width, height) = img.dimensions();
GpuConstImage::from_bytes(
fw,
bytemuck::cast_slice(img),
width * Pixel::GpgpuPixel::byte_size() as u32,
height,
)
}
}
impl<'fw, P> GpuImage<'fw, P>
where
P: PixelInfo + GpgpuToImage,
<<P as GpgpuToImage>::ImgPixel as image::Pixel>::Subpixel: bytemuck::Pod,
{
pub async fn read_into_image_buffer(
&self,
buf: &mut ::image::ImageBuffer<
P::ImgPixel,
Vec<<<P as GpgpuToImage>::ImgPixel as image::Pixel>::Subpixel>,
>,
) -> Result<usize, ImageOutputError> {
let output_slice = bytemuck::cast_slice_mut(buf);
self.read(output_slice).await
}
pub fn read_into_image_buffer_blocking(
&self,
buf: &mut ::image::ImageBuffer<
P::ImgPixel,
Vec<<<P as GpgpuToImage>::ImgPixel as image::Pixel>::Subpixel>,
>,
) -> Result<usize, ImageOutputError> {
futures::executor::block_on(self.read_into_image_buffer(buf))
}
pub async fn read_to_image_buffer(
&self,
) -> Result<
::image::ImageBuffer<
P::ImgPixel,
Vec<<<P as GpgpuToImage>::ImgPixel as image::Pixel>::Subpixel>,
>,
ImageOutputError,
> {
let bytes = self.read_vec().await?;
let container = bytes_to_primitive_vec::<P::ImgPixel>(bytes);
let (width, height) = self.dimensions();
Ok(image::ImageBuffer::from_vec(width, height, container).expect("Cannot fail here."))
}
pub fn read_to_image_buffer_blocking(
&self,
) -> Result<::image::ImageBuffer<P::ImgPixel, PixelContainer<P>>, ImageOutputError> {
futures::executor::block_on(self.read_to_image_buffer())
}
pub fn write_image_buffer(
&self,
buf: &::image::ImageBuffer<
P::ImgPixel,
Vec<<<P as GpgpuToImage>::ImgPixel as image::Pixel>::Subpixel>,
>,
) -> Result<usize, ImageInputError> {
let bytes = bytemuck::cast_slice(buf);
self.write(bytes)
}
}
impl<'fw, P> GpuConstImage<'fw, P>
where
P: PixelInfo + GpgpuToImage,
<<P as GpgpuToImage>::ImgPixel as image::Pixel>::Subpixel: bytemuck::Pod,
{
pub fn write_image_buffer(
&self,
buf: &::image::ImageBuffer<
P::ImgPixel,
Vec<<<P as GpgpuToImage>::ImgPixel as image::Pixel>::Subpixel>,
>,
) -> Result<usize, ImageInputError> {
let bytes = bytemuck::cast_slice(buf);
self.write(bytes)
}
}
pub(crate) fn bytes_to_primitive_vec<P>(mut bytes: Vec<u8>) -> Vec<P::Subpixel>
where
P: image::Pixel,
P::Subpixel: bytemuck::Pod,
{
bytes.shrink_to_fit();
assert_eq!(bytes.len(), bytes.capacity());
let mut man_drop = std::mem::ManuallyDrop::new(bytes);
let (_, new_type, _) = bytemuck::pod_align_to_mut(&mut man_drop);
let ptr = new_type.as_mut_ptr();
unsafe { Vec::from_raw_parts(ptr, new_type.len(), new_type.len()) }
}