Skip to content

Commit d70b4a3

Browse files
authored
UI batching Fix (#9610)
# Objective Reimplement #8793 on top of the recent rendering changes. ## Solution The batch creation logic is quite convoluted, but I tested it on enough examples to convince myself that it works. The initial value of `batch_image_handle` is changed from `HandleId::Id(Uuid::nil(), u64::MAX)` to `DEFAULT_IMAGE_HANDLE.id()`, which allowed me to make the if-block simpler I think. The default image from `DEFAULT_IMAGE_HANDLE` is always inserted into `UiImageBindGroups` even if it's not used. I tried to add a check so that it would be only inserted when there is only one batch using the default image but this crashed. --- ## Changelog `prepare_uinodes` * Changed the initial value of `batch_image_handle` to `DEFAULT_IMAGE_HANDLE.id()`. * The default image is added to the UI image bind groups before assembling the batches. * A new `UiBatch` isn't created when the next `ExtractedUiNode`s image is set to `DEFAULT_IMAGE_HANDLE` (unless it is the first item in the UI phase items list).
1 parent 5cc3352 commit d70b4a3

File tree

1 file changed

+33
-12
lines changed
  • crates/bevy_ui/src/render

1 file changed

+33
-12
lines changed

crates/bevy_ui/src/render/mod.rs

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -732,6 +732,7 @@ pub fn queue_uinodes(
732732
transparent_phase
733733
.items
734734
.reserve(extracted_uinodes.uinodes.len());
735+
735736
for (entity, extracted_uinode) in extracted_uinodes.uinodes.iter() {
736737
transparent_phase.add(TransparentUi {
737738
draw_function,
@@ -781,11 +782,6 @@ pub fn prepare_uinodes(
781782
};
782783
}
783784

784-
#[inline]
785-
fn is_textured(image: AssetId<Image>) -> bool {
786-
image != AssetId::default()
787-
}
788-
789785
if let Some(view_binding) = view_uniforms.uniforms.binding() {
790786
let mut batches: Vec<(Entity, UiBatch)> = Vec::with_capacity(*previous_len);
791787

@@ -798,19 +794,21 @@ pub fn prepare_uinodes(
798794

799795
// Vertex buffer index
800796
let mut index = 0;
801-
802797
for mut ui_phase in &mut phases {
803798
let mut batch_item_index = 0;
804799
let mut batch_image_handle = AssetId::invalid();
805800

806801
for item_index in 0..ui_phase.items.len() {
807802
let item = &mut ui_phase.items[item_index];
808803
if let Some(extracted_uinode) = extracted_uinodes.uinodes.get(&item.entity) {
809-
let mut existing_batch = batches
810-
.last_mut()
811-
.filter(|_| batch_image_handle == extracted_uinode.image);
812-
813-
if existing_batch.is_none() {
804+
let mut existing_batch = batches.last_mut();
805+
806+
if batch_image_handle == AssetId::invalid()
807+
|| existing_batch.is_none()
808+
|| (batch_image_handle != AssetId::default()
809+
&& extracted_uinode.image != AssetId::default()
810+
&& batch_image_handle != extracted_uinode.image)
811+
{
814812
if let Some(gpu_image) = gpu_images.get(extracted_uinode.image) {
815813
batch_item_index = item_index;
816814
batch_image_handle = extracted_uinode.image;
@@ -840,9 +838,32 @@ pub fn prepare_uinodes(
840838
} else {
841839
continue;
842840
}
841+
} else if batch_image_handle == AssetId::default()
842+
&& extracted_uinode.image != AssetId::default()
843+
{
844+
if let Some(gpu_image) = gpu_images.get(extracted_uinode.image) {
845+
batch_image_handle = extracted_uinode.image;
846+
existing_batch.as_mut().unwrap().1.image = extracted_uinode.image;
847+
848+
image_bind_groups
849+
.values
850+
.entry(batch_image_handle)
851+
.or_insert_with(|| {
852+
render_device.create_bind_group(
853+
"ui_material_bind_group",
854+
&ui_pipeline.image_layout,
855+
&BindGroupEntries::sequential((
856+
&gpu_image.texture_view,
857+
&gpu_image.sampler,
858+
)),
859+
)
860+
});
861+
} else {
862+
continue;
863+
}
843864
}
844865

845-
let mode = if is_textured(extracted_uinode.image) {
866+
let mode = if extracted_uinode.image != AssetId::default() {
846867
TEXTURED_QUAD
847868
} else {
848869
UNTEXTURED_QUAD

0 commit comments

Comments
 (0)