mirror of
https://github.com/penpot/penpot.git
synced 2025-06-05 09:21:39 +02:00
🐛 Fix TileSurfaceCache not deref surfaces
This commit is contained in:
parent
6953a57333
commit
b6ac1dea4d
2 changed files with 61 additions and 27 deletions
|
@ -451,21 +451,28 @@ impl RenderState {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// TODO: Maybe we should calculate the interest area based on the actual viewport. See how.
|
// First we retrieve the extended area of the viewport that we could render.
|
||||||
let (sx, sy, ex, ey) = tiles::get_tiles_for_viewbox_with_interest(
|
let (isx, isy, iex, iey) = tiles::get_tiles_for_viewbox_with_interest(
|
||||||
self.viewbox,
|
self.viewbox,
|
||||||
VIEWPORT_INTEREST_AREA_THRESHOLD,
|
VIEWPORT_INTEREST_AREA_THRESHOLD,
|
||||||
);
|
);
|
||||||
debug::render_debug_tiles_for_viewbox(self, sx, sy, ex, ey);
|
// Then we get the real amount of tiles rendered for the current viewbox.
|
||||||
let tile_center = ((ex - sx) / 2, (ey - sy) / 2);
|
let (sx, sy, ex, ey) = tiles::get_tiles_for_viewbox(self.viewbox);
|
||||||
|
debug::render_debug_tiles_for_viewbox(self, isx, isy, iex, iey);
|
||||||
|
let tile_center = ((iex - isx) / 2, (iey - isy) / 2);
|
||||||
self.pending_tiles = vec![];
|
self.pending_tiles = vec![];
|
||||||
self.surfaces.cache_clear_visited();
|
self.surfaces.cache_clear_visited();
|
||||||
for y in sy..=ey {
|
for y in isy..=iey {
|
||||||
for x in sx..=ex {
|
for x in isx..=iex {
|
||||||
let tile = (x, y);
|
let tile = (x, y);
|
||||||
let distance = tiles::manhattan_distance(tile, tile_center);
|
let distance = tiles::manhattan_distance(tile, tile_center);
|
||||||
self.pending_tiles.push((x, y, distance));
|
self.pending_tiles.push((x, y, distance));
|
||||||
self.surfaces.cache_visit(tile);
|
// We only need to mark as visited the visible
|
||||||
|
// tiles, the ones that are outside the viewport
|
||||||
|
// should not be rendered.
|
||||||
|
if x >= sx && x <= ex && y >= sy && y <= ey {
|
||||||
|
self.surfaces.cache_visit(tile);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.pending_nodes = vec![];
|
self.pending_nodes = vec![];
|
||||||
|
@ -851,7 +858,7 @@ impl RenderState {
|
||||||
) {
|
) {
|
||||||
for (uuid, matrix) in modifiers {
|
for (uuid, matrix) in modifiers {
|
||||||
if let Some(shape) = tree.get(uuid) {
|
if let Some(shape) = tree.get(uuid) {
|
||||||
let mut shape = shape.clone();
|
let mut shape: Shape = shape.clone();
|
||||||
shape.apply_transform(matrix);
|
shape.apply_transform(matrix);
|
||||||
self.update_tile_for(&shape);
|
self.update_tile_for(&shape);
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,7 @@ pub struct Surfaces {
|
||||||
margins: skia::ISize,
|
margins: skia::ISize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
impl Surfaces {
|
impl Surfaces {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
gpu_state: &mut GpuState,
|
gpu_state: &mut GpuState,
|
||||||
|
@ -301,6 +302,7 @@ pub struct SurfacePool {
|
||||||
pub index: usize,
|
pub index: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
impl SurfacePool {
|
impl SurfacePool {
|
||||||
pub fn with_capacity(surface: &mut skia::Surface, dims: skia::ISize, capacity: usize) -> Self {
|
pub fn with_capacity(surface: &mut skia::Surface, dims: skia::ISize, capacity: usize) -> Self {
|
||||||
let mut surfaces = Vec::with_capacity(capacity);
|
let mut surfaces = Vec::with_capacity(capacity);
|
||||||
|
@ -347,6 +349,11 @@ impl SurfacePool {
|
||||||
.surfaces
|
.surfaces
|
||||||
.get_mut(surface_ref_to_deallocate.index)
|
.get_mut(surface_ref_to_deallocate.index)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
// This could happen when the "clear" method of the pool is called.
|
||||||
|
if surface_ref.in_use == false {
|
||||||
|
return;
|
||||||
|
}
|
||||||
surface_ref.in_use = false;
|
surface_ref.in_use = false;
|
||||||
self.index = surface_ref_to_deallocate.index;
|
self.index = surface_ref_to_deallocate.index;
|
||||||
}
|
}
|
||||||
|
@ -375,6 +382,7 @@ pub struct TileSurfaceCache {
|
||||||
visited: HashMap<Tile, bool>,
|
visited: HashMap<Tile, bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
impl TileSurfaceCache {
|
impl TileSurfaceCache {
|
||||||
pub fn new(pool: SurfacePool) -> Self {
|
pub fn new(pool: SurfacePool) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
@ -388,28 +396,46 @@ impl TileSurfaceCache {
|
||||||
return self.grid.contains_key(&tile);
|
return self.grid.contains_key(&tile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn remove_list(&mut self, marked: Vec<Tile>) {
|
||||||
|
for tile in marked.iter() {
|
||||||
|
self.grid.remove(tile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_get_or_create(&mut self, tile: Tile) -> Result<skia::Surface, String> {
|
||||||
|
// TODO: I don't know yet how to improve this but I don't like it. I think
|
||||||
|
// there should be a better solution.
|
||||||
|
let mut marked = vec![];
|
||||||
|
for (tile, surface_ref) in self.grid.iter_mut() {
|
||||||
|
let exists_as_visited = self.visited.contains_key(tile);
|
||||||
|
if !exists_as_visited {
|
||||||
|
marked.push(tile.clone());
|
||||||
|
self.pool.deallocate(surface_ref);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let is_visited = self.visited.get(tile).unwrap();
|
||||||
|
if !*is_visited {
|
||||||
|
marked.push(tile.clone());
|
||||||
|
self.pool.deallocate(surface_ref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.remove_list(marked);
|
||||||
|
|
||||||
|
if let Some(surface_ref) = self.pool.allocate() {
|
||||||
|
self.grid.insert(tile, surface_ref.clone());
|
||||||
|
return Ok(surface_ref.surface.clone());
|
||||||
|
}
|
||||||
|
return Err("Not enough surfaces".into());
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_or_create(&mut self, tile: Tile) -> Result<skia::Surface, String> {
|
pub fn get_or_create(&mut self, tile: Tile) -> Result<skia::Surface, String> {
|
||||||
if let Some(surface_ref) = self.pool.allocate() {
|
if let Some(surface_ref) = self.pool.allocate() {
|
||||||
self.grid.insert(tile, surface_ref.clone());
|
self.grid.insert(tile, surface_ref.clone());
|
||||||
Ok(surface_ref.surface.clone())
|
return Ok(surface_ref.surface.clone());
|
||||||
} else {
|
|
||||||
// TODO: I don't know yet how to improve this but I don't like it. I think
|
|
||||||
// there should be a better solution.
|
|
||||||
for (tile, surface_ref) in self.grid.iter() {
|
|
||||||
if !self.visited.contains_key(tile) {
|
|
||||||
self.pool.deallocate(surface_ref);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if !self.visited.get(tile).unwrap() {
|
|
||||||
self.pool.deallocate(surface_ref);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(surface_ref) = self.pool.allocate() {
|
|
||||||
self.grid.insert(tile, surface_ref.clone());
|
|
||||||
return Ok(surface_ref.surface.clone());
|
|
||||||
}
|
|
||||||
return Err("Not enough surfaces".into());
|
|
||||||
}
|
}
|
||||||
|
self.try_get_or_create(tile)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&mut self, tile: Tile) -> Result<&mut skia::Surface, String> {
|
pub fn get(&mut self, tile: Tile) -> Result<&mut skia::Surface, String> {
|
||||||
|
@ -420,7 +446,8 @@ impl TileSurfaceCache {
|
||||||
if !self.grid.contains_key(&tile) {
|
if !self.grid.contains_key(&tile) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
self.grid.remove(&tile);
|
let surface_ref_to_deallocate = self.grid.remove(&tile);
|
||||||
|
self.pool.deallocate(&surface_ref_to_deallocate.unwrap());
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue