Skip to content
Merged
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
62 changes: 62 additions & 0 deletions graphics/src/mesh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ use crate::gradient;

use bytemuck::{Pod, Zeroable};

use std::sync::atomic::{self, AtomicU64};
use std::sync::{Arc, Weak};

/// A low-level primitive to render a mesh of triangles.
#[derive(Debug, Clone, PartialEq)]
pub enum Mesh {
Expand Down Expand Up @@ -141,8 +144,67 @@ pub fn attribute_count_of(meshes: &[Mesh]) -> AttributeCount {
})
}

/// A cache of multiple meshes.
#[derive(Debug, Clone)]
pub struct Cache {
id: Id,
batch: Arc<[Mesh]>,
version: usize,
}

/// The unique id of a [`Cache`].
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Id(u64);

impl Cache {
/// Creates a new [`Cache`] for the given meshes.
pub fn new(meshes: Arc<[Mesh]>) -> Self {
static NEXT_ID: AtomicU64 = AtomicU64::new(0);

Self {
id: Id(NEXT_ID.fetch_add(1, atomic::Ordering::Relaxed)),
batch: meshes,
version: 0,
}
}

/// Returns the [`Id`] of the [`Cache`].
pub fn id(&self) -> Id {
self.id
}

/// Returns the current version of the [`Cache`].
pub fn version(&self) -> usize {
self.version
}

/// Returns the batch of meshes in the [`Cache`].
pub fn batch(&self) -> &[Mesh] {
&self.batch
}

/// Returns a [`Weak`] reference to the contents of the [`Cache`].
pub fn downgrade(&self) -> Weak<[Mesh]> {
Arc::downgrade(&self.batch)
}

/// Returns true if the [`Cache`] is empty.
pub fn is_empty(&self) -> bool {
self.batch.is_empty()
}

/// Updates the [`Cache`] with the given meshes.
pub fn update(&mut self, meshes: Arc<[Mesh]>) {
self.batch = meshes;
self.version += 1;
}
}

/// A renderer capable of drawing a [`Mesh`].
pub trait Renderer {
/// Draws the given [`Mesh`].
fn draw_mesh(&mut self, mesh: Mesh);

/// Draws the given [`Cache`].
fn draw_mesh_cache(&mut self, cache: Cache);
}
4 changes: 4 additions & 0 deletions renderer/src/fallback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,10 @@ where
fn draw_mesh(&mut self, mesh: graphics::Mesh) {
delegate!(self, renderer, renderer.draw_mesh(mesh));
}

fn draw_mesh_cache(&mut self, cache: mesh::Cache) {
delegate!(self, renderer, renderer.draw_mesh_cache(cache));
}
}

/// A compositor `A` with a fallback strategy `B`.
Expand Down
4 changes: 4 additions & 0 deletions tiny_skia/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,10 @@ impl graphics::mesh::Renderer for Renderer {
fn draw_mesh(&mut self, _mesh: graphics::Mesh) {
log::warn!("iced_tiny_skia does not support drawing meshes");
}

fn draw_mesh_cache(&mut self, _cache: iced_graphics::mesh::Cache) {
log::warn!("iced_tiny_skia does not support drawing meshes");
}
}

#[cfg(feature = "image")]
Expand Down
17 changes: 13 additions & 4 deletions wgpu/src/geometry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ use crate::graphics::gradient::{self, Gradient};
use crate::graphics::mesh::{self, Mesh};
use crate::graphics::{Image, Text};
use crate::text;
use crate::triangle;

use lyon::geom::euclid;
use lyon::tessellation;
Expand All @@ -33,7 +32,7 @@ pub enum Geometry {

#[derive(Debug, Clone, Default)]
pub struct Cache {
pub meshes: Option<triangle::Cache>,
pub meshes: Option<mesh::Cache>,
pub images: Option<Arc<[Image]>>,
pub text: Option<text::Cache>,
}
Expand Down Expand Up @@ -62,11 +61,17 @@ impl Cached for Geometry {
Some(Arc::from(images))
};

let meshes = Arc::from(meshes);

if let Some(mut previous) = previous {
if let Some(cache) = &mut previous.meshes {
cache.update(meshes);
} else {
previous.meshes = triangle::Cache::new(meshes);
previous.meshes = if meshes.is_empty() {
None
} else {
Some(mesh::Cache::new(meshes))
};
}

if let Some(cache) = &mut previous.text {
Expand All @@ -80,7 +85,11 @@ impl Cached for Geometry {
previous
} else {
Cache {
meshes: triangle::Cache::new(meshes),
meshes: if meshes.is_empty() {
None
} else {
Some(mesh::Cache::new(meshes))
},
images,
text: text::Cache::new(group, text),
}
Expand Down
3 changes: 2 additions & 1 deletion wgpu/src/layer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use crate::graphics;
use crate::graphics::Mesh;
use crate::graphics::color;
use crate::graphics::layer;
use crate::graphics::mesh;
use crate::graphics::text::{Editor, Paragraph};
use crate::image::{self, Image};
use crate::primitive::{self, Primitive};
Expand Down Expand Up @@ -230,7 +231,7 @@ impl Layer {

pub fn draw_mesh_cache(
&mut self,
cache: triangle::Cache,
cache: mesh::Cache,
transformation: Transformation,
) {
self.flush_meshes();
Expand Down
6 changes: 6 additions & 0 deletions wgpu/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ use crate::core::renderer;
use crate::core::{
Background, Color, Font, Pixels, Point, Rectangle, Size, Transformation,
};
use crate::graphics::mesh;
use crate::graphics::text::{Editor, Paragraph};
use crate::graphics::{Shell, Viewport};

Expand Down Expand Up @@ -845,6 +846,11 @@ impl graphics::mesh::Renderer for Renderer {
let (layer, transformation) = self.layers.current_mut();
layer.draw_mesh(mesh, transformation);
}

fn draw_mesh_cache(&mut self, cache: mesh::Cache) {
let (layer, transformation) = self.layers.current_mut();
layer.draw_mesh_cache(cache, transformation);
}
}

#[cfg(feature = "geometry")]
Expand Down
70 changes: 19 additions & 51 deletions wgpu/src/triangle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ use crate::graphics::mesh::{self, Mesh};

use rustc_hash::FxHashMap;
use std::collections::hash_map;
use std::sync::atomic::{self, AtomicU64};
use std::sync::{self, Arc};
use std::sync::Weak;

const INITIAL_INDEX_COUNT: usize = 1_000;
const INITIAL_VERTEX_COUNT: usize = 1_000;
Expand All @@ -24,65 +23,34 @@ pub enum Item {
},
Cached {
transformation: Transformation,
cache: Cache,
cache: mesh::Cache,
},
}

#[derive(Debug, Clone)]
pub struct Cache {
id: Id,
batch: Arc<[Mesh]>,
version: usize,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Id(u64);

impl Cache {
pub fn new(meshes: Vec<Mesh>) -> Option<Self> {
static NEXT_ID: AtomicU64 = AtomicU64::new(0);

if meshes.is_empty() {
return None;
}

Some(Self {
id: Id(NEXT_ID.fetch_add(1, atomic::Ordering::Relaxed)),
batch: Arc::from(meshes),
version: 0,
})
}

pub fn update(&mut self, meshes: Vec<Mesh>) {
self.batch = Arc::from(meshes);
self.version += 1;
}
}

#[derive(Debug)]
struct Upload {
layer: Layer,
transformation: Transformation,
version: usize,
batch: sync::Weak<[Mesh]>,
batch: Weak<[Mesh]>,
}

#[derive(Debug, Default)]
pub struct Storage {
uploads: FxHashMap<Id, Upload>,
uploads: FxHashMap<mesh::Id, Upload>,
}

impl Storage {
pub fn new() -> Self {
Self::default()
}

fn get(&self, cache: &Cache) -> Option<&Upload> {
if cache.batch.is_empty() {
fn get(&self, cache: &mesh::Cache) -> Option<&Upload> {
if cache.is_empty() {
return None;
}

self.uploads.get(&cache.id)
self.uploads.get(&cache.id())
}

fn prepare(
Expand All @@ -92,15 +60,15 @@ impl Storage {
belt: &mut wgpu::util::StagingBelt,
solid: &solid::Pipeline,
gradient: &gradient::Pipeline,
cache: &Cache,
cache: &mesh::Cache,
new_transformation: Transformation,
) {
match self.uploads.entry(cache.id) {
match self.uploads.entry(cache.id()) {
hash_map::Entry::Occupied(entry) => {
let upload = entry.into_mut();

if !cache.batch.is_empty()
&& (upload.version != cache.version
if !cache.is_empty()
&& (upload.version != cache.version()
|| upload.transformation != new_transformation)
{
upload.layer.prepare(
Expand All @@ -109,12 +77,12 @@ impl Storage {
belt,
solid,
gradient,
&cache.batch,
cache.batch(),
new_transformation,
);

upload.batch = Arc::downgrade(&cache.batch);
upload.version = cache.version;
upload.batch = cache.downgrade();
upload.version = cache.version();
upload.transformation = new_transformation;
}
}
Expand All @@ -127,20 +95,20 @@ impl Storage {
belt,
solid,
gradient,
&cache.batch,
cache.batch(),
new_transformation,
);

let _ = entry.insert(Upload {
layer,
transformation: new_transformation,
version: 0,
batch: Arc::downgrade(&cache.batch),
batch: cache.downgrade(),
});

log::debug!(
"New mesh upload: {} (total: {})",
cache.id.0,
"New mesh upload: {:?} (total: {})",
cache.id(),
self.uploads.len()
);
}
Expand Down Expand Up @@ -278,7 +246,7 @@ impl State {

Some((
&upload.layer,
&cache.batch,
cache.batch(),
screen_transformation * *transformation,
))
}
Expand Down
Loading