From 46425f1e380c9b6b0a7af7fdcf1b77cf68fde81d Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Sun, 28 Mar 2021 23:16:19 +0200 Subject: [PATCH] Optimize: add #[inline(always)] to various low-level things saves up to 20% (text tesselation), and at least 5% overall --- egui/src/id.rs | 1 + emath/src/lib.rs | 5 ++++ emath/src/numeric.rs | 8 +++++++ emath/src/pos2.rs | 18 +++++++++++++++ emath/src/rect.rs | 48 +++++++++++++++++++++++++++++++++------ emath/src/vec2.rs | 34 +++++++++++++++++++++++++++ epaint/src/color.rs | 26 +++++++++++++++++++++ epaint/src/mesh.rs | 5 ++++ epaint/src/tessellator.rs | 2 ++ epaint/src/text/font.rs | 4 ++++ 10 files changed, 144 insertions(+), 7 deletions(-) diff --git a/egui/src/id.rs b/egui/src/id.rs index 7915954a..6a901992 100644 --- a/egui/src/id.rs +++ b/egui/src/id.rs @@ -61,6 +61,7 @@ impl Id { format!("{:04X}", self.0 as u16) } + #[inline(always)] pub(crate) fn value(&self) -> u64 { self.0 } diff --git a/emath/src/lib.rs b/emath/src/lib.rs index a7bf9ed8..4c6ae089 100644 --- a/emath/src/lib.rs +++ b/emath/src/lib.rs @@ -92,11 +92,13 @@ pub trait One { fn one() -> Self; } impl One for f32 { + #[inline(always)] fn one() -> Self { 1.0 } } impl One for f64 { + #[inline(always)] fn one() -> Self { 1.0 } @@ -121,6 +123,7 @@ impl Real for f64 {} // ---------------------------------------------------------------------------- /// Linear interpolation. +#[inline(always)] pub fn lerp(range: RangeInclusive, t: T) -> R where T: Real + Mul, @@ -309,9 +312,11 @@ pub trait NumExt { macro_rules! impl_num_ext { ($t: ty) => { impl NumExt for $t { + #[inline(always)] fn at_least(self, lower_limit: Self) -> Self { self.max(lower_limit) } + #[inline(always)] fn at_most(self, upper_limit: Self) -> Self { self.min(upper_limit) } diff --git a/emath/src/numeric.rs b/emath/src/numeric.rs index cef1daab..5a8f670c 100644 --- a/emath/src/numeric.rs +++ b/emath/src/numeric.rs @@ -20,9 +20,13 @@ macro_rules! impl_numeric_float { const INTEGRAL: bool = false; const MIN: Self = std::$t::MIN; const MAX: Self = std::$t::MAX; + + #[inline(always)] fn to_f64(self) -> f64 { self as f64 } + + #[inline(always)] fn from_f64(num: f64) -> Self { num as Self } @@ -36,9 +40,13 @@ macro_rules! impl_numeric_integer { const INTEGRAL: bool = true; const MIN: Self = std::$t::MIN; const MAX: Self = std::$t::MAX; + + #[inline(always)] fn to_f64(self) -> f64 { self as f64 } + + #[inline(always)] fn from_f64(num: f64) -> Self { num as Self } diff --git a/emath/src/pos2.rs b/emath/src/pos2.rs index 1c59e0f8..5833bb74 100644 --- a/emath/src/pos2.rs +++ b/emath/src/pos2.rs @@ -26,24 +26,28 @@ pub const fn pos2(x: f32, y: f32) -> Pos2 { // Compatibility and convenience conversions to and from [f32; 2]: impl From<[f32; 2]> for Pos2 { + #[inline(always)] fn from(v: [f32; 2]) -> Self { Self { x: v[0], y: v[1] } } } impl From<&[f32; 2]> for Pos2 { + #[inline(always)] fn from(v: &[f32; 2]) -> Self { Self { x: v[0], y: v[1] } } } impl From for [f32; 2] { + #[inline(always)] fn from(v: Pos2) -> Self { [v.x, v.y] } } impl From<&Pos2> for [f32; 2] { + #[inline(always)] fn from(v: &Pos2) -> Self { [v.x, v.y] } @@ -53,24 +57,28 @@ impl From<&Pos2> for [f32; 2] { // Compatibility and convenience conversions to and from (f32, f32): impl From<(f32, f32)> for Pos2 { + #[inline(always)] fn from(v: (f32, f32)) -> Self { Self { x: v.0, y: v.1 } } } impl From<&(f32, f32)> for Pos2 { + #[inline(always)] fn from(v: &(f32, f32)) -> Self { Self { x: v.0, y: v.1 } } } impl From for (f32, f32) { + #[inline(always)] fn from(v: Pos2) -> Self { (v.x, v.y) } } impl From<&Pos2> for (f32, f32) { + #[inline(always)] fn from(v: &Pos2) -> Self { (v.x, v.y) } @@ -95,6 +103,7 @@ impl Pos2 { /// The vector from origin to this position. /// `p.to_vec2()` is equivalent to `p - Pos2::default()`. + #[inline(always)] pub fn to_vec2(self) -> Vec2 { Vec2 { x: self.x, @@ -153,6 +162,7 @@ impl Pos2 { impl std::ops::Index for Pos2 { type Output = f32; + fn index(&self, index: usize) -> &f32 { match index { 0 => &self.x, @@ -175,6 +185,7 @@ impl std::ops::IndexMut for Pos2 { impl Eq for Pos2 {} impl AddAssign for Pos2 { + #[inline(always)] fn add_assign(&mut self, rhs: Vec2) { *self = Pos2 { x: self.x + rhs.x, @@ -184,6 +195,7 @@ impl AddAssign for Pos2 { } impl SubAssign for Pos2 { + #[inline(always)] fn sub_assign(&mut self, rhs: Vec2) { *self = Pos2 { x: self.x - rhs.x, @@ -194,6 +206,8 @@ impl SubAssign for Pos2 { impl Add for Pos2 { type Output = Pos2; + + #[inline(always)] fn add(self, rhs: Vec2) -> Pos2 { Pos2 { x: self.x + rhs.x, @@ -204,6 +218,8 @@ impl Add for Pos2 { impl Sub for Pos2 { type Output = Vec2; + + #[inline(always)] fn sub(self, rhs: Pos2) -> Vec2 { Vec2 { x: self.x - rhs.x, @@ -214,6 +230,8 @@ impl Sub for Pos2 { impl Sub for Pos2 { type Output = Pos2; + + #[inline(always)] fn sub(self, rhs: Vec2) -> Pos2 { Pos2 { x: self.x - rhs.x, diff --git a/emath/src/rect.rs b/emath/src/rect.rs index 87f47567..3584a185 100644 --- a/emath/src/rect.rs +++ b/emath/src/rect.rs @@ -74,6 +74,7 @@ impl Rect { Self::NAN } + #[inline(always)] pub const fn from_min_max(min: Pos2, max: Pos2) -> Self { Rect { min, max } } @@ -196,11 +197,9 @@ impl Rect { } #[must_use] + #[inline(always)] pub fn contains(&self, p: Pos2) -> bool { - self.min.x <= p.x - && p.x <= self.min.x + self.size().x - && self.min.y <= p.y - && p.y <= self.min.y + self.size().y + self.min.x <= p.x && p.x <= self.max.x && self.min.y <= p.y && p.y <= self.max.y } /// Return the given points clamped to be inside the rectangle @@ -234,18 +233,25 @@ impl Rect { } } + #[inline(always)] pub fn center(&self) -> Pos2 { Pos2 { - x: self.min.x + self.size().x / 2.0, - y: self.min.y + self.size().y / 2.0, + x: (self.min.x + self.max.x) / 2.0, + y: (self.min.y + self.max.y) / 2.0, } } + + #[inline(always)] pub fn size(&self) -> Vec2 { self.max - self.min } + + #[inline(always)] pub fn width(&self) -> f32 { self.max.x - self.min.x } + + #[inline(always)] pub fn height(&self) -> f32 { self.max.y - self.min.y } @@ -292,6 +298,7 @@ impl Rect { } /// `max.x < min.x` or `max.y < min.y`. + #[inline(always)] pub fn is_negative(&self) -> bool { self.max.x < self.min.x || self.max.y < self.min.y } @@ -314,79 +321,106 @@ impl Rect { /// ## Convenience functions (assumes origin is towards left top): impl Rect { - /// `min.x` + /// `min.x + #[inline(always)] pub fn left(&self) -> f32 { self.min.x } /// `min.x` + #[inline(always)] pub fn left_mut(&mut self) -> &mut f32 { &mut self.min.x } /// `min.x` + #[inline(always)] pub fn set_left(&mut self, x: f32) { self.min.x = x; } /// `max.x` + #[inline(always)] pub fn right(&self) -> f32 { self.max.x } /// `max.x` + #[inline(always)] pub fn right_mut(&mut self) -> &mut f32 { &mut self.max.x } /// `max.x` + #[inline(always)] pub fn set_right(&mut self, x: f32) { self.max.x = x; } /// `min.y` + #[inline(always)] pub fn top(&self) -> f32 { self.min.y } /// `min.y` + #[inline(always)] pub fn top_mut(&mut self) -> &mut f32 { &mut self.min.y } /// `min.y` + #[inline(always)] pub fn set_top(&mut self, y: f32) { self.min.y = y; } /// `max.y` + #[inline(always)] pub fn bottom(&self) -> f32 { self.max.y } /// `max.y` + #[inline(always)] pub fn bottom_mut(&mut self) -> &mut f32 { &mut self.max.y } /// `max.y` + #[inline(always)] pub fn set_bottom(&mut self, y: f32) { self.max.y = y; } + #[inline(always)] pub fn left_top(&self) -> Pos2 { pos2(self.left(), self.top()) } + + #[inline(always)] pub fn center_top(&self) -> Pos2 { pos2(self.center().x, self.top()) } + + #[inline(always)] pub fn right_top(&self) -> Pos2 { pos2(self.right(), self.top()) } + + #[inline(always)] pub fn left_center(&self) -> Pos2 { pos2(self.left(), self.center().y) } + + #[inline(always)] pub fn right_center(&self) -> Pos2 { pos2(self.right(), self.center().y) } + + #[inline(always)] pub fn left_bottom(&self) -> Pos2 { pos2(self.left(), self.bottom()) } + + #[inline(always)] pub fn center_bottom(&self) -> Pos2 { pos2(self.center().x, self.bottom()) } + + #[inline(always)] pub fn right_bottom(&self) -> Pos2 { pos2(self.right(), self.bottom()) } diff --git a/emath/src/vec2.rs b/emath/src/vec2.rs index 7d956863..77f9f681 100644 --- a/emath/src/vec2.rs +++ b/emath/src/vec2.rs @@ -23,24 +23,28 @@ pub const fn vec2(x: f32, y: f32) -> Vec2 { // Compatibility and convenience conversions to and from [f32; 2]: impl From<[f32; 2]> for Vec2 { + #[inline(always)] fn from(v: [f32; 2]) -> Self { Self { x: v[0], y: v[1] } } } impl From<&[f32; 2]> for Vec2 { + #[inline(always)] fn from(v: &[f32; 2]) -> Self { Self { x: v[0], y: v[1] } } } impl From for [f32; 2] { + #[inline(always)] fn from(v: Vec2) -> Self { [v.x, v.y] } } impl From<&Vec2> for [f32; 2] { + #[inline(always)] fn from(v: &Vec2) -> Self { [v.x, v.y] } @@ -50,24 +54,28 @@ impl From<&Vec2> for [f32; 2] { // Compatibility and convenience conversions to and from (f32, f32): impl From<(f32, f32)> for Vec2 { + #[inline(always)] fn from(v: (f32, f32)) -> Self { Self { x: v.0, y: v.1 } } } impl From<&(f32, f32)> for Vec2 { + #[inline(always)] fn from(v: &(f32, f32)) -> Self { Self { x: v.0, y: v.1 } } } impl From for (f32, f32) { + #[inline(always)] fn from(v: Vec2) -> Self { (v.x, v.y) } } impl From<&Vec2> for (f32, f32) { + #[inline(always)] fn from(v: &Vec2) -> Self { (v.x, v.y) } @@ -92,16 +100,20 @@ impl Vec2 { Self::INFINITY } + #[inline(always)] pub const fn new(x: f32, y: f32) -> Self { Self { x, y } } /// Set both `x` and `y` to the same value. + #[inline(always)] pub const fn splat(v: f32) -> Self { Self { x: v, y: v } } + /// Safe normalize: returns zero if input is zero. #[must_use] + #[inline(always)] pub fn normalized(self) -> Self { let len = self.length(); if len <= 0.0 { @@ -118,10 +130,12 @@ impl Vec2 { vec2(self.y, -self.x) } + #[inline(always)] pub fn length(self) -> f32 { self.x.hypot(self.y) } + #[inline(always)] pub fn length_sq(self) -> f32 { self.x * self.x + self.y * self.y } @@ -129,6 +143,7 @@ impl Vec2 { /// Create a unit vector with the given angle (in radians). /// * An angle of zero gives the unit X axis. /// * An angle of 𝞃/4 = 90° gives the unit Y axis. + #[inline(always)] pub fn angled(angle: f32) -> Self { vec2(angle.cos(), angle.sin()) } @@ -191,6 +206,7 @@ impl Vec2 { impl std::ops::Index for Vec2 { type Output = f32; + fn index(&self, index: usize) -> &f32 { match index { 0 => &self.x, @@ -215,12 +231,14 @@ impl Eq for Vec2 {} impl Neg for Vec2 { type Output = Vec2; + #[inline(always)] fn neg(self) -> Vec2 { vec2(-self.x, -self.y) } } impl AddAssign for Vec2 { + #[inline(always)] fn add_assign(&mut self, rhs: Vec2) { *self = Vec2 { x: self.x + rhs.x, @@ -230,6 +248,7 @@ impl AddAssign for Vec2 { } impl SubAssign for Vec2 { + #[inline(always)] fn sub_assign(&mut self, rhs: Vec2) { *self = Vec2 { x: self.x - rhs.x, @@ -240,6 +259,8 @@ impl SubAssign for Vec2 { impl Add for Vec2 { type Output = Vec2; + + #[inline(always)] fn add(self, rhs: Vec2) -> Vec2 { Vec2 { x: self.x + rhs.x, @@ -250,6 +271,8 @@ impl Add for Vec2 { impl Sub for Vec2 { type Output = Vec2; + + #[inline(always)] fn sub(self, rhs: Vec2) -> Vec2 { Vec2 { x: self.x - rhs.x, @@ -261,6 +284,8 @@ impl Sub for Vec2 { /// Element-wise multiplication impl Mul for Vec2 { type Output = Vec2; + + #[inline(always)] fn mul(self, vec: Vec2) -> Vec2 { Vec2 { x: self.x * vec.x, @@ -272,6 +297,8 @@ impl Mul for Vec2 { /// Element-wise division impl Div for Vec2 { type Output = Vec2; + + #[inline(always)] fn div(self, rhs: Vec2) -> Vec2 { Vec2 { x: self.x / rhs.x, @@ -281,6 +308,7 @@ impl Div for Vec2 { } impl MulAssign for Vec2 { + #[inline(always)] fn mul_assign(&mut self, rhs: f32) { self.x *= rhs; self.y *= rhs; @@ -289,6 +317,8 @@ impl MulAssign for Vec2 { impl Mul for Vec2 { type Output = Vec2; + + #[inline(always)] fn mul(self, factor: f32) -> Vec2 { Vec2 { x: self.x * factor, @@ -299,6 +329,8 @@ impl Mul for Vec2 { impl Mul for f32 { type Output = Vec2; + + #[inline(always)] fn mul(self, vec: Vec2) -> Vec2 { Vec2 { x: self * vec.x, @@ -309,6 +341,8 @@ impl Mul for f32 { impl Div for Vec2 { type Output = Vec2; + + #[inline(always)] fn div(self, factor: f32) -> Vec2 { Vec2 { x: self.x / factor, diff --git a/epaint/src/color.rs b/epaint/src/color.rs index b42b4c0a..317081ee 100644 --- a/epaint/src/color.rs +++ b/epaint/src/color.rs @@ -100,19 +100,27 @@ impl Color32 { Self([l, l, l, 0]) } + #[inline(always)] pub fn is_opaque(&self) -> bool { self.a() == 255 } + #[inline(always)] pub fn r(&self) -> u8 { self.0[0] } + + #[inline(always)] pub fn g(&self) -> u8 { self.0[1] } + + #[inline(always)] pub fn b(&self) -> u8 { self.0[2] } + + #[inline(always)] pub fn a(&self) -> u8 { self.0[3] } @@ -129,11 +137,13 @@ impl Color32 { } /// Premultiplied RGBA + #[inline(always)] pub fn to_array(&self) -> [u8; 4] { [self.r(), self.g(), self.b(), self.a()] } /// Premultiplied RGBA + #[inline(always)] pub fn to_tuple(&self) -> (u8, u8, u8, u8) { (self.r(), self.g(), self.b(), self.a()) } @@ -212,6 +222,7 @@ impl Rgba { } /// Multiply with e.g. 0.5 to make us half transparent + #[inline(always)] pub fn multiply(self, alpha: f32) -> Self { Self([ alpha * self[0], @@ -221,15 +232,22 @@ impl Rgba { ]) } + #[inline(always)] pub fn r(&self) -> f32 { self.0[0] } + + #[inline(always)] pub fn g(&self) -> f32 { self.0[1] } + + #[inline(always)] pub fn b(&self) -> f32 { self.0[2] } + + #[inline(always)] pub fn a(&self) -> f32 { self.0[3] } @@ -258,6 +276,8 @@ impl Rgba { impl std::ops::Add for Rgba { type Output = Rgba; + + #[inline(always)] fn add(self, rhs: Rgba) -> Rgba { Rgba([ self[0] + rhs[0], @@ -270,6 +290,8 @@ impl std::ops::Add for Rgba { impl std::ops::Mul for Rgba { type Output = Rgba; + + #[inline(always)] fn mul(self, other: Rgba) -> Rgba { Rgba([ self[0] * other[0], @@ -282,6 +304,8 @@ impl std::ops::Mul for Rgba { impl std::ops::Mul for Rgba { type Output = Rgba; + + #[inline(always)] fn mul(self, factor: f32) -> Rgba { Rgba([ self[0] * factor, @@ -294,6 +318,8 @@ impl std::ops::Mul for Rgba { impl std::ops::Mul for f32 { type Output = Rgba; + + #[inline(always)] fn mul(self, rgba: Rgba) -> Rgba { Rgba([ self * rgba[0], diff --git a/epaint/src/mesh.rs b/epaint/src/mesh.rs index a5239aab..58abdc41 100644 --- a/epaint/src/mesh.rs +++ b/epaint/src/mesh.rs @@ -92,6 +92,7 @@ impl Mesh { } } + #[inline(always)] pub fn colored_vertex(&mut self, pos: Pos2, color: Color32) { debug_assert!(self.texture_id == TextureId::Egui); self.vertices.push(Vertex { @@ -102,6 +103,7 @@ impl Mesh { } /// Add a triangle. + #[inline(always)] pub fn add_triangle(&mut self, a: u32, b: u32, c: u32) { self.indices.push(a); self.indices.push(b); @@ -110,12 +112,14 @@ impl Mesh { /// Make room for this many additional triangles (will reserve 3x as many indices). /// See also `reserve_vertices`. + #[inline(always)] pub fn reserve_triangles(&mut self, additional_triangles: usize) { self.indices.reserve(3 * additional_triangles); } /// Make room for this many additional vertices. /// See also `reserve_triangles`. + #[inline(always)] pub fn reserve_vertices(&mut self, additional: usize) { self.vertices.reserve(additional); } @@ -151,6 +155,7 @@ impl Mesh { } /// Uniformly colored rectangle. + #[inline(always)] pub fn add_colored_rect(&mut self, rect: Rect, color: Color32) { debug_assert!(self.texture_id == TextureId::Egui); self.add_rect_with_uv(rect, [WHITE_UV, WHITE_UV].into(), color) diff --git a/epaint/src/tessellator.rs b/epaint/src/tessellator.rs index cd79dbef..147e175c 100644 --- a/epaint/src/tessellator.rs +++ b/epaint/src/tessellator.rs @@ -34,10 +34,12 @@ pub struct PathPoint { struct Path(Vec); impl Path { + #[inline(always)] pub fn clear(&mut self) { self.0.clear(); } + #[inline(always)] pub fn reserve(&mut self, additional: usize) { self.0.reserve(additional) } diff --git a/epaint/src/text/font.rs b/epaint/src/text/font.rs index 60ce8544..9242f7a5 100644 --- a/epaint/src/text/font.rs +++ b/epaint/src/text/font.rs @@ -138,10 +138,12 @@ impl FontImpl { } /// Height of one row of text. In points + #[inline(always)] pub fn row_height(&self) -> f32 { self.height_in_points } + #[inline(always)] pub fn pixels_per_point(&self) -> f32 { self.pixels_per_point } @@ -202,11 +204,13 @@ impl Font { slf } + #[inline] pub fn round_to_pixel(&self, point: f32) -> f32 { (point * self.pixels_per_point).round() / self.pixels_per_point } /// Height of one row of text. In points + #[inline(always)] pub fn row_height(&self) -> f32 { self.row_height }