Skip to content

Commit 74d114b

Browse files
committed
docs(geometry): record virtual draw evidence
1 parent 92daf0e commit 74d114b

3 files changed

Lines changed: 271 additions & 14 deletions

File tree

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
{
2+
"schema": "bloom-virtual-draw-emission-evidence-v1",
3+
"issue": 131,
4+
"qualified_revision": "92daf0eae684ca5a0b359cc8c991f728ffb83600",
5+
"gpu_abi": {
6+
"draw_command_bytes": 16,
7+
"emission_state_bytes": 48,
8+
"dispatch_command_bytes": 12,
9+
"float32_vertex_bytes": 72,
10+
"quantized_vertex_bytes": 32,
11+
"local_index_bytes": 1,
12+
"draw_capacity_matches_selected_capacity": true,
13+
"first_instance_addresses_selected_record": true
14+
},
15+
"construction_limits": {
16+
"storage_buffer_count_checked": true,
17+
"command_buffer_size_checked": true,
18+
"storage_binding_size_checked": true,
19+
"workgroup_size_checked": true,
20+
"dispatch_dimension_checked": true,
21+
"selector_identity_checked": true
22+
},
23+
"whole_batch_fallback": {
24+
"selected_attempts": 4,
25+
"selected_capacity": 2,
26+
"selected_overflow": 2,
27+
"published_draw_count": 0,
28+
"published_dispatch_x": 0,
29+
"batch_fallback": 1,
30+
"emitted_draws": 0,
31+
"emitted_triangles": 0,
32+
"invalid_missing_counter_saturates": true,
33+
"capacity_mismatch_fails_closed": true
34+
},
35+
"resident_ancestor_request_overflow": {
36+
"request_attempts": 2,
37+
"request_capacity": 1,
38+
"request_overflow": 1,
39+
"resident_ancestor_draws": 2,
40+
"batch_fallback": 0
41+
},
42+
"metal_decode_oracle": {
43+
"backend": "metal",
44+
"selected_clusters": 4,
45+
"decoded_corners_per_format": 12,
46+
"encodings": ["float32", "quantized32"],
47+
"position_match": true,
48+
"normal_match": true,
49+
"tangent_match": true,
50+
"uv0_match": true,
51+
"uv1_match": true,
52+
"color_match": true,
53+
"local_index_match": true,
54+
"maximum_test_tolerance": 0.00001
55+
},
56+
"metal_indirect_raster_oracle": {
57+
"commands": 4,
58+
"triangles": 4,
59+
"target_format": "Rgba8Uint",
60+
"readback_red": [1, 2, 3, 4],
61+
"first_instance_exact": true,
62+
"same_encoder_after_compute": true
63+
},
64+
"default_path": {
65+
"engine_state_fields_added": 0,
66+
"renderer_fields_added": 0,
67+
"model_manager_fields_added": 0,
68+
"passes_added": 0,
69+
"draws_added": 0,
70+
"buffers_constructed": 0,
71+
"bindings_added": 0,
72+
"shader_branches_added": 0,
73+
"pixels_changed": false
74+
},
75+
"qualification": {
76+
"quick_lane": "pass",
77+
"quick_lane_seconds": 51,
78+
"shared_unit_tests_passed": 401,
79+
"shared_unit_tests_ignored": 1,
80+
"virtual_geometry_tests_passed": 22,
81+
"golden_tests_passed": 59,
82+
"golden_tests_ignored": 2,
83+
"render_target_tests_passed": 4,
84+
"visibility_parity_tests_passed": 2,
85+
"visibility_runtime_tests_passed": 2,
86+
"cooker_tests_passed": 29,
87+
"quality_governance_tests_passed": 39,
88+
"visual_fault_engine_tests_passed": 3,
89+
"strict_production_clippy": "pass",
90+
"format": "pass",
91+
"contracts_ffi_file_ratchet": "pass",
92+
"wasm_no_default_check": "pass",
93+
"wasm_models3d_check": "pass",
94+
"native_models3d_check": "pass",
95+
"no_default_optional_dependency_boundary": "pass"
96+
},
97+
"acceptance_boxes_changed": 0,
98+
"remaining": [
99+
"current and previous transform plus material remap ABI",
100+
"visibility and exact PBR material composition",
101+
"bounded submission on adapters without indirect-count support",
102+
"conservative previous-frame Hi-Z occlusion",
103+
"asynchronous request feedback and artifact streaming",
104+
"crack and temporal image corpus",
105+
"per-MRT parity",
106+
"10-million-triangle stress and total GPU timing",
107+
"integrated and discrete adapter qualification"
108+
]
109+
}
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
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.

docs/virtualized-geometry.md

Lines changed: 45 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
# Virtualized geometry
22

3-
Bloom's virtualized-geometry work is opt-in and staged. The offline #131
4-
milestones establish a deterministic meshlet/page contract; the first runtime
5-
milestone adds one shared strict reader, immutable archive ownership, and a
6-
fixed-budget residency plan with deterministic ancestor fallback. It does not
7-
yet enable a new renderer, change ordinary glTF loading, or claim
8-
Nanite-equivalent GPU traversal/streaming.
3+
Bloom's virtualized-geometry work is opt-in and staged. The #131 milestones now
4+
cover the deterministic meshlet/page contract, strict runtime loading,
5+
fixed-budget GPU residency, projected-error GPU hierarchy selection, raw-page
6+
vertex decoding, and bounded indirect draw emission. They still do not enable
7+
a production renderer, change ordinary glTF loading, or claim complete
8+
Nanite-equivalent streaming, occlusion, material, or visibility integration.
99

1010
## Cook and inspect
1111

@@ -234,27 +234,54 @@ resident state, and pinned state. Telemetry distinguishes allocated GPU bytes,
234234
resident slot bytes, useful payload bytes, pinned/retiring slots, frame and
235235
lifetime upload/eviction counts, denials, and exact/ancestor fallback results.
236236

237+
`GpuVirtualHierarchySelector` consumes fixed 128-byte instance records and
238+
walks each atomic hierarchy group on the GPU. Projected pixel error controls
239+
LOD. Frustum and transform-safe normal-cone tests reject invisible work;
240+
non-uniform or sheared transforms conservatively disable only cone rejection.
241+
Refinement requires the complete child group to be resident. Otherwise the
242+
selector keeps the resident ancestor and writes bounded page requests. Camera
243+
cuts and instance motion consume no prior selection state.
244+
245+
`GpuVirtualDrawEmitter` converts the bounded selected table into compact
246+
16-byte non-indexed indirect commands. `first_instance` addresses the matching
247+
selected-cluster record for vertex pulling. Selection overflow, an invalid
248+
record, or a missing current page publishes a zero draw count for the whole
249+
virtual batch; request overflow remains safe because the complete resident
250+
ancestor batch is still selected. Construction validates command-buffer and
251+
compute-dispatch limits up front.
252+
253+
The shared WGSL page decoder reads local `u8` triangle indices directly from
254+
the fixed physical pool and reconstructs every version 1 Float32 or version 2
255+
quantized vertex lane. A Metal compute oracle reads the real mesh, cluster,
256+
selection, and physical-page buffers. A separate Metal render oracle consumes
257+
the emitted indirect commands and proves the exact `first_instance` values.
258+
An eventual production consumer must use indirect-count support or provide a
259+
separately qualified bounded fallback; unsupported adapters remain on the
260+
compatibility renderer.
261+
237262
The renderer integration remains deliberately explicit:
238263

239264
- zero production render passes, draws, buffers, bindings, allocations, or
240265
shader branches unless a caller explicitly constructs the GPU pool;
241266
- zero changes to existing immediate-mode or glTF selection and pixels;
242267
- no silent `.bgeo` replacement of an ordinary model;
243-
- no asynchronous file/store IO, feedback readback, or traversal dispatch yet.
268+
- no asynchronous file/store IO, request-feedback scheduling, production
269+
visibility raster, or virtual-geometry material composition yet.
244270

245-
The next #131 runtime milestones are asynchronous #136 index resolution and
246-
request feedback, projected-error hierarchy traversal, and integration with
247-
#27's visibility/material path and #28's GPU-driven submission. The
248-
compatibility renderer remains responsible for unsupported and
249-
not-yet-virtualized content throughout that work.
271+
The next #131 runtime milestones are temporal instance/material records,
272+
integration with #27's visibility/material path, a non-indirect-count fallback,
273+
conservative previous-frame Hi-Z, and asynchronous #136 index resolution plus
274+
request feedback. The compatibility renderer remains responsible for
275+
unsupported and not-yet-qualified content throughout that work.
250276

251277
The default version 1 artifact remains byte-identical to the qualified
252278
leaf-only milestone (`parent` and `first_child` absent, both relation counts
253279
zero, level/error zero). Opt-in hierarchy artifacts populate those formerly
254280
reserved fields without changing the 128-byte cluster record. Opt-in packed
255281
vertices use format version 2 so a version 1 reader can never reinterpret the
256-
32-byte stride as float32. Runtime streaming remains disabled until residency,
257-
traversal, occlusion, and fallback milestones are independently qualified.
282+
32-byte stride as float32. Runtime activation remains disabled until temporal
283+
data, visibility/material composition, streaming feedback, occlusion, and
284+
platform fallback milestones are independently qualified.
258285

259286
## Qualification
260287

@@ -303,3 +330,7 @@ loose-store qualification are recorded in
303330
The fixed physical GPU pool, stable ID/page-table ABI, bounded frame work, and
304331
Metal readback proof are recorded in
305332
`docs/evidence/issue-131-gpu-page-pool-v1.{md,json}`.
333+
GPU hierarchy selection and independent CPU parity are recorded in
334+
`docs/evidence/issue-131-gpu-hierarchy-traversal-v1.{md,json}`. Raw-page decode,
335+
bounded indirect emission, and executable Metal raster proof are recorded in
336+
`docs/evidence/issue-131-virtual-draw-emission-v1.{md,json}`.

0 commit comments

Comments
 (0)