1use core::ops::Deref;
2use wgpu::{Instance, Surface};
3
4mod touch;
5pub use touch::*;
6
7#[cfg_attr(
8 any(target_os = "ios", all(feature = "mac_catalyst", target_os = "macos")),
9 path = "ios.rs"
10)]
11#[cfg_attr(target_os = "android", path = "android.rs")]
12#[cfg_attr(
13 all(target_arch = "wasm32", feature = "web_rwh"),
14 path = "web_rwh/mod.rs"
15)]
16#[cfg_attr(
17 any(
18 all(not(feature = "mac_catalyst"), target_os = "macos"),
19 target_os = "windows",
20 target_os = "linux",
21 ),
22 path = "app_surface_use_winit.rs"
23)]
24#[cfg_attr(
25 all(target_arch = "wasm32", not(feature = "web_rwh")),
26 path = "app_surface_use_winit.rs"
27)]
28mod app_surface;
29pub use app_surface::*;
30
31#[repr(C)]
38#[derive(Debug)]
39pub struct ViewSize {
40 pub width: u32,
41 pub height: u32,
42}
43
44#[cfg(target_arch = "wasm32")]
45use std::rc::Rc as SharedPtr;
46#[cfg(not(target_arch = "wasm32"))]
47use std::sync::Arc as SharedPtr;
48#[derive(Clone)]
50pub struct IASDQContext {
51 pub instance: wgpu::Instance,
52 pub surface: SharedPtr<wgpu::Surface<'static>>,
53 pub config: wgpu::SurfaceConfiguration,
54 pub adapter: wgpu::Adapter,
55 pub device: wgpu::Device,
56 pub queue: wgpu::Queue,
57}
58
59impl IASDQContext {
60 pub fn update_config_format(&mut self, format: wgpu::TextureFormat) {
61 self.config.format = format;
62 if cfg!(feature = "webgl") {
63 } else if format == format.remove_srgb_suffix() {
65 self.config.view_formats = vec![format.add_srgb_suffix()];
66 } else {
67 self.config.view_formats = vec![format];
68 }
69 self.surface.configure(&self.device, &self.config);
70 }
71}
72
73impl Deref for AppSurface {
74 type Target = IASDQContext;
75 fn deref(&self) -> &Self::Target {
76 &self.ctx
77 }
78}
79
80pub trait SurfaceFrame {
81 fn view_size(&self) -> ViewSize;
82 fn resize_surface(&mut self);
84 fn resize_surface_by_size(&mut self, size: (u32, u32));
85 fn pintch(&mut self, _touch: Touch, _scale: f32) {}
86 fn touch(&mut self, _touch: Touch) {}
87 fn normalize_touch_point(&self, _touch_point_x: f32, _touch_point_y: f32) -> (f32, f32) {
88 unimplemented!()
89 }
90 fn enter_frame(&mut self) {}
91 fn get_current_frame_view(
92 &self,
93 _view_format: Option<wgpu::TextureFormat>,
94 ) -> Option<(wgpu::SurfaceTexture, wgpu::TextureView)> {
95 unimplemented!()
96 }
97 fn create_current_frame_view(
98 &self,
99 device: &wgpu::Device,
100 surface: &wgpu::Surface,
101 config: &wgpu::SurfaceConfiguration,
102 view_format: Option<wgpu::TextureFormat>,
103 ) -> Option<(wgpu::SurfaceTexture, wgpu::TextureView)> {
104 let frame = match surface.get_current_texture() {
105 wgpu::CurrentSurfaceTexture::Success(frame)
106 | wgpu::CurrentSurfaceTexture::Suboptimal(frame) => frame,
107 wgpu::CurrentSurfaceTexture::Timeout
108 | wgpu::CurrentSurfaceTexture::Outdated
109 | wgpu::CurrentSurfaceTexture::Lost => {
110 surface.configure(device, config);
111 match surface.get_current_texture() {
112 wgpu::CurrentSurfaceTexture::Success(frame)
113 | wgpu::CurrentSurfaceTexture::Suboptimal(frame) => frame,
114 _ => panic!("Failed to acquire next swap chain texture!"),
115 }
116 }
117 wgpu::CurrentSurfaceTexture::Occluded => return None,
118 wgpu::CurrentSurfaceTexture::Validation => panic!("Validation error acquiring texture"),
119 };
120 let view = frame.texture.create_view(&wgpu::TextureViewDescriptor {
121 label: Some("frame texture view"),
122 format: if view_format.is_none() {
123 Some(config.format.add_srgb_suffix())
125 } else {
126 view_format
127 },
128 ..Default::default()
129 });
130 Some((frame, view))
131 }
132}
133
134impl SurfaceFrame for AppSurface {
135 fn view_size(&self) -> ViewSize {
136 let size = self.get_view_size();
137 ViewSize {
138 width: size.0,
139 height: size.1,
140 }
141 }
142
143 fn resize_surface(&mut self) {
144 let size = self.get_view_size();
145 self.ctx.config.width = size.0;
146 self.ctx.config.height = size.1;
147 self.surface.configure(&self.device, &self.config);
148 }
149
150 fn resize_surface_by_size(&mut self, size: (u32, u32)) {
151 self.ctx.config.width = size.0;
152 self.ctx.config.height = size.1;
153 self.surface.configure(&self.device, &self.config);
154 }
155
156 fn normalize_touch_point(&self, touch_point_x: f32, touch_point_y: f32) -> (f32, f32) {
157 let size = self.get_view_size();
158 (
159 touch_point_x * self.scale_factor / size.0 as f32,
160 touch_point_y * self.scale_factor / size.1 as f32,
161 )
162 }
163
164 fn get_current_frame_view(
165 &self,
166 view_format: Option<wgpu::TextureFormat>,
167 ) -> Option<(wgpu::SurfaceTexture, wgpu::TextureView)> {
168 self.create_current_frame_view(&self.device, &self.surface, &self.config, view_format)
169 }
170}
171
172async fn create_iasdq_context(
173 instance: Instance,
174 surface: Surface<'static>,
175 physical_size: (u32, u32),
176) -> IASDQContext {
177 let (adapter, device, queue) = crate::request_device(&instance, &surface).await;
178
179 let caps = surface.get_capabilities(&adapter);
180 let prefered = caps.formats[0];
181
182 let format = if cfg!(all(target_arch = "wasm32", not(feature = "webgl"))) {
183 prefered.remove_srgb_suffix()
186 } else {
187 prefered
188 };
189 let view_formats = if cfg!(feature = "webgl") {
190 vec![]
194 } else if cfg!(target_os = "android") {
195 vec![format]
205 } else if format.is_srgb() {
206 vec![format, format.remove_srgb_suffix()]
207 } else {
208 vec![format.add_srgb_suffix(), format.remove_srgb_suffix()]
209 };
210
211 let mut config = surface
212 .get_default_config(&adapter, physical_size.0, physical_size.1)
213 .expect("Surface isn't supported by the adapter.");
214
215 config.view_formats = view_formats;
216 config.format = format;
217
218 surface.configure(&device, &config);
219
220 IASDQContext {
221 instance,
222 surface: SharedPtr::new(surface),
223 config,
224 adapter,
225 device,
226 queue,
227 }
228}
229
230async fn request_device(
231 instance: &Instance,
232 surface: &Surface<'static>,
233) -> (wgpu::Adapter, wgpu::Device, wgpu::Queue) {
234 let adapter = instance
235 .request_adapter(&wgpu::RequestAdapterOptions {
236 power_preference: wgpu::PowerPreference::from_env()
237 .unwrap_or(wgpu::PowerPreference::HighPerformance),
238 force_fallback_adapter: false,
239 compatible_surface: Some(surface),
240 })
241 .await
242 .expect("No suitable GPU adapters found on the system!");
243
244 let adapter_info = adapter.get_info();
245 println!("Using {} ({:?})", adapter_info.name, adapter_info.backend);
246
247 let base_dir = std::env::var("CARGO_MANIFEST_DIR");
248 let _trace_path = if let Ok(base_dir) = base_dir {
249 Some(std::path::PathBuf::from(&base_dir).join("WGPU_TRACE_ERROR"))
250 } else {
251 None
252 };
253
254 let mut adp_features = adapter.features();
257 #[cfg(target_family = "unix")]
258 {
259 if adapter_info.name.contains("NVIDIA") {
260 adp_features.remove(wgpu::Features::EXPERIMENTAL_RAY_QUERY);
261 }
262 }
263 let res = adapter
267 .request_device(&wgpu::DeviceDescriptor {
268 label: None,
269 required_features: adp_features,
270 required_limits: adapter.limits(),
271 experimental_features: unsafe { wgpu::ExperimentalFeatures::enabled() },
272 memory_hints: wgpu::MemoryHints::Performance,
273 trace: wgpu::Trace::Off,
274 })
275 .await;
276
277 match res {
278 Err(err) => {
279 panic!("request_device failed: {err:?}");
280 }
281 Ok(tuple) => (adapter, tuple.0, tuple.1),
282 }
283}