Support for transparent backbuffer in wgpu winit binding (#2684)
* Support for transparent backbuffer in wgpu winit binding Choose best fitting composite alpha mode on the fly. * Compilation fix * Add line to eframe CHANGELOG * Attempt to mollify CI: try different way to install apt packages --------- Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
This commit is contained in:
parent
b1e214bbdf
commit
b52cd2052f
5 changed files with 107 additions and 50 deletions
33
.github/workflows/rust.yml
vendored
33
.github/workflows/rust.yml
vendored
|
@ -16,66 +16,87 @@ jobs:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
- uses: actions-rs/toolchain@v1
|
- uses: actions-rs/toolchain@v1
|
||||||
with:
|
with:
|
||||||
profile: default
|
profile: default
|
||||||
toolchain: 1.65.0
|
toolchain: 1.65.0
|
||||||
override: true
|
override: true
|
||||||
|
|
||||||
- name: Install packages (Linux)
|
- name: Install packages (Linux)
|
||||||
if: runner.os == 'Linux'
|
if: runner.os == 'Linux'
|
||||||
run: sudo apt-get update && sudo apt-get install libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev libspeechd-dev libxkbcommon-dev libssl-dev libgtk-3-dev # libgtk-3-dev is used by rfd
|
#uses: awalsh128/cache-apt-pkgs-action@v1.2.2
|
||||||
|
#TODO(emilk) use upstream when https://github.com/awalsh128/cache-apt-pkgs-action/pull/90 is merged
|
||||||
|
uses: rerun-io/cache-apt-pkgs-action@59534850182063abf1b2c11bb3686722a12a8397
|
||||||
|
with:
|
||||||
|
packages: libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev libspeechd-dev libxkbcommon-dev libssl-dev libgtk-3-dev # libgtk-3-dev is used by rfd
|
||||||
|
version: 1.0
|
||||||
|
execute_install_scripts: true
|
||||||
|
|
||||||
- name: Set up cargo cache
|
- name: Set up cargo cache
|
||||||
uses: Swatinem/rust-cache@v2
|
uses: Swatinem/rust-cache@v2
|
||||||
|
|
||||||
- name: Rustfmt
|
- name: Rustfmt
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
command: fmt
|
command: fmt
|
||||||
args: --all -- --check
|
args: --all -- --check
|
||||||
|
|
||||||
- name: Install cargo-cranky
|
- name: Install cargo-cranky
|
||||||
uses: baptiste0928/cargo-install@v1
|
uses: baptiste0928/cargo-install@v1
|
||||||
with:
|
with:
|
||||||
crate: cargo-cranky
|
crate: cargo-cranky
|
||||||
|
|
||||||
- name: Check all features
|
- name: Check all features
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
command: check
|
command: check
|
||||||
args: --locked --all-features
|
args: --locked --all-features
|
||||||
|
|
||||||
- name: Check default features
|
- name: Check default features
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
command: check
|
command: check
|
||||||
args: --locked
|
args: --locked
|
||||||
|
|
||||||
- name: Check no default features
|
- name: Check no default features
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
command: check
|
command: check
|
||||||
args: --locked --no-default-features --lib
|
args: --locked --no-default-features --lib
|
||||||
|
|
||||||
- name: Test doc-tests
|
- name: Test doc-tests
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
command: test
|
command: test
|
||||||
args: --doc --all-features
|
args: --doc --all-features
|
||||||
|
|
||||||
- name: cargo doc --lib
|
- name: cargo doc --lib
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
command: doc
|
command: doc
|
||||||
args: --lib --no-deps --all-features
|
args: --lib --no-deps --all-features
|
||||||
|
|
||||||
- name: cargo doc --document-private-items
|
- name: cargo doc --document-private-items
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
command: doc
|
command: doc
|
||||||
args: --document-private-items --no-deps --all-features
|
args: --document-private-items --no-deps --all-features
|
||||||
|
|
||||||
- name: Test
|
- name: Test
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
command: test
|
command: test
|
||||||
args: --all-features
|
args: --all-features
|
||||||
|
|
||||||
- name: Cranky
|
- name: Cranky
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
command: cranky
|
command: cranky
|
||||||
args: --all-targets --all-features -- -D warnings
|
args: --all-targets --all-features -- -D warnings
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
check_wasm:
|
check_wasm:
|
||||||
name: Check wasm32 + wasm-bindgen
|
name: Check wasm32 + wasm-bindgen
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
|
@ -129,6 +150,8 @@ jobs:
|
||||||
command: cranky
|
command: cranky
|
||||||
args: --target wasm32-unknown-unknown --all-features -p egui_demo_app --lib -- -D warnings
|
args: --target wasm32-unknown-unknown --all-features -p egui_demo_app --lib -- -D warnings
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
cargo-deny:
|
cargo-deny:
|
||||||
name: cargo deny
|
name: cargo deny
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
|
@ -138,22 +161,29 @@ jobs:
|
||||||
with:
|
with:
|
||||||
rust-version: "1.65.0"
|
rust-version: "1.65.0"
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
android:
|
android:
|
||||||
name: android
|
name: android
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
- uses: actions-rs/toolchain@v1
|
- uses: actions-rs/toolchain@v1
|
||||||
with:
|
with:
|
||||||
profile: minimal
|
profile: minimal
|
||||||
toolchain: 1.65.0
|
toolchain: 1.65.0
|
||||||
target: aarch64-linux-android
|
target: aarch64-linux-android
|
||||||
override: true
|
override: true
|
||||||
|
|
||||||
- name: Set up cargo cache
|
- name: Set up cargo cache
|
||||||
uses: Swatinem/rust-cache@v2
|
uses: Swatinem/rust-cache@v2
|
||||||
|
|
||||||
- run: cargo check --features wgpu --target aarch64-linux-android
|
- run: cargo check --features wgpu --target aarch64-linux-android
|
||||||
working-directory: crates/eframe
|
working-directory: crates/eframe
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
windows:
|
windows:
|
||||||
name: Check Windows
|
name: Check Windows
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
|
@ -173,4 +203,3 @@ jobs:
|
||||||
with:
|
with:
|
||||||
command: check
|
command: check
|
||||||
args: --all-targets --all-features
|
args: --all-targets --all-features
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ NOTE: [`egui-winit`](../egui-winit/CHANGELOG.md), [`egui_glium`](../egui_glium/C
|
||||||
* Fixed window position persistence for Windows ([#2583](https://github.com/emilk/egui/issues/2583)).
|
* Fixed window position persistence for Windows ([#2583](https://github.com/emilk/egui/issues/2583)).
|
||||||
* Update to `winit` 0.28, adding support for mac trackpad zoom ([#2654](https://github.com/emilk/egui/pull/2654)).
|
* Update to `winit` 0.28, adding support for mac trackpad zoom ([#2654](https://github.com/emilk/egui/pull/2654)).
|
||||||
* Fix bug where the cursor could get stuck using the wrong icon.
|
* Fix bug where the cursor could get stuck using the wrong icon.
|
||||||
|
* `NativeOptions::transparent` now works with the wgpu backend ([#2684](https://github.com/emilk/egui/pull/2684)).
|
||||||
|
|
||||||
#### Web:
|
#### Web:
|
||||||
* Prevent ctrl-P/cmd-P from opening the print dialog ([#2598](https://github.com/emilk/egui/pull/2598)).
|
* Prevent ctrl-P/cmd-P from opening the print dialog ([#2598](https://github.com/emilk/egui/pull/2598)).
|
||||||
|
|
|
@ -958,6 +958,7 @@ mod wgpu_integration {
|
||||||
self.native_options.wgpu_options.clone(),
|
self.native_options.wgpu_options.clone(),
|
||||||
self.native_options.multisampling.max(1) as _,
|
self.native_options.multisampling.max(1) as _,
|
||||||
self.native_options.depth_buffer,
|
self.native_options.depth_buffer,
|
||||||
|
self.native_options.transparent,
|
||||||
);
|
);
|
||||||
pollster::block_on(painter.set_window(Some(&window)))?;
|
pollster::block_on(painter.set_window(Some(&window)))?;
|
||||||
painter
|
painter
|
||||||
|
|
|
@ -7,6 +7,7 @@ All notable changes to the `egui-wgpu` integration will be noted in this file.
|
||||||
* Return `Err` instead of panic if we can't find a device ([#2428](https://github.com/emilk/egui/pull/2428)).
|
* Return `Err` instead of panic if we can't find a device ([#2428](https://github.com/emilk/egui/pull/2428)).
|
||||||
* `winit::Painter::set_window` is now `async` ([#2434](https://github.com/emilk/egui/pull/2434)).
|
* `winit::Painter::set_window` is now `async` ([#2434](https://github.com/emilk/egui/pull/2434)).
|
||||||
* `egui-wgpu` now only depends on `epaint` instead of the entire `egui` ([#2438](https://github.com/emilk/egui/pull/2438)).
|
* `egui-wgpu` now only depends on `epaint` instead of the entire `egui` ([#2438](https://github.com/emilk/egui/pull/2438)).
|
||||||
|
* `winit::Painter` now supports transparent backbuffer ([#2684](https://github.com/emilk/egui/pull/2684)).
|
||||||
|
|
||||||
|
|
||||||
## 0.20.0 - 2022-12-08 - web support
|
## 0.20.0 - 2022-12-08 - web support
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use tracing::error;
|
|
||||||
use wgpu::{Adapter, Instance, Surface};
|
|
||||||
|
|
||||||
use epaint::mutex::RwLock;
|
use epaint::mutex::RwLock;
|
||||||
|
|
||||||
|
use tracing::error;
|
||||||
|
|
||||||
use crate::{renderer, RenderState, Renderer, SurfaceErrorAction, WgpuConfiguration};
|
use crate::{renderer, RenderState, Renderer, SurfaceErrorAction, WgpuConfiguration};
|
||||||
|
|
||||||
struct SurfaceState {
|
struct SurfaceState {
|
||||||
surface: Surface,
|
surface: wgpu::Surface,
|
||||||
|
alpha_mode: wgpu::CompositeAlphaMode,
|
||||||
width: u32,
|
width: u32,
|
||||||
height: u32,
|
height: u32,
|
||||||
}
|
}
|
||||||
|
@ -19,11 +19,12 @@ struct SurfaceState {
|
||||||
pub struct Painter {
|
pub struct Painter {
|
||||||
configuration: WgpuConfiguration,
|
configuration: WgpuConfiguration,
|
||||||
msaa_samples: u32,
|
msaa_samples: u32,
|
||||||
|
support_transparent_backbuffer: bool,
|
||||||
depth_format: Option<wgpu::TextureFormat>,
|
depth_format: Option<wgpu::TextureFormat>,
|
||||||
depth_texture_view: Option<wgpu::TextureView>,
|
depth_texture_view: Option<wgpu::TextureView>,
|
||||||
|
|
||||||
instance: Instance,
|
instance: wgpu::Instance,
|
||||||
adapter: Option<Adapter>,
|
adapter: Option<wgpu::Adapter>,
|
||||||
render_state: Option<RenderState>,
|
render_state: Option<RenderState>,
|
||||||
surface_state: Option<SurfaceState>,
|
surface_state: Option<SurfaceState>,
|
||||||
}
|
}
|
||||||
|
@ -41,7 +42,12 @@ impl Painter {
|
||||||
/// [`set_window()`](Self::set_window) once you have
|
/// [`set_window()`](Self::set_window) once you have
|
||||||
/// a [`winit::window::Window`] with a valid `.raw_window_handle()`
|
/// a [`winit::window::Window`] with a valid `.raw_window_handle()`
|
||||||
/// associated.
|
/// associated.
|
||||||
pub fn new(configuration: WgpuConfiguration, msaa_samples: u32, depth_bits: u8) -> Self {
|
pub fn new(
|
||||||
|
configuration: WgpuConfiguration,
|
||||||
|
msaa_samples: u32,
|
||||||
|
depth_bits: u8,
|
||||||
|
support_transparent_backbuffer: bool,
|
||||||
|
) -> Self {
|
||||||
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
|
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
|
||||||
backends: configuration.backends,
|
backends: configuration.backends,
|
||||||
dx12_shader_compiler: Default::default(), //
|
dx12_shader_compiler: Default::default(), //
|
||||||
|
@ -50,6 +56,7 @@ impl Painter {
|
||||||
Self {
|
Self {
|
||||||
configuration,
|
configuration,
|
||||||
msaa_samples,
|
msaa_samples,
|
||||||
|
support_transparent_backbuffer,
|
||||||
depth_format: (depth_bits > 0).then_some(wgpu::TextureFormat::Depth32Float),
|
depth_format: (depth_bits > 0).then_some(wgpu::TextureFormat::Depth32Float),
|
||||||
depth_texture_view: None,
|
depth_texture_view: None,
|
||||||
|
|
||||||
|
@ -69,7 +76,7 @@ impl Painter {
|
||||||
|
|
||||||
async fn init_render_state(
|
async fn init_render_state(
|
||||||
&self,
|
&self,
|
||||||
adapter: &Adapter,
|
adapter: &wgpu::Adapter,
|
||||||
target_format: wgpu::TextureFormat,
|
target_format: wgpu::TextureFormat,
|
||||||
) -> Result<RenderState, wgpu::RequestDeviceError> {
|
) -> Result<RenderState, wgpu::RequestDeviceError> {
|
||||||
adapter
|
adapter
|
||||||
|
@ -94,7 +101,7 @@ impl Painter {
|
||||||
// will have the same format and so this render state will remain valid.
|
// will have the same format and so this render state will remain valid.
|
||||||
async fn ensure_render_state_for_surface(
|
async fn ensure_render_state_for_surface(
|
||||||
&mut self,
|
&mut self,
|
||||||
surface: &Surface,
|
surface: &wgpu::Surface,
|
||||||
) -> Result<(), wgpu::RequestDeviceError> {
|
) -> Result<(), wgpu::RequestDeviceError> {
|
||||||
if self.adapter.is_none() {
|
if self.adapter.is_none() {
|
||||||
self.adapter = self
|
self.adapter = self
|
||||||
|
@ -121,34 +128,23 @@ impl Painter {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn configure_surface(&mut self, width_in_pixels: u32, height_in_pixels: u32) {
|
fn configure_surface(
|
||||||
crate::profile_function!();
|
surface_state: &SurfaceState,
|
||||||
|
render_state: &RenderState,
|
||||||
let render_state = self
|
present_mode: wgpu::PresentMode,
|
||||||
.render_state
|
) {
|
||||||
.as_ref()
|
surface_state.surface.configure(
|
||||||
.expect("Render state should exist before surface configuration");
|
&render_state.device,
|
||||||
let format = render_state.target_format;
|
&wgpu::SurfaceConfiguration {
|
||||||
|
|
||||||
let config = wgpu::SurfaceConfiguration {
|
|
||||||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
||||||
format,
|
format: render_state.target_format,
|
||||||
width: width_in_pixels,
|
width: surface_state.width,
|
||||||
height: height_in_pixels,
|
height: surface_state.height,
|
||||||
present_mode: self.configuration.present_mode,
|
present_mode,
|
||||||
alpha_mode: wgpu::CompositeAlphaMode::Auto,
|
alpha_mode: surface_state.alpha_mode,
|
||||||
view_formats: vec![format],
|
view_formats: vec![render_state.target_format],
|
||||||
};
|
},
|
||||||
|
);
|
||||||
let surface_state = self
|
|
||||||
.surface_state
|
|
||||||
.as_mut()
|
|
||||||
.expect("Surface state should exist before surface configuration");
|
|
||||||
surface_state
|
|
||||||
.surface
|
|
||||||
.configure(&render_state.device, &config);
|
|
||||||
surface_state.width = width_in_pixels;
|
|
||||||
surface_state.height = height_in_pixels;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Updates (or clears) the [`winit::window::Window`] associated with the [`Painter`]
|
/// Updates (or clears) the [`winit::window::Window`] associated with the [`Painter`]
|
||||||
|
@ -188,15 +184,34 @@ impl Painter {
|
||||||
|
|
||||||
self.ensure_render_state_for_surface(&surface).await?;
|
self.ensure_render_state_for_surface(&surface).await?;
|
||||||
|
|
||||||
|
let alpha_mode = if self.support_transparent_backbuffer {
|
||||||
|
let supported_alpha_modes = surface
|
||||||
|
.get_capabilities(self.adapter.as_ref().unwrap())
|
||||||
|
.alpha_modes;
|
||||||
|
|
||||||
|
// Prefer pre multiplied over post multiplied!
|
||||||
|
if supported_alpha_modes.contains(&wgpu::CompositeAlphaMode::PreMultiplied) {
|
||||||
|
wgpu::CompositeAlphaMode::PreMultiplied
|
||||||
|
} else if supported_alpha_modes
|
||||||
|
.contains(&wgpu::CompositeAlphaMode::PostMultiplied)
|
||||||
|
{
|
||||||
|
wgpu::CompositeAlphaMode::PostMultiplied
|
||||||
|
} else {
|
||||||
|
tracing::warn!("Transparent window was requested, but the active wgpu surface does not support a `CompositeAlphaMode` with transparency.");
|
||||||
|
wgpu::CompositeAlphaMode::Auto
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
wgpu::CompositeAlphaMode::Auto
|
||||||
|
};
|
||||||
|
|
||||||
let size = window.inner_size();
|
let size = window.inner_size();
|
||||||
let width = size.width;
|
|
||||||
let height = size.height;
|
|
||||||
self.surface_state = Some(SurfaceState {
|
self.surface_state = Some(SurfaceState {
|
||||||
surface,
|
surface,
|
||||||
width,
|
width: size.width,
|
||||||
height,
|
height: size.height,
|
||||||
|
alpha_mode,
|
||||||
});
|
});
|
||||||
self.resize_and_generate_depth_texture_view(width, height);
|
self.resize_and_generate_depth_texture_view(size.width, size.height);
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
self.surface_state = None;
|
self.surface_state = None;
|
||||||
|
@ -221,10 +236,17 @@ impl Painter {
|
||||||
width_in_pixels: u32,
|
width_in_pixels: u32,
|
||||||
height_in_pixels: u32,
|
height_in_pixels: u32,
|
||||||
) {
|
) {
|
||||||
self.configure_surface(width_in_pixels, height_in_pixels);
|
let render_state = self.render_state.as_ref().unwrap();
|
||||||
let device = &self.render_state.as_ref().unwrap().device;
|
let surface_state = self.surface_state.as_mut().unwrap();
|
||||||
|
|
||||||
|
surface_state.width = width_in_pixels;
|
||||||
|
surface_state.height = height_in_pixels;
|
||||||
|
|
||||||
|
Self::configure_surface(surface_state, render_state, self.configuration.present_mode);
|
||||||
|
|
||||||
self.depth_texture_view = self.depth_format.map(|depth_format| {
|
self.depth_texture_view = self.depth_format.map(|depth_format| {
|
||||||
device
|
render_state
|
||||||
|
.device
|
||||||
.create_texture(&wgpu::TextureDescriptor {
|
.create_texture(&wgpu::TextureDescriptor {
|
||||||
label: Some("egui_depth_texture"),
|
label: Some("egui_depth_texture"),
|
||||||
size: wgpu::Extent3d {
|
size: wgpu::Extent3d {
|
||||||
|
@ -269,7 +291,6 @@ impl Painter {
|
||||||
Some(rs) => rs,
|
Some(rs) => rs,
|
||||||
None => return,
|
None => return,
|
||||||
};
|
};
|
||||||
let (width, height) = (surface_state.width, surface_state.height);
|
|
||||||
|
|
||||||
let output_frame = {
|
let output_frame = {
|
||||||
crate::profile_scope!("get_current_texture");
|
crate::profile_scope!("get_current_texture");
|
||||||
|
@ -282,7 +303,11 @@ impl Painter {
|
||||||
#[allow(clippy::single_match_else)]
|
#[allow(clippy::single_match_else)]
|
||||||
Err(e) => match (*self.configuration.on_surface_error)(e) {
|
Err(e) => match (*self.configuration.on_surface_error)(e) {
|
||||||
SurfaceErrorAction::RecreateSurface => {
|
SurfaceErrorAction::RecreateSurface => {
|
||||||
self.configure_surface(width, height);
|
Self::configure_surface(
|
||||||
|
surface_state,
|
||||||
|
render_state,
|
||||||
|
self.configuration.present_mode,
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SurfaceErrorAction::SkipFrame => {
|
SurfaceErrorAction::SkipFrame => {
|
||||||
|
@ -300,7 +325,7 @@ impl Painter {
|
||||||
|
|
||||||
// Upload all resources for the GPU.
|
// Upload all resources for the GPU.
|
||||||
let screen_descriptor = renderer::ScreenDescriptor {
|
let screen_descriptor = renderer::ScreenDescriptor {
|
||||||
size_in_pixels: [width, height],
|
size_in_pixels: [surface_state.width, surface_state.height],
|
||||||
pixels_per_point,
|
pixels_per_point,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue