rafx_api/
api.rs

1#[cfg(feature = "rafx-dx12")]
2use crate::dx12::RafxApiDx12;
3#[cfg(any(
4    feature = "rafx-empty",
5    not(any(
6        feature = "rafx-dx12",
7        feature = "rafx-metal",
8        feature = "rafx-vulkan",
9        feature = "rafx-gles2",
10        feature = "rafx-gles3"
11    ))
12))]
13use crate::empty::RafxApiEmpty;
14#[cfg(feature = "rafx-gles2")]
15use crate::gles2::RafxApiGles2;
16#[cfg(feature = "rafx-gles3")]
17use crate::gles3::RafxApiGles3;
18#[cfg(feature = "rafx-metal")]
19use crate::metal::RafxApiMetal;
20#[cfg(feature = "rafx-vulkan")]
21use crate::vulkan::RafxApiVulkan;
22
23use crate::*;
24use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle};
25
26/// Primary entry point to using the API. Use the `new_*` functions to initialize the desired
27/// backend.
28///
29/// **This API object must persist for the lifetime of all objects created through it.** This
30/// is verified at runtime when the API object is destroyed - either explicitly via `destroy()` or
31/// by dropping the object.
32///
33/// Once the API object is created, use `device_context()` to obtain a cloneable handle to the
34/// device. The `RafxDeviceContext` is the primary way of interacting with the API once it has been
35/// initialized. These contexts and all other objects created through them must be dropped before
36/// dropping `RafxApi` or calling `RafxApi::destroy()`.
37pub enum RafxApi {
38    #[cfg(feature = "rafx-dx12")]
39    Dx12(RafxApiDx12),
40    #[cfg(feature = "rafx-vulkan")]
41    Vk(RafxApiVulkan),
42    #[cfg(feature = "rafx-metal")]
43    Metal(RafxApiMetal),
44    #[cfg(feature = "rafx-gles2")]
45    Gles2(RafxApiGles2),
46    #[cfg(feature = "rafx-gles3")]
47    Gles3(RafxApiGles3),
48    #[cfg(any(
49        feature = "rafx-empty",
50        not(any(
51            feature = "rafx-dx12",
52            feature = "rafx-metal",
53            feature = "rafx-vulkan",
54            feature = "rafx-gles2",
55            feature = "rafx-gles3"
56        ))
57    ))]
58    Empty(RafxApiEmpty),
59}
60
61impl RafxApi {
62    /// Create a device using the "default" backend for the platform.
63    ///
64    /// # Safety
65    ///
66    /// GPU programming is fundamentally unsafe, so all rafx APIs that interact with the GPU should
67    /// be considered unsafe. However, rafx APIs are only gated by unsafe if they can cause undefined
68    /// behavior on the CPU for reasons other than interacting with the GPU.
69    #[allow(unreachable_code)]
70    pub unsafe fn new(
71        _display: &dyn HasRawDisplayHandle,
72        _window: &dyn HasRawWindowHandle,
73        _api_def: &RafxApiDef,
74    ) -> RafxResult<Self> {
75        #[cfg(feature = "rafx-metal")]
76        {
77            return RafxApi::new_metal(_window, _api_def);
78        }
79
80        #[cfg(feature = "rafx-dx12")]
81        {
82            return RafxApi::new_dx12(_window, _api_def);
83        }
84
85        #[cfg(feature = "rafx-vulkan")]
86        {
87            return RafxApi::new_vulkan(_display, _window, _api_def);
88        }
89
90        #[cfg(feature = "rafx-gles3")]
91        {
92            return RafxApi::new_gles3(_display, _window, _api_def);
93        }
94
95        #[cfg(feature = "rafx-gles2")]
96        {
97            return RafxApi::new_gles2(_display, _window, _api_def);
98        }
99
100        return Err("Rafx was compiled with no backend feature flag. Use on of the following features: rafx-metal, rafx-vulkan, rafx-gles2")?;
101    }
102
103    /// Initialize a device using dx12
104    ///
105    /// # Safety
106    ///
107    /// GPU programming is fundamentally unsafe, so all rafx APIs that interact with the GPU should
108    /// be considered unsafe. However, rafx APIs are only gated by unsafe if they can cause undefined
109    /// behavior on the CPU for reasons other than interacting with the GPU.
110    #[cfg(feature = "rafx-dx12")]
111    pub unsafe fn new_dx12(
112        window: &dyn HasRawWindowHandle,
113        api_def: &RafxApiDef,
114    ) -> RafxResult<Self> {
115        Ok(RafxApi::Dx12(RafxApiDx12::new(
116            window,
117            api_def,
118            &api_def.dx12_options.as_ref().unwrap_or(&Default::default()),
119        )?))
120    }
121
122    /// Initialize a device using vulkan
123    ///
124    /// # Safety
125    ///
126    /// GPU programming is fundamentally unsafe, so all rafx APIs that interact with the GPU should
127    /// be considered unsafe. However, rafx APIs are only gated by unsafe if they can cause undefined
128    /// behavior on the CPU for reasons other than interacting with the GPU.
129    #[cfg(feature = "rafx-vulkan")]
130    pub unsafe fn new_vulkan(
131        display: &dyn HasRawDisplayHandle,
132        window: &dyn HasRawWindowHandle,
133        api_def: &RafxApiDef,
134    ) -> RafxResult<Self> {
135        Ok(RafxApi::Vk(RafxApiVulkan::new(
136            display,
137            window,
138            api_def,
139            &api_def.vk_options.as_ref().unwrap_or(&Default::default()),
140        )?))
141    }
142
143    /// Initialize a device using metal
144    ///
145    /// # Safety
146    ///
147    /// GPU programming is fundamentally unsafe, so all rafx APIs that interact with the GPU should
148    /// be considered unsafe. However, rafx APIs are only gated by unsafe if they can cause undefined
149    /// behavior on the CPU for reasons other than interacting with the GPU.
150    #[cfg(feature = "rafx-metal")]
151    pub unsafe fn new_metal(
152        window: &dyn HasRawWindowHandle,
153        api_def: &RafxApiDef,
154    ) -> RafxResult<Self> {
155        Ok(RafxApi::Metal(RafxApiMetal::new(
156            window,
157            api_def,
158            &api_def
159                .metal_options
160                .as_ref()
161                .unwrap_or(&Default::default()),
162        )?))
163    }
164
165    /// Initialize a device using OpenGL ES 2.0
166    ///
167    /// # Safety
168    ///
169    /// GPU programming is fundamentally unsafe, so all rafx APIs that interact with the GPU should
170    /// be considered unsafe. However, rafx APIs are only gated by unsafe if they can cause undefined
171    /// behavior on the CPU for reasons other than interacting with the GPU.
172    #[cfg(feature = "rafx-gles2")]
173    pub unsafe fn new_gles2(
174        display: &dyn HasRawDisplayHandle,
175        window: &dyn HasRawWindowHandle,
176        api_def: &RafxApiDef,
177    ) -> RafxResult<Self> {
178        Ok(RafxApi::Gles2(RafxApiGles2::new(
179            display,
180            window,
181            api_def,
182            &api_def
183                .gles2_options
184                .as_ref()
185                .unwrap_or(&Default::default()),
186        )?))
187    }
188
189    /// Initialize a device using OpenGL ES 3.0
190    ///
191    /// # Safety
192    ///
193    /// GPU programming is fundamentally unsafe, so all rafx APIs that interact with the GPU should
194    /// be considered unsafe. However, rafx APIs are only gated by unsafe if they can cause undefined
195    /// behavior on the CPU for reasons other than interacting with the GPU.
196    #[cfg(feature = "rafx-gles3")]
197    pub unsafe fn new_gles3(
198        display: &dyn HasRawDisplayHandle,
199        window: &dyn HasRawWindowHandle,
200        api_def: &RafxApiDef,
201    ) -> RafxResult<Self> {
202        Ok(RafxApi::Gles3(RafxApiGles3::new(
203            display,
204            window,
205            api_def,
206            &api_def
207                .gles3_options
208                .as_ref()
209                .unwrap_or(&Default::default()),
210        )?))
211    }
212
213    /// Create a cloneable handle to the device. Most of the interaction with the graphics backend
214    /// is done through this handle.
215    ///
216    /// The `RafxDeviceContext` does not need to be kept in scope. As long as the `RafxApi` remains
217    /// in scope, dropping the device context does not do anything, and it can be obtained again
218    /// by calling this function.
219    ///
220    /// This context is intended to be safely shared across threads. This function is thread-safe,
221    /// and generally all APIs on the device context itself are thread-safe.
222    pub fn device_context(&self) -> RafxDeviceContext {
223        match self {
224            #[cfg(feature = "rafx-dx12")]
225            RafxApi::Dx12(inner) => RafxDeviceContext::Dx12(inner.device_context().clone()),
226            #[cfg(feature = "rafx-vulkan")]
227            RafxApi::Vk(inner) => RafxDeviceContext::Vk(inner.device_context().clone()),
228            #[cfg(feature = "rafx-metal")]
229            RafxApi::Metal(inner) => RafxDeviceContext::Metal(inner.device_context().clone()),
230            #[cfg(feature = "rafx-gles2")]
231            RafxApi::Gles2(inner) => RafxDeviceContext::Gles2(inner.device_context().clone()),
232            #[cfg(feature = "rafx-gles3")]
233            RafxApi::Gles3(inner) => RafxDeviceContext::Gles3(inner.device_context().clone()),
234            #[cfg(any(
235                feature = "rafx-empty",
236                not(any(
237                    feature = "rafx-dx12",
238                    feature = "rafx-metal",
239                    feature = "rafx-vulkan",
240                    feature = "rafx-gles2",
241                    feature = "rafx-gles3"
242                ))
243            ))]
244            RafxApi::Empty(inner) => RafxDeviceContext::Empty(inner.device_context().clone()),
245        }
246    }
247
248    /// Destroys the graphics API instance. Any `RafxDeviceContext` created through this API, and
249    /// any object created through those device contexts, must be dropped before calling destroy()
250    ///
251    /// `destroy()` is automatically called if RafxApi is dropped and it has not yet been called, so
252    /// it is not necessary to call this function explicitly.
253    pub fn destroy(&mut self) -> RafxResult<()> {
254        match self {
255            #[cfg(feature = "rafx-dx12")]
256            RafxApi::Dx12(inner) => inner.destroy(),
257            #[cfg(feature = "rafx-vulkan")]
258            RafxApi::Vk(inner) => inner.destroy(),
259            #[cfg(feature = "rafx-metal")]
260            RafxApi::Metal(inner) => inner.destroy(),
261            #[cfg(feature = "rafx-gles2")]
262            RafxApi::Gles2(inner) => inner.destroy(),
263            #[cfg(feature = "rafx-gles3")]
264            RafxApi::Gles3(inner) => inner.destroy(),
265            #[cfg(any(
266                feature = "rafx-empty",
267                not(any(
268                    feature = "rafx-dx12",
269                    feature = "rafx-metal",
270                    feature = "rafx-vulkan",
271                    feature = "rafx-gles2",
272                    feature = "rafx-gles3"
273                ))
274            ))]
275            RafxApi::Empty(inner) => inner.destroy(),
276        }
277    }
278
279    /// Get the underlying vulkan API object. This provides access to any internally created
280    /// vulkan objects.
281    #[cfg(feature = "rafx-dx12")]
282    pub fn dx12_api(&self) -> Option<&RafxApiDx12> {
283        match self {
284            #[cfg(feature = "rafx-dx12")]
285            RafxApi::Dx12(inner) => Some(inner),
286            #[cfg(feature = "rafx-vulkan")]
287            RafxApi::Vk(_) => None,
288            #[cfg(feature = "rafx-metal")]
289            RafxApi::Metal(_) => None,
290            #[cfg(feature = "rafx-gles2")]
291            RafxApi::Gles2(_) => None,
292            #[cfg(feature = "rafx-gles3")]
293            RafxApi::Gles3(_) => None,
294            #[cfg(any(
295                feature = "rafx-empty",
296                not(any(
297                    feature = "rafx-dx12",
298                    feature = "rafx-metal",
299                    feature = "rafx-vulkan",
300                    feature = "rafx-gles2",
301                    feature = "rafx-gles3"
302                ))
303            ))]
304            RafxApi::Empty(_) => None,
305        }
306    }
307
308    /// Get the underlying vulkan API object. This provides access to any internally created
309    /// vulkan objects.
310    #[cfg(feature = "rafx-vulkan")]
311    pub fn vk_api(&self) -> Option<&RafxApiVulkan> {
312        match self {
313            #[cfg(feature = "rafx-dx12")]
314            RafxApi::Dx12(_) => None,
315            #[cfg(feature = "rafx-vulkan")]
316            RafxApi::Vk(inner) => Some(inner),
317            #[cfg(feature = "rafx-metal")]
318            RafxApi::Metal(_) => None,
319            #[cfg(feature = "rafx-gles2")]
320            RafxApi::Gles2(_) => None,
321            #[cfg(feature = "rafx-gles3")]
322            RafxApi::Gles3(_) => None,
323            #[cfg(any(
324                feature = "rafx-empty",
325                not(any(
326                    feature = "rafx-dx12",
327                    feature = "rafx-metal",
328                    feature = "rafx-vulkan",
329                    feature = "rafx-gles2",
330                    feature = "rafx-gles3"
331                ))
332            ))]
333            RafxApi::Empty(_) => None,
334        }
335    }
336
337    /// Get the underlying metal API object. This provides access to any internally created
338    /// metal objects.
339    #[cfg(feature = "rafx-metal")]
340    pub fn metal_api(&self) -> Option<&RafxApiMetal> {
341        match self {
342            #[cfg(feature = "rafx-dx12")]
343            RafxApi::Dx12(_) => None,
344            #[cfg(feature = "rafx-vulkan")]
345            RafxApi::Vk(_) => None,
346            #[cfg(feature = "rafx-metal")]
347            RafxApi::Metal(inner) => Some(inner),
348            #[cfg(feature = "rafx-gles2")]
349            RafxApi::Gles2(_) => None,
350            #[cfg(feature = "rafx-gles3")]
351            RafxApi::Gles3(_) => None,
352            #[cfg(any(
353                feature = "rafx-empty",
354                not(any(
355                    feature = "rafx-dx12",
356                    feature = "rafx-metal",
357                    feature = "rafx-vulkan",
358                    feature = "rafx-gles2",
359                    feature = "rafx-gles3"
360                ))
361            ))]
362            RafxApi::Empty(_) => None,
363        }
364    }
365
366    /// Get the underlying gl API object. This provides access to any internally created
367    /// metal objects.
368    #[cfg(feature = "rafx-gles2")]
369    pub fn gles2_api(&self) -> Option<&RafxApiGles2> {
370        match self {
371            #[cfg(feature = "rafx-dx12")]
372            RafxApi::Dx12(_) => None,
373            #[cfg(feature = "rafx-vulkan")]
374            RafxApi::Vk(_) => None,
375            #[cfg(feature = "rafx-metal")]
376            RafxApi::Metal(_) => None,
377            #[cfg(feature = "rafx-gles2")]
378            RafxApi::Gles2(inner) => Some(inner),
379            #[cfg(feature = "rafx-gles3")]
380            RafxApi::Gles3(_) => None,
381            #[cfg(any(
382                feature = "rafx-empty",
383                not(any(
384                    feature = "rafx-dx12",
385                    feature = "rafx-metal",
386                    feature = "rafx-vulkan",
387                    feature = "rafx-gles2",
388                    feature = "rafx-gles3"
389                ))
390            ))]
391            RafxApi::Empty(_) => None,
392        }
393    }
394
395    /// Get the underlying gl API object. This provides access to any internally created
396    /// metal objects.
397    #[cfg(feature = "rafx-gles3")]
398    pub fn gles3_api(&self) -> Option<&RafxApiGles3> {
399        match self {
400            #[cfg(feature = "rafx-dx12")]
401            RafxApi::Dx12(_) => None,
402            #[cfg(feature = "rafx-vulkan")]
403            RafxApi::Vk(_) => None,
404            #[cfg(feature = "rafx-metal")]
405            RafxApi::Metal(_) => None,
406            #[cfg(feature = "rafx-gles2")]
407            RafxApi::Gles2(_) => None,
408            #[cfg(feature = "rafx-gles3")]
409            RafxApi::Gles3(inner) => Some(inner),
410            #[cfg(any(
411                feature = "rafx-empty",
412                not(any(
413                    feature = "rafx-dx12",
414                    feature = "rafx-metal",
415                    feature = "rafx-vulkan",
416                    feature = "rafx-gles2",
417                    feature = "rafx-gles3"
418                ))
419            ))]
420            RafxApi::Empty(_) => None,
421        }
422    }
423
424    /// Get the underlying metal API object. This provides access to any internally created
425    /// metal objects.
426    #[cfg(any(
427        feature = "rafx-empty",
428        not(any(
429            feature = "rafx-dx12",
430            feature = "rafx-metal",
431            feature = "rafx-vulkan",
432            feature = "rafx-gles2",
433            feature = "rafx-gles3"
434        ))
435    ))]
436    pub fn empty_api(&self) -> Option<&RafxApiEmpty> {
437        match self {
438            #[cfg(feature = "rafx-dx12")]
439            RafxApi::Dx12(_) => None,
440            #[cfg(feature = "rafx-vulkan")]
441            RafxApi::Vk(_) => None,
442            #[cfg(feature = "rafx-metal")]
443            RafxApi::Metal(_) => None,
444            #[cfg(feature = "rafx-gles2")]
445            RafxApi::Gles2(_) => None,
446            #[cfg(feature = "rafx-gles3")]
447            RafxApi::Gles3(_) => None,
448            #[cfg(any(
449                feature = "rafx-empty",
450                not(any(
451                    feature = "rafx-dx12",
452                    feature = "rafx-metal",
453                    feature = "rafx-vulkan",
454                    feature = "rafx-gles2",
455                    feature = "rafx-gles3"
456                ))
457            ))]
458            RafxApi::Empty(inner) => Some(inner),
459        }
460    }
461}