Harbor

Changelog 3eb959f66a74

flip indirect draw capability

@sky · 1 month ago · parent b856ad9efb88
0 added 3 modified 0 deleted
backend/backend.odin +3 -1 modified
50 unchanged lines hidden
51 51 implemented_base_capabilities :: proc(
52 52 max_color_targets, max_push_constant_size: u32,
53 53 ) -> Capabilities {
54 - features := Capability_Flags{.Compute_Dispatch, .Storage_Buffers, .Offscreen_Targets, .Sampled_Targets}
54 + features := Capability_Flags{.Compute_Dispatch, .Storage_Buffers, .Indirect_Draws, .Offscreen_Targets, .Sampled_Targets}
55 55 if max_color_targets > 1 {
56 56 features += {.Multiple_Render_Targets}
57 57 }
636 unchanged lines hidden
694 694 b.destroy_shader != nil &&
695 695 b.draw != nil &&
696 696 b.draw_indexed != nil &&
697 + b.draw_indirect != nil &&
698 + b.draw_indexed_indirect != nil &&
697 699 b.create_compute_pipeline != nil &&
698 700 b.destroy_compute_pipeline != nil &&
699 701 b.bind_compute_pipeline != nil &&
9 unchanged lines hidden
docs/gpu_intent_api.md +7 -5 modified
18 unchanged lines hidden
19 19
20 20 ## Execution model
21 21
22 - The authoritative runtime direction is a planned-IR executor: validation produces diagnostics, planning orders commands, and backend lowering walks the planned IR to issue backend operations. A gated backend-native planned draw path now handles materialized IR buffers, render passes, shaders, graphics pipelines, descriptor sets, direct indexed draws, direct non-indexed draws, supported borrowed imported mesh buffers, lit imported meshes, imported rect clips, the generated 2D rect/line/circle slice, generated textured quads with concrete texture IDs, and generated glyph quads with texture-backed materials. The current runtime translator that maps remaining generated/imported producer forms into legacy 2D/3D renderer calls is migration-only. New backend parity work must not add feature-specific translator branches unless the branch is a temporary, tracked bridge with a removal path.
22 + The authoritative runtime direction is a planned-IR executor: validation produces diagnostics, planning orders commands, and backend lowering walks the planned IR to issue backend operations. A gated backend-native planned draw path now handles materialized IR buffers, render passes, shaders, graphics pipelines, descriptor sets, direct indexed draws, direct non-indexed draws, single-command indirect indexed/non-indexed draws, supported borrowed imported mesh buffers, lit imported meshes, imported rect clips, the generated 2D rect/line/circle slice, generated textured quads with concrete texture IDs, and generated glyph quads with texture-backed materials. The current runtime translator that maps remaining generated/imported producer forms into legacy 2D/3D renderer calls is migration-only. New backend parity work must not add feature-specific translator branches unless the branch is a temporary, tracked bridge with a removal path.
23 23
24 24 Runtime lowering must not fail silently. If a command cannot be lowered, `gpu` records a structured diagnostic with the command handle and reason, then fails submission or mode classification explicitly.
25 25
24 unchanged lines hidden
50 50
51 51 CPU mapping is only valid for host-visible buffers. GPU-local/default buffers are not mappable through `map_buffer` or `get_buffer_mapped`; backends must report that explicitly and return `nil`. Host-visible upload buffers may stay persistently mapped when the backend memory model allows it.
52 52
53 - `compute_barrier(ctx)` is a conservative/global **in-frame** barrier for compute-written storage/UAV data consumed by later backend work in the same frame. Its consumer scope is later compute shader reads/writes, vertex/fragment shader reads, vertex/index fetch, and future indirect command reads. It is intentionally over-synchronized for correctness; it is not a render-target transition substitute, CPU readback fence, cross-frame lifetime rule, or feedback-loop validator. Backends that lack a complete storage descriptor path must report that separately through capabilities or diagnostics instead of pretending the barrier enables unsupported binding.
53 + `compute_barrier(ctx)` is a conservative/global **in-frame** barrier for compute-written storage/UAV data consumed by later backend work in the same frame. Its consumer scope is later compute shader reads/writes, vertex/fragment shader reads, vertex/index fetch, and indirect command reads. It is intentionally over-synchronized for correctness; it is not a render-target transition substitute, CPU readback fence, cross-frame lifetime rule, or feedback-loop validator. Backends that lack a complete storage descriptor path must report that separately through capabilities or diagnostics instead of pretending the barrier enables unsupported binding.
54 54
55 + Indirect draw argument buffers use the backend-neutral `Indirect_Draw_Args` and `Indirect_Draw_Indexed_Args` ABI. The layouts are intentionally byte-identical to Vulkan, D3D11, D3D12, and OpenGL single-command indirect arguments: 16 bytes for non-indexed draws and 20 bytes for indexed draws. In IR, `packet.instances.indirect` is the argument-buffer resource, `packet.instances.offset` is the byte offset, `packet.instances.stride` is zero-or-ABI-size for Phase 7a, and `packet.instances.count` is limited to one command. True per-instance vertex streams remain separate unsupported vertex-input work.
56 +
55 57 D3D12 runtime fence behavior cannot be executed by Linux CI. D3D12 lifetime and transition work is accepted by static backend checks, pure fence-order tests where available, and explicit Windows runtime verification debt.
56 58
57 59 Current backend sync matrix:
58 60
59 61 | Backend | Compute barrier scope | Sampled target feedback | Runtime proof |
60 62 | --- | --- | --- | --- |
61 - | Vulkan | Conservative compute-write barrier for later shader reads/writes, vertex/index fetch, and future indirect command reads. Indirect draw execution stays Phase 7. | Render pass final layouts come from target usage; descriptor layout is caller-declared. | Static checks now; device smoke gate still needed. |
63 + | Vulkan | Conservative compute-write barrier for later shader reads/writes, vertex/index fetch, and indirect command reads. | Render pass final layouts come from target usage; descriptor layout is caller-declared. | Static checks now; device smoke gate still needed. |
62 64 | D3D11 | Immediate context resolves many SRV/RTV/UAV conflicts by auto-unbinding and debug warnings. Manual hazard cleanup needs slot tracking before it is safe. | No explicit image states; render-target/SRV overlap needs future warning-proof validation, not broad unbinds. | Windows runtime deferred. |
63 - | D3D12 | Global UAV barrier for compute storage visibility. Future indirect execution still needs argument-buffer state handling. | Render/depth targets transition to write at pass begin and to shader-resource lazily when bound as sampled descriptors. | Windows runtime deferred. |
64 - | OpenGL | Storage, texture-fetch, framebuffer, and future command/indirect barriers are emitted after compute when requested. Indirect draw execution stays Phase 7. | Feedback-loop validation is a future diagnostics gap; current backend does not track attached texture handles at descriptor bind. | Linux device smoke gate still needed. |
65 + | D3D12 | Global UAV barrier for compute storage visibility; indirect draws transition argument buffers to `INDIRECT_ARGUMENT`. | Render/depth targets transition to write at pass begin and to shader-resource lazily when bound as sampled descriptors. | Windows runtime deferred. |
66 + | OpenGL | Storage, texture-fetch, framebuffer, and command/indirect barriers are emitted after compute when requested. | Feedback-loop validation is a future diagnostics gap; current backend does not track attached texture handles at descriptor bind. | Linux device smoke gate still needed. |
65 67
66 68 ## Public frame shape
67 69
185 unchanged lines hidden
tests/capabilities_test.odin +1 -1 modified
25 unchanged lines hidden
26 26 testing.expect(t, bk.supports(caps, .Storage_Buffers))
27 27 testing.expect(t, bk.supports(caps, .Offscreen_Targets))
28 28 testing.expect(t, bk.supports(caps, .Sampled_Targets))
29 + testing.expect(t, bk.supports(caps, .Indirect_Draws))
29 30 testing.expect(t, !bk.supports(caps, .Multiple_Render_Targets))
30 31 testing.expect(t, !bk.supports(caps, .Stencil_Clips))
31 - testing.expect(t, !bk.supports(caps, .Indirect_Draws))
32 32 testing.expect_value(t, caps.max_color_targets, u32(1))
33 33 testing.expect_value(t, caps.max_push_constant_size, u32(240))
34 34 testing.expect_value(t, caps.max_frames_in_flight, u32(bk.MAX_FRAMES_IN_FLIGHT))
63 unchanged lines hidden