#![deny(unsafe_code)]
#![cfg_attr(not(test), warn(unused_crate_dependencies))]
use std::boxed::Box;
#[cfg(not(any(feature = "wgpu-27", feature = "wgpu-28", feature = "wgpu-29")))]
compile_error!("Enable one of `wgpu-27`, `wgpu-28`, or `wgpu-29`.");
#[derive(Debug)]
pub enum TextureTargetError {
InvalidTarget(&'static str),
DimensionsTooLarge,
UnsupportedTextureFormat,
CreateGpuContext(&'static str),
CreateGpuSurface,
UnsupportedGpuBackend,
}
impl core::fmt::Display for TextureTargetError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::InvalidTarget(message) => f.write_str(message),
Self::DimensionsTooLarge => f.write_str("render dimensions exceed backend limits"),
Self::UnsupportedTextureFormat => {
f.write_str("backend does not support the requested texture format")
}
Self::CreateGpuContext(message) => f.write_str(message),
Self::CreateGpuSurface => {
f.write_str("backend could not wrap the texture as a GPU render surface")
}
Self::UnsupportedGpuBackend => {
f.write_str("no supported GPU backend was available for the supplied wgpu setup")
}
}
}
}
impl core::error::Error for TextureTargetError {}
#[derive(Debug)]
pub enum TextureRendererError {
Content(imaging::render::RenderContentError),
Target(TextureTargetError),
Unsupported(imaging::render::RenderUnsupportedError),
Backend(Box<dyn core::error::Error + Send + Sync + 'static>),
}
impl TextureRendererError {
#[must_use]
pub fn backend(error: impl core::error::Error + Send + Sync + 'static) -> Self {
Self::Backend(Box::new(error))
}
}
impl core::fmt::Display for TextureRendererError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::Content(error) => core::fmt::Display::fmt(error, f),
Self::Target(error) => core::fmt::Display::fmt(error, f),
Self::Unsupported(error) => core::fmt::Display::fmt(error, f),
Self::Backend(error) => core::fmt::Display::fmt(error, f),
}
}
}
impl core::error::Error for TextureRendererError {
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
match self {
Self::Content(error) => Some(error),
Self::Target(error) => Some(error),
Self::Unsupported(error) => Some(error),
Self::Backend(error) => Some(error.as_ref()),
}
}
}
macro_rules! define_wgpu_lane {
($module:ident, $wgpu:ident) => {
pub mod $module {
use imaging::render::{ImageRenderer, RenderSource};
use std::vec::Vec;
pub use $wgpu as wgpu;
#[derive(Clone, Debug)]
pub struct TextureViewTarget {
pub view: wgpu::TextureView,
pub width: u32,
pub height: u32,
}
impl TextureViewTarget {
#[must_use]
pub fn new(view: &wgpu::TextureView, width: u32, height: u32) -> Self {
Self {
view: view.clone(),
width,
height,
}
}
}
pub trait TextureRenderer: ImageRenderer {
type TextureTarget;
type Texture;
fn supported_texture_formats(&self) -> Vec<wgpu::TextureFormat>;
fn render_source_into_texture(
&mut self,
source: &mut dyn RenderSource,
target: Self::TextureTarget,
) -> Result<(), crate::TextureRendererError>;
fn render_source_texture(
&mut self,
source: &mut dyn RenderSource,
width: u32,
height: u32,
) -> Result<Self::Texture, crate::TextureRendererError>;
}
}
};
}
#[cfg(feature = "wgpu-27")]
define_wgpu_lane!(v27, wgpu_27);
#[cfg(feature = "wgpu-28")]
define_wgpu_lane!(v28, wgpu_28);
#[cfg(feature = "wgpu-29")]
define_wgpu_lane!(v29, wgpu_29);
#[cfg(all(
not(any(feature = "wgpu-28", feature = "wgpu-29")),
feature = "wgpu-27"
))]
pub use v27::{TextureRenderer, TextureViewTarget, wgpu};
#[cfg(all(not(feature = "wgpu-29"), feature = "wgpu-28"))]
pub use v28::{TextureRenderer, TextureViewTarget, wgpu};
#[cfg(feature = "wgpu-29")]
pub use v29::{TextureRenderer, TextureViewTarget, wgpu};