diff --git a/crates/anyrender_skia/src/image_renderer.rs b/crates/anyrender_skia/src/image_renderer.rs index 10f8de9..a521e22 100644 --- a/crates/anyrender_skia/src/image_renderer.rs +++ b/crates/anyrender_skia/src/image_renderer.rs @@ -64,6 +64,7 @@ impl ImageRenderer for SkiaImageRenderer { draw_fn(&mut SkiaScenePainter { inner: surface.canvas(), cache: &mut self.scene_cache, + base_color: Color::WHITE, }); timer.record_time("render"); @@ -89,6 +90,7 @@ impl ImageRenderer for SkiaImageRenderer { draw_fn(&mut SkiaScenePainter { inner: surface.canvas(), cache: &mut self.scene_cache, + base_color: Color::WHITE, }); timer.record_time("render"); diff --git a/crates/anyrender_skia/src/scene.rs b/crates/anyrender_skia/src/scene.rs index 2dabd4e..107bf2f 100644 --- a/crates/anyrender_skia/src/scene.rs +++ b/crates/anyrender_skia/src/scene.rs @@ -54,6 +54,7 @@ impl Default for SkiaSceneCache { pub struct SkiaScenePainter<'a> { pub(crate) inner: &'a Canvas, pub(crate) cache: &'a mut SkiaSceneCache, + pub(crate) base_color: Color, } impl SkiaScenePainter<'_> { @@ -364,7 +365,7 @@ impl SkiaScenePainter<'_> { impl PaintScene for SkiaScenePainter<'_> { fn reset(&mut self) { - self.inner.clear(Color::WHITE); + self.inner.clear(self.base_color); } fn push_layer( diff --git a/crates/anyrender_skia/src/window_renderer.rs b/crates/anyrender_skia/src/window_renderer.rs index c6e3df4..0bdb987 100644 --- a/crates/anyrender_skia/src/window_renderer.rs +++ b/crates/anyrender_skia/src/window_renderer.rs @@ -25,6 +25,7 @@ struct ActiveRenderState { pub struct SkiaWindowRenderer { render_state: RenderState, + base_color: Color, } impl Default for SkiaWindowRenderer { @@ -37,6 +38,14 @@ impl SkiaWindowRenderer { pub fn new() -> Self { Self { render_state: RenderState::Suspended, + base_color: Color::WHITE, + } + } + pub fn with_base_color(base_color: peniko::Color) -> Self { + let base_color = base_color.to_rgba8(); + Self { + render_state: RenderState::Suspended, + base_color: Color::from_argb(base_color.a, base_color.r, base_color.g, base_color.b), } } } @@ -92,11 +101,12 @@ impl WindowRenderer for SkiaWindowRenderer { }; surface.canvas().restore_to_count(1); - surface.canvas().clear(Color::WHITE); + surface.canvas().clear(self.base_color); draw_fn(&mut SkiaScenePainter { inner: surface.canvas(), cache: &mut state.scene_cache, + base_color: self.base_color, }); timer.record_time("cmd"); diff --git a/crates/anyrender_vello/src/window_renderer.rs b/crates/anyrender_vello/src/window_renderer.rs index 886aae5..a688c97 100644 --- a/crates/anyrender_vello/src/window_renderer.rs +++ b/crates/anyrender_vello/src/window_renderer.rs @@ -128,6 +128,12 @@ impl WindowRenderer for VelloWindowRenderer { } fn resume(&mut self, window_handle: Arc, width: u32, height: u32) { + let alpha_mode = if self.config.base_color.components[3] < 1.0 { + wgpu::CompositeAlphaMode::PreMultiplied + } else { + wgpu::CompositeAlphaMode::Auto + }; + // Create wgpu_context::SurfaceRenderer let render_surface = pollster::block_on(self.wgpu_context.create_surface( window_handle.clone(), @@ -138,7 +144,7 @@ impl WindowRenderer for VelloWindowRenderer { height, present_mode: PresentMode::AutoVsync, desired_maximum_frame_latency: 2, - alpha_mode: wgpu::CompositeAlphaMode::Auto, + alpha_mode, view_formats: vec![], }, Some(TextureConfiguration { diff --git a/crates/wgpu_context/src/surface_renderer.rs b/crates/wgpu_context/src/surface_renderer.rs index 4fb46a6..e649438 100644 --- a/crates/wgpu_context/src/surface_renderer.rs +++ b/crates/wgpu_context/src/surface_renderer.rs @@ -2,7 +2,8 @@ use crate::{DeviceHandle, WgpuContextError, util::create_texture}; use wgpu::{ CommandEncoderDescriptor, CompositeAlphaMode, Device, PresentMode, Queue, Surface, SurfaceConfiguration, SurfaceTexture, TextureFormat, TextureUsages, TextureView, - TextureViewDescriptor, util::TextureBlitter, + TextureViewDescriptor, + util::{TextureBlitter, TextureBlitterBuilder}, }; #[derive(Clone)] @@ -126,6 +127,22 @@ impl<'s> SurfaceRenderer<'s> { view_formats: surface_renderer_config.view_formats, }; + // `TextureBlitter::new` only does post-multiplied alpha + let blitter = if surface_renderer_config.alpha_mode == CompositeAlphaMode::PreMultiplied { + TextureBlitterBuilder::new(&device_handle.device, surface_config.format) + .blend_state(wgpu::BlendState { + alpha: wgpu::BlendComponent::REPLACE, + color: wgpu::BlendComponent { + src_factor: wgpu::BlendFactor::SrcAlpha, + dst_factor: wgpu::BlendFactor::Zero, + operation: wgpu::BlendOperation::Add, + }, + }) + .build() + } else { + TextureBlitter::new(&device_handle.device, surface_config.format) + }; + let intermediate_texture = intermediate_texture_config.map(|texture_config| { Box::new(IntermediateTextureStuff { config: texture_config.clone(), @@ -136,7 +153,7 @@ impl<'s> SurfaceRenderer<'s> { texture_config.usage, &device_handle.device, ), - blitter: TextureBlitter::new(&device_handle.device, surface_config.format), + blitter, }) });