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.
/// Can be used to implement drag-and-drop (see relevant demo).
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> {

View file

@ -3,7 +3,9 @@
use crate::{Id, *};
use epaint::ahash::AHashMap;
use epaint::mutex::Mutex;
use epaint::{ClippedShape, Shape};
use std::sync::Arc;
/// Different layer categories
#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
@ -120,10 +122,10 @@ impl PaintList {
}
#[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 {
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]
.entry(layer_id.id)
.or_default()
@ -138,20 +140,20 @@ impl GraphicLayers {
// If a layer is empty at the start of the frame
// the nobody has added to it, and it is old and defunct.
// 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:
for layer_id in area_order {
if layer_id.order == order {
if let Some(shapes) = order_map.get_mut(&layer_id.id) {
all_shapes.extend(shapes.0.drain(..));
if let Some(list) = order_map.get_mut(&layer_id.id) {
all_shapes.extend(list.lock().0.drain(..));
}
}
}
// Also draw areas that are missing in `area_order`:
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::{
emath::{Align2, Pos2, Rect, Vec2},
layers::{LayerId, ShapeIdx},
layers::{LayerId, PaintList, ShapeIdx},
Color32, CtxRef,
};
use epaint::{
mutex::Mutex,
text::{Fonts, Galley, TextStyle},
Shape, Stroke,
};
@ -19,6 +20,8 @@ pub struct Painter {
/// Where we paint
layer_id: LayerId,
paint_list: std::sync::Arc<Mutex<PaintList>>,
/// Everything painted in this `Painter` will be clipped against this.
/// This means nothing outside of this rectangle will be visible on screen.
clip_rect: Rect,
@ -30,9 +33,11 @@ pub struct Painter {
impl Painter {
pub fn new(ctx: CtxRef, layer_id: LayerId, clip_rect: Rect) -> Self {
let paint_list = ctx.graphics().list(layer_id).clone();
Self {
ctx,
layer_id,
paint_list,
clip_rect,
fade_to_color: None,
}
@ -40,8 +45,10 @@ impl Painter {
#[must_use]
pub fn with_layer_id(self, layer_id: LayerId) -> Self {
let paint_list = self.ctx.graphics().list(layer_id).clone();
Self {
ctx: self.ctx,
paint_list,
layer_id,
clip_rect: self.clip_rect,
fade_to_color: None,
@ -51,6 +58,7 @@ impl Painter {
/// redirect
pub fn set_layer_id(&mut self, layer_id: LayerId) {
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
@ -66,6 +74,7 @@ impl Painter {
Self {
ctx: self.ctx.clone(),
layer_id: self.layer_id,
paint_list: self.paint_list.clone(),
clip_rect: rect.intersect(self.clip_rect),
fade_to_color: self.fade_to_color,
}
@ -129,10 +138,7 @@ impl Painter {
/// NOTE: all coordinates are screen coordinates!
pub fn add(&self, mut shape: Shape) -> ShapeIdx {
self.transform_shape(&mut shape);
self.ctx
.graphics()
.list(self.layer_id)
.add(self.clip_rect, shape)
self.paint_list.lock().add(self.clip_rect, shape)
}
/// Add many shapes at once.
@ -146,20 +152,14 @@ impl Painter {
}
}
self.ctx
.graphics()
.list(self.layer_id)
.extend(self.clip_rect, shapes);
self.paint_list.lock().extend(self.clip_rect, shapes);
}
}
/// Modify an existing [`Shape`].
pub fn set(&self, idx: ShapeIdx, mut shape: Shape) {
self.transform_shape(&mut shape);
self.ctx
.graphics()
.list(self.layer_id)
.set(idx, self.clip_rect, shape)
self.paint_list.lock().set(idx, self.clip_rect, shape)
}
}