Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Incremental rendering #811

Merged
merged 71 commits into from
Sep 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
b00e670
feat: WIP Incremental rendering
marc2332 Aug 8, 2024
41f6880
chore: Clean up
marc2332 Aug 10, 2024
72b8dbd
feat: Layer-based incremental rendering
marc2332 Aug 11, 2024
c3fff31
chore: Improvements
marc2332 Aug 12, 2024
486a12c
chore: Render modified and affected nodes only
marc2332 Aug 14, 2024
d17bb7c
chore: Clean up resizing
marc2332 Aug 14, 2024
2961956
chore: Bug fixes
marc2332 Aug 14, 2024
4ce7dd5
feat: Consider the area of removed nodes, and modified nodes of the p…
marc2332 Aug 15, 2024
def2043
chore: Add missing mocked skia apis
marc2332 Aug 15, 2024
9bd031e
fix: Make draw mocked method public
marc2332 Aug 15, 2024
260c7ce
refactor: Clean up a lot of code
marc2332 Aug 15, 2024
34de233
refactor: Move size conversion of freya-renderer to a trait
marc2332 Aug 15, 2024
9ecd61e
fix: Clear canvas before drawing from dirty surface
marc2332 Aug 15, 2024
16f3387
fix: Small fixes and improvements
marc2332 Aug 15, 2024
34a5c46
chore: Minor code clean up
marc2332 Aug 15, 2024
004ed40
fix: Use actual window config background color for canvas clearing
marc2332 Aug 15, 2024
0e363c2
fix: Add missing `new_surface_with_dimensions` skia mocked method
marc2332 Aug 15, 2024
044ae3b
refactor: Refactor ParagraphElements
marc2332 Aug 15, 2024
08b0cd4
fix: Fix rendering of layers
marc2332 Aug 15, 2024
a51604f
fix: Add missing mocked `Isize` struct of skia
marc2332 Aug 15, 2024
ce1fd3b
chore: Revert some examples
marc2332 Aug 15, 2024
f614b93
fix: fix Isize mocking
marc2332 Aug 15, 2024
795d12e
fix: fix Isize mocking
marc2332 Aug 15, 2024
88a4975
fix: Safely get the area of removed nodes from torin upon removing
marc2332 Aug 15, 2024
e3271f7
refactor: Fixes and improvements
marc2332 Aug 15, 2024
7e8d7d5
chore: Improve tracing integration
marc2332 Aug 15, 2024
a79a91e
chore: Code cleanup
marc2332 Aug 15, 2024
4cc1f64
chore: Doc comment
marc2332 Aug 15, 2024
c395f8a
fix: fix vscode config feature tracing
marc2332 Aug 15, 2024
c53da82
fix: cargo fmt
marc2332 Aug 15, 2024
3c30136
fix: Make Isize mocked struct public
marc2332 Aug 15, 2024
a09d6b4
chore: Basic unit test for compositor
marc2332 Aug 15, 2024
a51d56c
chore: Remove println from test
marc2332 Aug 15, 2024
af0e966
chore: 1 less call to mutex lock
marc2332 Aug 15, 2024
14bf1d1
feat: Basic support for shadows and border for incremental rendering
marc2332 Aug 16, 2024
d04cc91
refactor: Try to clean up the code
marc2332 Aug 16, 2024
9d89cad
refactor: More clean up
marc2332 Aug 16, 2024
692fae2
chore: mocked bounds method of Path
marc2332 Aug 16, 2024
e2ab85e
perf: hot path
marc2332 Aug 16, 2024
7e7f01c
perf: small improvement
marc2332 Aug 17, 2024
80a6557
chore: mocked getters fo Rect
marc2332 Aug 17, 2024
90a4d44
chore: Some tracing clean up
marc2332 Aug 17, 2024
074a72b
feat: Incremental rendering for text with shadows (pain)
marc2332 Aug 17, 2024
71f1a7c
chore: Fixes and clean up
marc2332 Aug 17, 2024
e07ba04
chore: Small tweaks
marc2332 Aug 18, 2024
334a25d
feat: make use_canvas actually work
marc2332 Aug 18, 2024
d57d8a4
fix: Render cursor properly
marc2332 Aug 18, 2024
ce347e2
feat: Support rotated elements
marc2332 Aug 18, 2024
22412d2
correctness improvement
marc2332 Aug 19, 2024
3df62e4
Merge branch 'main' of https://github.com/marc2332/freya into feat/in…
marc2332 Aug 19, 2024
1117603
tweaks
marc2332 Aug 19, 2024
dc85f14
feat: opacity and and rotate support
marc2332 Aug 20, 2024
c79ceaf
refactor: RenderPipeline
marc2332 Aug 20, 2024
4438c06
chore: Simplify code, wip
marc2332 Aug 20, 2024
212ecd9
fix: Render to the dirty canvas
marc2332 Aug 21, 2024
02a88ce
clean up
marc2332 Aug 21, 2024
5451cfd
shadow tests
marc2332 Aug 21, 2024
890f65c
chore: Simplify tests
marc2332 Aug 21, 2024
ed8cd84
chore: Calculate expanded area of rotated elements by using the layou…
marc2332 Aug 22, 2024
1e4b200
feat: `mark-incremental-render-areas` feature
marc2332 Aug 22, 2024
bdced12
feat: consider viewports when expanding the dirty area
marc2332 Aug 23, 2024
daf1391
chore: Just comments
marc2332 Aug 25, 2024
55714e9
feat: Use the actual text font height to invalidate the areas of text…
marc2332 Aug 29, 2024
bc11356
chore: Resolve conflicts
marc2332 Sep 1, 2024
fa15ab4
fix: Mock `get_style_metrics`
marc2332 Sep 1, 2024
0bdea44
chore: Remov extra slash in doc comment
marc2332 Sep 1, 2024
e4d73f9
fix: Update mock `get_style_metrics`
marc2332 Sep 1, 2024
f956a40
chore: Fix font metrics mocked api
marc2332 Sep 1, 2024
7d7f972
feat: More tests and bug fixes
marc2332 Sep 1, 2024
2ad420e
Merge branch 'main' into feat/incremental-rendering
marc2332 Sep 7, 2024
f607535
chore: Revert some unnecessary changes on the examples
marc2332 Sep 7, 2024
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
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"rust-analyzer.cargo.features": [
"devtools",
"log",
"tracing-subscriber",
"use_camera"
]
}
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ edition = "2021"
members = ["crates/renderer", "crates/state", "crates/freya", "crates/elements", "crates/components", "crates/hooks", "crates/common", "crates/core", "crates/testing", "crates/devtools", "crates/torin", "crates/engine", "./examples/installer", "crates/native-core", "crates/native-core-macro"]

[features]
log = ["freya/log"]
tracing-subscriber = ["freya/tracing-subscriber"]
devtools = ["freya/devtools"]
use_camera = ["freya/use_camera"]
hot-reload = ["freya/hot-reload"]
custom-tokio-rt = ["freya/custom-tokio-rt"]
performance-overlay = ["freya/performance-overlay"]
fade-cached-incremental-areas = ["freya/fade-cached-incremental-areas"]

[patch.crates-io]
# dioxus = { git = "https://github.com/DioxusLabs/dioxus", rev = "7beacdf9c76ae5412d3c2bcd55f7c5d87f486a0f" }
Expand Down
8 changes: 8 additions & 0 deletions crates/common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,12 @@ freya-engine = { workspace = true }
freya-native-core = { workspace = true }
rustc-hash= { workspace = true }

itertools = "0.13.0"
uuid = { workspace = true }


[dev-dependencies]
dioxus = { workspace = true }
freya = { path = "../freya" }
freya-testing = { path = "../testing" }
tokio = { workspace = true }
31 changes: 31 additions & 0 deletions crates/common/src/compositor_dirty_nodes.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use std::ops::{
Deref,
DerefMut,
};

use freya_native_core::NodeId;
use rustc_hash::FxHashSet;

#[derive(Clone, Default, Debug)]
pub struct CompositorDirtyNodes(FxHashSet<NodeId>);

impl Deref for CompositorDirtyNodes {
type Target = FxHashSet<NodeId>;

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl DerefMut for CompositorDirtyNodes {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}

impl CompositorDirtyNodes {
/// Mark a certain node as invalidated.
pub fn invalidate(&mut self, node_id: NodeId) {
self.0.insert(node_id);
}
}
47 changes: 28 additions & 19 deletions crates/common/src/layers.rs
Original file line number Diff line number Diff line change
@@ -1,39 +1,48 @@
use std::sync::{
Arc,
Mutex,
MutexGuard,
use std::{
self,
ops::{
Deref,
DerefMut,
},
};

use freya_native_core::NodeId;
use rustc_hash::FxHashMap;

#[derive(Default, Clone)]
pub struct Layers {
pub layers: Arc<Mutex<FxHashMap<i16, Vec<NodeId>>>>,
}
#[derive(Default, Clone, Debug, PartialEq)]
pub struct Layers(FxHashMap<i16, Vec<NodeId>>);

impl Layers {
pub fn insert_node_in_layer(&self, node_id: NodeId, layer_n: i16) {
let mut layers = self.layers.lock().unwrap();
let layer = layers.entry(layer_n).or_default();
/// Insert the given [NodeId] in the given layer. Will create an entry for the layer if missing.
pub fn insert_node_in_layer(&mut self, node_id: NodeId, layer_n: i16) {
let layer = self.0.entry(layer_n).or_default();
if layer.contains(&node_id) {
return;
}
layer.push(node_id);
}

pub fn remove_node_from_layer(&self, node_id: NodeId, layer_n: i16) {
let mut layers = self.layers.lock().unwrap();
let layer = layers.get_mut(&layer_n).unwrap();
/// Remove the [NodeId] from the given layer. Will remove the entry of the layer if it becomes empty.
pub fn remove_node_from_layer(&mut self, node_id: NodeId, layer_n: i16) {
let layer = self.0.get_mut(&layer_n).unwrap();
layer.retain(|id| *id != node_id);

if layer.is_empty() {
layers.remove(&layer_n);
self.0.remove(&layer_n);
}
}
}

pub fn layers(&self) -> MutexGuard<FxHashMap<i16, Vec<NodeId>>> {
self.layers.lock().unwrap()
impl Deref for Layers {
type Target = FxHashMap<i16, Vec<NodeId>>;

fn deref(&self) -> &Self::Target {
&self.0
}
}

pub fn len_layers(&self) -> usize {
self.layers.lock().unwrap().len()
impl DerefMut for Layers {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
2 changes: 1 addition & 1 deletion crates/common/src/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ pub enum CursorLayoutResponse {
TextSelection { from: usize, to: usize, id: usize },
}

pub struct CachedParagraph(pub Paragraph);
pub struct CachedParagraph(pub Paragraph, pub f32);

/// # Safety
/// Skia `Paragraph` are neither Sync or Send, but in order to store them in the Associated
Expand Down
2 changes: 2 additions & 0 deletions crates/common/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
mod compositor_dirty_nodes;
mod layers;
mod layout;
mod paragraphs;

pub use compositor_dirty_nodes::*;
pub use layers::*;
pub use layout::*;
pub use paragraphs::*;
44 changes: 24 additions & 20 deletions crates/common/src/paragraphs.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use std::sync::{
Arc,
Mutex,
MutexGuard,
use std::{
self,
ops::{
Deref,
DerefMut,
},
};

use freya_native_core::NodeId;
Expand All @@ -12,36 +14,38 @@ use rustc_hash::{
use uuid::Uuid;

#[derive(Default, Clone)]
pub struct ParagraphElements {
pub paragraphs: Arc<Mutex<FxHashMap<Uuid, FxHashSet<NodeId>>>>,
}
pub struct ParagraphElements(FxHashMap<Uuid, FxHashSet<NodeId>>);

impl ParagraphElements {
pub fn insert_paragraph(&self, node_id: NodeId, text_id: Uuid) {
let mut paragraphs = self.paragraphs.lock().unwrap();
let text_group = paragraphs.entry(text_id).or_default();
pub fn insert_paragraph(&mut self, node_id: NodeId, text_id: Uuid) {
let text_group = self.0.entry(text_id).or_default();

text_group.insert(node_id);
}

pub fn paragraphs(&self) -> MutexGuard<FxHashMap<Uuid, FxHashSet<NodeId>>> {
self.paragraphs.lock().unwrap()
}

pub fn remove_paragraph(&self, node_id: NodeId, text_id: &Uuid) {
let mut paragraphs = self.paragraphs.lock().unwrap();
let text_group = paragraphs.get_mut(text_id);
pub fn remove_paragraph(&mut self, node_id: NodeId, text_id: &Uuid) {
let text_group = self.0.get_mut(text_id);

if let Some(text_group) = text_group {
text_group.retain(|id| *id != node_id);

if text_group.is_empty() {
paragraphs.remove(text_id);
self.0.remove(text_id);
}
}
}
}

impl Deref for ParagraphElements {
type Target = FxHashMap<Uuid, FxHashSet<NodeId>>;

fn deref(&self) -> &Self::Target {
&self.0
}
}

pub fn len_paragraphs(&self) -> usize {
self.paragraphs.lock().unwrap().len()
impl DerefMut for ParagraphElements {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
9 changes: 5 additions & 4 deletions crates/components/src/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use freya_engine::prelude::*;
use freya_hooks::{
use_applied_theme,
use_canvas_with_deps,
use_node_signal,
use_platform,
GraphTheme,
GraphThemeWith,
Expand Down Expand Up @@ -45,13 +46,12 @@ pub struct GraphProps {
#[allow(non_snake_case)]
pub fn Graph(props: GraphProps) -> Element {
let platform = use_platform();
let (reference, size) = use_node_signal();
let GraphTheme { width, height } = use_applied_theme!(&props.theme, graph);

use_effect(use_reactive(&props, move |_| {
let canvas = use_canvas_with_deps(&props, move |props| {
platform.invalidate_drawing_area(size.peek().area);
platform.request_animation_frame();
}));

let canvas = use_canvas_with_deps(&props, |props| {
Box::new(move |ctx: &mut CanvasRunnerContext| {
ctx.canvas.translate((ctx.area.min_x(), ctx.area.min_y()));

Expand Down Expand Up @@ -165,6 +165,7 @@ pub fn Graph(props: GraphProps) -> Element {
background: "white",
rect {
canvas_reference: canvas.attribute(),
reference,
width: "100%",
height: "100%",
}
Expand Down
7 changes: 4 additions & 3 deletions crates/components/src/slider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ use freya_hooks::{
use_platform,
SliderThemeWith,
};
use tracing::info;
use winit::window::CursorIcon;

/// Properties for the [`Slider`] component.
Expand All @@ -33,10 +32,12 @@ pub struct SliderProps {
#[inline]
fn ensure_correct_slider_range(value: f64) -> f64 {
if value < 0.0 {
info!("Slider value is less than 0.0, setting to 0.0");
#[cfg(debug_assertions)]
tracing::info!("Slider value is less than 0.0, setting to 0.0");
0.0
} else if value > 100.0 {
info!("Slider value is greater than 100.0, setting to 100.0");
#[cfg(debug_assertions)]
tracing::info!("Slider value is greater than 100.0, setting to 100.0");
100.0
} else {
value
Expand Down
1 change: 1 addition & 0 deletions crates/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ features = ["freya-engine/mocked-engine"]
[features]
shared = []
skia-engine = ["freya-engine/skia-engine"]
fade-cached-incremental-areas = []

[dependencies]
freya-node-state = { workspace = true }
Expand Down
Loading
Loading