Optimize: store a reference to the target PaintList in Painter

Saves us a hash lookup for each paint call, giving us 5% perf gain
This commit is contained in:
Emil Ernerfeldt 2021-03-31 17:03:20 +02:00
parent 17983e1bbc
commit 4984d51f99
3 changed files with 24 additions and 20 deletions

View file

@ -685,7 +685,9 @@ impl Context {
/// Move all the graphics at the given layer. /// Move all the graphics at the given layer.
/// Can be used to implement drag-and-drop (see relevant demo). /// Can be used to implement drag-and-drop (see relevant demo).
pub fn translate_layer(&self, layer_id: LayerId, delta: Vec2) { pub fn translate_layer(&self, layer_id: LayerId, delta: Vec2) {
self.graphics().list(layer_id).translate(delta); if delta != Vec2::ZERO {
self.graphics().list(layer_id).lock().translate(delta);
}
} }
pub fn layer_id_at(&self, pos: Pos2) -> Option<LayerId> { pub fn layer_id_at(&self, pos: Pos2) -> Option<LayerId> {

View file

@ -3,7 +3,9 @@
use crate::{Id, *}; use crate::{Id, *};
use epaint::ahash::AHashMap; use epaint::ahash::AHashMap;
use epaint::mutex::Mutex;
use epaint::{ClippedShape, Shape}; use epaint::{ClippedShape, Shape};
use std::sync::Arc;
/// Different layer categories /// Different layer categories
#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)] #[derive(Clone, Copy, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
@ -120,10 +122,10 @@ impl PaintList {
} }
#[derive(Clone, Default)] #[derive(Clone, Default)]
pub(crate) struct GraphicLayers([AHashMap<Id, PaintList>; Order::COUNT]); pub(crate) struct GraphicLayers([AHashMap<Id, Arc<Mutex<PaintList>>>; Order::COUNT]);
impl GraphicLayers { impl GraphicLayers {
pub fn list(&mut self, layer_id: LayerId) -> &mut PaintList { pub fn list(&mut self, layer_id: LayerId) -> &Arc<Mutex<PaintList>> {
self.0[layer_id.order as usize] self.0[layer_id.order as usize]
.entry(layer_id.id) .entry(layer_id.id)
.or_default() .or_default()
@ -138,20 +140,20 @@ impl GraphicLayers {
// If a layer is empty at the start of the frame // If a layer is empty at the start of the frame
// the nobody has added to it, and it is old and defunct. // the nobody has added to it, and it is old and defunct.
// Free it to save memory: // Free it to save memory:
order_map.retain(|_, list| !list.is_empty()); order_map.retain(|_, list| !list.lock().is_empty());
// First do the layers part of area_order: // First do the layers part of area_order:
for layer_id in area_order { for layer_id in area_order {
if layer_id.order == order { if layer_id.order == order {
if let Some(shapes) = order_map.get_mut(&layer_id.id) { if let Some(list) = order_map.get_mut(&layer_id.id) {
all_shapes.extend(shapes.0.drain(..)); all_shapes.extend(list.lock().0.drain(..));
} }
} }
} }
// Also draw areas that are missing in `area_order`: // Also draw areas that are missing in `area_order`:
for shapes in order_map.values_mut() { for shapes in order_map.values_mut() {
all_shapes.extend(shapes.0.drain(..)); all_shapes.extend(shapes.lock().0.drain(..));
} }
} }

View file

@ -1,9 +1,10 @@
use crate::{ use crate::{
emath::{Align2, Pos2, Rect, Vec2}, emath::{Align2, Pos2, Rect, Vec2},
layers::{LayerId, ShapeIdx}, layers::{LayerId, PaintList, ShapeIdx},
Color32, CtxRef, Color32, CtxRef,
}; };
use epaint::{ use epaint::{
mutex::Mutex,
text::{Fonts, Galley, TextStyle}, text::{Fonts, Galley, TextStyle},
Shape, Stroke, Shape, Stroke,
}; };
@ -19,6 +20,8 @@ pub struct Painter {
/// Where we paint /// Where we paint
layer_id: LayerId, layer_id: LayerId,
paint_list: std::sync::Arc<Mutex<PaintList>>,
/// Everything painted in this `Painter` will be clipped against this. /// Everything painted in this `Painter` will be clipped against this.
/// This means nothing outside of this rectangle will be visible on screen. /// This means nothing outside of this rectangle will be visible on screen.
clip_rect: Rect, clip_rect: Rect,
@ -30,9 +33,11 @@ pub struct Painter {
impl Painter { impl Painter {
pub fn new(ctx: CtxRef, layer_id: LayerId, clip_rect: Rect) -> Self { pub fn new(ctx: CtxRef, layer_id: LayerId, clip_rect: Rect) -> Self {
let paint_list = ctx.graphics().list(layer_id).clone();
Self { Self {
ctx, ctx,
layer_id, layer_id,
paint_list,
clip_rect, clip_rect,
fade_to_color: None, fade_to_color: None,
} }
@ -40,8 +45,10 @@ impl Painter {
#[must_use] #[must_use]
pub fn with_layer_id(self, layer_id: LayerId) -> Self { pub fn with_layer_id(self, layer_id: LayerId) -> Self {
let paint_list = self.ctx.graphics().list(layer_id).clone();
Self { Self {
ctx: self.ctx, ctx: self.ctx,
paint_list,
layer_id, layer_id,
clip_rect: self.clip_rect, clip_rect: self.clip_rect,
fade_to_color: None, fade_to_color: None,
@ -51,6 +58,7 @@ impl Painter {
/// redirect /// redirect
pub fn set_layer_id(&mut self, layer_id: LayerId) { pub fn set_layer_id(&mut self, layer_id: LayerId) {
self.layer_id = layer_id; self.layer_id = layer_id;
self.paint_list = self.ctx.graphics().list(self.layer_id).clone();
} }
/// If set, colors will be modified to look like this /// If set, colors will be modified to look like this
@ -66,6 +74,7 @@ impl Painter {
Self { Self {
ctx: self.ctx.clone(), ctx: self.ctx.clone(),
layer_id: self.layer_id, layer_id: self.layer_id,
paint_list: self.paint_list.clone(),
clip_rect: rect.intersect(self.clip_rect), clip_rect: rect.intersect(self.clip_rect),
fade_to_color: self.fade_to_color, fade_to_color: self.fade_to_color,
} }
@ -129,10 +138,7 @@ impl Painter {
/// NOTE: all coordinates are screen coordinates! /// NOTE: all coordinates are screen coordinates!
pub fn add(&self, mut shape: Shape) -> ShapeIdx { pub fn add(&self, mut shape: Shape) -> ShapeIdx {
self.transform_shape(&mut shape); self.transform_shape(&mut shape);
self.ctx self.paint_list.lock().add(self.clip_rect, shape)
.graphics()
.list(self.layer_id)
.add(self.clip_rect, shape)
} }
/// Add many shapes at once. /// Add many shapes at once.
@ -146,20 +152,14 @@ impl Painter {
} }
} }
self.ctx self.paint_list.lock().extend(self.clip_rect, shapes);
.graphics()
.list(self.layer_id)
.extend(self.clip_rect, shapes);
} }
} }
/// Modify an existing [`Shape`]. /// Modify an existing [`Shape`].
pub fn set(&self, idx: ShapeIdx, mut shape: Shape) { pub fn set(&self, idx: ShapeIdx, mut shape: Shape) {
self.transform_shape(&mut shape); self.transform_shape(&mut shape);
self.ctx self.paint_list.lock().set(idx, self.clip_rect, shape)
.graphics()
.list(self.layer_id)
.set(idx, self.clip_rect, shape)
} }
} }