orbit/renderer/wgpu/
mod.rs1#[cfg(feature = "wgpu")]
4use std::sync::Arc;
5#[cfg(feature = "wgpu")]
6use wgpu::{Adapter, Device, Instance, Queue, Surface, SurfaceConfiguration};
7
8#[cfg(feature = "wgpu")]
9use crate::component::Node;
10#[cfg(feature = "wgpu")]
11use crate::renderer::{RenderContext, Renderer};
12#[cfg(feature = "wgpu")]
13use crate::Error;
14
15#[cfg(feature = "wgpu")]
17pub struct WgpuRenderer {
18 #[allow(dead_code)]
20 instance: Instance,
21
22 device: Arc<Device>,
24
25 queue: Arc<Queue>,
27
28 surface: Option<Surface<'static>>,
30
31 surface_config: Option<SurfaceConfiguration>,
33
34 adapter: Adapter,
36}
37
38#[cfg(feature = "wgpu")]
39impl WgpuRenderer {
40 pub async fn new() -> Result<Self, Error> {
42 let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
44 backends: wgpu::Backends::all(),
45 flags: wgpu::InstanceFlags::default(),
46 dx12_shader_compiler: wgpu::Dx12Compiler::default(),
47 gles_minor_version: wgpu::Gles3MinorVersion::default(),
48 });
49
50 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_else(|| Error::Renderer("Failed to find GPU adapter".to_string()))?;
59
60 let (device, queue) = adapter
62 .request_device(
63 &wgpu::DeviceDescriptor {
64 label: Some("Orbit WGPU Device"),
65 required_features: wgpu::Features::empty(),
66 required_limits: wgpu::Limits::default(),
67 },
68 None,
69 )
70 .await
71 .map_err(|e| Error::Renderer(format!("Failed to create device: {e}")))?;
72
73 Ok(Self {
74 instance,
75 device: Arc::new(device),
76 queue: Arc::new(queue),
77 surface: None,
78 surface_config: None,
79 adapter,
80 })
81 }
82
83 pub fn configure_surface(
85 &mut self,
86 surface: Surface<'static>,
87 width: u32,
88 height: u32,
89 ) -> Result<(), Error> {
90 let surface_caps = surface.get_capabilities(&self.adapter);
91 let surface_format = surface_caps
92 .formats
93 .iter()
94 .copied()
95 .find(|f| f.is_srgb())
96 .unwrap_or(surface_caps.formats[0]);
97
98 let config = wgpu::SurfaceConfiguration {
99 usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
100 format: surface_format,
101 width,
102 height,
103 present_mode: surface_caps.present_modes[0],
104 alpha_mode: surface_caps.alpha_modes[0],
105 view_formats: vec![],
106 desired_maximum_frame_latency: 2, };
108
109 surface.configure(&self.device, &config);
110
111 self.surface = Some(surface);
112 self.surface_config = Some(config);
113
114 Ok(())
115 }
116
117 pub fn device(&self) -> &Device {
119 &self.device
120 }
121
122 pub fn queue(&self) -> &Queue {
124 &self.queue
125 }
126
127 pub fn resize(&mut self, width: u32, height: u32) -> Result<(), Error> {
129 if let Some(surface) = &self.surface {
130 if let Some(config) = &mut self.surface_config {
131 config.width = width;
132 config.height = height;
133 surface.configure(&self.device, config);
134 Ok(())
135 } else {
136 Err(Error::Renderer("Surface not configured".to_string()))
137 }
138 } else {
139 Err(Error::Renderer("Surface not initialized".to_string()))
140 }
141 }
142}
143
144#[cfg(feature = "wgpu")]
145impl Renderer for WgpuRenderer {
146 fn init(&mut self) -> Result<(), crate::Error> {
147 Ok(())
149 }
150
151 fn render(&mut self, _root: &Node, _context: &mut RenderContext) -> Result<(), Error> {
152 if let Some(surface) = &self.surface {
154 let frame = surface
155 .get_current_texture()
156 .map_err(|e| Error::Renderer(format!("Failed to get next frame: {e}")))?;
157
158 let view = frame
159 .texture
160 .create_view(&wgpu::TextureViewDescriptor::default());
161
162 let mut encoder = self
163 .device
164 .create_command_encoder(&wgpu::CommandEncoderDescriptor {
165 label: Some("Render Encoder"),
166 });
167
168 {
170 let _render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
171 label: Some("Render Pass"),
172 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
173 view: &view,
174 resolve_target: None,
175 ops: wgpu::Operations {
176 load: wgpu::LoadOp::Clear(wgpu::Color {
177 r: 0.1,
178 g: 0.2,
179 b: 0.3,
180 a: 1.0,
181 }),
182 store: wgpu::StoreOp::Store,
183 },
184 })],
185 depth_stencil_attachment: None,
186 timestamp_writes: None,
187 occlusion_query_set: None,
188 });
189
190 }
192
193 self.queue.submit(std::iter::once(encoder.finish()));
195 frame.present();
196
197 Ok(())
198 } else {
199 Err(Error::Renderer("Surface not initialized".to_string()))
200 }
201 }
202
203 fn flush(&mut self) -> Result<(), Error> {
204 Ok(())
207 }
208
209 fn cleanup(&mut self) -> Result<(), Error> {
210 self.surface = None;
212 self.surface_config = None;
213 Ok(())
214 }
215
216 fn name(&self) -> &str {
217 "WGPU Renderer"
218 }
219}