1use {
9 rendy_command::Families,
10 rendy_core::{
11 backend_enum,
12 hal::{device::CreationError, Backend, Instance as _, UnsupportedBackend},
13 rendy_backend, rendy_with_dx12_backend, rendy_with_empty_backend, rendy_with_gl_backend,
14 rendy_with_metal_backend, rendy_with_vulkan_backend, EnabledBackend, Instance,
15 },
16 rendy_factory::{Config, DevicesConfigure, Factory, HeapsConfigure, QueuesConfigure},
17};
18
19#[cfg(feature = "winit")]
20mod windowed;
21
22#[cfg(feature = "winit")]
23pub use windowed::*;
24
25#[derive(Clone, Debug, PartialEq)]
27pub enum RendyInitError {
28 CreationError(CreationError),
30
31 UnsupportedBackend(UnsupportedBackend),
33}
34
35impl From<CreationError> for RendyInitError {
36 fn from(err: CreationError) -> Self {
37 RendyInitError::CreationError(err)
38 }
39}
40
41impl From<UnsupportedBackend> for RendyInitError {
42 fn from(err: UnsupportedBackend) -> Self {
43 RendyInitError::UnsupportedBackend(err)
44 }
45}
46
47impl std::fmt::Display for RendyInitError {
48 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
49 match self {
50 RendyInitError::CreationError(err) => write!(fmt, "Cannot init rendy: {:#?}", err),
51 RendyInitError::UnsupportedBackend(err) => write!(fmt, "Cannot init rendy: {:#?}", err),
52 }
53 }
54}
55
56impl std::error::Error for RendyInitError {
57 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
58 match self {
59 RendyInitError::CreationError(_err) => None, RendyInitError::UnsupportedBackend(_err) => None, }
62 }
63}
64
65#[derive(Debug)]
70pub struct Rendy<B: Backend> {
71 pub families: Families<B>,
72 pub factory: Factory<B>,
73}
74
75impl<B: Backend> Rendy<B> {
76 pub fn init(
77 config: &Config<impl DevicesConfigure, impl HeapsConfigure, impl QueuesConfigure>,
78 ) -> Result<Self, RendyInitError> {
79 let instance = B::Instance::create("Rendy", 1)?;
80 let (factory, families) =
81 rendy_factory::init_with_instance(Instance::new(instance), config)?;
82 Ok(Rendy { factory, families })
83 }
84}
85
86pub struct RendyAutoInitError {
88 pub errors: Vec<(EnabledBackend, RendyInitError)>,
89}
90
91impl std::fmt::Debug for RendyAutoInitError {
92 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
93 std::fmt::Display::fmt(self, fmt)
94 }
95}
96
97impl std::fmt::Display for RendyAutoInitError {
98 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
99 if fmt.alternate() {
100 if self.errors.is_empty() {
101 writeln!(fmt, "No enabled backends among:")?;
102 for &backend in &BASIC_PRIORITY {
103 writeln!(fmt, " {:#}", backend)?;
104 }
105 } else {
106 writeln!(fmt, "Initialization failed for all backends")?;
107 for (backend, error) in &self.errors {
108 writeln!(fmt, " {:#}: {:#}", backend, error)?;
109 }
110 }
111 } else {
112 if self.errors.is_empty() {
113 write!(fmt, "No enabled backends among:")?;
114 for &backend in &BASIC_PRIORITY {
115 write!(fmt, " {}", backend)?;
116 }
117 } else {
118 write!(fmt, "Initialization failed for all backends")?;
119 for (backend, error) in &self.errors {
120 write!(fmt, " {}: {}", backend, error)?;
121 }
122 }
123 }
124 Ok(())
125 }
126}
127
128backend_enum! { #[derive(Debug)] pub enum AnyRendy(Rendy); }
129
130impl AnyRendy {
131 pub fn init_auto(
132 config: &Config<impl DevicesConfigure, impl HeapsConfigure, impl QueuesConfigure>,
133 ) -> Result<Self, RendyAutoInitError> {
134 let mut errors = Vec::with_capacity(5);
135
136 for backend in BASIC_PRIORITY
137 .iter()
138 .filter_map(|b| std::convert::TryInto::try_into(*b).ok())
139 {
140 match Self::init(backend, config) {
141 Ok(rendy) => return Ok(rendy),
142 Err(err) => errors.push((backend, err)),
143 }
144 }
145
146 Err(RendyAutoInitError { errors })
147 }
148
149 #[rustfmt::skip]
150 pub fn init(
151 back: EnabledBackend,
152 config: &Config<impl DevicesConfigure, impl HeapsConfigure, impl QueuesConfigure>,
153 ) -> Result<Self, RendyInitError> {
154 #![allow(unused_variables)]
155 rendy_backend!(match (back): EnabledBackend {
156 Dx12 => { Ok(AnyRendy::Dx12(Rendy::<rendy_core::dx12::Backend>::init(config)?)) }
157 Empty => { Ok(AnyRendy::Empty(Rendy::<rendy_core::empty::Backend>::init(config)?)) }
158 Gl => { Ok(AnyRendy::Gl(Rendy::<rendy_core::gl::Backend>::init(config)?)) }
159 Metal => { Ok(AnyRendy::Metal(Rendy::<rendy_core::metal::Backend>::init(config)?)) }
160 Vulkan => { Ok(AnyRendy::Vulkan(Rendy::<rendy_core::vulkan::Backend>::init(config)?)) }
161 })
162 }
163}
164
165pub fn available_backends() -> smallvec::SmallVec<[EnabledBackend; 5]> {
167 #[allow(unused_mut)]
168 let mut backends = smallvec::SmallVec::<[EnabledBackend; 5]>::new();
169 rendy_with_dx12_backend!(backends.push(EnabledBackend::Dx12));
170 rendy_with_empty_backend!(backends.push(EnabledBackend::Empty));
171 rendy_with_gl_backend!(backends.push(EnabledBackend::Gl));
172 rendy_with_metal_backend!(backends.push(EnabledBackend::Metal));
173 rendy_with_vulkan_backend!(backends.push(EnabledBackend::Vulkan));
174 backends
175}
176
177pub const BASIC_PRIORITY: [rendy_core::Backend; 4] = [
178 rendy_core::Backend::Vulkan,
179 rendy_core::Backend::Dx12,
180 rendy_core::Backend::Metal,
181 rendy_core::Backend::Gl,
182];
183
184pub fn pick_backend(
185 priority: impl IntoIterator<Item = rendy_core::Backend>,
186) -> Option<EnabledBackend> {
187 priority
188 .into_iter()
189 .filter_map(|b| std::convert::TryInto::try_into(b).ok())
190 .next()
191}