Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 21 additions & 3 deletions crates/anyrender/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,17 @@ pub trait RenderContext {
}
}

pub enum Backdrop {
Preserve,
Clear(Color),
}

impl Default for Backdrop {
fn default() -> Self {
Self::Clear(Color::TRANSPARENT)
}
}

/// Abstraction for rendering a scene to a window
pub trait WindowRenderer: RenderContext {
type ScenePainter<'a>: PaintScene
Expand Down Expand Up @@ -149,7 +160,7 @@ pub trait WindowRenderer: RenderContext {
false
}
fn set_size(&mut self, width: u32, height: u32);
fn render<F: FnOnce(&mut Self::ScenePainter<'_>)>(&mut self, draw_fn: F);
fn render<F: FnOnce(&mut Self::ScenePainter<'_>)>(&mut self, backdrop: Backdrop, draw_fn: F);
}

/// Abstraction for rendering a scene to an image buffer
Expand All @@ -162,21 +173,28 @@ pub trait ImageRenderer: RenderContext {
fn reset(&mut self);
fn render_to_vec<F: FnOnce(&mut Self::ScenePainter<'_>)>(
&mut self,
backdrop: Backdrop,
draw_fn: F,
vec: &mut Vec<u8>,
);
fn render<F: FnOnce(&mut Self::ScenePainter<'_>)>(&mut self, draw_fn: F, buffer: &mut [u8]);
fn render<F: FnOnce(&mut Self::ScenePainter<'_>)>(
&mut self,
backdrop: Backdrop,
draw_fn: F,
buffer: &mut [u8],
);
}

/// Draw a scene to a buffer using an `ImageRenderer`
pub fn render_to_buffer<R: ImageRenderer, F: FnOnce(&mut R::ScenePainter<'_>)>(
backdrop: Backdrop,
draw_fn: F,
width: u32,
height: u32,
) -> Vec<u8> {
let mut buf = Vec::with_capacity((width * height * 4) as usize);
let mut renderer = R::new(width, height);
renderer.render_to_vec(draw_fn, &mut buf);
renderer.render_to_vec(backdrop, draw_fn, &mut buf);

buf
}
Expand Down
16 changes: 13 additions & 3 deletions crates/anyrender/src/null_backend.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
//! A dummy implementation of the AnyRender traits while simply ignores all commands

use crate::{Filter, ImageRenderer, PaintScene, RenderContext, WindowHandle, WindowRenderer};
use crate::{
Backdrop, Filter, ImageRenderer, PaintScene, RenderContext, WindowHandle, WindowRenderer,
};
use std::sync::Arc;

#[derive(Copy, Clone, Default)]
Expand Down Expand Up @@ -46,7 +48,8 @@ impl WindowRenderer for NullWindowRenderer {

fn set_size(&mut self, _width: u32, _height: u32) {}

fn render<F: FnOnce(&mut Self::ScenePainter<'_>)>(&mut self, _draw_fn: F) {}
fn render<F: FnOnce(&mut Self::ScenePainter<'_>)>(&mut self, _backdrop: Backdrop, _draw_fn: F) {
}
}

#[derive(Copy, Clone, Default)]
Expand Down Expand Up @@ -75,12 +78,19 @@ impl ImageRenderer for NullImageRenderer {

fn render_to_vec<F: FnOnce(&mut Self::ScenePainter<'_>)>(
&mut self,
_backdrop: Backdrop,
_draw_fn: F,
_vec: &mut Vec<u8>,
) {
}

fn render<F: FnOnce(&mut Self::ScenePainter<'_>)>(&mut self, _draw_fn: F, _buffer: &mut [u8]) {}
fn render<F: FnOnce(&mut Self::ScenePainter<'_>)>(
&mut self,
_backdrop: Backdrop,
_draw_fn: F,
_buffer: &mut [u8],
) {
}
}

#[derive(Copy, Clone, Default)]
Expand Down
26 changes: 19 additions & 7 deletions crates/anyrender_skia/src/image_renderer.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use anyrender::{ImageRenderer, RenderContext};
use anyrender::{Backdrop, ImageRenderer, RenderContext};
use debug_timer::debug_timer;
use skia_safe::{AlphaType, Color, ColorType, ImageInfo, SurfaceProps, graphics, surfaces};
use skia_safe::{AlphaType, ColorType, ImageInfo, SurfaceProps, graphics, surfaces};

use crate::{SkiaScenePainter, scene::SkiaSceneCache};

Expand Down Expand Up @@ -47,6 +47,7 @@ impl ImageRenderer for SkiaImageRenderer {

fn render_to_vec<F: FnOnce(&mut Self::ScenePainter<'_>)>(
&mut self,
backdrop: Backdrop,
draw_fn: F,
buffer: &mut Vec<u8>,
) {
Expand All @@ -62,8 +63,11 @@ impl ImageRenderer for SkiaImageRenderer {
)
.unwrap();

// Clear surface with transparent background to allow transparency in rendered images
surface.canvas().clear(Color::TRANSPARENT);
if let Backdrop::Clear(color) = backdrop {
surface
.canvas()
.clear(crate::scene::sk_peniko::color4f_from_alpha_color(color));
}

draw_fn(&mut SkiaScenePainter {
inner: surface.canvas(),
Expand All @@ -77,7 +81,12 @@ impl ImageRenderer for SkiaImageRenderer {
timer.print_times("skia_raster: ");
}

fn render<F: FnOnce(&mut Self::ScenePainter<'_>)>(&mut self, draw_fn: F, buffer: &mut [u8]) {
fn render<F: FnOnce(&mut Self::ScenePainter<'_>)>(
&mut self,
backdrop: Backdrop,
draw_fn: F,
buffer: &mut [u8],
) {
debug_timer!(timer, feature = "log_frame_times");

let mut surface = surfaces::wrap_pixels(
Expand All @@ -88,8 +97,11 @@ impl ImageRenderer for SkiaImageRenderer {
)
.unwrap();

// Clear surface with transparent background to allow transparency in rendered images
surface.canvas().clear(Color::TRANSPARENT);
if let Backdrop::Clear(color) = backdrop {
surface
.canvas()
.clear(crate::scene::sk_peniko::color4f_from_alpha_color(color));
}

draw_fn(&mut SkiaScenePainter {
inner: surface.canvas(),
Expand Down
4 changes: 2 additions & 2 deletions crates/anyrender_skia/src/scene.rs
Original file line number Diff line number Diff line change
Expand Up @@ -917,7 +917,7 @@ fn distant_light_direction(light: &DistantLightSource) -> Point3 {
)
}

mod sk_peniko {
pub(crate) mod sk_peniko {
use peniko::color::{AlphaColor, ColorSpaceTag, HueDirection, Srgb};
use peniko::{
BlendMode, Compose, Extend, Gradient, GradientKind, ImageAlphaType, ImageBrush, ImageData,
Expand Down Expand Up @@ -1140,7 +1140,7 @@ mod sk_peniko {
}
}

pub(super) fn color4f_from_alpha_color(color: AlphaColor<Srgb>) -> SkColor4f {
pub(crate) fn color4f_from_alpha_color(color: AlphaColor<Srgb>) -> SkColor4f {
SkColor4f::new(
color.components[0],
color.components[1],
Expand Down
23 changes: 8 additions & 15 deletions crates/anyrender_skia/src/window_renderer.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use anyrender::{RenderContext, WindowRenderer};
use anyrender::{Backdrop, RenderContext, WindowRenderer};
use debug_timer::debug_timer;
use skia_safe::{Color, Surface, graphics};
use skia_safe::{Surface, graphics};
use std::any::Any;
use std::sync::Arc;

Expand Down Expand Up @@ -28,8 +28,6 @@ struct ActiveRenderState {
#[derive(Debug, Clone)]
#[non_exhaustive]
pub struct SkiaRendererOptions {
/// Background color used to clear the canvas.
pub base_color: Color,
/// Alpha mode used when compositing the window surface.
pub composite_alpha_mode: anyrender::CompositeAlphaMode,
}
Expand All @@ -43,15 +41,10 @@ impl Default for SkiaRendererOptions {
impl SkiaRendererOptions {
pub const fn new() -> Self {
Self {
base_color: Color::WHITE,
composite_alpha_mode: anyrender::CompositeAlphaMode::Auto,
}
}

pub const fn base_color(self, base_color: Color) -> Self {
Self { base_color, ..self }
}

pub const fn composite_alpha_mode(
self,
composite_alpha_mode: anyrender::CompositeAlphaMode,
Expand All @@ -66,10 +59,6 @@ impl SkiaRendererOptions {
impl From<anyrender::RendererConfig> for SkiaRendererOptions {
fn from(config: anyrender::RendererConfig) -> Self {
let mut options = Self::default();
if let Some(color) = config.base_color {
let rgba8 = color.to_rgba8();
options.base_color = skia_safe::Color::from_argb(rgba8.a, rgba8.r, rgba8.g, rgba8.b);
}
if let Some(mode) = config.composite_alpha_mode {
options.composite_alpha_mode = mode;
}
Expand Down Expand Up @@ -163,7 +152,7 @@ impl WindowRenderer for SkiaWindowRenderer {
}
}

fn render<F: FnOnce(&mut Self::ScenePainter<'_>)>(&mut self, draw_fn: F) {
fn render<F: FnOnce(&mut Self::ScenePainter<'_>)>(&mut self, backdrop: Backdrop, draw_fn: F) {
let RenderState::Active(state) = &mut self.render_state else {
return;
};
Expand All @@ -176,7 +165,11 @@ impl WindowRenderer for SkiaWindowRenderer {
};

surface.canvas().restore_to_count(1);
surface.canvas().clear(self.options.base_color);
if let Backdrop::Clear(color) = backdrop {
surface
.canvas()
.clear(crate::scene::sk_peniko::color4f_from_alpha_color(color));
}

draw_fn(&mut SkiaScenePainter {
inner: surface.canvas(),
Expand Down
31 changes: 27 additions & 4 deletions crates/anyrender_vello/src/image_renderer.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use anyrender::{ImageRenderer, RenderContext, ResourceId};
use anyrender::{Backdrop, ImageRenderer, RenderContext, ResourceId};
use peniko::ImageData;
use rustc_hash::FxHashMap;
use vello::{Renderer as VelloRenderer, RendererOptions, Scene as VelloScene};
Expand Down Expand Up @@ -77,16 +77,18 @@ impl ImageRenderer for VelloImageRenderer {

fn render_to_vec<F: FnOnce(&mut Self::ScenePainter<'_>)>(
&mut self,
backdrop: Backdrop,
draw_fn: F,
cpu_buffer: &mut Vec<u8>,
) {
let size = self.buffer_renderer.size();
cpu_buffer.resize((size.width * size.height * 4) as usize, 0);
self.render(draw_fn, cpu_buffer);
self.render(backdrop, draw_fn, cpu_buffer);
}

fn render<F: FnOnce(&mut Self::ScenePainter<'_>)>(
&mut self,
backdrop: Backdrop,
draw_fn: F,
cpu_buffer: &mut [u8],
) {
Expand All @@ -96,23 +98,44 @@ impl ImageRenderer for VelloImageRenderer {
device_handle: None,
texture_handles: Some(&mut self.texture_handles),
});
let texture_view = self.buffer_renderer.target_texture_view();
let backdrop_image = if matches!(backdrop, Backdrop::Preserve) {
let mut scene = VelloScene::new();
let image_data = self
.vello_renderer
.register_texture(texture_view.texture().clone());
let image = peniko::ImageBrush::new(image_data.clone());
scene.draw_image(&image, kurbo::Affine::IDENTITY);
std::mem::swap(&mut self.scene, &mut scene);
self.scene.append(&scene, None);
Some(image_data)
} else {
None
};

let size = self.buffer_renderer.size();
self.vello_renderer
.render_to_texture(
self.buffer_renderer.device(),
self.buffer_renderer.queue(),
&self.scene,
&self.buffer_renderer.target_texture_view(),
&texture_view,
&vello::RenderParams {
base_color: vello::peniko::Color::TRANSPARENT,
base_color: match backdrop {
Backdrop::Preserve => vello::peniko::Color::TRANSPARENT,
Backdrop::Clear(color) => color,
},
width: size.width,
height: size.height,
antialiasing_method: vello::AaConfig::Area,
},
)
.expect("Got non-Send/Sync error from rendering");

if let Some(image) = backdrop_image {
self.vello_renderer.unregister_texture(image);
}

self.buffer_renderer.copy_texture_to_buffer(cpu_buffer);

// Empty the Vello scene (memory optimisation)
Expand Down
Loading
Loading