egui_render_wgpu/
surface.rs1use rwh::HasWindowHandle;
2use tracing::{debug, info};
3use wgpu::*;
4pub struct SurfaceManager {
5 pub surface_view: Option<TextureView>,
10 pub surface_current_image: Option<SurfaceTexture>,
12 pub surface: Option<Surface<'static>>,
14 pub surface_config: SurfaceConfiguration,
16 surface_formats_priority: Vec<TextureFormat>,
21}
22impl Drop for SurfaceManager {
23 fn drop(&mut self) {
24 tracing::warn!("dropping wgpu surface");
25 }
26}
27impl SurfaceManager {
28 #[allow(clippy::too_many_arguments)]
29 pub fn new(
30 window: Option<Box<dyn WindowHandle>>,
31 transparent: Option<bool>,
32 latest_fb_size: [u32; 2],
33 instance: &Instance,
34 adapter: &Adapter,
35 device: &Device,
36 surface: Option<Surface<'static>>,
37 surface_formats_priority: Vec<TextureFormat>,
38 surface_config: SurfaceConfiguration,
39 ) -> Self {
40 let mut surface_manager = Self {
41 surface_view: None,
42 surface_current_image: None,
43 surface,
44 surface_config,
45 surface_formats_priority,
46 };
47 surface_manager.reconfigure_surface(
48 window,
49 transparent,
50 latest_fb_size,
51 instance,
52 adapter,
53 device,
54 );
55 surface_manager
56 }
57 pub fn create_current_surface_texture_view(
58 &mut self,
59 mut latest_framebuffer_size_getter: impl FnMut() -> [u32; 2],
60 device: &Device,
61 ) {
62 if let Some(surface) = self.surface.as_ref() {
63 let current_surface_image = surface.get_current_texture().unwrap_or_else(|_| {
64 let latest_fb_size = latest_framebuffer_size_getter();
65 self.surface_config.width = latest_fb_size[0];
66 self.surface_config.height = latest_fb_size[1];
67 surface.configure(device, &self.surface_config);
68 surface.get_current_texture().unwrap_or_else(|e| {
69 panic!("failed to get surface even after reconfiguration. {e}")
70 })
71 });
72 if current_surface_image.suboptimal {
73 tracing::warn!("current surface image is suboptimal. ");
74 }
75 let surface_view = current_surface_image
76 .texture
77 .create_view(&TextureViewDescriptor {
78 label: Some("surface view"),
79 format: Some(self.surface_config.format),
80 dimension: Some(TextureViewDimension::D2),
81 aspect: TextureAspect::All,
82 base_mip_level: 0,
83 mip_level_count: None,
84 base_array_layer: 0,
85 array_layer_count: None,
86 });
87
88 self.surface_view = Some(surface_view);
89 self.surface_current_image = Some(current_surface_image);
90 } else {
91 tracing::warn!(
92 "skipping acquiring the currnet surface image because there's no surface"
93 );
94 }
95 }
96 pub fn reconfigure_surface(
100 &mut self,
101 window: Option<Box<dyn WindowHandle>>,
102 transparent: Option<bool>,
103 latest_fb_size: [u32; 2],
104 instance: &Instance,
105 adapter: &Adapter,
106 device: &Device,
107 ) {
108 if let Some(window) = window {
109 if self.surface.is_none() {
110 self.surface = Some({
111 tracing::debug!("creating a surface with {:?}", window.window_handle());
112 instance
113 .create_surface(SurfaceTarget::Window(window))
114 .expect("failed to create surface")
115 });
116 }
117
118 let capabilities = self.surface.as_ref().unwrap().get_capabilities(adapter);
119 let supported_formats = capabilities.formats;
120 debug!(
121 "supported alpha modes: {:#?}",
122 &capabilities.alpha_modes[..]
123 );
124
125 if transparent.unwrap_or_default() {
126 use CompositeAlphaMode::*;
127 let alpha_modes: Vec<CompositeAlphaMode> = capabilities.alpha_modes.to_vec();
128 tracing::info!(?alpha_modes, "supported alpha modes");
129 {
130 self.surface_config.alpha_mode = if alpha_modes.contains(&Inherit) {
131 Inherit
132 } else if alpha_modes.contains(&PreMultiplied) {
133 PreMultiplied
134 } else if alpha_modes.contains(&PostMultiplied) {
135 PostMultiplied
136 } else {
137 Auto
138 };
139 }
140 }
141 debug!("supported formats of the surface: {supported_formats:#?}");
142
143 let mut compatible_format_found = false;
144 for sfmt in self.surface_formats_priority.iter() {
145 debug!("checking if {sfmt:?} is supported");
146 if supported_formats.contains(sfmt) {
147 debug!("{sfmt:?} is supported. setting it as surface format");
148 self.surface_config.format = *sfmt;
149 compatible_format_found = true;
150 break;
151 }
152 }
153 if !compatible_format_found {
154 if !self.surface_formats_priority.is_empty() {
155 tracing::warn!(
156 "could not find compatible surface format from user provided formats. choosing first supported format instead"
157 );
158 }
159 self.surface_config.format = supported_formats
160 .iter()
161 .find(|f| f.is_srgb())
162 .copied()
163 .unwrap_or_else(|| {
164 supported_formats
165 .first()
166 .copied()
167 .expect("surface has zero supported texture formats")
168 })
169 }
170 let view_format = if self.surface_config.format.is_srgb() {
171 self.surface_config.format
172 } else {
173 tracing::warn!(
174 "surface format is not srgb: {:?}",
175 self.surface_config.format
176 );
177 match self.surface_config.format {
178 TextureFormat::Rgba8Unorm => TextureFormat::Rgba8UnormSrgb,
179 TextureFormat::Bgra8Unorm => TextureFormat::Bgra8UnormSrgb,
180 _ => self.surface_config.format,
181 }
182 };
183 self.surface_config.view_formats = vec![view_format];
184
185 #[cfg(target_os = "emscripten")]
186 {
187 self.surface_config.view_formats = vec![];
188 }
189
190 debug!(
191 "using format: {:#?} for surface configuration",
192 self.surface_config.format
193 );
194 self.resize_framebuffer(device, latest_fb_size);
195 }
196 }
197
198 pub fn resize_framebuffer(&mut self, device: &Device, latest_fb_size: [u32; 2]) {
199 self.surface_config.width = latest_fb_size[0];
200 self.surface_config.height = latest_fb_size[1];
201 info!(
202 "reconfiguring surface with config: {:#?}",
203 &self.surface_config
204 );
205 self.surface
206 .as_ref()
207 .unwrap()
208 .configure(device, &self.surface_config);
209 }
210 pub fn suspend(&mut self) {
211 self.surface = None;
212 self.surface_current_image = None;
213 self.surface_view = None;
214 }
215}