Skip to content

Commit 5b4abf6

Browse files
committed
Fix the colors of Borderless Windowed/Keep Res mode to match Fullscreen (Standard)
This (lower brightness) has been the major downside of using Borderless for years, so this is a fix of great value to MTA.
1 parent 6526361 commit 5b4abf6

File tree

5 files changed

+155
-3
lines changed

5 files changed

+155
-3
lines changed

Client/core/DXHook/CProxyDirect3D9.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,30 @@ HRESULT CProxyDirect3D9::CreateDevice(UINT Adapter, D3DDEVTYPE DeviceType, HWND
246246
hResult =
247247
HandleCreateDeviceResult(hResult, m_pDevice, Adapter, DeviceType, hFocusWindow, BehaviorFlags, pPresentationParameters, ppReturnedDeviceInterface);
248248

249+
// After successful device creation
250+
if (SUCCEEDED(hResult) && *ppReturnedDeviceInterface)
251+
{
252+
// Check if we're in borderless mode
253+
bool bIsBorderlessMode = pPresentationParameters->Windowed == TRUE;
254+
255+
if (bIsBorderlessMode)
256+
{
257+
// Enable sRGB correction for borderless mode to compensate for DWM composition
258+
CProxyDirect3DDevice9* pProxyDevice = static_cast<CProxyDirect3DDevice9*>(*ppReturnedDeviceInterface);
259+
260+
// Set initial render states for proper color handling
261+
pProxyDevice->SetRenderState(D3DRS_SRGBWRITEENABLE, TRUE);
262+
263+
// Configure samplers for sRGB texture reading
264+
for (DWORD i = 0; i < 8; i++)
265+
{
266+
pProxyDevice->SetSamplerState(i, D3DSAMP_SRGBTEXTURE, TRUE);
267+
}
268+
269+
WriteDebugEvent("Applied sRGB color correction for borderless mode");
270+
}
271+
}
272+
249273
return hResult;
250274
}
251275

Client/core/DXHook/CProxyDirect3DDevice9.cpp

Lines changed: 113 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
bool g_bInGTAScene = false;
1616
CProxyDirect3DDevice9* g_pProxyDevice = NULL;
1717
CProxyDirect3DDevice9::SD3DDeviceState* g_pDeviceState = NULL;
18+
SGammaState g_GammaState;
1819

1920
// Proxy constructor and destructor.
2021
CProxyDirect3DDevice9::CProxyDirect3DDevice9(IDirect3DDevice9* pDevice)
@@ -123,6 +124,22 @@ CProxyDirect3DDevice9::~CProxyDirect3DDevice9()
123124
{
124125
WriteDebugEvent(SString("CProxyDirect3DDevice9::~CProxyDirect3DDevice9 %08x", this));
125126

127+
// Reset gamma state when device is destroyed
128+
if (g_pProxyDevice == this)
129+
{
130+
// Restore original gamma if we had stored it
131+
if (g_GammaState.bOriginalGammaStored && m_pDevice)
132+
{
133+
m_pDevice->SetGammaRamp(g_GammaState.lastSwapChain, 0, &g_GammaState.originalGammaRamp);
134+
WriteDebugEvent("Restored original gamma ramp on device destruction");
135+
}
136+
137+
// Reset gamma state
138+
g_GammaState.bOriginalGammaStored = false;
139+
g_GammaState.bLastWasBorderless = false;
140+
ZeroMemory(&g_GammaState.originalGammaRamp, sizeof(g_GammaState.originalGammaRamp));
141+
}
142+
126143
// Release our reference to the wrapped device
127144
// Note: We don't check m_ulRefCount here because destructor is only called
128145
// when Release() determined the count reached 0
@@ -374,6 +391,12 @@ HRESULT CProxyDirect3DDevice9::Reset(D3DPRESENT_PARAMETERS* pPresentationParamet
374391
return D3DERR_INVALIDCALL;
375392
}
376393

394+
// Reset gamma state since display mode might change
395+
g_GammaState.bOriginalGammaStored = false;
396+
g_GammaState.bLastWasBorderless = false;
397+
ZeroMemory(&g_GammaState.originalGammaRamp, sizeof(g_GammaState.originalGammaRamp));
398+
WriteDebugEvent("Reset gamma state due to device reset");
399+
377400
// Check cooperative level before attempting reset
378401
HRESULT hCoopLevel = m_pDevice->TestCooperativeLevel();
379402
if (hCoopLevel == D3DERR_DEVICELOST)
@@ -473,6 +496,7 @@ HRESULT CProxyDirect3DDevice9::Reset(D3DPRESENT_PARAMETERS* pPresentationParamet
473496
return hResult;
474497
}
475498

499+
476500
HRESULT CProxyDirect3DDevice9::Present(CONST RECT* pSourceRect, CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion)
477501
{
478502
CDirect3DEvents9::OnPresent(m_pDevice);
@@ -508,12 +532,99 @@ HRESULT CProxyDirect3DDevice9::SetDialogBoxMode(BOOL bEnableDialogs)
508532

509533
VOID CProxyDirect3DDevice9::SetGammaRamp(UINT iSwapChain, DWORD Flags, CONST D3DGAMMARAMP* pRamp)
510534
{
511-
m_pDevice->SetGammaRamp(iSwapChain, Flags, pRamp);
535+
// Validate inputs first
536+
if (!pRamp)
537+
{
538+
WriteDebugEvent("CProxyDirect3DDevice9::SetGammaRamp - Invalid gamma ramp pointer");
539+
return;
540+
}
541+
542+
// Validate swap chain index
543+
if (iSwapChain >= GetNumberOfSwapChains())
544+
{
545+
WriteDebugEvent(SString("CProxyDirect3DDevice9::SetGammaRamp - Invalid swap chain index: %d", iSwapChain));
546+
return;
547+
}
548+
549+
// Get current display mode state - use a timeout to avoid race conditions during mode transitions
550+
CVideoModeManagerInterface* pVideoModeManager = GetVideoModeManager();
551+
if (!pVideoModeManager)
552+
{
553+
// Fallback to original behavior if video mode manager is unavailable
554+
m_pDevice->SetGammaRamp(iSwapChain, Flags, pRamp);
555+
return;
556+
}
557+
558+
bool bIsBorderlessMode = pVideoModeManager->IsDisplayModeWindowed() || pVideoModeManager->IsDisplayModeFullScreenWindow();
559+
560+
// Store original gamma ramp on first call or mode change
561+
if (!g_GammaState.bOriginalGammaStored || g_GammaState.lastSwapChain != iSwapChain || g_GammaState.bLastWasBorderless != bIsBorderlessMode)
562+
{
563+
if (!bIsBorderlessMode || !g_GammaState.bOriginalGammaStored)
564+
{
565+
// In fullscreen mode or first time - this is likely the original gamma
566+
g_GammaState.originalGammaRamp = *pRamp;
567+
g_GammaState.bOriginalGammaStored = true;
568+
g_GammaState.lastSwapChain = iSwapChain;
569+
}
570+
g_GammaState.bLastWasBorderless = bIsBorderlessMode;
571+
}
572+
573+
if (bIsBorderlessMode)
574+
{
575+
// Apply brightness and contrast adjustment to match fullscreen mode
576+
D3DGAMMARAMP adjustedRamp = *pRamp;
577+
578+
// Use lighter gamma correction to prevent darkening effect
579+
// and optimize brightness boost for better visibility
580+
const float fGammaCorrection = 1.0f / 1.3f;
581+
const float fBrightnessBoost = 1.4f;
582+
583+
for (int i = 0; i < 256; i++)
584+
{
585+
// Convert to normalized float (0.0 - 1.0)
586+
float fRed = static_cast<float>(pRamp->red[i]) / 65535.0f;
587+
float fGreen = static_cast<float>(pRamp->green[i]) / 65535.0f;
588+
float fBlue = static_cast<float>(pRamp->blue[i]) / 65535.0f;
589+
590+
// Clamp input values to valid range
591+
fRed = std::max(0.0f, std::min(1.0f, fRed));
592+
fGreen = std::max(0.0f, std::min(1.0f, fGreen));
593+
fBlue = std::max(0.0f, std::min(1.0f, fBlue));
594+
595+
// Apply gentler gamma correction first
596+
fRed = powf(fRed, fGammaCorrection);
597+
fGreen = powf(fGreen, fGammaCorrection);
598+
fBlue = powf(fBlue, fGammaCorrection);
599+
600+
// Then apply balanced brightness boost
601+
fRed = std::min(1.0f, fRed * fBrightnessBoost);
602+
fGreen = std::min(1.0f, fGreen * fBrightnessBoost);
603+
fBlue = std::min(1.0f, fBlue * fBrightnessBoost);
604+
605+
// Convert back to WORD values with proper rounding
606+
adjustedRamp.red[i] = static_cast<WORD>(fRed * 65535.0f + 0.5f);
607+
adjustedRamp.green[i] = static_cast<WORD>(fGreen * 65535.0f + 0.5f);
608+
adjustedRamp.blue[i] = static_cast<WORD>(fBlue * 65535.0f + 0.5f);
609+
}
610+
611+
// Set the adjusted gamma ramp
612+
m_pDevice->SetGammaRamp(iSwapChain, Flags, &adjustedRamp);
613+
614+
WriteDebugEvent("Applied gamma adjustment for borderless windowed mode");
615+
}
616+
else
617+
{
618+
// In exclusive fullscreen mode, use the original gamma ramp
619+
m_pDevice->SetGammaRamp(iSwapChain, Flags, pRamp);
620+
621+
WriteDebugEvent("Applied original gamma ramp for fullscreen mode");
622+
}
512623
}
513624

514625
VOID CProxyDirect3DDevice9::GetGammaRamp(UINT iSwapChain, D3DGAMMARAMP* pRamp)
515626
{
516-
m_pDevice->GetGammaRamp(iSwapChain, pRamp);
627+
return m_pDevice->GetGammaRamp(iSwapChain, pRamp);
517628
}
518629

519630
HRESULT CProxyDirect3DDevice9::CreateTexture(UINT Width, UINT Height, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DTexture9** ppTexture,

Client/core/DXHook/CProxyDirect3DDevice9.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -557,3 +557,19 @@ interface CProxyDirect3DDevice9 : public IDirect3DDevice9
557557

558558
extern CProxyDirect3DDevice9* g_pProxyDevice;
559559
extern CProxyDirect3DDevice9::SD3DDeviceState* g_pDeviceState;
560+
561+
// Add gamma state management
562+
struct SGammaState
563+
{
564+
volatile bool bOriginalGammaStored;
565+
volatile bool bLastWasBorderless;
566+
D3DGAMMARAMP originalGammaRamp;
567+
volatile UINT lastSwapChain;
568+
569+
SGammaState() : bOriginalGammaStored(false), bLastWasBorderless(false), lastSwapChain(0)
570+
{
571+
ZeroMemory(&originalGammaRamp, sizeof(originalGammaRamp));
572+
}
573+
};
574+
575+
extern SGammaState g_GammaState;

Client/core/Graphics/CVideoModeManager.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,9 @@ class CVideoModeManager : public CVideoModeManagerInterface
4242
virtual bool GetRequiredDisplayResolution(int& iOutWidth, int& iOutHeight, int& iOutColorBits, int& iOutAdapterIndex) override;
4343
virtual int GetFullScreenStyle() override { return m_iCurrentFullscreenStyle; }
4444
virtual bool IsDisplayModeWindowed() override;
45+
virtual bool IsDisplayModeFullScreenWindow() override;
4546

4647
bool IsDisplayModeFullScreen();
47-
bool IsDisplayModeFullScreenWindow();
4848
bool GetCurrentAdapterRect(LPRECT pOutRect);
4949
SString GetCurrentAdapterDeviceName();
5050

Client/core/Graphics/CVideoModeManager.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ class CVideoModeManagerInterface
3737
virtual bool GetRequiredDisplayResolution(int& iOutWidth, int& iOutHeight, int& iOutColorBits, int& iOutAdapterIndex) = 0;
3838
virtual int GetFullScreenStyle() = 0;
3939
virtual bool IsDisplayModeWindowed() = 0;
40+
virtual bool IsDisplayModeFullScreenWindow() = 0;
4041
};
4142

4243
CVideoModeManagerInterface* GetVideoModeManager();

0 commit comments

Comments
 (0)