use {
rendy_command::Families,
rendy_core::{
backend_enum,
hal::{device::CreationError, Backend, Instance as _, UnsupportedBackend},
rendy_backend, rendy_with_dx12_backend, rendy_with_empty_backend, rendy_with_gl_backend,
rendy_with_metal_backend, rendy_with_vulkan_backend, EnabledBackend, Instance,
},
rendy_factory::{Config, DevicesConfigure, Factory, HeapsConfigure, QueuesConfigure},
};
#[cfg(feature = "winit")]
mod windowed;
#[cfg(feature = "winit")]
pub use windowed::*;
#[derive(Clone, Debug, PartialEq)]
pub enum RendyInitError {
CreationError(CreationError),
UnsupportedBackend(UnsupportedBackend),
}
impl From<CreationError> for RendyInitError {
fn from(err: CreationError) -> Self {
RendyInitError::CreationError(err)
}
}
impl From<UnsupportedBackend> for RendyInitError {
fn from(err: UnsupportedBackend) -> Self {
RendyInitError::UnsupportedBackend(err)
}
}
impl std::fmt::Display for RendyInitError {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
RendyInitError::CreationError(err) => write!(fmt, "Cannot init rendy: {:#?}", err),
RendyInitError::UnsupportedBackend(err) => write!(fmt, "Cannot init rendy: {:#?}", err),
}
}
}
impl std::error::Error for RendyInitError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
RendyInitError::CreationError(_err) => None, RendyInitError::UnsupportedBackend(_err) => None, }
}
}
#[derive(Debug)]
pub struct Rendy<B: Backend> {
pub families: Families<B>,
pub factory: Factory<B>,
}
impl<B: Backend> Rendy<B> {
pub fn init(
config: &Config<impl DevicesConfigure, impl HeapsConfigure, impl QueuesConfigure>,
) -> Result<Self, RendyInitError> {
let instance = B::Instance::create("Rendy", 1)?;
let (factory, families) =
rendy_factory::init_with_instance(Instance::new(instance), config)?;
Ok(Rendy { factory, families })
}
}
pub struct RendyAutoInitError {
pub errors: Vec<(EnabledBackend, RendyInitError)>,
}
impl std::fmt::Debug for RendyAutoInitError {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(self, fmt)
}
}
impl std::fmt::Display for RendyAutoInitError {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if fmt.alternate() {
if self.errors.is_empty() {
writeln!(fmt, "No enabled backends among:")?;
for &backend in &BASIC_PRIORITY {
writeln!(fmt, " {:#}", backend)?;
}
} else {
writeln!(fmt, "Initialization failed for all backends")?;
for (backend, error) in &self.errors {
writeln!(fmt, " {:#}: {:#}", backend, error)?;
}
}
} else {
if self.errors.is_empty() {
write!(fmt, "No enabled backends among:")?;
for &backend in &BASIC_PRIORITY {
write!(fmt, " {}", backend)?;
}
} else {
write!(fmt, "Initialization failed for all backends")?;
for (backend, error) in &self.errors {
write!(fmt, " {}: {}", backend, error)?;
}
}
}
Ok(())
}
}
backend_enum! { #[derive(Debug)] pub enum AnyRendy(Rendy); }
impl AnyRendy {
pub fn init_auto(
config: &Config<impl DevicesConfigure, impl HeapsConfigure, impl QueuesConfigure>,
) -> Result<Self, RendyAutoInitError> {
let mut errors = Vec::with_capacity(5);
for backend in BASIC_PRIORITY
.iter()
.filter_map(|b| std::convert::TryInto::try_into(*b).ok())
{
match Self::init(backend, config) {
Ok(rendy) => return Ok(rendy),
Err(err) => errors.push((backend, err)),
}
}
Err(RendyAutoInitError { errors })
}
#[rustfmt::skip]
pub fn init(
back: EnabledBackend,
config: &Config<impl DevicesConfigure, impl HeapsConfigure, impl QueuesConfigure>,
) -> Result<Self, RendyInitError> {
#![allow(unused_variables)]
rendy_backend!(match (back): EnabledBackend {
Dx12 => { Ok(AnyRendy::Dx12(Rendy::<rendy_core::dx12::Backend>::init(config)?)) }
Empty => { Ok(AnyRendy::Empty(Rendy::<rendy_core::empty::Backend>::init(config)?)) }
Gl => { Ok(AnyRendy::Gl(Rendy::<rendy_core::gl::Backend>::init(config)?)) }
Metal => { Ok(AnyRendy::Metal(Rendy::<rendy_core::metal::Backend>::init(config)?)) }
Vulkan => { Ok(AnyRendy::Vulkan(Rendy::<rendy_core::vulkan::Backend>::init(config)?)) }
})
}
}
pub fn available_backends() -> smallvec::SmallVec<[EnabledBackend; 5]> {
#[allow(unused_mut)]
let mut backends = smallvec::SmallVec::<[EnabledBackend; 5]>::new();
rendy_with_dx12_backend!(backends.push(EnabledBackend::Dx12));
rendy_with_empty_backend!(backends.push(EnabledBackend::Empty));
rendy_with_gl_backend!(backends.push(EnabledBackend::Gl));
rendy_with_metal_backend!(backends.push(EnabledBackend::Metal));
rendy_with_vulkan_backend!(backends.push(EnabledBackend::Vulkan));
backends
}
pub const BASIC_PRIORITY: [rendy_core::Backend; 4] = [
rendy_core::Backend::Vulkan,
rendy_core::Backend::Dx12,
rendy_core::Backend::Metal,
rendy_core::Backend::Gl,
];
pub fn pick_backend(
priority: impl IntoIterator<Item = rendy_core::Backend>,
) -> Option<EnabledBackend> {
priority
.into_iter()
.filter_map(|b| std::convert::TryInto::try_into(b).ok())
.next()
}