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
109 changes: 102 additions & 7 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ members = [
"crates/anyrender_vello_cpu",
"crates/anyrender_vello_hybrid",
"crates/anyrender_svg",
"crates/anyrender_tiny_skia",
"crates/wgpu_context",
"crates/pixels_window_renderer",
"crates/softbuffer_window_renderer",
Expand All @@ -27,6 +28,7 @@ rust-version = "1.88.0"
# AnyRender dependencies (in-repo)
anyrender = { version = "0.7.0", path = "./crates/anyrender" }
anyrender_skia = { version = "0.4.0", path = "./crates/anyrender_skia" }
anyrender_tiny_skia = { version = "0.1.0", path = "./crates/anyrender_tiny_skia" }
anyrender_vello = { version = "0.7.0", path = "./crates/anyrender_vello" }
anyrender_vello_cpu = { version = "0.9.0", path = "./crates/anyrender_vello_cpu" }
anyrender_vello_hybrid = { version = "0.2.0", path = "./crates/anyrender_vello_hybrid" }
Expand Down Expand Up @@ -61,6 +63,7 @@ rustc-hash = "2"
futures-util = "0.3.31"
futures-intrusive = "0.5.0"
pollster = "0.4"
swash = "0.2.5"

# Dev-dependencies
winit = { version = "0.30.2", features = ["rwh_06"] }
36 changes: 36 additions & 0 deletions crates/anyrender_tiny_skia/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
[package]
name = "anyrender_tiny_skia"
description = "tiny-skia backend for anyrender"
version = "0.1.0"
documentation = "https://docs.rs/anyrender_tiny_skia"
homepage.workspace = true
repository.workspace = true
license.workspace = true
edition.workspace = true

[dependencies]
anyrender = { workspace = true }

anyhow = "1.0"
debug_timer = { workspace = true }
kurbo = { workspace = true }
peniko = { workspace = true }
tiny-skia = "0.12"
swash = { workspace = true }

# WindowRenderer backends
softbuffer_window_renderer = { workspace = true, optional = true }
pixels_window_renderer = { workspace = true, optional = true }

[features]
pixels_window_renderer = ["dep:pixels_window_renderer"]
softbuffer_window_renderer = ["dep:softbuffer_window_renderer"]
log_frame_times = [
"debug_timer/enable",
"softbuffer_window_renderer?/log_frame_times",
"pixels_window_renderer?/log_frame_times",
]

[package.metadata.docs.rs]
features = ["pixels_window_renderer", "softbuffer_window_renderer"]

93 changes: 93 additions & 0 deletions crates/anyrender_tiny_skia/src/image_renderer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
use anyrender::{ImageRenderer, PaintScene};
use debug_timer::debug_timer;
use tiny_skia::Pixmap;

use crate::TinySkiaScenePainter;

pub struct TinySkiaImageRenderer {
pub(crate) scene: TinySkiaScenePainter,
}

impl ImageRenderer for TinySkiaImageRenderer {
type ScenePainter<'a> = TinySkiaScenePainter;

fn new(width: u32, height: u32) -> Self {
Self {
scene: TinySkiaScenePainter::new(width, height),
}
}

fn resize(&mut self, width: u32, height: u32) {
if let Some(crate::scene::LayerOrClip::Layer(layer)) = self.scene.layers.get_mut(0) {
layer.pixmap = Pixmap::new(width, height).expect("Failed to create pixmap");
layer.mask = None;
}
}

fn reset(&mut self) {
self.scene.reset();
}

fn render_to_vec<F: FnOnce(&mut Self::ScenePainter<'_>)>(
&mut self,
draw_fn: F,
vec: &mut Vec<u8>,
) {
vec.clear();
if let Some(crate::scene::LayerOrClip::Layer(layer)) = self.scene.layers.first() {
vec.reserve((layer.pixmap.width() * layer.pixmap.height() * 4) as usize);
}

let painter = &mut self.scene;

painter.reset();
draw_fn(painter);

// Convert pixmap to RGBA8
if let Some(crate::scene::LayerOrClip::Layer(layer)) = self.scene.layers.first() {
for pixel in layer.pixmap.pixels() {
vec.push(pixel.red());
vec.push(pixel.green());
vec.push(pixel.blue());
vec.push(pixel.alpha());
}
}
}

fn render<F: FnOnce(&mut Self::ScenePainter<'_>)>(&mut self, draw_fn: F, buffer: &mut [u8]) {
debug_timer!(timer, feature = "log_frame_times");
let painter = &mut self.scene;
painter.reset();
draw_fn(painter);
timer.record_time("cmd");

if let Some(crate::scene::LayerOrClip::Layer(layer)) = self.scene.layers.first() {
let pixmap = &layer.pixmap;
let width = pixmap.width() as usize;
let height = pixmap.height() as usize;
let expected_len = width * height * 4;

assert!(
buffer.len() >= expected_len,
"buffer too small: {} < {}",
buffer.len(),
expected_len
);

let pixels = pixmap.pixels();

buffer[..expected_len]
.chunks_exact_mut(4)
.zip(pixels.iter())
.for_each(|(chunk, pixel)| {
chunk[0] = pixel.red();
chunk[1] = pixel.green();
chunk[2] = pixel.blue();
chunk[3] = pixel.alpha();
});
}

timer.record_time("render");
timer.print_times("tiny-skia image: ");
}
}
15 changes: 15 additions & 0 deletions crates/anyrender_tiny_skia/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//! A [`tiny skia`] backend for the [`anyrender`] 2D drawing abstraction
#![cfg_attr(docsrs, feature(doc_cfg))]

mod image_renderer;
mod scene;
mod window_renderer;

pub use image_renderer::TinySkiaImageRenderer;
pub use scene::TinySkiaScenePainter;

#[cfg(any(
feature = "pixels_window_renderer",
feature = "softbuffer_window_renderer"
))]
pub use window_renderer::*;
Loading