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.BackBufferWidth = screenWidth;
|
||||||
mPresentParams.BackBufferHeight = screenHeight;
|
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;
|
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
|
// Execute Method, performs the rendering of one frame
|
||||||
//
|
//
|
||||||
@@ -8801,6 +8878,8 @@ void DPLRenderer::ExecuteImplementation(RendererComplexity, RendererOrigin::Inte
|
|||||||
mPresentParams.BackBufferCount = bbCount;
|
mPresentParams.BackBufferCount = bbCount;
|
||||||
mPresentParams.BackBufferWidth = bbWidth;
|
mPresentParams.BackBufferWidth = bbWidth;
|
||||||
mPresentParams.BackBufferHeight = bbHeight;
|
mPresentParams.BackBufferHeight = bbHeight;
|
||||||
|
|
||||||
|
BTVerifyCockpitCanvasAfterReset(mDevice); // Gitea #56 guard
|
||||||
}
|
}
|
||||||
|
|
||||||
ticks = HiResNowTicks();
|
ticks = HiResNowTicks();
|
||||||
@@ -9079,6 +9158,8 @@ void DPLRenderer::ExecuteIdle()
|
|||||||
mPresentParams.BackBufferCount = bbCount;
|
mPresentParams.BackBufferCount = bbCount;
|
||||||
mPresentParams.BackBufferWidth = bbWidth;
|
mPresentParams.BackBufferWidth = bbWidth;
|
||||||
mPresentParams.BackBufferHeight = bbHeight;
|
mPresentParams.BackBufferHeight = bbHeight;
|
||||||
|
|
||||||
|
BTVerifyCockpitCanvasAfterReset(mDevice); // Gitea #56 guard
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user