From 2893fc3e8bdec79f9bf1c738767cacdc9a7c6843 Mon Sep 17 00:00:00 2001 From: re0312 <45868716+re0312@users.noreply.github.com> Date: Wed, 3 Jul 2024 20:48:34 +0800 Subject: [PATCH] Using simple approx round up in ui_layout_system (#14079) # Objective - built-in `f32::round `is slow - splits from #14064 ## Solution - using a simple floor instead of round ## Testing - I am not an expert on floating-point values, but I enumerated all f32 values to test for potential errors compared to the previous function. [rust playground](https://play.rust-lang.org/?version=stable&mode=release&edition=2021&gist=0d8ed5604499e7bd9c61ce57d47e8c06) three cases where the behavior differs between the new and previous functions: | value | previous | new | |---|---|---| | [-0.5,0) | -0 | +0 | | 0.49999997 | 0 | 1 | | +-8388609 | 8388609 | 8388610 | ## Performance ![image](https://github.com/bevyengine/bevy/assets/45868716/1910f342-e55b-4f5c-851c-24a142d5c72e) --- crates/bevy_ui/src/layout/mod.rs | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/crates/bevy_ui/src/layout/mod.rs b/crates/bevy_ui/src/layout/mod.rs index db6163344a..04c07faa6c 100644 --- a/crates/bevy_ui/src/layout/mod.rs +++ b/crates/bevy_ui/src/layout/mod.rs @@ -254,11 +254,11 @@ pub fn ui_layout_system( absolute_location += layout_location; - let rounded_size = round_layout_coords(absolute_location + layout_size) - - round_layout_coords(absolute_location); + let rounded_size = approx_round_layout_coords(absolute_location + layout_size) + - approx_round_layout_coords(absolute_location); let rounded_location = - round_layout_coords(layout_location) + 0.5 * (rounded_size - parent_size); + approx_round_layout_coords(layout_location) + 0.5 * (rounded_size - parent_size); // only trigger change detection when the new values are different if node.calculated_size != rounded_size || node.unrounded_size != layout_size { @@ -315,15 +315,8 @@ pub fn resolve_outlines_system( #[inline] /// Round `value` to the nearest whole integer, with ties (values with a fractional part equal to 0.5) rounded towards positive infinity. -fn round_ties_up(value: f32) -> f32 { - if value.fract() != -0.5 { - // The `round` function rounds ties away from zero. For positive numbers "away from zero" is towards positive infinity. - // So for all positive values, and negative values with a fractional part not equal to 0.5, `round` returns the correct result. - value.round() - } else { - // In the remaining cases, where `value` is negative and its fractional part is equal to 0.5, we use `ceil` to round it up towards positive infinity. - value.ceil() - } +fn approx_round_ties_up(value: f32) -> f32 { + (value + 0.5).floor() } #[inline] @@ -334,10 +327,10 @@ fn round_ties_up(value: f32) -> f32 { /// Example: The width between bounds of -50.5 and 49.5 before rounding is 100, using: /// - `f32::round`: width becomes 101 (rounds to -51 and 50). /// - `round_ties_up`: width is 100 (rounds to -50 and 50). -fn round_layout_coords(value: Vec2) -> Vec2 { +fn approx_round_layout_coords(value: Vec2) -> Vec2 { Vec2 { - x: round_ties_up(value.x), - y: round_ties_up(value.y), + x: approx_round_ties_up(value.x), + y: approx_round_ties_up(value.y), } } @@ -376,7 +369,7 @@ mod tests { use bevy_window::WindowResolution; use bevy_window::WindowScaleFactorChanged; - use crate::layout::round_layout_coords; + use crate::layout::approx_round_layout_coords; use crate::layout::ui_surface::UiSurface; use crate::prelude::*; use crate::ui_layout_system; @@ -385,7 +378,10 @@ mod tests { #[test] fn round_layout_coords_must_round_ties_up() { - assert_eq!(round_layout_coords(vec2(-50.5, 49.5)), vec2(-50., 50.)); + assert_eq!( + approx_round_layout_coords(vec2(-50.5, 49.5)), + vec2(-50., 50.) + ); } // these window dimensions are easy to convert to and from percentage values