Skip to content

Metal: lower large indexed multi-draws to ICBs#263

Open
besmpl wants to merge 3 commits into
gogpu:mainfrom
besmpl:besmpl/metal-icb-lowering
Open

Metal: lower large indexed multi-draws to ICBs#263
besmpl wants to merge 3 commits into
gogpu:mainfrom
besmpl:besmpl/metal-icb-lowering

Conversation

@besmpl

@besmpl besmpl commented Jul 15, 2026

Copy link
Copy Markdown

Stack and review order

This is a stacked PR built on the current head of #253 (1953452) and is ready for review. Please approve the prerequisite PRs before this one.

Please review and land the stack in this order:

  1. fix(dx12): match indirect descriptor ABI size #258
  2. Add fixed-count indirect multi-draw #253
  3. this PR

Until #253 lands, GitHub shows its commits in this PR's diff because its head branch is in a fork and cannot be selected as an upstream base. After the prerequisites settle, this branch will be rebased onto main and the verification below rerun.

What changed

  • Delay Metal render-command-encoder creation until the first draw while retaining bounded, latest-value pre-draw state. Clear/store/resolve-only passes still instantiate at pass end.
  • Privately mark eligible buffer-only triangle pipelines as ICB-compatible. A rejected flagged pipeline transparently retries ordinary creation.
  • Translate a profitable first indexed multi-draw into one bounded Metal indirect command buffer with one compute dispatch and one ICB execution.
  • Retain every ICB-referenced argument, index, vertex, and bound buffer through command-buffer completion, with once-only cleanup across completion, discard, setup failure, and teardown.
  • Preserve the exact Add fixed-count indirect multi-draw #253 loop for count zero, small or oversized counts, later draws, non-indexed draws, incompatible pipelines, writable storage bindings, unsupported devices, and every preflight failure.

Scope

The optimization is entirely private to hal/metal. It adds no public feature, flag, token, prepared-command API, or caller-managed lifetime. Metal feature reporting remains unchanged.

The initial eligibility policy is intentionally narrow:

  • Apple7-family support or later, with runtime selector checks
  • first draw in the pass
  • triangle-list indexed draw
  • 1,024 through 52,428 commands
  • buffer-only pipeline with no writable storage binding

Verification

  • CGO_ENABLED=0 go test ./...
  • focused Metal unit tests and race tests
  • native Metal pixel/readback parity for uint16 and uint32 indices, non-zero argument/index offsets, baseVertex, firstInstance, GPU-written indirect arguments, bound uniform/read-only-storage buffers, first-vs-later execution, and clear-only passes
  • Linux amd64 and Windows amd64 cgo-free builds
  • Rust-tag build
  • browser/WASM root build and browser-package compile
  • git diff --check and formatting checks

Paired Apple M1 complete-frame benchmarks against the exact #253 base measured median improvements of about 19% at 1,024 commands and 60% at 10,000 commands. Direct, count-1, and count-20 controls stayed within the 5% time/allocation gate in the stable paired run.

@besmpl besmpl marked this pull request as ready for review July 15, 2026 11:52
@besmpl besmpl requested a review from kolkov as a code owner July 15, 2026 11:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant