From 8c74012d8db901f06865e3778c077ceceb07520b Mon Sep 17 00:00:00 2001 From: ickshonpe Date: Thu, 8 Jun 2023 19:06:04 +0100 Subject: [PATCH 01/20] In `prepare_uinodes` set the UVs to a large number if the quad is untextured rather than switching textures and creating a new `UiBatch`. Add a condition to the fragment shader that only multiplies by the color value from `textureSample` if the quad is actually textured. --- crates/bevy_ui/src/render/mod.rs | 20 +++++++++++--------- crates/bevy_ui/src/render/ui.wgsl | 6 +++++- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index f203c4b227565..76f1aa5443043 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -398,17 +398,19 @@ pub fn prepare_uinodes( let mut start = 0; let mut end = 0; - let mut current_batch_handle = Default::default(); + let mut current_batch_handle = DEFAULT_IMAGE_HANDLE.typed(); let mut last_z = 0.0; for extracted_uinode in &extracted_uinodes.uinodes { if current_batch_handle != extracted_uinode.image { - if start != end { - commands.spawn(UiBatch { - range: start..end, - image: current_batch_handle, - z: last_z, - }); - start = end; + if current_batch_handle.id() != DEFAULT_IMAGE_HANDLE.id() { + if start != end { + commands.spawn(UiBatch { + range: start..end, + image: current_batch_handle, + z: last_z, + }); + start = end; + } } current_batch_handle = extracted_uinode.image.clone_weak(); } @@ -470,7 +472,7 @@ pub fn prepare_uinodes( } } let uvs = if current_batch_handle.id() == DEFAULT_IMAGE_HANDLE.id() { - [Vec2::ZERO, Vec2::X, Vec2::ONE, Vec2::Y] + [Vec2::splat(f32::MAX), Vec2::splat(f32::MAX), Vec2::splat(f32::MAX), Vec2::splat(f32::MAX)] } else { let atlas_extent = extracted_uinode.atlas_size.unwrap_or(uinode_rect.max); if extracted_uinode.flip_x { diff --git a/crates/bevy_ui/src/render/ui.wgsl b/crates/bevy_ui/src/render/ui.wgsl index 11ce13aa5468d..8f91be6a33eaa 100644 --- a/crates/bevy_ui/src/render/ui.wgsl +++ b/crates/bevy_ui/src/render/ui.wgsl @@ -30,6 +30,10 @@ var sprite_sampler: sampler; @fragment fn fragment(in: VertexOutput) -> @location(0) vec4 { var color = textureSample(sprite_texture, sprite_sampler, in.uv); - color = in.color * color; + if in.uv.x < 1.e+20 { + color = in.color * color; + } else { + color = in.color; + } return color; } From 293eea685c4a5c61d7891f2f349d4537f72f84c0 Mon Sep 17 00:00:00 2001 From: ickshonpe Date: Thu, 8 Jun 2023 19:41:47 +0100 Subject: [PATCH 02/20] cargo fmt --all --- crates/bevy_ui/src/render/mod.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index 76f1aa5443043..d73f04c2176e4 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -472,7 +472,12 @@ pub fn prepare_uinodes( } } let uvs = if current_batch_handle.id() == DEFAULT_IMAGE_HANDLE.id() { - [Vec2::splat(f32::MAX), Vec2::splat(f32::MAX), Vec2::splat(f32::MAX), Vec2::splat(f32::MAX)] + [ + Vec2::splat(f32::MAX), + Vec2::splat(f32::MAX), + Vec2::splat(f32::MAX), + Vec2::splat(f32::MAX), + ] } else { let atlas_extent = extracted_uinode.atlas_size.unwrap_or(uinode_rect.max); if extracted_uinode.flip_x { From f119009c8cff8fa55030041701db85e271217ea7 Mon Sep 17 00:00:00 2001 From: ickshonpe Date: Thu, 8 Jun 2023 19:52:01 +0100 Subject: [PATCH 03/20] clippy::collapsible-if --- crates/bevy_ui/src/render/mod.rs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index d73f04c2176e4..f064f83a1b177 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -402,15 +402,13 @@ pub fn prepare_uinodes( let mut last_z = 0.0; for extracted_uinode in &extracted_uinodes.uinodes { if current_batch_handle != extracted_uinode.image { - if current_batch_handle.id() != DEFAULT_IMAGE_HANDLE.id() { - if start != end { - commands.spawn(UiBatch { - range: start..end, - image: current_batch_handle, - z: last_z, - }); - start = end; - } + if current_batch_handle.id() != DEFAULT_IMAGE_HANDLE.id() && start != end { + commands.spawn(UiBatch { + range: start..end, + image: current_batch_handle, + z: last_z, + }); + start = end; } current_batch_handle = extracted_uinode.image.clone_weak(); } From a50b00d0ec11c5798bc368c8300a30fe1c9e010b Mon Sep 17 00:00:00 2001 From: ickshonpe Date: Thu, 8 Jun 2023 21:09:51 +0100 Subject: [PATCH 04/20] Improved improved batching. --- crates/bevy_ui/src/render/mod.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index f064f83a1b177..3cd83fd1e9b0f 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -401,8 +401,9 @@ pub fn prepare_uinodes( let mut current_batch_handle = DEFAULT_IMAGE_HANDLE.typed(); let mut last_z = 0.0; for extracted_uinode in &extracted_uinodes.uinodes { - if current_batch_handle != extracted_uinode.image { - if current_batch_handle.id() != DEFAULT_IMAGE_HANDLE.id() && start != end { + if current_batch_handle.id() != extracted_uinode.image.id() { + if current_batch_handle.id() != DEFAULT_IMAGE_HANDLE.id() + && extracted_uinode.image.id() != DEFAULT_IMAGE_HANDLE.id() && start != end { commands.spawn(UiBatch { range: start..end, image: current_batch_handle, From 14f555c784fd2d1a2013de8ff8d720d7d8445e56 Mon Sep 17 00:00:00 2001 From: ickshonpe Date: Thu, 8 Jun 2023 21:51:08 +0100 Subject: [PATCH 05/20] cargo fmt --all --- crates/bevy_ui/src/render/mod.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index 3cd83fd1e9b0f..f0bd9debb8607 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -402,8 +402,10 @@ pub fn prepare_uinodes( let mut last_z = 0.0; for extracted_uinode in &extracted_uinodes.uinodes { if current_batch_handle.id() != extracted_uinode.image.id() { - if current_batch_handle.id() != DEFAULT_IMAGE_HANDLE.id() - && extracted_uinode.image.id() != DEFAULT_IMAGE_HANDLE.id() && start != end { + if current_batch_handle.id() != DEFAULT_IMAGE_HANDLE.id() + && extracted_uinode.image.id() != DEFAULT_IMAGE_HANDLE.id() + && start != end + { commands.spawn(UiBatch { range: start..end, image: current_batch_handle, From 3373cdd3ae2624a07773b94e2c9d4245b5752d40 Mon Sep 17 00:00:00 2001 From: ickshonpe Date: Fri, 9 Jun 2023 01:55:04 +0100 Subject: [PATCH 06/20] Fixed multiple textures bug. --- crates/bevy_ui/src/render/mod.rs | 35 ++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index f0bd9debb8607..382c271058b91 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -398,22 +398,27 @@ pub fn prepare_uinodes( let mut start = 0; let mut end = 0; - let mut current_batch_handle = DEFAULT_IMAGE_HANDLE.typed(); + let mut stored_batch_handle = DEFAULT_IMAGE_HANDLE.typed(); let mut last_z = 0.0; + let default_id = DEFAULT_IMAGE_HANDLE.id(); + for extracted_uinode in &extracted_uinodes.uinodes { - if current_batch_handle.id() != extracted_uinode.image.id() { - if current_batch_handle.id() != DEFAULT_IMAGE_HANDLE.id() - && extracted_uinode.image.id() != DEFAULT_IMAGE_HANDLE.id() - && start != end - { - commands.spawn(UiBatch { - range: start..end, - image: current_batch_handle, - z: last_z, - }); - start = end; + if extracted_uinode.image.id() != default_id { + if stored_batch_handle.id() != default_id { + if stored_batch_handle.id() != extracted_uinode.image.id() { + if start != end { + commands.spawn(UiBatch { + range: start..end, + image: stored_batch_handle, + z: last_z, + }); + start = end; + } + stored_batch_handle = extracted_uinode.image.clone_weak(); + } + } else { + stored_batch_handle = extracted_uinode.image.clone_weak(); } - current_batch_handle = extracted_uinode.image.clone_weak(); } let mut uinode_rect = extracted_uinode.rect; @@ -472,7 +477,7 @@ pub fn prepare_uinodes( continue; } } - let uvs = if current_batch_handle.id() == DEFAULT_IMAGE_HANDLE.id() { + let uvs = if extracted_uinode.image.id() == DEFAULT_IMAGE_HANDLE.id() { [ Vec2::splat(f32::MAX), Vec2::splat(f32::MAX), @@ -533,7 +538,7 @@ pub fn prepare_uinodes( if start != end { commands.spawn(UiBatch { range: start..end, - image: current_batch_handle, + image: stored_batch_handle, z: last_z, }); } From 7bfb12ffd090a1733fb20ccce48fe57fe859c24b Mon Sep 17 00:00:00 2001 From: ickshonpe Date: Fri, 9 Jun 2023 13:54:55 +0100 Subject: [PATCH 07/20] Switch to using a flag --- crates/bevy_ui/src/render/mod.rs | 13 +++++++------ crates/bevy_ui/src/render/pipeline.rs | 2 ++ crates/bevy_ui/src/render/ui.wgsl | 5 ++++- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index 382c271058b91..9ee5c6096bdf1 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -349,6 +349,7 @@ struct UiVertex { pub position: [f32; 3], pub uv: [f32; 2], pub color: [f32; 4], + pub mode: u32, } #[derive(Resource)] @@ -401,9 +402,11 @@ pub fn prepare_uinodes( let mut stored_batch_handle = DEFAULT_IMAGE_HANDLE.typed(); let mut last_z = 0.0; let default_id = DEFAULT_IMAGE_HANDLE.id(); + let mut mode; for extracted_uinode in &extracted_uinodes.uinodes { if extracted_uinode.image.id() != default_id { + mode = 0; if stored_batch_handle.id() != default_id { if stored_batch_handle.id() != extracted_uinode.image.id() { if start != end { @@ -419,6 +422,8 @@ pub fn prepare_uinodes( } else { stored_batch_handle = extracted_uinode.image.clone_weak(); } + } else { + mode = 1; } let mut uinode_rect = extracted_uinode.rect; @@ -478,12 +483,7 @@ pub fn prepare_uinodes( } } let uvs = if extracted_uinode.image.id() == DEFAULT_IMAGE_HANDLE.id() { - [ - Vec2::splat(f32::MAX), - Vec2::splat(f32::MAX), - Vec2::splat(f32::MAX), - Vec2::splat(f32::MAX), - ] + [Vec2::ZERO, Vec2::X, Vec2::ONE, Vec2::Y] } else { let atlas_extent = extracted_uinode.atlas_size.unwrap_or(uinode_rect.max); if extracted_uinode.flip_x { @@ -527,6 +527,7 @@ pub fn prepare_uinodes( position: positions_clipped[i].into(), uv: uvs[i].into(), color, + mode, }); } diff --git a/crates/bevy_ui/src/render/pipeline.rs b/crates/bevy_ui/src/render/pipeline.rs index 84cc74d11ebd7..f6b4b0cc3c1ea 100644 --- a/crates/bevy_ui/src/render/pipeline.rs +++ b/crates/bevy_ui/src/render/pipeline.rs @@ -77,6 +77,8 @@ impl SpecializedRenderPipeline for UiPipeline { VertexFormat::Float32x2, // color VertexFormat::Float32x4, + // mode + VertexFormat::Uint32, ], ); let shader_defs = Vec::new(); diff --git a/crates/bevy_ui/src/render/ui.wgsl b/crates/bevy_ui/src/render/ui.wgsl index 8f91be6a33eaa..751c3b67412f3 100644 --- a/crates/bevy_ui/src/render/ui.wgsl +++ b/crates/bevy_ui/src/render/ui.wgsl @@ -6,6 +6,7 @@ var view: View; struct VertexOutput { @location(0) uv: vec2, @location(1) color: vec4, + @location(3) mode: u32, @builtin(position) position: vec4, }; @@ -14,11 +15,13 @@ fn vertex( @location(0) vertex_position: vec3, @location(1) vertex_uv: vec2, @location(2) vertex_color: vec4, + @location(3) mode: u32, ) -> VertexOutput { var out: VertexOutput; out.uv = vertex_uv; out.position = view.view_proj * vec4(vertex_position, 1.0); out.color = vertex_color; + out.mode = mode; return out; } @@ -30,7 +33,7 @@ var sprite_sampler: sampler; @fragment fn fragment(in: VertexOutput) -> @location(0) vec4 { var color = textureSample(sprite_texture, sprite_sampler, in.uv); - if in.uv.x < 1.e+20 { + if in.mode == 0u { color = in.color * color; } else { color = in.color; From 42a279676af227f54faf25a21a92bac4d3f6f258 Mon Sep 17 00:00:00 2001 From: ickshonpe Date: Fri, 9 Jun 2023 16:11:19 +0100 Subject: [PATCH 08/20] replace mode values with consts --- crates/bevy_ui/src/render/mod.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index 9ee5c6096bdf1..77e52aa2efba5 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -383,6 +383,9 @@ pub struct UiBatch { pub z: f32, } +const TEXTURED_QUAD: u32 = 0; +const UNTEXTURED_QUAD: u32 = 1; + pub fn prepare_uinodes( mut commands: Commands, render_device: Res, @@ -402,11 +405,9 @@ pub fn prepare_uinodes( let mut stored_batch_handle = DEFAULT_IMAGE_HANDLE.typed(); let mut last_z = 0.0; let default_id = DEFAULT_IMAGE_HANDLE.id(); - let mut mode; for extracted_uinode in &extracted_uinodes.uinodes { - if extracted_uinode.image.id() != default_id { - mode = 0; + let mode = if extracted_uinode.image.id() != default_id { if stored_batch_handle.id() != default_id { if stored_batch_handle.id() != extracted_uinode.image.id() { if start != end { @@ -422,9 +423,10 @@ pub fn prepare_uinodes( } else { stored_batch_handle = extracted_uinode.image.clone_weak(); } + TEXTURED_QUAD } else { - mode = 1; - } + UNTEXTURED_QUAD + }; let mut uinode_rect = extracted_uinode.rect; @@ -482,7 +484,7 @@ pub fn prepare_uinodes( continue; } } - let uvs = if extracted_uinode.image.id() == DEFAULT_IMAGE_HANDLE.id() { + let uvs = if mode == UNTEXTURED_QUAD { [Vec2::ZERO, Vec2::X, Vec2::ONE, Vec2::Y] } else { let atlas_extent = extracted_uinode.atlas_size.unwrap_or(uinode_rect.max); From 1bffb98cdac71a1e44e85150c44cdd77c29ef309 Mon Sep 17 00:00:00 2001 From: ickshonpe Date: Sat, 10 Jun 2023 11:41:55 +0100 Subject: [PATCH 09/20] Set `stored_batch_handle` where the code paths join after deciding whether to add a new batch. --- crates/bevy_ui/src/render/mod.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index 77e52aa2efba5..e44b5ccb205ab 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -418,11 +418,9 @@ pub fn prepare_uinodes( }); start = end; } - stored_batch_handle = extracted_uinode.image.clone_weak(); } - } else { - stored_batch_handle = extracted_uinode.image.clone_weak(); } + stored_batch_handle = extracted_uinode.image.clone_weak(); TEXTURED_QUAD } else { UNTEXTURED_QUAD From de1b468796bd64336671bc0f5cc727f213ba7646 Mon Sep 17 00:00:00 2001 From: ickshonpe Date: Sat, 10 Jun 2023 11:44:49 +0100 Subject: [PATCH 10/20] Removed `last_z` from UiBatch` as it is always equal to `0` --- crates/bevy_ui/src/render/mod.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index e44b5ccb205ab..73d1029b92668 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -380,7 +380,6 @@ const QUAD_INDICES: [usize; 6] = [0, 2, 3, 0, 1, 2]; pub struct UiBatch { pub range: Range, pub image: Handle, - pub z: f32, } const TEXTURED_QUAD: u32 = 0; @@ -403,7 +402,6 @@ pub fn prepare_uinodes( let mut start = 0; let mut end = 0; let mut stored_batch_handle = DEFAULT_IMAGE_HANDLE.typed(); - let mut last_z = 0.0; let default_id = DEFAULT_IMAGE_HANDLE.id(); for extracted_uinode in &extracted_uinodes.uinodes { @@ -414,7 +412,6 @@ pub fn prepare_uinodes( commands.spawn(UiBatch { range: start..end, image: stored_batch_handle, - z: last_z, }); start = end; } @@ -531,7 +528,6 @@ pub fn prepare_uinodes( }); } - last_z = extracted_uinode.transform.w_axis[2]; end += QUAD_INDICES.len() as u32; } @@ -540,7 +536,6 @@ pub fn prepare_uinodes( commands.spawn(UiBatch { range: start..end, image: stored_batch_handle, - z: last_z, }); } @@ -618,7 +613,7 @@ pub fn queue_uinodes( draw_function: draw_ui_function, pipeline, entity, - sort_key: FloatOrd(batch.z), + sort_key: FloatOrd(0.), }); } } From 5bb1fb6dfca1274470312dbf7ee62076dbfb50b5 Mon Sep 17 00:00:00 2001 From: ickshonpe Date: Sat, 10 Jun 2023 11:52:26 +0100 Subject: [PATCH 11/20] Removed the `start != end` check in the main loop as it's redundant now. --- crates/bevy_ui/src/render/mod.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index 73d1029b92668..7a2df4275a696 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -403,18 +403,17 @@ pub fn prepare_uinodes( let mut end = 0; let mut stored_batch_handle = DEFAULT_IMAGE_HANDLE.typed(); let default_id = DEFAULT_IMAGE_HANDLE.id(); + for extracted_uinode in &extracted_uinodes.uinodes { let mode = if extracted_uinode.image.id() != default_id { if stored_batch_handle.id() != default_id { if stored_batch_handle.id() != extracted_uinode.image.id() { - if start != end { - commands.spawn(UiBatch { - range: start..end, - image: stored_batch_handle, - }); - start = end; - } + commands.spawn(UiBatch { + range: start..end, + image: stored_batch_handle, + }); + start = end; } } stored_batch_handle = extracted_uinode.image.clone_weak(); From 189fe19185359f802d9e560822d397bced8fdf75 Mon Sep 17 00:00:00 2001 From: ickshonpe Date: Sat, 10 Jun 2023 12:00:44 +0100 Subject: [PATCH 12/20] Replaced `handle.id() != default_id` predicates with a function `is_textured` --- crates/bevy_ui/src/render/mod.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index 7a2df4275a696..a62cb5d71371a 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -402,12 +402,13 @@ pub fn prepare_uinodes( let mut start = 0; let mut end = 0; let mut stored_batch_handle = DEFAULT_IMAGE_HANDLE.typed(); - let default_id = DEFAULT_IMAGE_HANDLE.id(); + #[inline] + fn is_textured(image: &Handle) -> bool { image.id() != DEFAULT_IMAGE_HANDLE.id() } for extracted_uinode in &extracted_uinodes.uinodes { - let mode = if extracted_uinode.image.id() != default_id { - if stored_batch_handle.id() != default_id { + let mode = if is_textured(&extracted_uinode.image) { + if is_textured(&stored_batch_handle) { if stored_batch_handle.id() != extracted_uinode.image.id() { commands.spawn(UiBatch { range: start..end, From 6b76e17912b06cbb075b4d43fe991a64195ad95b Mon Sep 17 00:00:00 2001 From: ickshonpe Date: Sat, 10 Jun 2023 12:31:05 +0100 Subject: [PATCH 13/20] renamed `staored_image_handle` to `current_batch_image` --- crates/bevy_ui/src/render/mod.rs | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index a62cb5d71371a..2a205a96a703d 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -401,23 +401,25 @@ pub fn prepare_uinodes( let mut start = 0; let mut end = 0; - let mut stored_batch_handle = DEFAULT_IMAGE_HANDLE.typed(); - + let mut current_batch_image = DEFAULT_IMAGE_HANDLE.typed(); + #[inline] - fn is_textured(image: &Handle) -> bool { image.id() != DEFAULT_IMAGE_HANDLE.id() } + fn is_textured(image: &Handle) -> bool { + image.id() != DEFAULT_IMAGE_HANDLE.id() + } for extracted_uinode in &extracted_uinodes.uinodes { let mode = if is_textured(&extracted_uinode.image) { - if is_textured(&stored_batch_handle) { - if stored_batch_handle.id() != extracted_uinode.image.id() { - commands.spawn(UiBatch { - range: start..end, - image: stored_batch_handle, - }); - start = end; - } + if is_textured(¤t_batch_image) + && current_batch_image.id() != extracted_uinode.image.id() + { + commands.spawn(UiBatch { + range: start..end, + image: current_batch_image, + }); + start = end; } - stored_batch_handle = extracted_uinode.image.clone_weak(); + current_batch_image = extracted_uinode.image.clone_weak(); TEXTURED_QUAD } else { UNTEXTURED_QUAD @@ -535,7 +537,7 @@ pub fn prepare_uinodes( if start != end { commands.spawn(UiBatch { range: start..end, - image: stored_batch_handle, + image: current_batch_image, }); } From 79fe5fd3e58d6eb45a6e299480cf6e8d3b919d4a Mon Sep 17 00:00:00 2001 From: ickshonpe Date: Sat, 10 Jun 2023 13:03:50 +0100 Subject: [PATCH 14/20] Don't need to update `current_batch_image` when it is already equal to the extracted image. --- crates/bevy_ui/src/render/mod.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index 2a205a96a703d..936bbe0ab2f72 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -410,18 +410,20 @@ pub fn prepare_uinodes( for extracted_uinode in &extracted_uinodes.uinodes { let mode = if is_textured(&extracted_uinode.image) { - if is_textured(¤t_batch_image) - && current_batch_image.id() != extracted_uinode.image.id() - { - commands.spawn(UiBatch { - range: start..end, + if current_batch_image.id() != extracted_uinode.image.id() { + if is_textured(¤t_batch_image) { + commands.spawn(UiBatch { + range: start..end, image: current_batch_image, - }); - start = end; + }); + start = end; + } + current_batch_image = extracted_uinode.image.clone_weak(); } - current_batch_image = extracted_uinode.image.clone_weak(); TEXTURED_QUAD } else { + // Untextured `UiBatch`es are never spawned within the loop. + // If all the `extracted_uinodes` are untextured a single untextured UiBatch will be spawned after the loop terminates. UNTEXTURED_QUAD }; From e7e686afd3b65ddbf1ca54abb751d191a37ebf63 Mon Sep 17 00:00:00 2001 From: ickshonpe Date: Sat, 10 Jun 2023 13:48:55 +0100 Subject: [PATCH 15/20] Removed the `sort_key` field from `TransparentUi` --- crates/bevy_ui/src/render/mod.rs | 2 -- crates/bevy_ui/src/render/render_pass.rs | 6 ++---- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index 936bbe0ab2f72..44a744195a983 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -33,7 +33,6 @@ use bevy_sprite::TextureAtlas; #[cfg(feature = "bevy_text")] use bevy_text::{PositionedGlyph, Text, TextLayoutInfo}; use bevy_transform::components::GlobalTransform; -use bevy_utils::FloatOrd; use bevy_utils::HashMap; use bytemuck::{Pod, Zeroable}; use std::ops::Range; @@ -617,7 +616,6 @@ pub fn queue_uinodes( draw_function: draw_ui_function, pipeline, entity, - sort_key: FloatOrd(0.), }); } } diff --git a/crates/bevy_ui/src/render/render_pass.rs b/crates/bevy_ui/src/render/render_pass.rs index 90e7b6059cecc..e98871ce4ef22 100644 --- a/crates/bevy_ui/src/render/render_pass.rs +++ b/crates/bevy_ui/src/render/render_pass.rs @@ -11,7 +11,6 @@ use bevy_render::{ renderer::*, view::*, }; -use bevy_utils::FloatOrd; pub struct UiPassNode { ui_view_query: QueryState< @@ -86,14 +85,13 @@ impl Node for UiPassNode { } pub struct TransparentUi { - pub sort_key: FloatOrd, pub entity: Entity, pub pipeline: CachedRenderPipelineId, pub draw_function: DrawFunctionId, } impl PhaseItem for TransparentUi { - type SortKey = FloatOrd; + type SortKey = (); #[inline] fn entity(&self) -> Entity { @@ -102,7 +100,7 @@ impl PhaseItem for TransparentUi { #[inline] fn sort_key(&self) -> Self::SortKey { - self.sort_key + () } #[inline] From d97219fff5e5e6f2ded7f310266b07e19bc390ea Mon Sep 17 00:00:00 2001 From: ickshonpe Date: Sat, 10 Jun 2023 14:18:00 +0100 Subject: [PATCH 16/20] fix clippy::unused-unit --- crates/bevy_ui/src/render/render_pass.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/crates/bevy_ui/src/render/render_pass.rs b/crates/bevy_ui/src/render/render_pass.rs index e98871ce4ef22..1ae7209f8239b 100644 --- a/crates/bevy_ui/src/render/render_pass.rs +++ b/crates/bevy_ui/src/render/render_pass.rs @@ -99,9 +99,7 @@ impl PhaseItem for TransparentUi { } #[inline] - fn sort_key(&self) -> Self::SortKey { - () - } + fn sort_key(&self) -> Self::SortKey {} #[inline] fn draw_function(&self) -> DrawFunctionId { From 34a1d4fc3b4ac1dcd3b36bfd155f5e7f66f9982a Mon Sep 17 00:00:00 2001 From: ickshonpe Date: Sun, 11 Jun 2023 23:06:55 +0100 Subject: [PATCH 17/20] Reversed the z ordering changes. They aren't important and can be left to another PR. --- crates/bevy_ui/src/render/mod.rs | 9 ++++++++- crates/bevy_ui/src/render/render_pass.rs | 8 ++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index 44a744195a983..aa2a3d7317807 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -33,6 +33,7 @@ use bevy_sprite::TextureAtlas; #[cfg(feature = "bevy_text")] use bevy_text::{PositionedGlyph, Text, TextLayoutInfo}; use bevy_transform::components::GlobalTransform; +use bevy_utils::FloatOrd; use bevy_utils::HashMap; use bytemuck::{Pod, Zeroable}; use std::ops::Range; @@ -379,6 +380,7 @@ const QUAD_INDICES: [usize; 6] = [0, 2, 3, 0, 1, 2]; pub struct UiBatch { pub range: Range, pub image: Handle, + pub z: f32, } const TEXTURED_QUAD: u32 = 0; @@ -401,6 +403,7 @@ pub fn prepare_uinodes( let mut start = 0; let mut end = 0; let mut current_batch_image = DEFAULT_IMAGE_HANDLE.typed(); + let mut last_z = 0.0; #[inline] fn is_textured(image: &Handle) -> bool { @@ -414,6 +417,7 @@ pub fn prepare_uinodes( commands.spawn(UiBatch { range: start..end, image: current_batch_image, + z: last_z, }); start = end; } @@ -531,7 +535,8 @@ pub fn prepare_uinodes( }); } - end += QUAD_INDICES.len() as u32; + last_z = extracted_uinode.transform.w_axis[2]; + end += QUAD_VERTEX_POSITIONS.len() as u32; } // if start != end, there is one last batch to process @@ -539,6 +544,7 @@ pub fn prepare_uinodes( commands.spawn(UiBatch { range: start..end, image: current_batch_image, + z: last_z, }); } @@ -616,6 +622,7 @@ pub fn queue_uinodes( draw_function: draw_ui_function, pipeline, entity, + sort_key: FloatOrd(batch.z), }); } } diff --git a/crates/bevy_ui/src/render/render_pass.rs b/crates/bevy_ui/src/render/render_pass.rs index 1ae7209f8239b..90e7b6059cecc 100644 --- a/crates/bevy_ui/src/render/render_pass.rs +++ b/crates/bevy_ui/src/render/render_pass.rs @@ -11,6 +11,7 @@ use bevy_render::{ renderer::*, view::*, }; +use bevy_utils::FloatOrd; pub struct UiPassNode { ui_view_query: QueryState< @@ -85,13 +86,14 @@ impl Node for UiPassNode { } pub struct TransparentUi { + pub sort_key: FloatOrd, pub entity: Entity, pub pipeline: CachedRenderPipelineId, pub draw_function: DrawFunctionId, } impl PhaseItem for TransparentUi { - type SortKey = (); + type SortKey = FloatOrd; #[inline] fn entity(&self) -> Entity { @@ -99,7 +101,9 @@ impl PhaseItem for TransparentUi { } #[inline] - fn sort_key(&self) -> Self::SortKey {} + fn sort_key(&self) -> Self::SortKey { + self.sort_key + } #[inline] fn draw_function(&self) -> DrawFunctionId { From be826185419507fc60191a0f6797de01c7ee621f Mon Sep 17 00:00:00 2001 From: ickshonpe Date: Mon, 12 Jun 2023 11:25:57 +0100 Subject: [PATCH 18/20] Should be `QUAD_INDICES.len()`, I don't know how this got changed. --- crates/bevy_ui/src/render/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index aa2a3d7317807..6574c35f18f7d 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -536,7 +536,7 @@ pub fn prepare_uinodes( } last_z = extracted_uinode.transform.w_axis[2]; - end += QUAD_VERTEX_POSITIONS.len() as u32; + end += QUAD_INDICES.len() as u32; } // if start != end, there is one last batch to process From ebe7a399c84c468d21ca2690be058c1ae9611a23 Mon Sep 17 00:00:00 2001 From: ickshonpe Date: Mon, 19 Jun 2023 15:05:29 +0100 Subject: [PATCH 19/20] The `start != end` check is required inside the loop as well to account for culled extracted nodes. --- crates/bevy_ui/src/render/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index 6574c35f18f7d..829157e47cea2 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -413,7 +413,7 @@ pub fn prepare_uinodes( for extracted_uinode in &extracted_uinodes.uinodes { let mode = if is_textured(&extracted_uinode.image) { if current_batch_image.id() != extracted_uinode.image.id() { - if is_textured(¤t_batch_image) { + if is_textured(¤t_batch_image) && start != end { commands.spawn(UiBatch { range: start..end, image: current_batch_image, From 75d4092923fc92bdcb2f88e2c91d9e23499907bb Mon Sep 17 00:00:00 2001 From: ickshonpe Date: Tue, 20 Jun 2023 16:36:55 +0100 Subject: [PATCH 20/20] `ui.wgsl` Replace mode value with a const. Added comment to the fragment shader explaining `textureSample` that cannot be called inside an if branch, only in uniform flow control. --- crates/bevy_ui/src/render/ui.wgsl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/crates/bevy_ui/src/render/ui.wgsl b/crates/bevy_ui/src/render/ui.wgsl index 751c3b67412f3..389bfcd1c5a30 100644 --- a/crates/bevy_ui/src/render/ui.wgsl +++ b/crates/bevy_ui/src/render/ui.wgsl @@ -1,5 +1,7 @@ #import bevy_render::view +const TEXTURED_QUAD: u32 = 0u; + @group(0) @binding(0) var view: View; @@ -32,8 +34,9 @@ var sprite_sampler: sampler; @fragment fn fragment(in: VertexOutput) -> @location(0) vec4 { + // textureSample can only be called in unform control flow, not inside an if branch. var color = textureSample(sprite_texture, sprite_sampler, in.uv); - if in.mode == 0u { + if in.mode == TEXTURED_QUAD { color = in.color * color; } else { color = in.color;