simvx.graphics.renderer.bindless_draw2d_pass

Bindless co-batched 2D pass for the item pipeline.

The main-framebuffer 2D submit. It carries texture_id and the is_msdf flag per vertex and draws through ONE unified pipeline (ui2d.vert / ui2d.frag). So a run of consecutive items sharing only (clip, blend) – different-texture sprites and glyph runs and untextured fills – collapses into a single vkCmdDrawIndexed that selects the texture per primitive via ui_textures[nonuniformEXT(tex_id)] and branches on the is_msdf bit (linear sample vs median-MSDF decode, the latter ported verbatim from text.frag so glyph AA is pixel-identical).

The MSDF atlas is registered into the engine’s bindless ui_textures[] array (the same array sprites use), so a glyph item just references that slot like any other textured item. The atlas slot is refreshed when the atlas version bumps (the view is recreated on re-upload).

Module Contents

Classes

BindlessBatch

One co-batched draw: a contiguous range under a (topology, clip, blend) scope.

BindlessDraw2DPass

GPU pass that draws bindless co-batched 2D geometry.

Data

API

simvx.graphics.renderer.bindless_draw2d_pass.__all__

[‘BindlessDraw2DPass’, ‘BindlessBatch’]

simvx.graphics.renderer.bindless_draw2d_pass.log

‘getLogger(…)’

simvx.graphics.renderer.bindless_draw2d_pass.FLAG_IS_MSDF

1

class simvx.graphics.renderer.bindless_draw2d_pass.BindlessBatch

Bases: typing.NamedTuple

One co-batched draw: a contiguous range under a (topology, clip, blend) scope.

clip is the scissor rect (or None for full-screen); blend is the blend-mode string selecting the per-blend pipeline. The texture and is_msdf selection are PER VERTEX, so a single triangle batch covers many textures (different-texture sprites + MSDF glyph runs + untextured fills).

Triangle batches (line=False) are indexed draws: vert_offset is the base vertex, idx_offset/count the index range. Line batches (line=True) are non-indexed: vert_offset is the first vertex and count the vertex count in the shared line vertex buffer. Lines use a different topology so they cannot merge with triangles; they break a run and render through the line pipeline, preserving painter order.

clip: tuple[int, int, int, int] | None

None

blend: str

None

vert_offset: int

None

idx_offset: int

None

count: int

None

line: bool

False

class simvx.graphics.renderer.bindless_draw2d_pass.BindlessDraw2DPass(engine: Any, text_pass: Any = None, light2d_pass: Any = None)

GPU pass that draws bindless co-batched 2D geometry.

Owns the unified ui2d pipeline (one per blend mode), one extended-vertex buffer + index buffer (host-visible, growable arena), and binds the engine’s bindless texture descriptor set (the same ui_textures[] sprites use). The MSDF atlas is registered into that array via :meth:sync_atlas_slot.

Initialization

__slots__

(‘_engine’, ‘_text_pass’, ‘_light2d_pass’, ‘_pipelines’, ‘_pipeline_layout’, ‘_line_pipeline’, ‘_lin…

setup(render_pass: Any = None, extent: tuple[int, int] | None = None, *, gbuffer: bool = False) → None
sync_atlas_slot() → int

Register / refresh the MSDF atlas in the bindless array; return its slot.

The glyph items reference this slot as their per-vertex tex_id. The atlas view is recreated when the atlas version bumps (re-upload), so the bindless descriptor is rewritten to the new view while keeping the same slot id stable (so already-built geometry stays valid).

property atlas_slot: int

The bindless slot of the MSDF atlas (-1 until :meth:sync_atlas_slot).

set_atlas_slot(slot: int) → None

Borrow an already-registered MSDF atlas slot (the HDR-lane pass).

The HDR-target 2D pass and the swapchain 2D pass bind the SAME engine bindless ui_textures[] descriptor set, so the atlas slot index is valid in both. Only the swapchain pass owns the registration (calls

Meth:

sync_atlas_slot); the HDR pass mirrors its slot here each frame to avoid a redundant second descriptor write for the same atlas view.

render(cmd: Any, width: int, height: int, ui_width: float, ui_height: float, *, verts: numpy.ndarray, indices: numpy.ndarray, line_verts: numpy.ndarray, batches: list[simvx.graphics.renderer.bindless_draw2d_pass.BindlessBatch], origin: tuple[int, int] = (0, 0)) → None

Upload the co-batched geometry and issue one draw per batch.

verts is a contiguous :data:UI2D_VERTEX_DTYPE array of triangle vertices (all batches concatenated, camera already applied), indices the matching uint32 index stream, line_verts the (separate) line vertices, batches the ordered per-(topology, clip, blend) runs. A triangle batch is ONE vkCmdDrawIndexed regardless of how many textures it touches; a line batch is ONE vkCmdDraw.

width x height at origin is the rect of the target the UI space maps onto: the whole target for every full-target submit, and the letterboxed design rect when the tree presents a design resolution into part of the window. Every scissor is clamped to it, so an item that overhangs the design rect is cut at the letterbox edge rather than drawn over a bar.

cleanup() → None