Skip to content

feat(engine): vertex and index buffers, and indexed draws, reachable from Python #1898

Description

@tato123

Change: docs/plan/changes/kernel-kind-parity-bar.md (approved 2026-08-17, PR #1897), disposition 1. Plan: [python-kernel-api] §Graphics.

That change narrows §Graphics' parity claim from every GPU capability to every kernel kind, and records the capabilities Python cannot reach as named dispositions rather than leaving them silent. This is one of them, filed post-MVP by owner ruling.

What & why

Rust authoring can build a graphics kernel that pulls geometry from a vertex buffer and draws it indexed. Python cannot: draw takes vertex_count, instance_count, first_vertex, first_instance and no buffer argument (_engine.pyi:711-721, :474-478), so a Python author fabricates geometry from gl_VertexIndex — the fullscreen-triangle idiom, which is enough for a video effect and nothing else.

The unusual part, and the reason this is not a straight mirroring job: the Rust side has zero callers anywhere. acquire_vertex_buffer (gpu_context.rs:1846) and acquire_index_buffer (:1861) appear only in gpu_context.rs itself — the definitions plus the GpuContextLimitedAccess (:3720, :3727) and GpuContextFullAccess (:3981, :3987) mirrors. set_vertex_buffer (vulkan_graphics_kernel.rs:1361), set_index_buffer (:1374) and record_draw_indexed (vulkan_command_recorder.rs:1166) have no exercise in the tree at all; constructs_kernel_with_vertex_input_buffers (vulkan_graphics_kernel.rs:2837) only sets pipeline_state.vertex_input and never binds or draws.

So this exposes a capability nothing has ever used. That argues for designing the Python spelling on its own terms and letting the Rust surface follow, rather than mirroring an untested one — worth settling before implementation rather than during it.

Design

The missing primitive is a buffer a surface id can name. Constraints, inlined so this ticket stands alone:

  • No escalate op mints a vertex or index buffer. acquire_pixel_buffer lands on HostVulkanBuffer::new with usage TRANSFER_SRC | TRANSFER_DST | STORAGE_BUFFER (vulkan_buffer.rs:151-154) and no VERTEX_BUFFER bit.
  • The setters take &impl VulkanVertexBindable / VulkanIndexBindable, implemented only by VertexBuffer / IndexBuffer (vulkan_storage_binding.rs). A compile_fail,E0277 doctest proves PixelBuffer is rejected.
  • RegisteredHandle carries only PixelBuffer | Texture | Image, so a helper has no way to name a buffer today.
  • The wire half already ships elsewhere and is the closest precedent: build_triangles_blas hex-encodes flat Python lists (python_processor_context.rs:1068-1069), decoded and minted engine-side (subprocess_escalate.rs:2791-2798, vulkan_acceleration_structure.rs:159). But it mints AsBuffer::new_host_visible — vertex :201-207, index :223-229, usage ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_KHR | SHADER_DEVICE_ADDRESS, host-visible by deliberate choice (:196-200) — which implements no bindable trait. The transfer shape carries over; the buffer type and usage flags do not.
  • An indexed draw needs the index-range check the BLAS path just gained (vulkan_acceleration_structure.rs, PR feat(engine)!: graphics and ray-tracing kernels at Python parity #1896) — except an indexed draw does have a robustness escape hatch where an acceleration-structure build does not, so the rule is not identical. State which applies.

Related but covering neither: #505 (the original graphics-kernel RHI), #658, #964 (buffer-model collapse), #503 (texel-buffer descriptor types).

Done means

  • An escalate op mints a vertex/index buffer and a surface id names it.
  • Binding resolution grows a buffer arm, so storage_buffer / uniform_buffer bindings and vertex/index buffers stop being refused for the same missing-primitive reason.
  • draw takes vertex buffers and an indexed variant, with _engine.pyi entries.
  • Four refusals retire: subprocess_escalate.rs:2492, :2504, :3512 (draw-time) and the register-time vertex_input_bindings refusal.
  • The §Graphics disposition naming this gap is removed from ARCHITECTURE.md in the same PR.

Validation shape

A Python processor draws indexed geometry from a vertex buffer it filled, end to end from a helper child. One test per retired refusal, asserting the capability rather than the message. An out-of-range index is refused before submission. requires_gpu tests execute on the rig only — CI green is not proof for this ticket.

Non-derivable notes

Filed post-MVP by owner ruling 2026-08-17: a fullscreen effect has no use for vertex buffers, and the MVP sentence invites editing a scaffolded processor rather than authoring geometry. Do not pull this into MVP without a plan change — the §Graphics entry names it as a known gap, and closing it silently would leave the plan claiming a gap that no longer exists.

Metadata

Metadata

Assignees

No one assigned

    Labels

    zone:engineEngine / iceoryx2 / transport internalszone:vulkanloop zone: Vulkan RHI / GPU

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions