perf(diag): complete trustworthy Slice A capture tooling

Correct whole-frame GPU timestamps so they bracket only the accepted render transaction and associate delayed query results with the owning CPU frame. Add route-wide frame-history summaries, fixed-camera screenshot comparison, process counters, contention traces, a pinned Arwic workload, and credential-safe launch disclosure.

The reference hardware/display contract now keeps local and RDP populations separate and defines the screenshot and re-baseline rules needed by later prepared-content gates.

Co-Authored-By: Codex <noreply@openai.com>
This commit is contained in:
Erik 2026-07-24 12:46:51 +02:00
parent bf7ec12f68
commit 3ee8ec537a
23 changed files with 1639 additions and 170 deletions

View file

@ -43,6 +43,18 @@ internal interface IRenderFrameResourcePhase
void Prepare(RenderFrameInput input);
}
/// <summary>
/// Diagnostic GPU timer bracketing only render-resource, world, and private
/// presentation submission. It deliberately excludes diagnostics, pacing,
/// and the idle interval before the next render callback.
/// </summary>
internal interface IRenderFrameGpuMeasurement
{
void BeginFrame();
void EndFrame();
}
internal interface IWorldSceneFramePhase
{
WorldRenderFrameOutcome Render(RenderFrameInput input);
@ -117,6 +129,7 @@ internal sealed class NullRenderFrameFailureRecovery : IRenderFrameFailureRecove
internal sealed class RenderFrameOrchestrator : IGameRenderFrameRoot
{
private readonly IRenderFrameLifetime _lifetime;
private readonly IRenderFrameGpuMeasurement _gpuMeasurement;
private readonly IRenderFrameResourcePhase _resources;
private readonly IWorldSceneFramePhase _world;
private readonly IPrivatePresentationFramePhase _presentation;
@ -126,6 +139,7 @@ internal sealed class RenderFrameOrchestrator : IGameRenderFrameRoot
public RenderFrameOrchestrator(
IRenderFrameLifetime lifetime,
IRenderFrameGpuMeasurement gpuMeasurement,
IRenderFrameResourcePhase resources,
IWorldSceneFramePhase world,
IPrivatePresentationFramePhase presentation,
@ -134,6 +148,8 @@ internal sealed class RenderFrameOrchestrator : IGameRenderFrameRoot
IRenderFrameFailureRecovery recovery)
{
_lifetime = lifetime ?? throw new ArgumentNullException(nameof(lifetime));
_gpuMeasurement = gpuMeasurement
?? throw new ArgumentNullException(nameof(gpuMeasurement));
_resources = resources ?? throw new ArgumentNullException(nameof(resources));
_world = world ?? throw new ArgumentNullException(nameof(world));
_presentation = presentation ?? throw new ArgumentNullException(nameof(presentation));
@ -149,10 +165,37 @@ internal sealed class RenderFrameOrchestrator : IGameRenderFrameRoot
Exception? renderFailure = null;
try
{
_resources.Prepare(input);
WorldRenderFrameOutcome world = _world.Render(input);
PrivatePresentationFrameOutcome presentation =
_presentation.Render(input, world);
WorldRenderFrameOutcome world;
PrivatePresentationFrameOutcome presentation;
Exception? measuredRenderFailure = null;
_gpuMeasurement.BeginFrame();
try
{
_resources.Prepare(input);
world = _world.Render(input);
presentation = _presentation.Render(input, world);
}
catch (Exception error)
{
measuredRenderFailure = error;
throw;
}
finally
{
try
{
_gpuMeasurement.EndFrame();
}
catch (Exception measurementFailure)
when (measuredRenderFailure is not null)
{
throw new AggregateException(
"Rendering failed and its GPU measurement could not be closed.",
measuredRenderFailure,
measurementFailure);
}
}
var outcome = new RenderFrameOutcome(world, presentation);
_diagnostics.Publish(input, outcome);
_postDiagnostics.Process(input, outcome);