Wait screen: hard cutoff at first real scene present (handoff flicker)
The launch handoff (LoadingMission -> RunningMission) could interleave the idle wait-overlay presents with the first real game frames (user report: "the wait screen is still there when game graphics come up"). gBTSceneHasPresented latches at the render path's Present; ExecuteIdle stands down permanently once set -- the overlay can never paint over (or alternate with) live graphics. Permanent one-shot/1Hz [waitscreen] diagnostics record the active paint path, the scene-live moment, and idle paints. Verified: 70-frame 0.5s capture across the handoff -- 54 wait frames, then game frames with at most ONE ambiguous frame at the cut (was repeated interleaving); no black frames. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
c421ec4af8
commit
66f22fb923
@@ -8697,6 +8697,14 @@ void DPLRenderer::ExecuteImplementation(RendererComplexity, RendererOrigin::Inte
|
||||
// DIAG (turn-hitch hunt): draw CPU is _rt0..here; Present blocks on the GPU.
|
||||
LARGE_INTEGER _rt1; QueryPerformanceCounter(&_rt1);
|
||||
hr = mDevice->Present(NULL, NULL, NULL, NULL);
|
||||
// The wait-screen overlay stands down PERMANENTLY the moment the first
|
||||
// REAL scene frame presents (user report 2026-07-22: the launch handoff
|
||||
// briefly interleaved idle-overlay presents with game frames = flicker).
|
||||
extern Logical gBTSceneHasPresented;
|
||||
if (!gBTSceneHasPresented)
|
||||
DEBUG_STREAM << "[waitscreen] scene LIVE (first real present) t="
|
||||
<< GetTickCount() << std::endl << std::flush;
|
||||
gBTSceneHasPresented = True;
|
||||
{
|
||||
LARGE_INTEGER _rt2, _rf; QueryPerformanceCounter(&_rt2); QueryPerformanceFrequency(&_rf);
|
||||
const double drawMs = (double)(_rt1.QuadPart - _rt0.QuadPart) * 1000.0 / (double)_rf.QuadPart;
|
||||
@@ -8844,10 +8852,30 @@ void BTWaitScreenPaint(const char *line1, const char *line2)
|
||||
ReleaseDC(wnd, dc);
|
||||
}
|
||||
|
||||
// One-way per-process latch: the real render path has presented a frame.
|
||||
// ExecuteIdle (the wait-screen overlay) stands down for good once set -- the
|
||||
// launch handoff must never interleave an idle black-clear/overlay present
|
||||
// with live game frames.
|
||||
Logical gBTSceneHasPresented = False;
|
||||
|
||||
void DPLRenderer::ExecuteIdle()
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
if (gBTSceneHasPresented)
|
||||
return; // game graphics own the screen now
|
||||
{
|
||||
static unsigned long s_lastIdleLog = 0;
|
||||
unsigned long now = GetTickCount();
|
||||
if (now - s_lastIdleLog > 1000UL)
|
||||
{
|
||||
s_lastIdleLog = now;
|
||||
DEBUG_STREAM << "[waitscreen] idle paint t=" << now << " state="
|
||||
<< (application ? (int)application->GetApplicationState() : -1)
|
||||
<< std::endl << std::flush;
|
||||
}
|
||||
}
|
||||
|
||||
hr = mDevice->Clear(0, NULL, D3DCLEAR_TARGET, 0xFF000000, 1.0f, 0);
|
||||
|
||||
hr = mDevice->BeginScene();
|
||||
|
||||
Reference in New Issue
Block a user