Skip to content

Commit

Permalink
UI batching Fix (#9610)
Browse files Browse the repository at this point in the history
# 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).
  • Loading branch information
ickshonpe committed Nov 3, 2023
1 parent 5cc3352 commit d70b4a3
Showing 1 changed file with 33 additions and 12 deletions.
45 changes: 33 additions & 12 deletions crates/bevy_ui/src/render/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -732,6 +732,7 @@ pub fn queue_uinodes(
transparent_phase
.items
.reserve(extracted_uinodes.uinodes.len());

for (entity, extracted_uinode) in extracted_uinodes.uinodes.iter() {
transparent_phase.add(TransparentUi {
draw_function,
Expand Down Expand Up @@ -781,11 +782,6 @@ pub fn prepare_uinodes(
};
}

#[inline]
fn is_textured(image: AssetId<Image>) -> bool {
image != AssetId::default()
}

if let Some(view_binding) = view_uniforms.uniforms.binding() {
let mut batches: Vec<(Entity, UiBatch)> = Vec::with_capacity(*previous_len);

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

// Vertex buffer index
let mut index = 0;

for mut ui_phase in &mut phases {
let mut batch_item_index = 0;
let mut batch_image_handle = AssetId::invalid();

for item_index in 0..ui_phase.items.len() {
let item = &mut ui_phase.items[item_index];
if let Some(extracted_uinode) = extracted_uinodes.uinodes.get(&item.entity) {
let mut existing_batch = batches
.last_mut()
.filter(|_| batch_image_handle == extracted_uinode.image);

if existing_batch.is_none() {
let mut existing_batch = batches.last_mut();

if batch_image_handle == AssetId::invalid()
|| existing_batch.is_none()
|| (batch_image_handle != AssetId::default()
&& extracted_uinode.image != AssetId::default()
&& batch_image_handle != extracted_uinode.image)
{
if let Some(gpu_image) = gpu_images.get(extracted_uinode.image) {
batch_item_index = item_index;
batch_image_handle = extracted_uinode.image;
Expand Down Expand Up @@ -840,9 +838,32 @@ pub fn prepare_uinodes(
} else {
continue;
}
} else if batch_image_handle == AssetId::default()
&& extracted_uinode.image != AssetId::default()
{
if let Some(gpu_image) = gpu_images.get(extracted_uinode.image) {
batch_image_handle = extracted_uinode.image;
existing_batch.as_mut().unwrap().1.image = extracted_uinode.image;

image_bind_groups
.values
.entry(batch_image_handle)
.or_insert_with(|| {
render_device.create_bind_group(
"ui_material_bind_group",
&ui_pipeline.image_layout,
&BindGroupEntries::sequential((
&gpu_image.texture_view,
&gpu_image.sampler,
)),
)
});
} else {
continue;
}
}

let mode = if is_textured(extracted_uinode.image) {
let mode = if extracted_uinode.image != AssetId::default() {
TEXTURED_QUAD
} else {
UNTEXTURED_QUAD
Expand Down

0 comments on commit d70b4a3

Please sign in to comment.