Skip to content

Commit 3fc49f0

Browse files
Preconvert colors before sending to shader (#20074)
# Objective - Fixes #20008 - Preconvert colors before sending them to the UI gradients shader for better performance ## Solution - Modified `prepare_gradient` in `gradient.rs` to convert colors from `LinearRgba` to `Srgba` on the CPU before sending to the GPU - Updated the gradient shader to remove per-pixel color space conversions since colors are now pre-converted - Added documentation to clarify that vertex colors are in sRGB space This optimization reduces the number of power operations per pixel from 3 to 1: - **Before**: Convert start color to sRGB, convert end color to sRGB, mix, convert back to linear (3 pow operations per pixel) - **After**: Colors pre-converted on CPU, mix in sRGB space, convert back to linear (1 pow operation per pixel) ## Testing - Verified that the UI gradient examples (`cargo run --example gradients`) compile and render correctly - The visual output should remain identical while performance improves, especially for large gradient areas - Changes maintain the same color interpolation behavior (mixing in sRGB space) To test: 1. Run `cargo run --example gradients` or `cargo run --example stacked_gradients` 2. Verify gradients render correctly --------- Co-authored-by: ickshonpe <david.curthoys@googlemail.com>
1 parent 8e14d99 commit 3fc49f0

File tree

5 files changed

+381
-182
lines changed

5 files changed

+381
-182
lines changed

Cargo.toml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3068,6 +3068,17 @@ description = "Test rendering of many UI elements"
30683068
category = "Stress Tests"
30693069
wasm = true
30703070

3071+
[[example]]
3072+
name = "many_gradients"
3073+
path = "examples/stress_tests/many_gradients.rs"
3074+
doc-scrape-examples = true
3075+
3076+
[package.metadata.example.many_gradients]
3077+
name = "Many Gradients"
3078+
description = "Stress test for gradient rendering performance"
3079+
category = "Stress Tests"
3080+
wasm = true
3081+
30713082
[[example]]
30723083
name = "many_cameras_lights"
30733084
path = "examples/stress_tests/many_cameras_lights.rs"

crates/bevy_ui_render/src/gradient.rs

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use core::{
77
use super::shader_flags::BORDER_ALL;
88
use crate::*;
99
use bevy_asset::*;
10-
use bevy_color::{ColorToComponents, LinearRgba};
10+
use bevy_color::{ColorToComponents, Hsla, Hsva, LinearRgba, Oklaba, Oklcha, Srgba};
1111
use bevy_ecs::{
1212
prelude::Component,
1313
system::{
@@ -654,6 +654,44 @@ struct UiGradientVertex {
654654
hint: f32,
655655
}
656656

657+
fn convert_color_to_space(color: LinearRgba, space: InterpolationColorSpace) -> [f32; 4] {
658+
match space {
659+
InterpolationColorSpace::Oklaba => {
660+
let oklaba: Oklaba = color.into();
661+
[oklaba.lightness, oklaba.a, oklaba.b, oklaba.alpha]
662+
}
663+
InterpolationColorSpace::Oklcha | InterpolationColorSpace::OklchaLong => {
664+
let oklcha: Oklcha = color.into();
665+
[
666+
oklcha.lightness,
667+
oklcha.chroma,
668+
oklcha.hue.to_radians(),
669+
oklcha.alpha,
670+
]
671+
}
672+
InterpolationColorSpace::Srgba => {
673+
let srgba: Srgba = color.into();
674+
[srgba.red, srgba.green, srgba.blue, srgba.alpha]
675+
}
676+
InterpolationColorSpace::LinearRgba => color.to_f32_array(),
677+
InterpolationColorSpace::Hsla | InterpolationColorSpace::HslaLong => {
678+
let hsla: Hsla = color.into();
679+
// Normalize hue to 0..1 range for shader
680+
[
681+
hsla.hue / 360.0,
682+
hsla.saturation,
683+
hsla.lightness,
684+
hsla.alpha,
685+
]
686+
}
687+
InterpolationColorSpace::Hsva | InterpolationColorSpace::HsvaLong => {
688+
let hsva: Hsva = color.into();
689+
// Normalize hue to 0..1 range for shader
690+
[hsva.hue / 360.0, hsva.saturation, hsva.value, hsva.alpha]
691+
}
692+
}
693+
}
694+
657695
pub fn prepare_gradient(
658696
mut commands: Commands,
659697
render_device: Res<RenderDevice>,
@@ -804,8 +842,9 @@ pub fn prepare_gradient(
804842
continue;
805843
}
806844
}
807-
let start_color = start_stop.0.to_f32_array();
808-
let end_color = end_stop.0.to_f32_array();
845+
let start_color =
846+
convert_color_to_space(start_stop.0, gradient.color_space);
847+
let end_color = convert_color_to_space(end_stop.0, gradient.color_space);
809848
let mut stop_flags = flags;
810849
if 0. < start_stop.1
811850
&& (stop_index == gradient.stops_range.start || segment_count == 0)

0 commit comments

Comments
 (0)