1use crate::time::{now, TimeStamp};
2use std::sync::Arc;
3use wgpu::{Backends, RequestAdapterOptions, SurfaceTarget};
4pub struct Gfx {
5 pub adapter: wgpu::Adapter,
6 pub device: wgpu::Device,
7 pub queue: wgpu::Queue,
8 pub surface: wgpu::Surface<'static>,
9 pub surface_config: Option<wgpu::SurfaceConfiguration>,
10 pub last_update: TimeStamp,
11 pub time: Arc<std::sync::Mutex<f32>>,
12 pub limit_fps: LimitFPS,
13 pub fps_history: Vec<f32>,
14 pub delta_time: f32,
15}
16impl Gfx {
17 pub async fn new(window: impl Into<SurfaceTarget<'static>>) -> Self {
18 #[cfg(target_arch = "wasm32")]
19 {
20 console_error_panic_hook::set_once();
21 }
22
23 #[cfg(target_arch = "wasm32")]
24 let instance = {
25 wgpu::Instance::new(&wgpu::InstanceDescriptor {
26 backends: Backends::BROWSER_WEBGPU,
27 ..Default::default()
28 })
29 };
30 #[cfg(not(target_arch = "wasm32"))]
31 let instance = wgpu::Instance::default();
32
33 let adapter = instance
34 .request_adapter(&RequestAdapterOptions::default())
35 .await
36 .unwrap();
37
38 let (device, queue) = adapter
39 .request_device(&wgpu::DeviceDescriptor::default(), None)
40 .await
41 .unwrap();
42
43 let surface = instance.create_surface(window).unwrap();
44
45 Gfx {
46 device,
47 queue,
48 surface,
49 adapter,
50 surface_config: None,
51 last_update: now(),
52 time: Arc::new(std::sync::Mutex::new(0.0)),
53 limit_fps: LimitFPS::default(),
54 fps_history: Vec::new(),
55 delta_time: 0.0,
56 }
57 }
58 pub fn set_zero_dt(&mut self) {
59 self.delta_time = 0.;
60 }
61 pub fn with_fps(mut self, fps: f32) -> Self {
62 self.limit_fps = LimitFPS::Limit(fps);
63 self
64 }
65 pub fn with_no_fps_limit(mut self) -> Self {
66 self.limit_fps = LimitFPS::NoLimit;
67 self
68 }
69
70 pub fn resize(&mut self, width: u32, height: u32) {
71 let mut surface_config = self
72 .surface
73 .get_default_config(&self.adapter, width, height)
74 .unwrap();
75 self.surface.configure(&self.device, &surface_config);
76 let view_format = surface_config.format.add_srgb_suffix();
77 surface_config.view_formats.push(view_format);
78 self.surface_config = Some(surface_config);
79 }
80
81 pub fn test(&self) -> Result<(), wgpu::SurfaceError> {
82 let output = self.surface.get_current_texture()?;
83 let view = output
84 .texture
85 .create_view(&wgpu::TextureViewDescriptor::default());
86
87 let mut encoder = self
88 .device
89 .create_command_encoder(&wgpu::CommandEncoderDescriptor {
90 label: Some("Render Encoder"),
91 });
92 {
93 let _render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
94 label: Some("Render Pass"),
95 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
96 view: &view,
97 resolve_target: None,
98 ops: wgpu::Operations {
99 load: wgpu::LoadOp::Clear(wgpu::Color {
100 r: 0.1,
101 g: 0.2,
102 b: 0.3,
103 a: 1.0,
104 }),
105 store: wgpu::StoreOp::Store,
106 },
107 })],
108 depth_stencil_attachment: None,
109 occlusion_query_set: None,
110 timestamp_writes: None,
111 });
112 }
113
114 self.queue.submit(std::iter::once(encoder.finish()));
116 output.present();
117 Ok(())
118 }
119}
120
121#[derive(PartialEq)]
122pub enum LimitFPS {
123 Limit(f32),
124 NoLimit,
125}
126impl Default for LimitFPS {
127 fn default() -> Self {
128 LimitFPS::Limit(30.0)
129 }
130}