helion_core/
backend.rs

1use std::sync::Arc;
2
3/// GPU backend type
4#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub enum BackendType {
6    WebGPU,
7    WebGL2,
8}
9
10/// GPU backend abstraction - OPTIONAL helper for web contexts
11/// 
12/// This struct is maintained for backward compatibility and web-based usage.
13/// For native window rendering (e.g., Python bindings), renderers can be
14/// created directly with device/queue/config without going through GPUBackend.
15/// 
16/// Design rationale:
17/// - Native contexts: Create device/queue/surface directly, pass to renderer
18/// - Web contexts: Use GPUBackend as a convenient factory/manager
19pub struct GPUBackend {
20    pub backend_type: BackendType,
21    pub device: Option<Arc<wgpu::Device>>,
22    pub queue: Option<Arc<wgpu::Queue>>,
23    pub surface: Option<wgpu::Surface<'static>>,
24    pub config: Option<wgpu::SurfaceConfiguration>,
25}
26
27impl GPUBackend {
28    /// Create a new GPU backend with automatic detection
29    pub async fn new() -> Result<Self, String> {
30        // Try WebGPU first
31        match Self::init_webgpu().await {
32            Ok(backend) => {
33                log::info!("Initialized WebGPU backend");
34                Ok(backend)
35            }
36            Err(e) => {
37                log::warn!("WebGPU initialization failed: {}, falling back to WebGL2", e);
38                // WebGL2 fallback will be implemented later
39                Err(format!("WebGPU failed: {}", e))
40            }
41        }
42    }
43
44    /// Initialize WebGPU backend
45    async fn init_webgpu() -> Result<Self, String> {
46        let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
47            backends: wgpu::Backends::all(),
48            ..Default::default()
49        });
50
51        let adapter = instance
52            .request_adapter(&wgpu::RequestAdapterOptions {
53                power_preference: wgpu::PowerPreference::HighPerformance,
54                compatible_surface: None,
55                force_fallback_adapter: false,
56            })
57            .await
58            .ok_or("Failed to find GPU adapter")?;
59
60        let (device, queue) = adapter
61            .request_device(
62                &wgpu::DeviceDescriptor {
63                    label: Some("Helion Device"),
64                    required_features: wgpu::Features::empty(),
65                    required_limits: wgpu::Limits::default(),
66                    memory_hints: Default::default(),
67                },
68                None,
69            )
70            .await
71            .map_err(|e| format!("Failed to create device: {}", e))?;
72
73        Ok(GPUBackend {
74            backend_type: BackendType::WebGPU,
75            device: Some(Arc::new(device)),
76            queue: Some(Arc::new(queue)),
77            surface: None,
78            config: None,
79        })
80    }
81
82    /// Configure surface for rendering
83    pub fn configure_surface(
84        &mut self,
85        surface: wgpu::Surface<'static>,
86        width: u32,
87        height: u32,
88    ) -> Result<(), String> {
89        let device = self.device.as_ref().ok_or("Device not initialized")?;
90
91        let config = wgpu::SurfaceConfiguration {
92            usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
93            format: wgpu::TextureFormat::Bgra8UnormSrgb,
94            width,
95            height,
96            present_mode: wgpu::PresentMode::Fifo,
97            alpha_mode: wgpu::CompositeAlphaMode::Opaque,
98            view_formats: vec![],
99            desired_maximum_frame_latency: 2,
100        };
101
102        surface.configure(device.as_ref(), &config);
103        
104        self.surface = Some(surface);
105        self.config = Some(config);
106
107        Ok(())
108    }
109
110    /// Get device reference
111    pub fn device(&self) -> Result<&wgpu::Device, String> {
112        self.device
113            .as_ref()
114            .map(|d| d.as_ref())
115            .ok_or("Device not initialized".to_string())
116    }
117
118    /// Get queue reference
119    pub fn queue(&self) -> Result<&wgpu::Queue, String> {
120        self.queue
121            .as_ref()
122            .map(|q| q.as_ref())
123            .ok_or("Queue not initialized".to_string())
124    }
125}