Skip to content

Commit

Permalink
Using simple approx round up in ui_layout_system (bevyengine#14079)
Browse files Browse the repository at this point in the history
# Objective

- built-in `f32::round `is slow 
- splits from bevyengine#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)
  • Loading branch information
re0312 authored and MrGVSV committed Jul 5, 2024
1 parent 51a3081 commit b6f9c11
Showing 1 changed file with 13 additions and 17 deletions.
30 changes: 13 additions & 17 deletions crates/bevy_ui/src/layout/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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]
Expand All @@ -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),
}
}

Expand Down Expand Up @@ -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;
Expand All @@ -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
Expand Down

0 comments on commit b6f9c11

Please sign in to comment.