From 248ae8f112720d65cebe76f60f062c5589268a05 Mon Sep 17 00:00:00 2001 From: Denver Gingerich Date: Mon, 10 Mar 2008 12:44:38 -0400 Subject: [PATCH] ddraw: Implement ForceRefreshRate registry entry for overriding DirectX refresh rate. --- dlls/ddraw/ddraw.c | 91 +++++++++++++++++++++++++------------- dlls/ddraw/ddraw_private.h | 2 + dlls/ddraw/main.c | 36 +++++++++++++++ 3 files changed, 99 insertions(+), 30 deletions(-) diff --git a/dlls/ddraw/ddraw.c b/dlls/ddraw/ddraw.c index 4cac55d42ff..60ffdcd4d98 100644 --- a/dlls/ddraw/ddraw.c +++ b/dlls/ddraw/ddraw.c @@ -3,6 +3,7 @@ * Copyright 1998-2000 Lionel Ulmer * Copyright 2000-2001 TransGaming Technologies Inc. * Copyright 2006 Stefan Dösinger + * Copyright 2008 Denver Gingerich * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -534,34 +535,24 @@ IDirectDrawImpl_SetCooperativeLevel(IDirectDraw7 *iface, } /***************************************************************************** - * IDirectDraw7::SetDisplayMode * - * Sets the display screen resolution, color depth and refresh frequency - * when in fullscreen mode (in theory). - * Possible return values listed in the SDK suggest that this method fails - * when not in fullscreen mode, but this is wrong. Windows 2000 happily sets - * the display mode in DDSCL_NORMAL mode without an hwnd specified. - * It seems to be valid to pass 0 for With and Height, this has to be tested - * It could mean that the current video mode should be left as-is. (But why - * call it then?) + * Helper function for SetDisplayMode and RestoreDisplayMode * - * Params: - * Height, Width: Screen dimension - * BPP: Color depth in Bits per pixel - * Refreshrate: Screen refresh rate - * Flags: Other stuff - * - * Returns - * DD_OK on success + * Implements DirectDraw's SetDisplayMode, but ignores the value of + * ForceRefreshRate, since it is already handled by + * IDirectDrawImpl_SetDisplayMode. RestoreDisplayMode can use this function + * without worrying that ForceRefreshRate will override the refresh rate. For + * argument and return value documentation, see + * IDirectDrawImpl_SetDisplayMode. * *****************************************************************************/ -static HRESULT WINAPI -IDirectDrawImpl_SetDisplayMode(IDirectDraw7 *iface, - DWORD Width, - DWORD Height, - DWORD BPP, - DWORD RefreshRate, - DWORD Flags) +static HRESULT +IDirectDrawImpl_SetDisplayModeNoOverride(IDirectDraw7 *iface, + DWORD Width, + DWORD Height, + DWORD BPP, + DWORD RefreshRate, + DWORD Flags) { ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface); WINED3DDISPLAYMODE Mode; @@ -615,6 +606,46 @@ IDirectDrawImpl_SetDisplayMode(IDirectDraw7 *iface, }; } +/***************************************************************************** + * IDirectDraw7::SetDisplayMode + * + * Sets the display screen resolution, color depth and refresh frequency + * when in fullscreen mode (in theory). + * Possible return values listed in the SDK suggest that this method fails + * when not in fullscreen mode, but this is wrong. Windows 2000 happily sets + * the display mode in DDSCL_NORMAL mode without an hwnd specified. + * It seems to be valid to pass 0 for With and Height, this has to be tested + * It could mean that the current video mode should be left as-is. (But why + * call it then?) + * + * Params: + * Height, Width: Screen dimension + * BPP: Color depth in Bits per pixel + * Refreshrate: Screen refresh rate + * Flags: Other stuff + * + * Returns + * DD_OK on success + * + *****************************************************************************/ +static HRESULT WINAPI +IDirectDrawImpl_SetDisplayMode(IDirectDraw7 *iface, + DWORD Width, + DWORD Height, + DWORD BPP, + DWORD RefreshRate, + DWORD Flags) +{ + if (force_refresh_rate != 0) + { + TRACE("ForceRefreshRate overriding passed-in refresh rate (%d Hz) to %d Hz\n", RefreshRate, force_refresh_rate); + RefreshRate = force_refresh_rate; + } + + return IDirectDrawImpl_SetDisplayModeNoOverride(iface, Width, Height, BPP, + RefreshRate, Flags); +} + /***************************************************************************** * IDirectDraw7::RestoreDisplayMode * @@ -642,12 +673,12 @@ IDirectDrawImpl_RestoreDisplayMode(IDirectDraw7 *iface) ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface); TRACE("(%p)\n", This); - return IDirectDraw7_SetDisplayMode(ICOM_INTERFACE(This, IDirectDraw7), - This->orig_width, - This->orig_height, - This->orig_bpp, - 0, - 0); + return IDirectDrawImpl_SetDisplayModeNoOverride(ICOM_INTERFACE(This, IDirectDraw7), + This->orig_width, + This->orig_height, + This->orig_bpp, + 0, + 0); } /***************************************************************************** diff --git a/dlls/ddraw/ddraw_private.h b/dlls/ddraw/ddraw_private.h index 9b78edf3163..c10f981fef0 100644 --- a/dlls/ddraw/ddraw_private.h +++ b/dlls/ddraw/ddraw_private.h @@ -83,6 +83,8 @@ extern ULONG WINAPI D3D7CB_DestroyDepthStencilSurface(IWineD3DSurface *pSurface) /* Global critical section */ extern CRITICAL_SECTION ddraw_cs; +extern DWORD force_refresh_rate; + /***************************************************************************** * IDirectDraw implementation structure *****************************************************************************/ diff --git a/dlls/ddraw/main.c b/dlls/ddraw/main.c index 4e77d4f6d2e..a33cb34e4cb 100644 --- a/dlls/ddraw/main.c +++ b/dlls/ddraw/main.c @@ -4,6 +4,7 @@ * Copyright 1998 Lionel Ulmer * Copyright 2000-2001 TransGaming Technologies Inc. * Copyright 2006 Stefan Dösinger + * Copyright 2008 Denver Gingerich * * This file contains the (internal) driver registration functions, * driver enumeration APIs and DirectDraw creation functions. @@ -68,6 +69,9 @@ static CRITICAL_SECTION_DEBUG ddraw_cs_debug = }; CRITICAL_SECTION ddraw_cs = { &ddraw_cs_debug, -1, 0, 0, 0, 0 }; +/* value of ForceRefreshRate */ +DWORD force_refresh_rate = 0; + /*********************************************************************** * * Helper function for DirectDrawCreate and friends @@ -886,6 +890,38 @@ DllMain(HINSTANCE hInstDLL, } } + /* On Windows one can force the refresh rate that DirectDraw uses by + * setting an override value in dxdiag. This is documented in KB315614 + * (main article), KB230002, and KB217348. By comparing registry dumps + * before and after setting the override, we see that the override value + * is stored in HKLM\Software\Microsoft\DirectDraw\ForceRefreshRate as a + * DWORD that represents the refresh rate to force. We use this + * registry entry to modify the behavior of SetDisplayMode so that Wine + * users can override the refresh rate in a Windows-compatible way. + * + * dxdiag will not accept a refresh rate lower than 40 or higher than + * 120 so this value should be within that range. It is, of course, + * possible for a user to set the registry entry value directly so that + * assumption might not hold. + * + * There is no current mechanism for setting this value through the Wine + * GUI. It would be most appropriate to set this value through a dxdiag + * clone, but it may be sufficient to use winecfg. + * + * TODO: Create a mechanism for setting this value through the Wine GUI. + */ + if ( !RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\DirectDraw", &hkey ) ) + { + DWORD type, data; + size = sizeof(data); + if (!RegQueryValueExA( hkey, "ForceRefreshRate", NULL, &type, (LPBYTE)&data, &size ) && type == REG_DWORD) + { + TRACE("ForceRefreshRate set; overriding refresh rate to %d Hz\n", data); + force_refresh_rate = data; + } + RegCloseKey( hkey ); + } + DisableThreadLibraryCalls(hInstDLL); } else if (Reason == DLL_PROCESS_DETACH)