Gitea #56 (+#50): pin the windowed backbuffer so a device reset cannot silently re-size it
ROOT CAUSE. mPresentParams.BackBufferWidth/Height were assigned ONLY in the fullscreen branch (L4VIDEO.cpp:3430-3434); windowed they stayed 0, which tells D3D9 to derive the backbuffer from the device window's client area at CreateDevice. Fine at startup -- but the device-lost recovery path saves and restores mPresentParams around Reset(), so it faithfully preserved those ZEROS and Reset re-derived the backbuffer from whatever the client area was at THAT moment, while gBTCockpitCanvasW/H still described the startup canvas. The cockpit layout is computed in backbuffer space and clicks are mapped client -> canvas (L4VB16.cpp BTCockpitMouseDown), so after that divergence panels are drawn for one geometry and clicks are mapped in another: buttons drift off their artwork, and at a large enough mismatch nothing is clickable at all -- which is #50 (SAURON: 'none of my MFDs clickable' while other players' worked). It needs BOTH a resize/maximise AND a device loss (alt-tab, Steam overlay, monitor sleep, UAC, RDP, driver hiccup), in that order. That is why it hits some players and never the operator, who does not resize the cockpit window -- and it matches the report exactly: the buttons 'become' misaligned rather than starting that way. FIX * windowed: record the client rect into BackBufferWidth/Height at CreateDevice. That is exactly what D3D would have derived, so startup behaviour is unchanged, but the save/restore now preserves a REAL size and Reset can never pick a different one. Deliberately NOT screenWidth/screenHeight -- those are the app's -res values (default 800x600) while the cockpit window is sized independently, so pinning to them would shrink the backbuffer. * BTVerifyCockpitCanvasAfterReset(): called at both device-lost recovery sites; compares the real backbuffer against the canvas globals, and if they ever disagree it says so and re-syncs instead of drifting silently. VERIFIED: solo cockpit run unchanged -- '[cockpit] view 900x440 canvas 1452x999', BT_SHOT still 1452x999, Heat panel renders correctly, no mismatch warning. NOTE: reverted an earlier scripted edit of this file that had corrupted an unrelated line -- L4VIDEO.cpp is CRLF and a Python join('\n') introduced a bare LF inside a string literal. Use the edit tool on this file, not line surgery. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0166KTsC7ADm7VXEi1HF1jNg
This commit is contained in:
co-authored by
Claude Opus 5
parent
08977ff128
commit
5bbe070e9d
@@ -3432,6 +3432,44 @@ DPLRenderer::DPLRenderer(
|
||||
mPresentParams.BackBufferWidth = screenWidth;
|
||||
mPresentParams.BackBufferHeight = screenHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// PIN THE WINDOWED BACKBUFFER (Gitea #56, and #50 -- the same bug).
|
||||
//
|
||||
// These were left at 0 for the windowed case, which tells D3D9 to derive the
|
||||
// backbuffer from the device window's client area at CreateDevice time. Fine
|
||||
// at startup -- but the device-lost recovery path saves and restores
|
||||
// mPresentParams around Reset(), so it faithfully preserves the ZEROS and
|
||||
// Reset re-derives the backbuffer from whatever the client area is at THAT
|
||||
// moment.
|
||||
//
|
||||
// Field consequence: a player resizes or maximises the window (harmless by
|
||||
// itself -- the cockpit layout lives in backbuffer space and the hit-test maps
|
||||
// client -> canvas), then the device is lost (alt-tab, Steam overlay, monitor
|
||||
// sleep, UAC prompt, RDP, driver hiccup). On recovery the backbuffer silently
|
||||
// becomes the NEW client size while gBTCockpitCanvasW/H still describe the
|
||||
// startup canvas -- so panels are drawn for one geometry and clicks are mapped
|
||||
// in another. Buttons drift off their artwork, and at a big enough mismatch
|
||||
// nothing is clickable at all (#50, "none of my MFDs clickable" while other
|
||||
// players' worked). It needs BOTH steps in that order, which is why the
|
||||
// operator -- who never resizes the cockpit window -- has never seen it.
|
||||
//
|
||||
// Recording the client rect here yields exactly what D3D would have derived,
|
||||
// so startup behaviour is unchanged, but the save/restore now preserves a REAL
|
||||
// size and Reset can never silently pick a different one. (Do NOT use
|
||||
// screenWidth/screenHeight: those are the app's -res values, default 800x600,
|
||||
// while the cockpit-surround window is sized independently -- pinning to them
|
||||
// would shrink the backbuffer and break the composite.)
|
||||
//
|
||||
RECT rc;
|
||||
if (hWnd != NULL && GetClientRect(hWnd, &rc)
|
||||
&& rc.right > rc.left && rc.bottom > rc.top)
|
||||
{
|
||||
mPresentParams.BackBufferWidth = (UINT)(rc.right - rc.left);
|
||||
mPresentParams.BackBufferHeight = (UINT)(rc.bottom - rc.top);
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT hr;
|
||||
|
||||
@@ -8067,6 +8105,45 @@ void
|
||||
}
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// BTVerifyCockpitCanvasAfterReset (Gitea #56)
|
||||
//
|
||||
// The cockpit-surround layout is computed in BACKBUFFER space and clicks are
|
||||
// mapped client -> backbuffer through gBTCockpitCanvasW/H (L4VB16.cpp
|
||||
// BTCockpitMouseDown). With the windowed backbuffer now pinned at CreateDevice
|
||||
// this should always agree -- so a mismatch here means the surface was re-created
|
||||
// at a different size behind our back, which is exactly the state where panels
|
||||
// draw in one geometry and clicks land in another. Say so, and re-sync, rather
|
||||
// than drift silently for the rest of the session.
|
||||
//
|
||||
static void BTVerifyCockpitCanvasAfterReset(LPDIRECT3DDEVICE9 device)
|
||||
{
|
||||
extern int gBTGaugeCockpit, gBTCockpitCanvasW, gBTCockpitCanvasH;
|
||||
if (device == NULL || !gBTGaugeCockpit || gBTCockpitCanvasW <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
IDirect3DSurface9 *back = NULL;
|
||||
if (FAILED(device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &back))
|
||||
|| back == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
D3DSURFACE_DESC desc;
|
||||
if (SUCCEEDED(back->GetDesc(&desc))
|
||||
&& ((int)desc.Width != gBTCockpitCanvasW
|
||||
|| (int)desc.Height != gBTCockpitCanvasH))
|
||||
{
|
||||
DEBUG_STREAM << "[resize] Gitea #56: backbuffer is " << desc.Width << "x"
|
||||
<< desc.Height << " after Reset but the cockpit canvas is "
|
||||
<< gBTCockpitCanvasW << "x" << gBTCockpitCanvasH
|
||||
<< " -- clicks would be mis-mapped; re-syncing" << std::endl;
|
||||
gBTCockpitCanvasW = (int)desc.Width;
|
||||
gBTCockpitCanvasH = (int)desc.Height;
|
||||
}
|
||||
back->Release();
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Execute Method, performs the rendering of one frame
|
||||
//
|
||||
@@ -8801,6 +8878,8 @@ void DPLRenderer::ExecuteImplementation(RendererComplexity, RendererOrigin::Inte
|
||||
mPresentParams.BackBufferCount = bbCount;
|
||||
mPresentParams.BackBufferWidth = bbWidth;
|
||||
mPresentParams.BackBufferHeight = bbHeight;
|
||||
|
||||
BTVerifyCockpitCanvasAfterReset(mDevice); // Gitea #56 guard
|
||||
}
|
||||
|
||||
ticks = HiResNowTicks();
|
||||
@@ -9079,6 +9158,8 @@ void DPLRenderer::ExecuteIdle()
|
||||
mPresentParams.BackBufferCount = bbCount;
|
||||
mPresentParams.BackBufferWidth = bbWidth;
|
||||
mPresentParams.BackBufferHeight = bbHeight;
|
||||
|
||||
BTVerifyCockpitCanvasAfterReset(mDevice); // Gitea #56 guard
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user