public static class DrawBatcherGroups a frame's commands into runs that can be drawn as one.
No guide page documents this yet — the page shows what the code says about itself.
Remarks
Runs of consecutive commands, and never a reordering. That is the whole design and it is worth being blunt about, because reordering is what batching means everywhere else: a 3D renderer sorts draws by material because a depth buffer decides what ends up in front. A user interface has no depth buffer. Order is the answer to what is in front, so moving two runs of the same font together across the panel between them draws the text over the panel that was supposed to cover it.
⚠ The renderer already agrees, and it is worth knowing where. RenderSortMode.ByGroup exists and its own remarks say it is "for UI and anything else already ordered" — depth left out, sorted on a group value alone. Which means a UI render feature has to make that group be the painting order: the sort is stable and orders by group, so a group that meant anything else — a material, a pipeline, a texture — would reorder the interface on the way to the screen and undo everything below. The batch index is that number.
⚠ It is not the batch index, and Vixen.Ui.Renderer settled it. A render object is one surface, not one batch: the store's objects live across frames and are indexed by a dense id every feature's parallel array is keyed on, so an object per batch would churn the whole store every time a label changed. The painting order within a surface is already the order these batches are in, and no sort can reach it. What the group orders is surfaces against each other — a modal over a document, a tooltip over the modal — which is a real ordering problem the sort is the right answer to. The conclusion above was right about ByGroup and wrong about what it counts.
So the win here is bounded and honest: adjacent things that happen to match are merged, and nothing else is. A list of a hundred alternating labels and boxes batches into two hundred batches, and that is the correct answer rather than a failure to optimise. What improves it is emitting fewer interleavings — which is a question for whoever writes the controls, not for this.
The batches are a partition: every command is in exactly one, in order, so a consumer walks the batches alone and never has to fall back to the commands to find what it missed.
⚠ The renderer does not work this way, and the difference is the point. MeshRenderFeature has no batch list: it walks its nodes in sorted order and re-binds only when the pipeline handle changes, which reaches the same runs with two locals and no array. That is right for a mesh, whose nodes are rebuilt from culling every frame so nothing precomputed would survive. A user interface is the opposite case — most frames draw exactly what the last one drew — so the runs are worked out behind the frame diff and a still interface pays nothing.
⚠ That open question is closed: this list is used, and not by the render feature. UiGeometryBuilder turns one batch into one UiDraw, which is what carries the resolved clip and the pipeline kind to the renderer; the renderer then does exactly what MeshRenderFeature does and re-binds on change. So the grouping is computed once behind the frame diff and consumed once per frame, which is the arrangement this was written hoping for rather than the one where it is dead weight.
Methods (1)
public static void Build(IReadOnlyList<DrawCommand> commands, List<DrawBatch> into)Groups commands into batches.
Used by (2)
- BatchTestsVixen.Ui.Tests
- DrawListVixen.Ui