|
| 1 | +# Issue #131 virtual draw emission and raw-page decode v1 evidence |
| 2 | + |
| 3 | +This checkpoint qualifies Bloom's first bounded virtual-cluster indirect |
| 4 | +stream and cooked-page GPU decoder at revision |
| 5 | +`92daf0eae684ca5a0b359cc8c991f728ffb83600`. It proves that selected resident |
| 6 | +clusters can become executable indirect work without expanding their cooked |
| 7 | +vertices. It does not yet register a production render path or change ordinary |
| 8 | +scene pixels. |
| 9 | + |
| 10 | +## Fixed ownership and ABI |
| 11 | + |
| 12 | +`GpuVirtualDrawEmitter` is constructed explicitly from one hierarchy selector. |
| 13 | +It rejects another selector, validates command-buffer and workgroup limits |
| 14 | +before allocation, and owns three fixed resources: |
| 15 | + |
| 16 | +| Record | Exact bytes | Purpose | |
| 17 | +|---|---:|---| |
| 18 | +| non-indexed draw command | 16 | triangle vertex count and selected-record address | |
| 19 | +| emission state/count | 48 | indirect count, whole-batch fallback, and counters | |
| 20 | +| compute dispatch command | 12 | bounded indirect emission dispatch | |
| 21 | + |
| 22 | +The command capacity exactly equals the selector's selected-cluster capacity. |
| 23 | +The prepare pass reads selection counters and publishes a bounded draw count and |
| 24 | +dispatch. The emit pass writes one command per admitted cluster; its |
| 25 | +`first_instance` is the matching selected-record index. Triangle counts come |
| 26 | +only from the strictly validated archive and remain bounded by the 4 MiB page |
| 27 | +ceiling. |
| 28 | + |
| 29 | +The state count lives at byte zero for `multi_draw_indirect_count`. That optional |
| 30 | +feature is not assumed for production activation: adapters without it must use |
| 31 | +a separately qualified bounded submission strategy or remain on compatibility |
| 32 | +rendering. This checkpoint's Metal raster oracle uses the supported fixed-count |
| 33 | +form with the fixture's known four commands. |
| 34 | + |
| 35 | +## Whole-batch safety |
| 36 | + |
| 37 | +The prepare shader suppresses the complete virtual batch when selection |
| 38 | +overflowed, the selector observed an invalid record, a current selected page is |
| 39 | +missing, or selected/count capacities disagree. Invalid-plus-missing telemetry |
| 40 | +saturates instead of wrapping. No partial geometry is published as a valid |
| 41 | +batch. |
| 42 | + |
| 43 | +The real Metal overflow fixture attempts four leaf selections against a |
| 44 | +two-record capacity and proves: |
| 45 | + |
| 46 | +- `selected_count = 4`, `selected_overflow = 2`; |
| 47 | +- `draw_count = 0`, `batch_fallback = 1`; |
| 48 | +- indirect dispatch x is zero; |
| 49 | +- emitted draw and triangle counters remain zero. |
| 50 | + |
| 51 | +Request overflow has different semantics. With only complete resident middle |
| 52 | +groups available, two leaf-page requests are attempted against one request |
| 53 | +slot, but the two resident ancestors remain a complete valid fallback batch. |
| 54 | +The emitter therefore publishes two draws with no batch fallback. This prevents |
| 55 | +feedback pressure from creating a visible hole. |
| 56 | + |
| 57 | +## Raw cooked-page vertex pulling |
| 58 | + |
| 59 | +The common WGSL decoder consumes the fixed physical page buffer directly. It |
| 60 | +supports both validated archive encodings: |
| 61 | + |
| 62 | +- version 1: 72-byte Float32 position, normal, tangent, UV0, UV1, and color; |
| 63 | +- version 2: 32-byte quantized AABB-local position, octahedral normal/tangent, |
| 64 | + binary16 UV0/UV1, UNORM8 color, handedness, and the missing-tangent flag. |
| 65 | + |
| 66 | +It reads each cluster's local `u8` corner index, page-local vertex/index offsets, |
| 67 | +stride, AABB, and mesh encoding from the production GPU tables. The Metal probe |
| 68 | +selects four resident leaves, decodes all twelve indexed corners for each |
| 69 | +format, and compares every output lane plus selected/cluster/corner/local-index |
| 70 | +identity. Float32 and quantized positions, normals, tangents, UV sets, and |
| 71 | +colors match their CPU-authored values within `1e-5`. |
| 72 | + |
| 73 | +## Executable Metal indirect proof |
| 74 | + |
| 75 | +A real render pass consumes the GPU-written command buffer in the same command |
| 76 | +encoder after hierarchy selection and emission. Four indirect triangles write |
| 77 | +four distinct `Rgba8Uint` pixels. Readback is exactly `[1, 2, 3, 4]` in the red |
| 78 | +channel, proving that every command executed and that `first_instance` retained |
| 79 | +the expected selected-record index. |
| 80 | + |
| 81 | +Together with the independent traversal oracle, the focused virtual-geometry |
| 82 | +suite now has 22 passing tests covering strict load, fixed residency, retirement, |
| 83 | +GPU table identity, LOD/frustum/cone selection, missing-page fallback, bounded |
| 84 | +overflows, camera cuts and motion, both vertex formats, command emission, and |
| 85 | +actual indirect rasterization. |
| 86 | + |
| 87 | +## Regression boundary and gates |
| 88 | + |
| 89 | +The pool, selector, emitter, and decoder have no `Renderer`, `EngineState`, |
| 90 | +`ModelManager`, frame-graph, scene, FFI, or ordinary glTF owner. The shipping |
| 91 | +path therefore constructs none of their buffers, pipelines, bindings, passes, |
| 92 | +draws, or branches. Existing rendering pixels, allocations, and steady-state |
| 93 | +work are unchanged. |
| 94 | + |
| 95 | +The complete governed quick lane passed in 51 seconds on the qualified tree: |
| 96 | + |
| 97 | +- 401 shared unit tests passed and one existing hot-reload test was ignored; |
| 98 | +- the negotiated real-device test passed; |
| 99 | +- 59 golden tests passed and two hardware-specific tests were ignored; |
| 100 | +- four render-target tests, two visibility parity tests, and both visibility |
| 101 | + runtime tests passed; |
| 102 | +- strict correctness/suspicious/performance Clippy, formatting, FFI/schema |
| 103 | + parity, CI contracts, and file-size governance passed; |
| 104 | +- 39 quality-governance tests, three visual fault-engine tests, and 29 cooker |
| 105 | + tests passed; |
| 106 | +- baseline wasm, native `models3d`, and wasm `web,models3d` checks passed; |
| 107 | +- the no-default dependency graph still contains neither |
| 108 | + `bloom-geometry-format` nor SHA-256. |
| 109 | + |
| 110 | +## Remaining acceptance work |
| 111 | + |
| 112 | +No #131 acceptance checkbox changes at this checkpoint. Selected virtual work |
| 113 | +still needs current/previous transform and material-remap records, integration |
| 114 | +with #27's exact PBR visibility composition, a bounded non-indirect-count path, |
| 115 | +conservative previous-frame Hi-Z, asynchronous request readback/streaming, |
| 116 | +crack and temporal image corpora, 10-million-triangle stress, per-MRT parity, |
| 117 | +total GPU timings, and integrated/discrete adapter qualification. |
0 commit comments