Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit ab18cea

Browse files
committedFeb 6, 2023
Support for transparent backbuffer in wgpu winit binding
Choose best fitting composite alpha mode on the fly.
1 parent b1e214b commit ab18cea

File tree

3 files changed

+75
-48
lines changed

3 files changed

+75
-48
lines changed
 

‎crates/eframe/src/native/run.rs

+1
Original file line numberDiff line numberDiff line change
@@ -958,6 +958,7 @@ mod wgpu_integration {
958958
self.native_options.wgpu_options.clone(),
959959
self.native_options.multisampling.max(1) as _,
960960
self.native_options.depth_buffer,
961+
self.native_options.transparent,
961962
);
962963
pollster::block_on(painter.set_window(Some(&window)))?;
963964
painter

‎crates/egui-wgpu/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ All notable changes to the `egui-wgpu` integration will be noted in this file.
77
* Return `Err` instead of panic if we can't find a device ([#2428](https://github.com/emilk/egui/pull/2428)).
88
* `winit::Painter::set_window` is now `async` ([#2434](https://github.com/emilk/egui/pull/2434)).
99
* `egui-wgpu` now only depends on `epaint` instead of the entire `egui` ([#2438](https://github.com/emilk/egui/pull/2438)).
10+
* `winit::Painter` now supports transparent backbuffer ([#2684](https://github.com/emilk/egui/pull/2684)).
1011

1112

1213
## 0.20.0 - 2022-12-08 - web support

‎crates/egui-wgpu/src/winit.rs

+73-48
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
use std::sync::Arc;
22

3-
use tracing::error;
4-
use wgpu::{Adapter, Instance, Surface};
5-
63
use epaint::mutex::RwLock;
74

5+
use tracing::error;
6+
87
use crate::{renderer, RenderState, Renderer, SurfaceErrorAction, WgpuConfiguration};
98

109
struct SurfaceState {
11-
surface: Surface,
10+
surface: wgpu::Surface,
11+
alpha_mode: wgpu::CompositeAlphaMode,
1212
width: u32,
1313
height: u32,
1414
}
@@ -19,11 +19,12 @@ struct SurfaceState {
1919
pub struct Painter {
2020
configuration: WgpuConfiguration,
2121
msaa_samples: u32,
22+
support_transparent_backbuffer: bool,
2223
depth_format: Option<wgpu::TextureFormat>,
2324
depth_texture_view: Option<wgpu::TextureView>,
2425

25-
instance: Instance,
26-
adapter: Option<Adapter>,
26+
instance: wgpu::Instance,
27+
adapter: Option<wgpu::Adapter>,
2728
render_state: Option<RenderState>,
2829
surface_state: Option<SurfaceState>,
2930
}
@@ -41,7 +42,12 @@ impl Painter {
4142
/// [`set_window()`](Self::set_window) once you have
4243
/// a [`winit::window::Window`] with a valid `.raw_window_handle()`
4344
/// associated.
44-
pub fn new(configuration: WgpuConfiguration, msaa_samples: u32, depth_bits: u8) -> Self {
45+
pub fn new(
46+
configuration: WgpuConfiguration,
47+
msaa_samples: u32,
48+
depth_bits: u8,
49+
support_transparent_backbuffer: bool,
50+
) -> Self {
4551
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
4652
backends: configuration.backends,
4753
dx12_shader_compiler: Default::default(), //
@@ -50,6 +56,7 @@ impl Painter {
5056
Self {
5157
configuration,
5258
msaa_samples,
59+
support_transparent_backbuffer,
5360
depth_format: (depth_bits > 0).then_some(wgpu::TextureFormat::Depth32Float),
5461
depth_texture_view: None,
5562

@@ -69,7 +76,7 @@ impl Painter {
6976

7077
async fn init_render_state(
7178
&self,
72-
adapter: &Adapter,
79+
adapter: &wgpu::Adapter,
7380
target_format: wgpu::TextureFormat,
7481
) -> Result<RenderState, wgpu::RequestDeviceError> {
7582
adapter
@@ -94,7 +101,7 @@ impl Painter {
94101
// will have the same format and so this render state will remain valid.
95102
async fn ensure_render_state_for_surface(
96103
&mut self,
97-
surface: &Surface,
104+
surface: &wgpu::Surface,
98105
) -> Result<(), wgpu::RequestDeviceError> {
99106
if self.adapter.is_none() {
100107
self.adapter = self
@@ -121,34 +128,23 @@ impl Painter {
121128
Ok(())
122129
}
123130

124-
fn configure_surface(&mut self, width_in_pixels: u32, height_in_pixels: u32) {
125-
crate::profile_function!();
126-
127-
let render_state = self
128-
.render_state
129-
.as_ref()
130-
.expect("Render state should exist before surface configuration");
131-
let format = render_state.target_format;
132-
133-
let config = wgpu::SurfaceConfiguration {
134-
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
135-
format,
136-
width: width_in_pixels,
137-
height: height_in_pixels,
138-
present_mode: self.configuration.present_mode,
139-
alpha_mode: wgpu::CompositeAlphaMode::Auto,
140-
view_formats: vec![format],
141-
};
142-
143-
let surface_state = self
144-
.surface_state
145-
.as_mut()
146-
.expect("Surface state should exist before surface configuration");
147-
surface_state
148-
.surface
149-
.configure(&render_state.device, &config);
150-
surface_state.width = width_in_pixels;
151-
surface_state.height = height_in_pixels;
131+
fn configure_surface(
132+
surface_state: &SurfaceState,
133+
render_state: &RenderState,
134+
present_mode: wgpu::PresentMode,
135+
) {
136+
surface_state.surface.configure(
137+
&render_state.device,
138+
&wgpu::SurfaceConfiguration {
139+
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
140+
format: render_state.target_format,
141+
width: surface_state.width,
142+
height: surface_state.height,
143+
present_mode,
144+
alpha_mode: surface_state.alpha_mode,
145+
view_formats: vec![render_state.target_format],
146+
},
147+
);
152148
}
153149

154150
/// Updates (or clears) the [`winit::window::Window`] associated with the [`Painter`]
@@ -188,15 +184,34 @@ impl Painter {
188184

189185
self.ensure_render_state_for_surface(&surface).await?;
190186

187+
let alpha_mode = if self.support_transparent_backbuffer {
188+
let supported_alpha_modes = surface
189+
.get_capabilities(self.adapter.as_ref().unwrap())
190+
.alpha_modes;
191+
192+
// Prefer pre multiplied over post multiplied!
193+
if supported_alpha_modes.contains(&wgpu::CompositeAlphaMode::PreMultiplied) {
194+
wgpu::CompositeAlphaMode::PreMultiplied
195+
} else if supported_alpha_modes
196+
.contains(&wgpu::CompositeAlphaMode::PostMultiplied)
197+
{
198+
wgpu::CompositeAlphaMode::PostMultiplied
199+
} else {
200+
warn!("Transparent window was requested, but the active wgpu surface does not support a `CompositeAlphaMode` with transparency.");
201+
wgpu::CompositeAlphaMode::Auto
202+
}
203+
} else {
204+
wgpu::CompositeAlphaMode::Auto
205+
};
206+
191207
let size = window.inner_size();
192-
let width = size.width;
193-
let height = size.height;
194208
self.surface_state = Some(SurfaceState {
195209
surface,
196-
width,
197-
height,
210+
width: size.width,
211+
height: size.height,
212+
alpha_mode,
198213
});
199-
self.resize_and_generate_depth_texture_view(width, height);
214+
self.resize_and_generate_depth_texture_view(size.width, size.height);
200215
}
201216
None => {
202217
self.surface_state = None;
@@ -221,10 +236,17 @@ impl Painter {
221236
width_in_pixels: u32,
222237
height_in_pixels: u32,
223238
) {
224-
self.configure_surface(width_in_pixels, height_in_pixels);
225-
let device = &self.render_state.as_ref().unwrap().device;
239+
let render_state = self.render_state.as_ref().unwrap();
240+
let surface_state = self.surface_state.as_mut().unwrap();
241+
242+
surface_state.width = width_in_pixels;
243+
surface_state.height = height_in_pixels;
244+
245+
Self::configure_surface(surface_state, render_state, self.configuration.present_mode);
246+
226247
self.depth_texture_view = self.depth_format.map(|depth_format| {
227-
device
248+
render_state
249+
.device
228250
.create_texture(&wgpu::TextureDescriptor {
229251
label: Some("egui_depth_texture"),
230252
size: wgpu::Extent3d {
@@ -269,7 +291,6 @@ impl Painter {
269291
Some(rs) => rs,
270292
None => return,
271293
};
272-
let (width, height) = (surface_state.width, surface_state.height);
273294

274295
let output_frame = {
275296
crate::profile_scope!("get_current_texture");
@@ -282,7 +303,11 @@ impl Painter {
282303
#[allow(clippy::single_match_else)]
283304
Err(e) => match (*self.configuration.on_surface_error)(e) {
284305
SurfaceErrorAction::RecreateSurface => {
285-
self.configure_surface(width, height);
306+
Self::configure_surface(
307+
surface_state,
308+
render_state,
309+
self.configuration.present_mode,
310+
);
286311
return;
287312
}
288313
SurfaceErrorAction::SkipFrame => {
@@ -300,7 +325,7 @@ impl Painter {
300325

301326
// Upload all resources for the GPU.
302327
let screen_descriptor = renderer::ScreenDescriptor {
303-
size_in_pixels: [width, height],
328+
size_in_pixels: [surface_state.width, surface_state.height],
304329
pixels_per_point,
305330
};
306331

0 commit comments

Comments
 (0)
Please sign in to comment.