diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 43e1c02a..32c4a58e 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -16,66 +16,87 @@ jobs: runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 with: profile: default toolchain: 1.65.0 override: true + - name: Install packages (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 uses: Swatinem/rust-cache@v2 + - name: Rustfmt uses: actions-rs/cargo@v1 with: command: fmt args: --all -- --check + - name: Install cargo-cranky uses: baptiste0928/cargo-install@v1 with: crate: cargo-cranky + - name: Check all features uses: actions-rs/cargo@v1 with: command: check args: --locked --all-features + - name: Check default features uses: actions-rs/cargo@v1 with: command: check args: --locked + - name: Check no default features uses: actions-rs/cargo@v1 with: command: check args: --locked --no-default-features --lib + - name: Test doc-tests uses: actions-rs/cargo@v1 with: command: test args: --doc --all-features + - name: cargo doc --lib uses: actions-rs/cargo@v1 with: command: doc args: --lib --no-deps --all-features + - name: cargo doc --document-private-items uses: actions-rs/cargo@v1 with: command: doc args: --document-private-items --no-deps --all-features + - name: Test uses: actions-rs/cargo@v1 with: command: test args: --all-features + - name: Cranky uses: actions-rs/cargo@v1 with: command: cranky args: --all-targets --all-features -- -D warnings + # --------------------------------------------------------------------------- + check_wasm: name: Check wasm32 + wasm-bindgen runs-on: ubuntu-22.04 @@ -129,6 +150,8 @@ jobs: command: cranky args: --target wasm32-unknown-unknown --all-features -p egui_demo_app --lib -- -D warnings + # --------------------------------------------------------------------------- + cargo-deny: name: cargo deny runs-on: ubuntu-22.04 @@ -138,22 +161,29 @@ jobs: with: rust-version: "1.65.0" + # --------------------------------------------------------------------------- + android: name: android runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 with: profile: minimal toolchain: 1.65.0 target: aarch64-linux-android override: true + - name: Set up cargo cache uses: Swatinem/rust-cache@v2 + - run: cargo check --features wgpu --target aarch64-linux-android working-directory: crates/eframe + # --------------------------------------------------------------------------- + windows: name: Check Windows runs-on: windows-latest @@ -173,4 +203,3 @@ jobs: with: command: check args: --all-targets --all-features - diff --git a/crates/eframe/CHANGELOG.md b/crates/eframe/CHANGELOG.md index 8ec57b66..c2ea81e6 100644 --- a/crates/eframe/CHANGELOG.md +++ b/crates/eframe/CHANGELOG.md @@ -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)). * 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. +* `NativeOptions::transparent` now works with the wgpu backend ([#2684](https://github.com/emilk/egui/pull/2684)). #### Web: * Prevent ctrl-P/cmd-P from opening the print dialog ([#2598](https://github.com/emilk/egui/pull/2598)). diff --git a/crates/eframe/src/native/run.rs b/crates/eframe/src/native/run.rs index 8f7b8d0c..a68fa3c9 100644 --- a/crates/eframe/src/native/run.rs +++ b/crates/eframe/src/native/run.rs @@ -958,6 +958,7 @@ mod wgpu_integration { self.native_options.wgpu_options.clone(), self.native_options.multisampling.max(1) as _, self.native_options.depth_buffer, + self.native_options.transparent, ); pollster::block_on(painter.set_window(Some(&window)))?; painter diff --git a/crates/egui-wgpu/CHANGELOG.md b/crates/egui-wgpu/CHANGELOG.md index b187497b..7126f970 100644 --- a/crates/egui-wgpu/CHANGELOG.md +++ b/crates/egui-wgpu/CHANGELOG.md @@ -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)). * `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)). +* `winit::Painter` now supports transparent backbuffer ([#2684](https://github.com/emilk/egui/pull/2684)). ## 0.20.0 - 2022-12-08 - web support diff --git a/crates/egui-wgpu/src/winit.rs b/crates/egui-wgpu/src/winit.rs index d10f1194..c6ef22b8 100644 --- a/crates/egui-wgpu/src/winit.rs +++ b/crates/egui-wgpu/src/winit.rs @@ -1,14 +1,14 @@ use std::sync::Arc; -use tracing::error; -use wgpu::{Adapter, Instance, Surface}; - use epaint::mutex::RwLock; +use tracing::error; + use crate::{renderer, RenderState, Renderer, SurfaceErrorAction, WgpuConfiguration}; struct SurfaceState { - surface: Surface, + surface: wgpu::Surface, + alpha_mode: wgpu::CompositeAlphaMode, width: u32, height: u32, } @@ -19,11 +19,12 @@ struct SurfaceState { pub struct Painter { configuration: WgpuConfiguration, msaa_samples: u32, + support_transparent_backbuffer: bool, depth_format: Option, depth_texture_view: Option, - instance: Instance, - adapter: Option, + instance: wgpu::Instance, + adapter: Option, render_state: Option, surface_state: Option, } @@ -41,7 +42,12 @@ impl Painter { /// [`set_window()`](Self::set_window) once you have /// a [`winit::window::Window`] with a valid `.raw_window_handle()` /// 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 { backends: configuration.backends, dx12_shader_compiler: Default::default(), // @@ -50,6 +56,7 @@ impl Painter { Self { configuration, msaa_samples, + support_transparent_backbuffer, depth_format: (depth_bits > 0).then_some(wgpu::TextureFormat::Depth32Float), depth_texture_view: None, @@ -69,7 +76,7 @@ impl Painter { async fn init_render_state( &self, - adapter: &Adapter, + adapter: &wgpu::Adapter, target_format: wgpu::TextureFormat, ) -> Result { adapter @@ -94,7 +101,7 @@ impl Painter { // will have the same format and so this render state will remain valid. async fn ensure_render_state_for_surface( &mut self, - surface: &Surface, + surface: &wgpu::Surface, ) -> Result<(), wgpu::RequestDeviceError> { if self.adapter.is_none() { self.adapter = self @@ -121,34 +128,23 @@ impl Painter { Ok(()) } - fn configure_surface(&mut self, width_in_pixels: u32, height_in_pixels: u32) { - crate::profile_function!(); - - let render_state = self - .render_state - .as_ref() - .expect("Render state should exist before surface configuration"); - let format = render_state.target_format; - - let config = wgpu::SurfaceConfiguration { - usage: wgpu::TextureUsages::RENDER_ATTACHMENT, - format, - width: width_in_pixels, - height: height_in_pixels, - present_mode: self.configuration.present_mode, - alpha_mode: wgpu::CompositeAlphaMode::Auto, - view_formats: vec![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; + fn configure_surface( + surface_state: &SurfaceState, + render_state: &RenderState, + present_mode: wgpu::PresentMode, + ) { + surface_state.surface.configure( + &render_state.device, + &wgpu::SurfaceConfiguration { + usage: wgpu::TextureUsages::RENDER_ATTACHMENT, + format: render_state.target_format, + width: surface_state.width, + height: surface_state.height, + present_mode, + alpha_mode: surface_state.alpha_mode, + view_formats: vec![render_state.target_format], + }, + ); } /// 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?; + 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 width = size.width; - let height = size.height; self.surface_state = Some(SurfaceState { surface, - width, - height, + width: size.width, + 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 => { self.surface_state = None; @@ -221,10 +236,17 @@ impl Painter { width_in_pixels: u32, height_in_pixels: u32, ) { - self.configure_surface(width_in_pixels, height_in_pixels); - let device = &self.render_state.as_ref().unwrap().device; + let render_state = self.render_state.as_ref().unwrap(); + 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| { - device + render_state + .device .create_texture(&wgpu::TextureDescriptor { label: Some("egui_depth_texture"), size: wgpu::Extent3d { @@ -269,7 +291,6 @@ impl Painter { Some(rs) => rs, None => return, }; - let (width, height) = (surface_state.width, surface_state.height); let output_frame = { crate::profile_scope!("get_current_texture"); @@ -282,7 +303,11 @@ impl Painter { #[allow(clippy::single_match_else)] Err(e) => match (*self.configuration.on_surface_error)(e) { SurfaceErrorAction::RecreateSurface => { - self.configure_surface(width, height); + Self::configure_surface( + surface_state, + render_state, + self.configuration.present_mode, + ); return; } SurfaceErrorAction::SkipFrame => { @@ -300,7 +325,7 @@ impl Painter { // Upload all resources for the GPU. let screen_descriptor = renderer::ScreenDescriptor { - size_in_pixels: [width, height], + size_in_pixels: [surface_state.width, surface_state.height], pixels_per_point, };