Skip to main content

ass_renderer/renderer/
probing.rs

1//! Backend auto-detection and probing
2
3use crate::backends::{BackendType, RenderBackend};
4use crate::renderer::RenderContext;
5use crate::utils::RenderError;
6
7#[cfg(feature = "nostd")]
8use alloc::{boxed::Box, vec::Vec};
9#[cfg(not(feature = "nostd"))]
10use std::vec::Vec;
11
12/// Backend prober for automatic backend selection
13pub struct BackendProber {
14    preferred_order: Vec<BackendType>,
15}
16
17impl BackendProber {
18    /// Create a new backend prober with default preferences
19    #[allow(clippy::vec_init_then_push)] // Conditional compilation makes vec! macro difficult
20    #[allow(unused_mut)] // mut is needed for conditional features
21    pub fn new() -> Self {
22        let mut preferred_order = Vec::new();
23
24        #[cfg(feature = "software-backend")]
25        preferred_order.push(BackendType::Software);
26
27        #[cfg(feature = "gpu")]
28        preferred_order.push(BackendType::Gpu);
29
30        Self { preferred_order }
31    }
32
33    /// Create prober with custom backend preference order
34    pub fn with_preference(preferred_order: Vec<BackendType>) -> Self {
35        Self { preferred_order }
36    }
37
38    /// Probe for the best available backend
39    pub fn probe_best_backend(
40        &self,
41        context: &RenderContext,
42    ) -> Result<Box<dyn RenderBackend>, RenderError> {
43        for backend_type in &self.preferred_order {
44            match self.try_create_backend(*backend_type, context) {
45                Ok(backend) => {
46                    return Ok(backend);
47                }
48                Err(_e) => {}
49            }
50        }
51
52        Err(RenderError::NoBackendAvailable)
53    }
54
55    /// Try to create a specific backend
56    fn try_create_backend(
57        &self,
58        backend_type: BackendType,
59        context: &RenderContext,
60    ) -> Result<Box<dyn RenderBackend>, RenderError> {
61        match backend_type {
62            #[cfg(feature = "software-backend")]
63            BackendType::Software => {
64                use crate::backends::software::SoftwareBackend;
65                Ok(Box::new(SoftwareBackend::new(context)?))
66            }
67
68            #[cfg(feature = "gpu")]
69            BackendType::Gpu => {
70                use crate::backends::gpu::GpuBackend;
71                Ok(Box::new(GpuBackend::new(
72                    context.width(),
73                    context.height(),
74                )?))
75            }
76
77            _ => Err(RenderError::UnsupportedBackend(backend_type.as_str())),
78        }
79    }
80
81    /// Check if a backend is available
82    pub fn is_backend_available(&self, backend_type: BackendType) -> bool {
83        match backend_type {
84            #[cfg(feature = "software-backend")]
85            BackendType::Software => true,
86
87            #[cfg(feature = "gpu")]
88            BackendType::Gpu => true,
89
90            _ => false,
91        }
92    }
93
94    /// Get list of available backends
95    pub fn available_backends(&self) -> Vec<BackendType> {
96        self.preferred_order
97            .iter()
98            .filter(|&&backend| self.is_backend_available(backend))
99            .copied()
100            .collect()
101    }
102}
103
104impl Default for BackendProber {
105    fn default() -> Self {
106        Self::new()
107    }
108}