acdream/src/AcDream.App
Erik 00e1b32177 perf(render): Campaign V slice V8 commit 1 - the Vulkan arm gets an instrument
V8 is the performance gate, and it opened on a plain fact: the Vulkan arm
emitted no [frame-prof] line at all. V6h wired it to
NullRenderFrameGpuMeasurement, whose BeginFrame does nothing - and that method
is the ONLY caller of FrameProfiler.FrameBoundary. So a Vulkan run produced no
CPU frame distribution, no allocation-per-frame column, no frame-history CSV
and no GPU sample. The campaign's own performance vehicle,
tools/run-connected-r6-soak.ps1, waits on [frame-prof] boundaries to time its
samples, so it could not be pointed at the backend V8 exists to judge. You
cannot measure what you have not instrumented, so the instrument lands first.

The bracket is deliberately identical on both arms. On GL,
FrameProfilerGpuMeasurement begins a TimeElapsed query at BeginFrame and ends
it at EndFrame, spanning resource preparation, the world scene and private
presentation, and NOT the swapchain present. VulkanFrameGpuMeasurement opens
and closes a Vulkan timestamp scope at exactly those two points. Two
differently-bracketed numbers in one comparison table would have been worse
than reporting none.

Vulkan timestamps resolve two or three frames late, so the sample carries the
profiler frame index that ISSUED it rather than being credited to the frame
that happened to read it - the pairing GpuFrameTimer already performs
internally on GL. VulkanGpuDevice opens the whole-frame scope tagged with that
index, reads the previous use of the slot back in BeginFrameResources BEFORE
the tag is overwritten, and hands completed (tag, microseconds) pairs to the
adapter through a bounded queue that never blocks.

VulkanGpuTimerPool gains TryTakeResolved, which consumes the value it reports.
TryResolve deliberately reports the last known measurement forever, which is
right for a diagnostic readout and wrong for a percentile: counting one
measurement into the distribution twice is how an instrument flatters itself.

FrameProfiler gains a GL-free FrameBoundary() overload and RecordGpuSample.
Every other line of its bookkeeping - the CPU delta, the per-thread allocation
delta, the stage buffers, the history row, the five-second report - is the same
code the GL arm runs. The GL path is byte-for-byte unchanged in behaviour:
FrameBoundary(GL) still owns and creates the query ring.

Gates: Release build green. App tests 4,152 passed / 3 skipped, exactly the
pre-slice baseline. Strict GL offline pixel gate against 13c8733d:
1.95e-05 (11 px of 563,200), inside the documented 9-31 px band, so GL did not
move. An offline Vulkan run now reports gpu_ms in [frame-prof] and fills gpu_us
in the frame-history CSV, where before this commit it reported neither.

No divergence-register row is owed: this is diagnostic apparatus and no
rendered pixel depends on it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-28 20:35:59 +02:00
..
Audio Revert "Campaign V slice V4a" - it lost world multisampling 2026-07-27 18:29:28 +02:00
Combat refactor(runtime): close simulation ownership 2026-07-26 15:53:31 +02:00
Composition perf(render): Campaign V slice V8 commit 1 - the Vulkan arm gets an instrument 2026-07-28 20:35:59 +02:00
Diagnostics perf(render): Campaign V slice V8 commit 1 - the Vulkan arm gets an instrument 2026-07-28 20:35:59 +02:00
Input Revert "Campaign V slice V4a" - it lost world multisampling 2026-07-27 18:29:28 +02:00
Interaction refactor(runtime): unify generation reset for direct hosts 2026-07-27 00:43:26 +02:00
Net feat(headless): hydrate isolated collision worlds 2026-07-27 09:25:58 +02:00
Physics Revert "Campaign V slice V4a" - it lost world multisampling 2026-07-27 18:29:28 +02:00
Platform feat(linux): gate graphical backends and capabilities 2026-07-27 12:26:58 +02:00
Plugins Revert "Campaign V slice V4a" - it lost world multisampling 2026-07-27 18:29:28 +02:00
Rendering perf(render): Campaign V slice V8 commit 1 - the Vulkan arm gets an instrument 2026-07-28 20:35:59 +02:00
Runtime feat(headless): complete deterministic bot command parity 2026-07-27 08:23:36 +02:00
Settings feat(render): Campaign V slice V6h — the Vulkan composition host 2026-07-28 11:47:37 +02:00
Spells Revert "Campaign V slice V4a" - it lost world multisampling 2026-07-27 18:29:28 +02:00
Streaming Revert "Campaign V slice V4a" - it lost world multisampling 2026-07-27 18:29:28 +02:00
Studio Revert "Campaign V slice V4a" - it lost world multisampling 2026-07-27 18:29:28 +02:00
UI feat(render): Campaign V slice V6l commit 3 - the offscreen viewports draw on Vulkan 2026-07-28 18:05:24 +02:00
Update refactor(runtime): cut graphical host over to canonical root 2026-07-26 19:06:09 +02:00
World fix(diag): Campaign V slice V7 commit 2 - pin the world clock, because the route never did 2026-07-28 19:34:13 +02:00
AcDream.App.csproj feat(render): Campaign V slice V6c - SPIR-V, pipelines, passes, and a Vulkan frame that draws 2026-07-28 08:17:24 +02:00
GlobalUsings.cs Revert "Campaign V slice V4a" - it lost world multisampling 2026-07-27 18:29:28 +02:00
Program.cs feat(linux): gate graphical backends and capabilities 2026-07-27 12:26:58 +02:00
RenderBackendKind.cs feat(render): Campaign V slice V5 - Vulkan bring-up, dark 2026-07-28 07:11:50 +02:00
RuntimeOptions.cs ci(render): Campaign V slice V9 - the Vulkan gate runs on lavapipe 2026-07-28 20:10:01 +02:00