StratoSDK is a framework with a declarative approach similar to Flutter/React, written and designed entirely for Rust.
| 1 | //! Device management for wgpu |
| 2 | //! |
| 3 | //! BLOCCO 1: Device Setup |
| 4 | //! Handles wgpu instance, adapter, device, and queue initialization |
| 5 | |
| 6 | use wgpu::{ |
| 7 | Adapter, AdapterInfo, Backends, Device, DeviceDescriptor, Features, Instance, |
| 8 | InstanceDescriptor, Limits, PowerPreference, Queue, RequestAdapterOptions, |
| 9 | }; |
| 10 | |
| 11 | /// Manages wgpu device and queue |
| 12 | pub struct DeviceManager { |
| 13 | instance: Instance, |
| 14 | adapter: Adapter, |
| 15 | device: Device, |
| 16 | queue: Queue, |
| 17 | } |
| 18 | |
| 19 | impl DeviceManager { |
| 20 | /// Create a new device manager |
| 21 | /// |
| 22 | /// # Arguments |
| 23 | /// * `backend` - Backend to use (Backends::all() for auto-selection) |
| 24 | /// |
| 25 | /// # Errors |
| 26 | /// Returns error if no suitable adapter found or device creation fails |
| 27 | pub async fn new(backend: Backends) -> anyhow::Result<Self> { |
| 28 | // Create wgpu instance |
| 29 | let instance = Instance::new(InstanceDescriptor { |
| 30 | backends: backend, |
| 31 | ..Default::default() |
| 32 | }); |
| 33 | |
| 34 | // Request adapter |
| 35 | let adapter = instance |
| 36 | .request_adapter(&RequestAdapterOptions { |
| 37 | power_preference: PowerPreference::HighPerformance, |
| 38 | compatible_surface: None, |
| 39 | force_fallback_adapter: false, |
| 40 | }) |
| 41 | .await |
| 42 | .ok_or_else(|| anyhow::anyhow!("Failed to find suitable GPU adapter"))?; |
| 43 | |
| 44 | // Log adapter info for debugging |
| 45 | let adapter_info = adapter.get_info(); |
| 46 | println!("=== GPU ADAPTER INFO ==="); |
| 47 | println!("Name: {}", adapter_info.name); |
| 48 | println!("Vendor: {:?}", adapter_info.vendor); |
| 49 | println!("Device: {:?}", adapter_info.device); |
| 50 | println!("Backend: {:?}", adapter_info.backend); |
| 51 | println!("========================"); |
| 52 | |
| 53 | // Request device and queue |
| 54 | let (device, queue) = adapter |
| 55 | .request_device( |
| 56 | &DeviceDescriptor { |
| 57 | label: Some("StratoUI Device"), |
| 58 | required_features: Features::empty(), |
| 59 | required_limits: Limits::default(), |
| 60 | }, |
| 61 | None, |
| 62 | ) |
| 63 | .await |
| 64 | .map_err(|e| anyhow::anyhow!("Failed to create device: {}", e))?; |
| 65 | |
| 66 | Ok(Self { |
| 67 | instance, |
| 68 | adapter, |
| 69 | device, |
| 70 | queue, |
| 71 | }) |
| 72 | } |
| 73 | |
| 74 | /// Get reference to the device |
| 75 | pub fn device(&self) -> &Device { |
| 76 | &self.device |
| 77 | } |
| 78 | |
| 79 | /// Get reference to the queue |
| 80 | pub fn queue(&self) -> &Queue { |
| 81 | &self.queue |
| 82 | } |
| 83 | |
| 84 | /// Get reference to the adapter |
| 85 | pub fn adapter(&self) -> &Adapter { |
| 86 | &self.adapter |
| 87 | } |
| 88 | |
| 89 | /// Get reference to the instance |
| 90 | pub fn instance(&self) -> &Instance { |
| 91 | &self.instance |
| 92 | } |
| 93 | |
| 94 | /// Get adapter information |
| 95 | pub fn adapter_info(&self) -> AdapterInfo { |
| 96 | self.adapter.get_info() |
| 97 | } |
| 98 | |
| 99 | /// Get device limits |
| 100 | pub fn limits(&self) -> Limits { |
| 101 | self.device.limits() |
| 102 | } |
| 103 | |
| 104 | /// Get device features |
| 105 | pub fn features(&self) -> Features { |
| 106 | self.device.features() |
| 107 | } |
| 108 | } |
| 109 | |
| 110 | #[cfg(test)] |
| 111 | mod tests { |
| 112 | use super::*; |
| 113 | |
| 114 | #[tokio::test] |
| 115 | async fn test_device_creation() { |
| 116 | let dm = DeviceManager::new(Backends::all()) |
| 117 | .await |
| 118 | .expect("Failed to create device manager"); |
| 119 | |
| 120 | // Verify device created successfully |
| 121 | assert!(dm.device().limits().max_texture_dimension_2d > 0); |
| 122 | } |
| 123 | |
| 124 | #[tokio::test] |
| 125 | async fn test_device_limits_reasonable() { |
| 126 | let dm = DeviceManager::new(Backends::all()) |
| 127 | .await |
| 128 | .expect("Failed to create device manager"); |
| 129 | |
| 130 | let limits = dm.limits(); |
| 131 | |
| 132 | // Verify reasonable limits for 2D rendering |
| 133 | assert!(limits.max_texture_dimension_2d >= 2048); |
| 134 | assert!(limits.max_buffer_size > 0); |
| 135 | assert!(limits.max_bind_groups > 0); |
| 136 | } |
| 137 | |
| 138 | #[tokio::test] |
| 139 | async fn test_adapter_info() { |
| 140 | let dm = DeviceManager::new(Backends::all()) |
| 141 | .await |
| 142 | .expect("Failed to create device manager"); |
| 143 | |
| 144 | let info = dm.adapter_info(); |
| 145 | |
| 146 | // Verify adapter info is populated |
| 147 | assert!(!info.name.is_empty()); |
| 148 | println!("Adapter: {}", info.name); |
| 149 | println!("Backend: {:?}", info.backend); |
| 150 | } |
| 151 | |
| 152 | #[tokio::test] |
| 153 | async fn test_queue_available() { |
| 154 | let dm = DeviceManager::new(Backends::all()) |
| 155 | .await |
| 156 | .expect("Failed to create device manager"); |
| 157 | |
| 158 | // Verify queue is accessible |
| 159 | let _queue = dm.queue(); |
| 160 | } |
| 161 | } |
| 162 |