♻️ Refactor surfaces (wasm)

This commit is contained in:
Belén Albeza 2025-02-21 12:09:00 +01:00
parent 80d5272248
commit 5ebfc603e6
6 changed files with 171 additions and 160 deletions

View file

@ -19,7 +19,7 @@ use crate::shapes::{Corners, Shape, Type};
use cache::CachedSurfaceImage; use cache::CachedSurfaceImage;
use gpu_state::GpuState; use gpu_state::GpuState;
use options::RenderOptions; use options::RenderOptions;
use surfaces::Surfaces; use surfaces::{SurfaceId, Surfaces};
pub use blend::BlendMode; pub use blend::BlendMode;
pub use images::*; pub use images::*;
@ -56,7 +56,6 @@ pub(crate) struct RenderState {
gpu_state: GpuState, gpu_state: GpuState,
pub options: RenderOptions, pub options: RenderOptions,
pub surfaces: Surfaces, pub surfaces: Surfaces,
pub sampling_options: skia::SamplingOptions,
pub font_provider: skia::textlayout::TypefaceFontProvider, pub font_provider: skia::textlayout::TypefaceFontProvider,
pub cached_surface_image: Option<CachedSurfaceImage>, pub cached_surface_image: Option<CachedSurfaceImage>,
pub viewbox: Viewbox, pub viewbox: Viewbox,
@ -75,7 +74,10 @@ impl RenderState {
pub fn new(width: i32, height: i32) -> RenderState { pub fn new(width: i32, height: i32) -> RenderState {
// This needs to be done once per WebGL context. // This needs to be done once per WebGL context.
let mut gpu_state = GpuState::new(); let mut gpu_state = GpuState::new();
let surfaces = Surfaces::new(&mut gpu_state, (width, height));
let sampling_options =
skia::SamplingOptions::new(skia::FilterMode::Linear, skia::MipmapMode::Nearest);
let surfaces = Surfaces::new(&mut gpu_state, (width, height), sampling_options);
let mut font_provider = skia::textlayout::TypefaceFontProvider::new(); let mut font_provider = skia::textlayout::TypefaceFontProvider::new();
let default_font = skia::FontMgr::default() let default_font = skia::FontMgr::default()
.new_from_data(DEFAULT_FONT_BYTES, None) .new_from_data(DEFAULT_FONT_BYTES, None)
@ -84,15 +86,12 @@ impl RenderState {
// This is used multiple times everywhere so instead of creating new instances every // This is used multiple times everywhere so instead of creating new instances every
// time we reuse this one. // time we reuse this one.
let sampling_options =
skia::SamplingOptions::new(skia::FilterMode::Linear, skia::MipmapMode::Nearest);
RenderState { RenderState {
gpu_state, gpu_state,
surfaces, surfaces,
cached_surface_image: None, cached_surface_image: None,
font_provider, font_provider,
sampling_options,
options: RenderOptions::default(), options: RenderOptions::default(),
viewbox: Viewbox::new(width as f32, height as f32), viewbox: Viewbox::new(width as f32, height as f32),
images: ImageStore::new(), images: ImageStore::new(),
@ -150,88 +149,64 @@ impl RenderState {
} }
pub fn flush(&mut self) { pub fn flush(&mut self) {
self.gpu_state self.surfaces
.context .flush_and_submit(&mut self.gpu_state, SurfaceId::Target);
.flush_and_submit_surface(&mut self.surfaces.target, None);
} }
pub fn reset_canvas(&mut self) { pub fn reset_canvas(&mut self) {
self.surfaces.shape.canvas().restore_to_count(1); self.surfaces.canvas(SurfaceId::Shape).restore_to_count(1);
self.surfaces.current.canvas().restore_to_count(1); self.surfaces.canvas(SurfaceId::Current).restore_to_count(1);
self.surfaces self.surfaces
.shape .canvas(SurfaceId::Shape)
.canvas()
.clear(self.background_color) .clear(self.background_color)
.reset_matrix(); .reset_matrix();
self.surfaces self.surfaces
.current .canvas(SurfaceId::Current)
.canvas()
.clear(self.background_color) .clear(self.background_color)
.reset_matrix(); .reset_matrix();
self.surfaces self.surfaces
.shadow .canvas(SurfaceId::Shadow)
.canvas()
.clear(self.background_color) .clear(self.background_color)
.reset_matrix(); .reset_matrix();
self.surfaces self.surfaces
.overlay .canvas(SurfaceId::Overlay)
.canvas()
.clear(self.background_color) .clear(self.background_color)
.reset_matrix(); .reset_matrix();
self.surfaces self.surfaces
.debug .canvas(SurfaceId::Debug)
.canvas()
.clear(skia::Color::TRANSPARENT) .clear(skia::Color::TRANSPARENT)
.reset_matrix(); .reset_matrix();
} }
pub fn apply_render_to_final_canvas(&mut self) { pub fn apply_render_to_final_canvas(&mut self) {
self.surfaces.current.draw( self.surfaces
&mut self.surfaces.target.canvas(), .draw_into(SurfaceId::Current, SurfaceId::Target, None);
(0.0, 0.0),
self.sampling_options,
Some(&skia::Paint::default()),
);
} }
pub fn apply_drawing_to_render_canvas(&mut self) { pub fn apply_drawing_to_render_canvas(&mut self) {
self.gpu_state self.surfaces
.context .flush_and_submit(&mut self.gpu_state, SurfaceId::Shape);
.flush_and_submit_surface(&mut self.surfaces.shape, None); self.surfaces
.draw_into(SurfaceId::Shape, SurfaceId::Current, None);
self.surfaces.shape.draw(
&mut self.surfaces.current.canvas(),
(0.0, 0.0),
self.sampling_options,
Some(&skia::Paint::default()),
);
self.gpu_state
.context
.flush_and_submit_surface(&mut self.surfaces.current, None);
self.gpu_state
.context
.flush_and_submit_surface(&mut self.surfaces.overlay, None);
self.surfaces.overlay.draw(
&mut self.surfaces.current.canvas(),
(0.0, 0.0),
self.sampling_options,
None,
);
self.surfaces self.surfaces
.shadow .flush_and_submit(&mut self.gpu_state, SurfaceId::Current);
.canvas() self.surfaces
.flush_and_submit(&mut self.gpu_state, SurfaceId::Overlay);
self.surfaces
.draw_into(SurfaceId::Overlay, SurfaceId::Current, None);
self.surfaces
.canvas(SurfaceId::Shadow)
.clear(skia::Color::TRANSPARENT); .clear(skia::Color::TRANSPARENT);
self.surfaces self.surfaces
.overlay .canvas(SurfaceId::Overlay)
.canvas()
.clear(skia::Color::TRANSPARENT); .clear(skia::Color::TRANSPARENT);
self.surfaces.shape.canvas().clear(skia::Color::TRANSPARENT); self.surfaces
.canvas(SurfaceId::Shape)
.clear(skia::Color::TRANSPARENT);
} }
pub fn invalidate_cache_if_needed(&mut self) { pub fn invalidate_cache_if_needed(&mut self) {
@ -246,20 +221,22 @@ impl RenderState {
modifiers: Option<&Matrix>, modifiers: Option<&Matrix>,
clip_bounds: Option<(Rect, Option<Corners>, Matrix)>, clip_bounds: Option<(Rect, Option<Corners>, Matrix)>,
) { ) {
self.surfaces.shape.canvas().save(); self.surfaces.canvas(SurfaceId::Shape).save();
if let Some((bounds, corners, transform)) = clip_bounds { if let Some((bounds, corners, transform)) = clip_bounds {
self.surfaces.shape.canvas().concat(&transform); self.surfaces.canvas(SurfaceId::Shape).concat(&transform);
if let Some(corners) = corners { if let Some(corners) = corners {
let rrect = RRect::new_rect_radii(bounds, &corners); let rrect = RRect::new_rect_radii(bounds, &corners);
self.surfaces self.surfaces.canvas(SurfaceId::Shape).clip_rrect(
.shape rrect,
.canvas() skia::ClipOp::Intersect,
.clip_rrect(rrect, skia::ClipOp::Intersect, true); true,
);
} else { } else {
self.surfaces self.surfaces.canvas(SurfaceId::Shape).clip_rect(
.shape bounds,
.canvas() skia::ClipOp::Intersect,
.clip_rect(bounds, skia::ClipOp::Intersect, true); true,
);
} }
if self.options.is_debug_visible() { if self.options.is_debug_visible() {
@ -267,12 +244,13 @@ impl RenderState {
paint.set_style(skia::PaintStyle::Stroke); paint.set_style(skia::PaintStyle::Stroke);
paint.set_color(skia::Color::from_argb(255, 255, 0, 0)); paint.set_color(skia::Color::from_argb(255, 255, 0, 0));
paint.set_stroke_width(4.); paint.set_stroke_width(4.);
self.surfaces.shape.canvas().draw_rect(bounds, &paint); self.surfaces
.canvas(SurfaceId::Shape)
.draw_rect(bounds, &paint);
} }
self.surfaces self.surfaces
.shape .canvas(SurfaceId::Shape)
.canvas()
.concat(&transform.invert().unwrap_or(Matrix::default())); .concat(&transform.invert().unwrap_or(Matrix::default()));
} }
@ -292,17 +270,17 @@ impl RenderState {
match &shape.shape_type { match &shape.shape_type {
Type::SVGRaw(sr) => { Type::SVGRaw(sr) => {
if let Some(modifiers) = modifiers { if let Some(modifiers) = modifiers {
self.surfaces.shape.canvas().concat(&modifiers); self.surfaces.canvas(SurfaceId::Shape).concat(&modifiers);
} }
self.surfaces.shape.canvas().concat(&matrix); self.surfaces.canvas(SurfaceId::Shape).concat(&matrix);
if let Some(svg) = shape.svg.as_ref() { if let Some(svg) = shape.svg.as_ref() {
svg.render(self.surfaces.shape.canvas()) svg.render(self.surfaces.canvas(SurfaceId::Shape))
} else { } else {
let font_manager = skia::FontMgr::from(self.font_provider.clone()); let font_manager = skia::FontMgr::from(self.font_provider.clone());
let dom_result = skia::svg::Dom::from_str(sr.content.to_string(), font_manager); let dom_result = skia::svg::Dom::from_str(sr.content.to_string(), font_manager);
match dom_result { match dom_result {
Ok(dom) => { Ok(dom) => {
dom.render(self.surfaces.shape.canvas()); dom.render(self.surfaces.canvas(SurfaceId::Shape));
shape.set_svg(dom); shape.set_svg(dom);
} }
Err(e) => { Err(e) => {
@ -312,7 +290,7 @@ impl RenderState {
} }
} }
_ => { _ => {
self.surfaces.shape.canvas().concat(&matrix); self.surfaces.canvas(SurfaceId::Shape).concat(&matrix);
for fill in shape.fills().rev() { for fill in shape.fills().rev() {
fills::render(self, &shape, fill); fills::render(self, &shape, fill);
@ -341,7 +319,7 @@ impl RenderState {
}; };
self.apply_drawing_to_render_canvas(); self.apply_drawing_to_render_canvas();
self.surfaces.shape.canvas().restore(); self.surfaces.canvas(SurfaceId::Shape).restore();
} }
pub fn start_render_loop( pub fn start_render_loop(
@ -356,13 +334,12 @@ impl RenderState {
} }
} }
self.reset_canvas(); self.reset_canvas();
self.surfaces.shape.canvas().scale(( self.surfaces.canvas(SurfaceId::Shape).scale((
self.viewbox.zoom * self.options.dpr(), self.viewbox.zoom * self.options.dpr(),
self.viewbox.zoom * self.options.dpr(), self.viewbox.zoom * self.options.dpr(),
)); ));
self.surfaces self.surfaces
.shape .canvas(SurfaceId::Shape)
.canvas()
.translate((self.viewbox.pan_x, self.viewbox.pan_y)); .translate((self.viewbox.pan_x, self.viewbox.pan_y));
// //
self.pending_nodes = vec![NodeRenderState { self.pending_nodes = vec![NodeRenderState {
@ -423,7 +400,7 @@ impl RenderState {
.map_or(true, |img| img.invalid) .map_or(true, |img| img.invalid)
{ {
self.cached_surface_image = Some(CachedSurfaceImage { self.cached_surface_image = Some(CachedSurfaceImage {
image: self.surfaces.current.image_snapshot(), image: self.surfaces.snapshot(SurfaceId::Current),
viewbox: self.viewbox, viewbox: self.viewbox,
invalid: false, invalid: false,
has_all_shapes: self.render_complete, has_all_shapes: self.render_complete,
@ -452,29 +429,29 @@ impl RenderState {
let image = &cached.image; let image = &cached.image;
let paint = skia::Paint::default(); let paint = skia::Paint::default();
self.surfaces.target.canvas().save(); self.surfaces.canvas(SurfaceId::Target).save();
self.surfaces.shape.canvas().save(); self.surfaces.canvas(SurfaceId::Shape).save();
let navigate_zoom = self.viewbox.zoom / cached.viewbox.zoom; let navigate_zoom = self.viewbox.zoom / cached.viewbox.zoom;
let navigate_x = cached.viewbox.zoom * (self.viewbox.pan_x - cached.viewbox.pan_x); let navigate_x = cached.viewbox.zoom * (self.viewbox.pan_x - cached.viewbox.pan_x);
let navigate_y = cached.viewbox.zoom * (self.viewbox.pan_y - cached.viewbox.pan_y); let navigate_y = cached.viewbox.zoom * (self.viewbox.pan_y - cached.viewbox.pan_y);
self.surfaces self.surfaces
.target .canvas(SurfaceId::Target)
.canvas()
.scale((navigate_zoom, navigate_zoom)); .scale((navigate_zoom, navigate_zoom));
self.surfaces.target.canvas().translate(( self.surfaces.canvas(SurfaceId::Target).translate((
navigate_x * self.options.dpr(), navigate_x * self.options.dpr(),
navigate_y * self.options.dpr(), navigate_y * self.options.dpr(),
)); ));
self.surfaces.target.canvas().clear(self.background_color);
self.surfaces self.surfaces
.target .canvas(SurfaceId::Target)
.canvas() .clear(self.background_color);
self.surfaces
.canvas(SurfaceId::Target)
.draw_image(image, (0, 0), Some(&paint)); .draw_image(image, (0, 0), Some(&paint));
self.surfaces.target.canvas().restore(); self.surfaces.canvas(SurfaceId::Target).restore();
self.surfaces.shape.canvas().restore(); self.surfaces.canvas(SurfaceId::Shape).restore();
self.flush(); self.flush();
@ -495,7 +472,9 @@ impl RenderState {
if group.masked { if group.masked {
let paint = skia::Paint::default(); let paint = skia::Paint::default();
let layer_rec = skia::canvas::SaveLayerRec::default().paint(&paint); let layer_rec = skia::canvas::SaveLayerRec::default().paint(&paint);
self.surfaces.current.canvas().save_layer(&layer_rec); self.surfaces
.canvas(SurfaceId::Current)
.save_layer(&layer_rec);
} }
} }
_ => {} _ => {}
@ -512,7 +491,9 @@ impl RenderState {
let mut mask_paint = skia::Paint::default(); let mut mask_paint = skia::Paint::default();
mask_paint.set_blend_mode(skia::BlendMode::DstIn); mask_paint.set_blend_mode(skia::BlendMode::DstIn);
let mask_rec = skia::canvas::SaveLayerRec::default().paint(&mask_paint); let mask_rec = skia::canvas::SaveLayerRec::default().paint(&mask_paint);
self.surfaces.current.canvas().save_layer(&mask_rec); self.surfaces
.canvas(SurfaceId::Current)
.save_layer(&mask_rec);
} }
if let Some(image_filter) = element.image_filter(self.viewbox.zoom * self.options.dpr()) { if let Some(image_filter) = element.image_filter(self.viewbox.zoom * self.options.dpr()) {
@ -520,7 +501,9 @@ impl RenderState {
} }
let layer_rec = skia::canvas::SaveLayerRec::default().paint(&paint); let layer_rec = skia::canvas::SaveLayerRec::default().paint(&paint);
self.surfaces.current.canvas().save_layer(&layer_rec); self.surfaces
.canvas(SurfaceId::Current)
.save_layer(&layer_rec);
} }
pub fn render_shape_exit(&mut self, element: &mut Shape, visited_mask: bool) { pub fn render_shape_exit(&mut self, element: &mut Shape, visited_mask: bool) {
@ -531,13 +514,13 @@ impl RenderState {
match element.shape_type { match element.shape_type {
Type::Group(group) => { Type::Group(group) => {
if group.masked { if group.masked {
self.surfaces.current.canvas().restore(); self.surfaces.canvas(SurfaceId::Current).restore();
} }
} }
_ => {} _ => {}
} }
} }
self.surfaces.current.canvas().restore(); self.surfaces.canvas(SurfaceId::Current).restore();
} }
pub fn render_shape_tree( pub fn render_shape_tree(

View file

@ -1,7 +1,7 @@
use crate::shapes::Shape; use crate::shapes::Shape;
use skia_safe as skia; use skia_safe as skia;
use super::RenderState; use super::{RenderState, SurfaceId};
fn render_debug_view(render_state: &mut RenderState) { fn render_debug_view(render_state: &mut RenderState) {
let mut paint = skia::Paint::default(); let mut paint = skia::Paint::default();
@ -18,13 +18,12 @@ fn render_debug_view(render_state: &mut RenderState) {
render_state render_state
.surfaces .surfaces
.debug .canvas(SurfaceId::Debug)
.canvas()
.draw_rect(scaled_rect, &paint); .draw_rect(scaled_rect, &paint);
} }
pub fn render_wasm_label(render_state: &mut RenderState) { pub fn render_wasm_label(render_state: &mut RenderState) {
let canvas = render_state.surfaces.current.canvas(); let canvas = render_state.surfaces.canvas(SurfaceId::Current);
let skia::ISize { width, height } = canvas.base_layer_size(); let skia::ISize { width, height } = canvas.base_layer_size();
let p = skia::Point::new(width as f32 - 100.0, height as f32 - 25.0); let p = skia::Point::new(width as f32 - 100.0, height as f32 - 25.0);
@ -59,18 +58,13 @@ pub fn render_debug_shape(render_state: &mut RenderState, element: &Shape, inter
render_state render_state
.surfaces .surfaces
.debug .canvas(SurfaceId::Debug)
.canvas()
.draw_rect(scaled_rect, &paint); .draw_rect(scaled_rect, &paint);
} }
pub fn render(render_state: &mut RenderState) { pub fn render(render_state: &mut RenderState) {
let paint = skia::Paint::default();
render_debug_view(render_state); render_debug_view(render_state);
render_state.surfaces.debug.draw( render_state
&mut render_state.surfaces.current.canvas(), .surfaces
(0.0, 0.0), .draw_into(SurfaceId::Debug, SurfaceId::Current, None);
render_state.sampling_options,
Some(&paint),
);
} }

View file

@ -1,8 +1,8 @@
use crate::shapes::{Fill, ImageFill, Shape, Type};
use skia_safe::{self as skia, RRect}; use skia_safe::{self as skia, RRect};
use super::RenderState; use super::{RenderState, SurfaceId};
use crate::math::Rect; use crate::math::Rect;
use crate::shapes::{Fill, ImageFill, Shape, Type};
fn draw_image_fill_in_container( fn draw_image_fill_in_container(
render_state: &mut RenderState, render_state: &mut RenderState,
@ -16,7 +16,7 @@ fn draw_image_fill_in_container(
} }
let size = image_fill.size(); let size = image_fill.size();
let canvas = render_state.surfaces.shape.canvas(); let canvas = render_state.surfaces.canvas(SurfaceId::Shape);
let container = &shape.selrect; let container = &shape.selrect;
let path_transform = shape.to_path_transform(); let path_transform = shape.to_path_transform();
let paint = fill.to_paint(container); let paint = fill.to_paint(container);
@ -96,7 +96,7 @@ fn draw_image_fill_in_container(
* This SHOULD be the only public function in this module. * This SHOULD be the only public function in this module.
*/ */
pub fn render(render_state: &mut RenderState, shape: &Shape, fill: &Fill) { pub fn render(render_state: &mut RenderState, shape: &Shape, fill: &Fill) {
let canvas = render_state.surfaces.shape.canvas(); let canvas = render_state.surfaces.canvas(SurfaceId::Shape);
let selrect = shape.selrect; let selrect = shape.selrect;
let path_transform = shape.to_path_transform(); let path_transform = shape.to_path_transform();

View file

@ -1,51 +1,37 @@
use skia_safe::{self as skia}; use skia_safe::{self as skia};
use super::RenderState; use super::{RenderState, SurfaceId};
use crate::shapes::Shadow; use crate::shapes::Shadow;
pub fn render_drop_shadow(render_state: &mut RenderState, shadow: &Shadow, scale: f32) { pub fn render_drop_shadow(render_state: &mut RenderState, shadow: &Shadow, scale: f32) {
let shadow_paint = shadow.to_paint(scale); let shadow_paint = shadow.to_paint(scale);
render_state.surfaces.shape.draw( render_state
&mut render_state.surfaces.shadow.canvas(), .surfaces
(0.0, 0.0), .draw_into(SurfaceId::Shape, SurfaceId::Shadow, Some(&shadow_paint));
render_state.sampling_options,
Some(&shadow_paint),
);
render_state.surfaces.shadow.draw(
&mut render_state.surfaces.current.canvas(),
(0.0, 0.0),
render_state.sampling_options,
Some(&skia::Paint::default()),
);
render_state render_state
.surfaces .surfaces
.shadow .draw_into(SurfaceId::Shadow, SurfaceId::Current, None);
.canvas()
render_state
.surfaces
.canvas(SurfaceId::Shadow)
.clear(skia::Color::TRANSPARENT); .clear(skia::Color::TRANSPARENT);
} }
pub fn render_inner_shadow(render_state: &mut RenderState, shadow: &Shadow, scale: f32) { pub fn render_inner_shadow(render_state: &mut RenderState, shadow: &Shadow, scale: f32) {
let shadow_paint = shadow.to_paint(scale); let shadow_paint = shadow.to_paint(scale);
render_state.surfaces.shape.draw( render_state
render_state.surfaces.shadow.canvas(), .surfaces
(0.0, 0.0), .draw_into(SurfaceId::Shape, SurfaceId::Shadow, Some(&shadow_paint)); // , ShadowPaint
render_state.sampling_options,
Some(&shadow_paint),
);
render_state.surfaces.shadow.draw(
&mut render_state.surfaces.overlay.canvas(),
(0.0, 0.0),
render_state.sampling_options,
None,
);
render_state render_state
.surfaces .surfaces
.shadow .draw_into(SurfaceId::Shadow, SurfaceId::Overlay, None); // , None
.canvas()
render_state
.surfaces
.canvas(SurfaceId::Shadow)
.clear(skia::Color::TRANSPARENT); .clear(skia::Color::TRANSPARENT);
} }

View file

@ -5,7 +5,7 @@ use crate::math::{Matrix, Point, Rect};
use crate::shapes::{Corners, Fill, ImageFill, Path, Shape, Stroke, StrokeCap, StrokeKind, Type}; use crate::shapes::{Corners, Fill, ImageFill, Path, Shape, Stroke, StrokeCap, StrokeKind, Type};
use skia_safe::{self as skia, RRect}; use skia_safe::{self as skia, RRect};
use super::RenderState; use super::{RenderState, SurfaceId};
fn draw_stroke_on_rect( fn draw_stroke_on_rect(
canvas: &skia::Canvas, canvas: &skia::Canvas,
@ -330,7 +330,7 @@ fn draw_image_stroke_in_container(
} }
let size = image_fill.size(); let size = image_fill.size();
let canvas = render_state.surfaces.shape.canvas(); let canvas = render_state.surfaces.canvas(SurfaceId::Shape);
let container = &shape.selrect; let container = &shape.selrect;
let path_transform = shape.to_path_transform(); let path_transform = shape.to_path_transform();
let svg_attrs = &shape.svg_attrs; let svg_attrs = &shape.svg_attrs;
@ -432,7 +432,7 @@ fn draw_image_stroke_in_container(
* This SHOULD be the only public function in this module. * This SHOULD be the only public function in this module.
*/ */
pub fn render(render_state: &mut RenderState, shape: &Shape, stroke: &Stroke) { pub fn render(render_state: &mut RenderState, shape: &Shape, stroke: &Stroke) {
let canvas = render_state.surfaces.shape.canvas(); let canvas = render_state.surfaces.canvas(SurfaceId::Shape);
let dpr_scale = render_state.viewbox.zoom * render_state.options.dpr(); let dpr_scale = render_state.viewbox.zoom * render_state.options.dpr();
let selrect = shape.selrect; let selrect = shape.selrect;
let path_transform = shape.to_path_transform(); let path_transform = shape.to_path_transform();

View file

@ -1,23 +1,38 @@
use super::gpu_state::GpuState; use super::gpu_state::GpuState;
use skia_safe as skia; use skia_safe as skia;
pub enum SurfaceId {
Target,
Current,
Shape,
Shadow,
Overlay,
Debug,
}
pub struct Surfaces { pub struct Surfaces {
// is the final destination surface, the one that it is represented in the canvas element. // is the final destination surface, the one that it is represented in the canvas element.
pub target: skia::Surface, target: skia::Surface,
// keeps the current render // keeps the current render
pub current: skia::Surface, current: skia::Surface,
// keeps the current shape // keeps the current shape
pub shape: skia::Surface, shape: skia::Surface,
// used for rendering shadows // used for rendering shadows
pub shadow: skia::Surface, shadow: skia::Surface,
// for drawing the things that are over shadows. // for drawing the things that are over shadows.
pub overlay: skia::Surface, overlay: skia::Surface,
// for drawing debug info. // for drawing debug info.
pub debug: skia::Surface, debug: skia::Surface,
sampling_options: skia::SamplingOptions,
} }
impl Surfaces { impl Surfaces {
pub fn new(gpu_state: &mut GpuState, (width, height): (i32, i32)) -> Self { pub fn new(
gpu_state: &mut GpuState,
(width, height): (i32, i32),
sampling_options: skia::SamplingOptions,
) -> Self {
let mut target = gpu_state.create_target_surface(width, height); let mut target = gpu_state.create_target_surface(width, height);
let current = target.new_surface_with_dimensions((width, height)).unwrap(); let current = target.new_surface_with_dimensions((width, height)).unwrap();
let shadow = target.new_surface_with_dimensions((width, height)).unwrap(); let shadow = target.new_surface_with_dimensions((width, height)).unwrap();
@ -32,20 +47,53 @@ impl Surfaces {
overlay, overlay,
shape, shape,
debug, debug,
sampling_options,
} }
} }
pub fn set(&mut self, new_surface: skia::Surface) { pub fn resize(&mut self, gpu_state: &mut GpuState, new_width: i32, new_height: i32) {
let dim = (new_surface.width(), new_surface.height()); self.reset_from_target(gpu_state.create_target_surface(new_width, new_height));
self.target = new_surface; }
pub fn snapshot(&mut self, id: SurfaceId) -> skia::Image {
self.get_mut(id).image_snapshot()
}
pub fn canvas(&mut self, id: SurfaceId) -> &skia::Canvas {
self.get_mut(id).canvas()
}
pub fn flush_and_submit(&mut self, gpu_state: &mut GpuState, id: SurfaceId) {
let surface = self.get_mut(id);
gpu_state.context.flush_and_submit_surface(surface, None);
}
pub fn draw_into(&mut self, from: SurfaceId, to: SurfaceId, paint: Option<&skia::Paint>) {
let sampling_options = self.sampling_options;
self.get_mut(from)
.clone()
.draw(self.canvas(to), (0.0, 0.0), sampling_options, paint);
}
fn get_mut(&mut self, id: SurfaceId) -> &mut skia::Surface {
match id {
SurfaceId::Target => &mut self.target,
SurfaceId::Current => &mut self.current,
SurfaceId::Shadow => &mut self.shadow,
SurfaceId::Overlay => &mut self.overlay,
SurfaceId::Shape => &mut self.shape,
SurfaceId::Debug => &mut self.debug,
}
}
fn reset_from_target(&mut self, target: skia::Surface) {
let dim = (target.width(), target.height());
self.target = target;
self.current = self.target.new_surface_with_dimensions(dim).unwrap(); self.current = self.target.new_surface_with_dimensions(dim).unwrap();
self.overlay = self.target.new_surface_with_dimensions(dim).unwrap(); self.overlay = self.target.new_surface_with_dimensions(dim).unwrap();
self.shadow = self.target.new_surface_with_dimensions(dim).unwrap(); self.shadow = self.target.new_surface_with_dimensions(dim).unwrap();
self.shape = self.target.new_surface_with_dimensions(dim).unwrap(); self.shape = self.target.new_surface_with_dimensions(dim).unwrap();
self.debug = self.target.new_surface_with_dimensions(dim).unwrap(); self.debug = self.target.new_surface_with_dimensions(dim).unwrap();
} }
pub fn resize(&mut self, gpu_state: &mut GpuState, new_width: i32, new_height: i32) {
self.set(gpu_state.create_target_surface(new_width, new_height));
}
} }