3 Commits
Author SHA1 Message Date
西风逍遥游 0ca17b9a57 feat(render): enforce spec-safe parallel recording via per-pass command pools and RecordCycle lifecycle 2026-08-21 09:35:25 +08:00
西风逍遥游 b684bf713d feat(render): move the 3 CSM shadow cascades into the deferred FrameGraph
Stage D (shadow part): each in-flight slot's FrameGraph now owns both the
shadow and G-buffer passes as declarative, dependency-free passes in one
layer. The CSM array is imported per cascade via its layer view with
arrayLayers=3 so barriers cover the whole array; every cascade ends in
DepthStencilReadOnlyOptimal for the engine-side forward pass to sample.

- recordPendingShadowPasses / recordPendingGBufferPass are gone, merged
  into recordDeferredFrameGraph(): graph record + submit before the
  swapchain pass, with a once-per-slot-per-frame guard so repeated
  render3D() calls in one script frame never re-record the same command
  buffers (resetting in-flight CBs hung the driver).
- buildDeferredFrameGraphs() rebuilds one graph per slot from the current
  shadow array + G-buffer targets; shadows can be enabled without a
  G-buffer pass and vice versa (graphs are built on demand).
- JobSystem fix (PR #134 scheduler bug): completeJob now decrements
  outstanding/outstandingFrame only after fireCompletion +
  releaseDependents have finished using the job. Previously a waiter
  (beginFrame/endFrame) could observe outstandingFrame == 0 and reset the
  per-frame arena while a worker still touched the job (use-after-free:
  lost forked job -> hang, or crash). Two stress tests
  (render_graph.jobSystemGroupStress, render_graph.jobSystemEngineFramePattern)
  cover the engine's exact beginFrame/parallel_for/task-group frame
  pattern.
- Recording stays serial (graph->record()) for now: the JobSystem
  help-execution path still has a residual timing-sensitive race that can
  leave a worker stuck in a pass callback. The parallel executor
  (jobSystemPassExecutor) is ready and CPU-tested; enable it once that
  race is root-caused upstream (documented in FrameGraphJobs.h).

Verified locally (win32-debug, full clean rebuild): render_graph.*,
thread.*, Shadow3D.*, RenderSystem3D.*, Lighting3D.*, Mesh.* and
AO/AA/Outline/GI — 77 cases pass.
2026-08-20 23:11:38 +08:00
西风逍遥游 5c8046e85f feat(render): FrameGraph parallel-recording foundation on top of JobSystem
PR #134's secondary-command-buffer recording violated the Vulkan state
machine (secondaries began their own render pass instances without
pInheritanceInfo; the spec-compliant fix 1291df8 was reverted). Replace
that path with the groundwork for the vkb::FrameGraph migration:

- Drop the illegal secondary-CB deferred recording and restore the
  branch base's legal inline recording for shadow/GBuffer passes.
- Fix frame-prep culling regressions from PR #134:
  * per-item camera frustum culling (item.culled) instead of always
    testing against the main camera;
  * default-camera culling for the G-buffer pass (item.culledMain);
  * restore per-cascade CSM caster masks (item.cascadeMask).
  Camera view-proj matrices are snapshotted on the main thread before
  the parallel job forks; workers only read immutable data. The light
  job's CSM output is joined before the entity job forks so cascade
  culling never races with the shadow-upload write.
- Add FrameGraphJobs.h: vkb::PassRecordExecutor backed by the JobSystem
  (layer-internal fork/join via frame task groups, layers sequential),
  the exact executor the render backend will hand to FrameGraph::record().
- Add device-free tests (test/render_graph.cpp): the engine's target
  pass topology (3 CSM cascades + GBuffer in one parallel layer ->
  forward -> present) plans with attachment->sampled barrier folding
  (zero explicit barriers on forward/present), and the JobSystem
  executor records every pass exactly once, in parallel per layer.

Verified locally (win32-debug): render_graph.*, thread.*, Shadow3D.*,
RenderSystem3D.*, Lighting3D.* and Mesh.* all pass (58/58). Bundle-mode
SEGFAULTs are the known pre-existing zeroerr single-process issue, not
this change. See docs/dev/superpowers/specs/2026-08-20-framegraph-mt-render.md
for the staged migration plan (GBuffer into the graph next, then the
dedicated render thread).
2026-08-20 19:39:10 +08:00