Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1369 lines
40 KiB

//=============================================================================
//
// Copyright (C) 1998 Microsoft Corporation. All rights reserved.
//
// File: ddmodent.c
// Content: DirectDraw display mode code for NT
//
// Date By Reason
// ---------- -------- -----------------------------------------------------
// 02/20/1998 johnstep Initialial implementation, replaces ddmode.c on NT
// 05/29/1998 jeffno ModeX emulation
//
//=============================================================================
#include "ddrawpr.h"
#include "ddrawgdi.h"
#define MODEX_WIDTH 320
#define MODEX_HEIGHT1 200
#define MODEX_HEIGHT2 240
#define MODEX_BPP 8
//=============================================================================
//
// Function: GetNumberOfMonitorAttachedToDesktop
//
// Count number of monitors attached to current desktop.
//
//=============================================================================
DWORD GetNumberOfMonitorAttachedToDesktop()
{
DWORD dwNumberOfMonitor = 0;
DWORD iDevNum = 0;
DISPLAY_DEVICE DisplayDevice;
ZeroMemory(&DisplayDevice,sizeof(DISPLAY_DEVICE));
DisplayDevice.cb = sizeof(DISPLAY_DEVICE);
while (EnumDisplayDevices(NULL,iDevNum,&DisplayDevice,0))
{
if (DisplayDevice.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP)
{
dwNumberOfMonitor++;
}
ZeroMemory(&DisplayDevice,sizeof(DISPLAY_DEVICE));
DisplayDevice.cb = sizeof(DISPLAY_DEVICE);
iDevNum++;
}
return dwNumberOfMonitor;
}
//=============================================================================
//
// Function: resetAllDirectDrawObjects
//
// On NT we have to reenable all the DirectDraw objects on any mode change
// because a mode change disables all the kernel mode DirectDraw objects due
// to desktop changes, etc.
//
//=============================================================================
void resetAllDirectDrawObjects()
{
LPDDRAWI_DIRECTDRAW_LCL pdd_lcl;
LPDDRAWI_DIRECTDRAW_GBL pdd_gbl;
BOOL bRestoreGamma;
HDC hdc;
WORD wMonitorsAttachedToDesktop = (WORD) GetNumberOfMonitorAttachedToDesktop();
// First mark all DirectDraw global objects as having not changed.
for (pdd_lcl = lpDriverLocalList; pdd_lcl;)
{
if (pdd_lcl->lpGbl)
{
pdd_lcl->lpGbl->dwFlags |= DDRAWI_DDRAWDATANOTFETCHED;
}
pdd_lcl = pdd_lcl->lpLink;
}
// Now reset all drivers unmarking them as we go. We may need to create
// temporary kernel mode DirectDraw objects in order to pass down a valid
// handle to the kernel.
for (pdd_lcl = lpDriverLocalList; pdd_lcl;)
{
pdd_gbl = pdd_lcl->lpGbl;
if (pdd_gbl && (pdd_gbl->dwFlags & DDRAWI_DDRAWDATANOTFETCHED))
{
// Determine if the gamma ramp needs to be restored
bRestoreGamma = ( pdd_lcl->lpPrimary != NULL ) &&
( pdd_lcl->lpPrimary->lpLcl->lpSurfMore->lpGammaRamp != NULL ) &&
( pdd_lcl->lpPrimary->lpLcl->dwFlags & DDRAWISURF_SETGAMMA );
pdd_gbl->dwFlags &= ~DDRAWI_DDRAWDATANOTFETCHED;
if (!(pdd_gbl->dwFlags & DDRAWI_MODEX))
{
// If we find a local for this process/driver pair, we will use
// its hDD to pass to the kernel. If not, we must create a
// temproary kernel mode DirectDraw object, and delete it after
// resetting the driver.
FetchDirectDrawData(pdd_gbl, TRUE, 0, NULL, NULL, 0, pdd_lcl);
}
else
{
DDHALMODEINFO mi =
{
MODEX_WIDTH, // width (in pixels) of mode
MODEX_HEIGHT1, // height (in pixels) of mode
MODEX_WIDTH, // pitch (in bytes) of mode
MODEX_BPP, // bits per pixel
(WORD)(DDMODEINFO_PALETTIZED | DDMODEINFO_MODEX), // flags
0, // refresh rate
0, // red bit mask
0, // green bit mask
0, // blue bit mask
0 // alpha bit mask
};
//fixup the height to the actual height:
mi.dwHeight = pdd_lcl->dmiPreferred.wHeight;
fetchModeXData( pdd_gbl, &mi, INVALID_HANDLE_VALUE );
}
pdd_gbl->dmiCurrent.wMonitorsAttachedToDesktop = (BYTE)wMonitorsAttachedToDesktop;
hdc = DD_CreateDC(pdd_gbl->cDriverName);
if ( pdd_gbl->dwFlags & DDRAWI_NOHARDWARE )
{
// The HEL will wipe out our hard-earned modex data otherwise
if (0 == (pdd_gbl->dwFlags & DDRAWI_MODEX) )
{
extern void UpdateDirectDrawMode(LPDDRAWI_DIRECTDRAW_GBL);
UpdateDirectDrawMode(pdd_gbl);
}
}
else
{
if( bRestoreGamma )
{
SetGamma( pdd_lcl->lpPrimary->lpLcl, pdd_lcl );
}
InitDIB(hdc, pdd_gbl->gpbmiSrc);
InitDIB(hdc, pdd_gbl->gpbmiDest);
}
DD_DoneDC(hdc);
}
pdd_lcl = pdd_lcl->lpLink;
}
CheckAliasedLocksOnModeChange();
}
//=============================================================================
//
// Function: ModeChangedOnENTERDDRAW
//
//=============================================================================
void ModeChangedOnENTERDDRAW(void)
{
resetAllDirectDrawObjects();
}
//=============================================================================
//
// Function: FillBitMasks
//
//=============================================================================
void FillBitMasks(LPDDPIXELFORMAT pddpf, HDC hdc)
{
if (hdc)
{
HBITMAP hbm;
BITMAPINFO *pbmi;
DWORD *pdwColors;
if (pbmi = LocalAlloc(LPTR, 3 * sizeof (RGBQUAD) + sizeof (BITMAPINFO)))
{
if (hbm = CreateCompatibleBitmap(hdc, 1, 1))
{
pbmi->bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
if (GetDIBits(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS))
{
if (pbmi->bmiHeader.biCompression == BI_BITFIELDS)
{
GetDIBits(hdc, hbm, 0, pbmi->bmiHeader.biHeight,
NULL, pbmi, DIB_RGB_COLORS);
pdwColors = (DWORD *) &pbmi->bmiColors[0];
pddpf->dwRBitMask = pdwColors[0];
pddpf->dwGBitMask = pdwColors[1];
pddpf->dwBBitMask = pdwColors[2];
pddpf->dwRGBAlphaBitMask = 0;
}
}
DeleteObject(hbm);
}
LocalFree(pbmi);
}
}
else
{
switch (pddpf->dwRGBBitCount)
{
case 15:
pddpf->dwRBitMask = 0x7C00;
pddpf->dwGBitMask = 0x03E0;
pddpf->dwBBitMask = 0x001F;
pddpf->dwRGBAlphaBitMask = 0;
break;
case 16:
pddpf->dwRBitMask = 0xF800;
pddpf->dwGBitMask = 0x07E0;
pddpf->dwBBitMask = 0x001F;
pddpf->dwRGBAlphaBitMask = 0;
break;
case 32:
pddpf->dwRBitMask = 0x00FF0000;
pddpf->dwGBitMask = 0x0000FF00;
pddpf->dwBBitMask = 0x000000FF;
pddpf->dwRGBAlphaBitMask = 0x00000000;
break;
default:
pddpf->dwRBitMask = 0;
pddpf->dwGBitMask = 0;
pddpf->dwBBitMask = 0;
pddpf->dwRGBAlphaBitMask = 0;
}
}
}
//=============================================================================
//
// Function: setPixelFormat
//
//=============================================================================
static void setPixelFormat(LPDDPIXELFORMAT pddpf, HDC hdc, DWORD bpp)
{
pddpf->dwSize = sizeof (DDPIXELFORMAT);
pddpf->dwFlags = DDPF_RGB;
pddpf->dwRGBBitCount = hdc ? GetDeviceCaps(hdc, BITSPIXEL) : bpp;
switch (pddpf->dwRGBBitCount)
{
case 8:
pddpf->dwFlags |= DDPF_PALETTEINDEXED8;
pddpf->dwRBitMask = 0;
pddpf->dwGBitMask = 0;
pddpf->dwBBitMask = 0;
pddpf->dwRGBAlphaBitMask = 0;
break;
case 24:
pddpf->dwRBitMask = 0x00FF0000;
pddpf->dwGBitMask = 0x0000FF00;
pddpf->dwBBitMask = 0x000000FF;
pddpf->dwRGBAlphaBitMask = 0x00000000;
break;
default:
FillBitMasks(pddpf, hdc);
break;
}
}
//=============================================================================
//
// Function: DD_GetDisplayMode
//
//=============================================================================
HRESULT DDAPI DD_GetDisplayMode(LPDIRECTDRAW pdd, LPDDSURFACEDESC pddsd)
{
LPDDRAWI_DIRECTDRAW_INT pdd_int;
LPDDRAWI_DIRECTDRAW_LCL pdd_lcl;
LPDDRAWI_DIRECTDRAW_GBL pdd_gbl;
HDC hdc;
ENTER_DDRAW();
DPF(2,A,"ENTERAPI: DD_GetDisplayMode");
TRY
{
pdd_int = (LPDDRAWI_DIRECTDRAW_INT) pdd;
if (!VALID_DIRECTDRAW_PTR(pdd_int))
{
DPF(0, "Invalid object");
LEAVE_DDRAW();
return DDERR_INVALIDOBJECT;
}
pdd_lcl = pdd_int->lpLcl;
pdd_gbl = pdd_lcl->lpGbl;
if (!VALIDEX_DDSURFACEDESC2_PTR(pddsd) &&
!VALIDEX_DDSURFACEDESC_PTR(pddsd))
{
DPF(0, "Invalid params");
LEAVE_DDRAW();
return DDERR_INVALIDPARAMS;
}
}
EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
DPF_ERR("DD_GetDisplayMode: Exception encountered validating parameters");
LEAVE_DDRAW();
return DDERR_INVALIDPARAMS;
}
ZeroMemory(pddsd, pddsd->dwSize);
if (LOWERTHANDDRAW4(pdd_int))
{
pddsd->dwSize = sizeof (DDSURFACEDESC);
}
else
{
pddsd->dwSize = sizeof (DDSURFACEDESC2);
}
pddsd->dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PITCH | DDSD_PIXELFORMAT | DDSD_REFRESHRATE;
hdc = DD_CreateDC(pdd_gbl->cDriverName);
pddsd->dwWidth = pdd_gbl->lpModeInfo->dwWidth;
pddsd->dwHeight = pdd_gbl->lpModeInfo->dwHeight;
pddsd->dwRefreshRate = pdd_gbl->lpModeInfo->wRefreshRate;
setPixelFormat(&(pddsd->ddpfPixelFormat), hdc, 0);
pddsd->lPitch = (pddsd->dwWidth * pddsd->ddpfPixelFormat.dwRGBBitCount) >> 3; // hack
// set stereo surface caps bits if driver marks mode as stereo mode
if (GetDDStereoMode(pdd_gbl,
pddsd->dwWidth,
pddsd->dwHeight,
pddsd->ddpfPixelFormat.dwRGBBitCount,
pddsd->dwRefreshRate) &&
!LOWERTHANDDRAW7(pdd_int) &&
VALIDEX_DDSURFACEDESC2_PTR(pddsd))
{
LPDDSURFACEDESC2 pddsd2 = (LPDDSURFACEDESC2)pddsd;
pddsd2->ddsCaps.dwCaps2 |= DDSCAPS2_STEREOSURFACELEFT;
}
DD_DoneDC(hdc);
LEAVE_DDRAW();
return DD_OK;
}
//=============================================================================
//
// Function: SetDisplayMode
//
//=============================================================================
/*
* IsRefreshRateSupported
*/
BOOL IsRefreshRateSupported(LPDDRAWI_DIRECTDRAW_GBL pdrv,
DWORD Width,
DWORD Height,
DWORD BitsPerPixel,
DWORD RefreshRate)
{
DEVMODE dm;
LPSTR pDeviceName;
int i;
pDeviceName = (_stricmp(pdrv->cDriverName, "display") == 0) ?
g_szPrimaryDisplay : pdrv->cDriverName;
for (i = 0;; i++)
{
ZeroMemory(&dm, sizeof dm);
dm.dmSize = sizeof dm;
if (EnumDisplaySettings(pDeviceName, i, &dm))
{
if ((dm.dmPelsWidth == Width) &&
(dm.dmPelsHeight == Height) &&
(dm.dmBitsPerPel == BitsPerPixel) &&
(dm.dmDisplayFrequency == RefreshRate))
{
return TRUE;
}
}
else
{
break;
}
}
return FALSE;
}
/*
* PickRefreshRate
*
* On NT, we want to pick a high reffresh rate, but we don't want to pick one
* too high. In theory, mode pruning would be 100% safe and we can always pick
* a high one, but we don't trust it 100%.
*/
DWORD PickRefreshRate(LPDDRAWI_DIRECTDRAW_GBL pdrv,
DWORD Width,
DWORD Height,
DWORD RefreshRate,
DWORD BitsPerPixel)
{
DEVMODE dm;
LPSTR pDeviceName;
pDeviceName = (_stricmp(pdrv->cDriverName, "display") == 0) ?
g_szPrimaryDisplay : pdrv->cDriverName;
if (dwRegFlags & DDRAW_REGFLAGS_FORCEREFRESHRATE)
{
if (IsRefreshRateSupported(pdrv,
Width,
Height,
BitsPerPixel,
dwForceRefreshRate))
{
return dwForceRefreshRate;
}
}
// If the app specified the refresh rate, we will use it; otherwise, we'll
// pick one ourselves.
if (RefreshRate == 0)
{
// If the mode requires no more bandwidth than the desktop mode from which
// the app was launched, we will go ahead and try that mode.
ZeroMemory(&dm, sizeof dm);
dm.dmSize = sizeof dm;
EnumDisplaySettings(pDeviceName, ENUM_REGISTRY_SETTINGS, &dm);
if ((Width <= dm.dmPelsWidth) &&
(Height <= dm.dmPelsHeight))
{
if (IsRefreshRateSupported(pdrv,
Width,
Height,
BitsPerPixel,
dm.dmDisplayFrequency))
{
RefreshRate = dm.dmDisplayFrequency;
}
}
// If we still don't have a refresh rate, try 75hz
if (RefreshRate == 0)
{
if (IsRefreshRateSupported(pdrv,
Width,
Height,
BitsPerPixel,
75))
{
RefreshRate = 75;
}
}
// If we still don't have a refresh rate, use 60hz
if (RefreshRate == 0)
{
if (IsRefreshRateSupported(pdrv,
Width,
Height,
BitsPerPixel,
60))
{
RefreshRate = 60;
}
}
}
return RefreshRate;
}
HRESULT SetDisplayMode(
LPDDRAWI_DIRECTDRAW_LCL pdd_lcl,
DWORD index,
BOOL force,
BOOL useRefreshRate)
{
LPDDRAWI_DIRECTDRAW_GBL pdd_gbl;
DEVMODE dm;
LONG result;
BOOL bNewMode;
DDHALINFO ddhi;
LPCTSTR pszDevice;
DWORD refreshRate;
BOOL forceRefresh;
pdd_lcl->dwLocalFlags |= DDRAWILCL_MODEHASBEENCHANGED;
pdd_gbl = pdd_lcl->lpGbl;
//
// If not forcing, do not change mode with surface locks.
//
if (!force)
{
if (pdd_gbl->dwSurfaceLockCount > 0)
{
LPDDRAWI_DDRAWSURFACE_INT pTemp;
// When we enabled vidmem vertex buffers in DX8, we found that some
// apps do not unlock them before the mode change, but we don't want
// to break them now, so we will hack around this by allowing the
// mode switch to occur if all that's locked are vidmem VBs.
pTemp = pdd_gbl->dsList;
while (pTemp != NULL)
{
if (pTemp->lpLcl->lpGbl->dwUsageCount > 0)
{
if ((pTemp->lpLcl->ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY) &&
!(pTemp->lpLcl->ddsCaps.dwCaps & DDSCAPS_EXECUTEBUFFER))
{
break;
}
}
pTemp = pTemp->lpLink;
}
if (pTemp != NULL)
{
return DDERR_SURFACEBUSY;
}
}
}
//
// Add code here to not set mode if it didn't change?
//
ZeroMemory(&dm, sizeof dm);
dm.dmSize = sizeof dm;
dm.dmBitsPerPel = pdd_lcl->dmiPreferred.wBPP;
dm.dmPelsWidth = pdd_lcl->dmiPreferred.wWidth;
dm.dmPelsHeight = pdd_lcl->dmiPreferred.wHeight;
if (dm.dmBitsPerPel == 16)
{
if (pdd_gbl->lpModeInfo->wFlags & DDMODEINFO_555MODE)
{
dm.dmBitsPerPel = 15;
}
}
dm.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
if (useRefreshRate)
{
dm.dmDisplayFrequency = PickRefreshRate(pdd_lcl->lpGbl,
dm.dmPelsWidth,
dm.dmPelsHeight,
pdd_lcl->dmiPreferred.wRefreshRate,
dm.dmBitsPerPel);
dm.dmFields |= DM_DISPLAYFREQUENCY;
}
else
{
dm.dmDisplayFrequency = PickRefreshRate(pdd_lcl->lpGbl,
dm.dmPelsWidth,
dm.dmPelsHeight,
0,
dm.dmBitsPerPel);
if (dm.dmDisplayFrequency > 0)
{
dm.dmFields |= DM_DISPLAYFREQUENCY;
pdd_lcl->dmiPreferred.wRefreshRate = (WORD) dm.dmDisplayFrequency;
}
}
if (_stricmp(pdd_gbl->cDriverName, "DISPLAY"))
{
pszDevice = pdd_gbl->cDriverName;
}
else
{
pszDevice = NULL;
}
// clean up any previous modex stuff:
pdd_gbl->dwFlags &= ~DDRAWI_MODEX;
NotifyDriverToDeferFrees();
pdd_gbl->dwFlags |= DDRAWI_CHANGINGMODE;
result = ChangeDisplaySettingsEx(pszDevice, &dm, NULL, CDS_FULLSCREEN, 0);
pdd_gbl->dwFlags &= ~DDRAWI_CHANGINGMODE;
DPF(5, "ChangeDisplaySettings: %d", result);
if (result != DISP_CHANGE_SUCCESSFUL)
{
//
// Check if it's a potentially emulated ModeX mode
//
if (pdd_lcl->dwLocalFlags & DDRAWILCL_ALLOWMODEX)
{
if (pdd_lcl->dmiPreferred.wBPP == MODEX_BPP &&
pdd_lcl->dmiPreferred.wWidth == MODEX_WIDTH)
{
if (pdd_lcl->dmiPreferred.wHeight == MODEX_HEIGHT2 || pdd_lcl->dmiPreferred.wHeight == MODEX_HEIGHT1)
{
// Set 640x480x8 for consistency with win9x and reliable mouse pos messages.
dm.dmFields &= ~DM_DISPLAYFREQUENCY;
dm.dmPelsWidth = 640;
dm.dmPelsHeight = 480;
pdd_gbl->dwFlags |= DDRAWI_CHANGINGMODE;
result = ChangeDisplaySettingsEx(pszDevice, &dm, NULL, CDS_FULLSCREEN, 0);
pdd_gbl->dwFlags &= ~DDRAWI_CHANGINGMODE;
}
}
}
if (result == DISP_CHANGE_SUCCESSFUL)
{
//now we are in 640x480, we need to mark the ddraw local that it's in emulated modex
pdd_gbl->dwFlags |= DDRAWI_MODEX;
}
else
{
//failed to set 640x480
NotifyDriverOfFreeAliasedLocks();
return DDERR_UNSUPPORTED;
}
}
uDisplaySettingsUnique = DdQueryDisplaySettingsUniqueness();
resetAllDirectDrawObjects();
pdd_lcl->dwLocalFlags |= DDRAWILCL_MODEHASBEENCHANGED | DDRAWILCL_DIRTYDC;
return DD_OK;
}
//=============================================================================
//
// Function: DD_SetDisplayMode
//
//=============================================================================
HRESULT DDAPI DD_SetDisplayMode(
LPDIRECTDRAW pdd,
DWORD dwWidth,
DWORD dwHeight,
DWORD dwBPP)
{
DPF(2,A,"ENTERAPI: DD_SetDisplayMode");
return DD_SetDisplayMode2(pdd, dwWidth, dwHeight, dwBPP, 0, 0);
}
//=============================================================================
//
// Function: DD_SetDisplayMode2
//
//=============================================================================
HRESULT DDAPI DD_SetDisplayMode2(
LPDIRECTDRAW pdd,
DWORD dwWidth,
DWORD dwHeight,
DWORD dwBPP,
DWORD dwRefreshRate,
DWORD dwFlags)
{
LPDDRAWI_DIRECTDRAW_INT pdd_int;
LPDDRAWI_DIRECTDRAW_LCL pdd_lcl;
LPDDRAWI_DIRECTDRAW_GBL pdd_gbl;
HRESULT hr;
DISPLAYMODEINFO dmiSave;
BOOL excl_exists,has_excl;
ENTER_DDRAW();
DPF(2,A,"ENTERAPI: DD_SetDisplayMode2");
TRY
{
pdd_int = (LPDDRAWI_DIRECTDRAW_INT) pdd;
if (!VALID_DIRECTDRAW_PTR(pdd_int))
{
DPF(0, "Invalid object");
LEAVE_DDRAW();
return DDERR_INVALIDOBJECT;
}
if (dwFlags & ~DDSDM_VALID)
{
DPF_ERR("Invalid flags");
LEAVE_DDRAW();
return DDERR_INVALIDPARAMS;
}
pdd_lcl = pdd_int->lpLcl;
pdd_gbl = pdd_lcl->lpGbl;
if (pdd_gbl->dwSurfaceLockCount > 0)
{
LPDDRAWI_DDRAWSURFACE_INT pTemp;
// When we enabled vidmem vertex buffers in DX8, we found that some
// apps do not unlock them before the mode change, but we don't want
// to break them now, so we will hack around this by allowing the
// mode switch to occur if all that's locked are vidmem VBs.
pTemp = pdd_gbl->dsList;
while (pTemp != NULL)
{
if (pTemp->lpLcl->lpGbl->dwUsageCount > 0)
{
if ((pTemp->lpLcl->ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY) &&
!(pTemp->lpLcl->ddsCaps.dwCaps & DDSCAPS_EXECUTEBUFFER))
{
break;
}
}
pTemp = pTemp->lpLink;
}
if (pTemp != NULL)
{
DPF_ERR("Surfaces are locked, can't switch the mode");
LEAVE_DDRAW();
return DDERR_SURFACEBUSY;
}
}
CheckExclusiveMode(pdd_lcl, &excl_exists, &has_excl, FALSE, NULL, FALSE);
if (excl_exists &&
(!has_excl))
{
DPF_ERR("Can't change mode; exclusive mode not owned");
LEAVE_DDRAW();
return DDERR_NOEXCLUSIVEMODE;
}
dmiSave = pdd_lcl->dmiPreferred;
pdd_lcl->dmiPreferred.wWidth = (WORD) dwWidth;
pdd_lcl->dmiPreferred.wHeight = (WORD) dwHeight;
pdd_lcl->dmiPreferred.wBPP = (BYTE) dwBPP;
pdd_lcl->dmiPreferred.wRefreshRate = (WORD) dwRefreshRate;
}
EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
DPF_ERR("DD_SetDisplayMode2: Exception encountered validating parameters");
LEAVE_DDRAW();
return DDERR_INVALIDPARAMS;
}
hr = SetDisplayMode(pdd_lcl, 0, FALSE, dwRefreshRate ? TRUE : FALSE);
if (FAILED(hr))
{
pdd_lcl->dmiPreferred = dmiSave;
}
else
{
pdd_lcl->dmiPreferred = pdd_gbl->dmiCurrent;
}
LEAVE_DDRAW();
return hr;
}
//=============================================================================
//
// Function: RestoreDisplayMode
//
//=============================================================================
HRESULT RestoreDisplayMode(LPDDRAWI_DIRECTDRAW_LCL pdd_lcl, BOOL force)
{
LPDDRAWI_DIRECTDRAW_GBL pdd_gbl;
LPCTSTR pszDevice;
LONG result;
pdd_gbl = pdd_lcl->lpGbl;
pdd_gbl->dwFlags &= ~DDRAWI_MODEX;
if (!(pdd_lcl->dwLocalFlags & DDRAWILCL_MODEHASBEENCHANGED))
{
DPF(2, "Mode was never changed by this app");
return DD_OK;
}
if (!force)
{
if (pdd_gbl->dwSurfaceLockCount > 0)
{
LPDDRAWI_DDRAWSURFACE_INT pTemp;
// When we enabled vidmem vertex buffers in DX8, we found that some
// apps do not unlock them before the mode change, but we don't want
// to break them now, so we will hack around this by allowing the
// mode switch to occur if all that's locked are vidmem VBs.
pTemp = pdd_gbl->dsList;
while (pTemp != NULL)
{
if (pTemp->lpLcl->lpGbl->dwUsageCount > 0)
{
if ((pTemp->lpLcl->ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY) &&
!(pTemp->lpLcl->ddsCaps.dwCaps & DDSCAPS_EXECUTEBUFFER))
{
break;
}
}
pTemp = pTemp->lpLink;
}
if (pTemp != NULL)
{
return DDERR_SURFACEBUSY;
}
}
}
if (_stricmp(pdd_gbl->cDriverName, "DISPLAY"))
{
pszDevice = pdd_gbl->cDriverName;
}
else
{
pszDevice = NULL;
}
NotifyDriverToDeferFrees();
pdd_gbl->dwFlags |= DDRAWI_CHANGINGMODE;
result = ChangeDisplaySettingsEx(pszDevice, NULL, NULL, CDS_FULLSCREEN, 0);
pdd_gbl->dwFlags &= ~DDRAWI_CHANGINGMODE;
if (result != DISP_CHANGE_SUCCESSFUL)
{
NotifyDriverOfFreeAliasedLocks();
return DDERR_UNSUPPORTED;
}
//
// FetchDirectDrawData here, which will update the global object with
// the new mode information.
//
uDisplaySettingsUnique = DdQueryDisplaySettingsUniqueness();
resetAllDirectDrawObjects();
pdd_lcl->dwLocalFlags &= ~DDRAWILCL_MODEHASBEENCHANGED;
pdd_lcl->dwLocalFlags |= DDRAWILCL_DIRTYDC;
RedrawWindow(NULL, NULL, NULL, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN);
return DD_OK;
}
//=============================================================================
//
// Function: DD_RestoreDisplayMode
//
//=============================================================================
HRESULT DDAPI DD_RestoreDisplayMode(LPDIRECTDRAW pdd)
{
LPDDRAWI_DIRECTDRAW_INT pdd_int;
LPDDRAWI_DIRECTDRAW_LCL pdd_lcl;
LPDDRAWI_DIRECTDRAW_GBL pdd_gbl;
BOOL excl_exists,has_excl;
HRESULT hr;
ENTER_DDRAW();
DPF(2,A,"ENTERAPI: DD_RestoreDisplayMode");
TRY
{
pdd_int = (LPDDRAWI_DIRECTDRAW_INT) pdd;
if (!VALID_DIRECTDRAW_PTR(pdd_int))
{
DPF(0, "Invalid object");
LEAVE_DDRAW();
return DDERR_INVALIDOBJECT;
}
pdd_lcl = pdd_int->lpLcl;
pdd_gbl = pdd_lcl->lpGbl;
CheckExclusiveMode(pdd_lcl, &excl_exists, &has_excl, FALSE, NULL, FALSE);
if (excl_exists &&
(!has_excl))
{
DPF_ERR("Can't change mode; exclusive mode owned");
LEAVE_DDRAW();
return DDERR_NOEXCLUSIVEMODE;
}
if (pdd_gbl->dwSurfaceLockCount > 0)
{
LPDDRAWI_DDRAWSURFACE_INT pTemp;
// When we enabled vidmem vertex buffers in DX8, we found that some
// apps do not unlock them before the mode change, but we don't want
// to break them now, so we will hack around this by allowing the
// mode switch to occur if all that's locked are vidmem VBs.
pTemp = pdd_gbl->dsList;
while (pTemp != NULL)
{
if (pTemp->lpLcl->lpGbl->dwUsageCount > 0)
{
if ((pTemp->lpLcl->ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY) &&
!(pTemp->lpLcl->ddsCaps.dwCaps & DDSCAPS_EXECUTEBUFFER))
{
break;
}
}
pTemp = pTemp->lpLink;
}
if (pTemp != NULL)
{
DPF_ERR("Surfaces are locked, can't switch the mode");
LEAVE_DDRAW();
return DDERR_SURFACEBUSY;
}
}
}
EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
DPF_ERR("DD_RestoreDisplayMode: Exception encountered validating parameters");
LEAVE_DDRAW();
return DDERR_INVALIDPARAMS;
}
hr = RestoreDisplayMode(pdd_lcl, TRUE);
LEAVE_DDRAW();
return hr;
}
//=============================================================================
//
// Function: DD_EnumDisplayModes
//
//=============================================================================
HRESULT DDAPI DD_EnumDisplayModes(
LPDIRECTDRAW pdd,
DWORD dwFlags,
LPDDSURFACEDESC pddsd,
LPVOID pContext,
LPDDENUMMODESCALLBACK pEnumCallback)
{
DPF(2,A,"ENTERAPI: DD_EnumDisplayModes");
if (pddsd)
{
DDSURFACEDESC2 ddsd2;
TRY
{
if(!VALID_DIRECTDRAW_PTR(((LPDDRAWI_DIRECTDRAW_INT) pdd)))
{
return DDERR_INVALIDOBJECT;
}
if(!VALID_DDSURFACEDESC_PTR(pddsd))
{
DPF_ERR("Invalid surface description. Did you set the dwSize member?");
DPF_APIRETURNS(DDERR_INVALIDPARAMS);
return DDERR_INVALIDPARAMS;
}
CopyMemory(&ddsd2, pddsd, sizeof *pddsd);
}
EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
DPF_ERR("Exception encountered validating parameters: Bad LPDDSURFACEDESC");
DPF_APIRETURNS(DDERR_INVALIDPARAMS);
return DDERR_INVALIDPARAMS;
}
ddsd2.dwSize = sizeof ddsd2;
ZeroMemory(((LPBYTE)&ddsd2 + sizeof *pddsd), (sizeof ddsd2) - (sizeof *pddsd));
return DD_EnumDisplayModes4(pdd, dwFlags, &ddsd2, pContext, (LPDDENUMMODESCALLBACK2) pEnumCallback);
}
return DD_EnumDisplayModes4(pdd, dwFlags, NULL, pContext, (LPDDENUMMODESCALLBACK2) pEnumCallback);
}
BOOL EnumerateMode(
LPDDRAWI_DIRECTDRAW_INT pdd_int,
LPDDENUMMODESCALLBACK2 pEnumCallback,
LPVOID pContext,
WORD wWidth,
WORD wHeight,
WORD wBPP,
WORD wRefreshRate,
DWORD dwFlags,
BOOL bIsEmulatedModex )
{
DDSURFACEDESC2 ddsd;
ZeroMemory(&ddsd, sizeof ddsd);
if (LOWERTHANDDRAW4(pdd_int))
{
ddsd.dwSize = sizeof (DDSURFACEDESC);
}
else
{
ddsd.dwSize = sizeof (DDSURFACEDESC2);
}
ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_PITCH | DDSD_REFRESHRATE;
ddsd.dwWidth = wWidth;
ddsd.dwHeight = wHeight;
ddsd.lPitch = (ddsd.dwWidth * wBPP) >> 3; // hack
setPixelFormat(&(ddsd.ddpfPixelFormat), NULL, wBPP);
if (dwFlags & DDEDM_REFRESHRATES)
{
ddsd.dwRefreshRate = wRefreshRate;
}
else
{
ddsd.dwRefreshRate = 0;
}
if ( bIsEmulatedModex )
{
ddsd.ddsCaps.dwCaps |= DDSCAPS_MODEX;
} else
{
// call driver here if this is a stereo mode!!!
if (!LOWERTHANDDRAW7(pdd_int) &&
GetDDStereoMode(pdd_int->lpLcl->lpGbl,
wWidth,
wHeight,
wBPP,
ddsd.dwRefreshRate))
{
ddsd.ddsCaps.dwCaps2 |= DDSCAPS2_STEREOSURFACELEFT;
}
}
return pEnumCallback(&ddsd, pContext);
}
//=============================================================================
//
// Function: DD_EnumDisplayModes4
//
//=============================================================================
HRESULT DDAPI DD_EnumDisplayModes4(
LPDIRECTDRAW pdd,
DWORD dwFlags,
LPDDSURFACEDESC2 pddsd,
LPVOID pContext,
LPDDENUMMODESCALLBACK2 pEnumCallback)
{
LPDDRAWI_DIRECTDRAW_INT pdd_int;
LPDDRAWI_DIRECTDRAW_LCL pdd_lcl;
LPDDRAWI_DIRECTDRAW_GBL pdd_gbl;
HRESULT hr;
DEVMODE dm;
int i, j;
DWORD dwResult;
DISPLAYMODEINFO *pdmi;
DISPLAYMODEINFO *pdmiTemp;
int numModes;
int maxModes;
LPCTSTR pszDevice;
BOOL bFound320x240x8 = FALSE;
BOOL bFound320x200x8 = FALSE;
BOOL bFound640x480x8 = FALSE;
ENTER_DDRAW();
DPF(2,A,"ENTERAPI: DD_EnumDisplayModes4");
TRY
{
pdd_int = (LPDDRAWI_DIRECTDRAW_INT) pdd;
if (!VALID_DIRECTDRAW_PTR(pdd_int))
{
DPF(0, "Invalid object");
LEAVE_DDRAW();
return DDERR_INVALIDOBJECT;
}
pdd_lcl = pdd_int->lpLcl;
pdd_gbl = pdd_lcl->lpGbl;
if (pddsd && !VALID_DDSURFACEDESC2_PTR(pddsd))
{
DPF_ERR("Invalid surface description");
LEAVE_DDRAW();
return DDERR_INVALIDPARAMS;
}
if (dwFlags & ~DDEDM_VALID)
{
DPF_ERR("Invalid flags");
LEAVE_DDRAW();
return DDERR_INVALIDPARAMS;
}
if (!VALIDEX_CODE_PTR(pEnumCallback))
{
DPF_ERR("Invalid enumerate callback pointer");
LEAVE_DDRAW();
return DDERR_INVALIDPARAMS;
}
}
EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
DPF_ERR("Exception encountered validating parameters: Bad LPDDSURFACEDESC");
LEAVE_DDRAW();
return DDERR_INVALIDPARAMS;
}
maxModes = 256; // enough to handle most drivers
pdmi = LocalAlloc(LMEM_FIXED, maxModes * sizeof (DISPLAYMODEINFO));
if (!pdmi)
{
DPF_ERR("Out of memory building mode list");
LEAVE_DDRAW();
return DDERR_GENERIC;
}
if (_stricmp(pdd_gbl->cDriverName, "DISPLAY"))
{
pszDevice = pdd_gbl->cDriverName;
}
else
{
pszDevice = NULL;
}
dm.dmSize = sizeof(dm);
for (numModes = 0, j = 0; EnumDisplaySettings(pszDevice, j, &dm); ++j)
{
//Filter MODEX driver modes
if ( (_stricmp(dm.dmDeviceName,"MODEX") == 0) || (_stricmp(dm.dmDeviceName,"VGA") == 0) )
{
DPF(5,"Filtered mode %dx%dx%d from %s",dm.dmPelsWidth,dm.dmPelsHeight,dm.dmBitsPerPel,dm.dmDeviceName);
continue;
}
if (dm.dmBitsPerPel == MODEX_BPP)
{
if (dm.dmPelsWidth == MODEX_WIDTH)
{
if (dm.dmPelsHeight == MODEX_HEIGHT1)
bFound320x200x8 = TRUE;
if (dm.dmPelsHeight == MODEX_HEIGHT2)
bFound320x240x8 = TRUE;
}
if (dm.dmPelsWidth == 640 && dm.dmPelsHeight == 480)
bFound640x480x8 = TRUE;
}
//Filter less than 256 color modes
if (dm.dmBitsPerPel < 8)
{
continue;
}
//
// NOTE: If the driver supports 15 bpp but not 16, then
// EnumDisplaySettings will return 16 for compatibility reasons. The
// bitmasks we fill in will be for 16 bpp (since we can't determine
// which mode it really is), so they may be incorrect.
//
// There should never be a case where we got only 15 bpp. If a driver
// only supports 555, it should be reported as 16 bpp.
//
if (dm.dmBitsPerPel == 15)
{
dm.dmBitsPerPel = 16;
}
//
// If the caller supplied a DDSURFACEDESC, check for width,
// height, bpp, and refresh rate for a match.
//
if (pddsd &&
(((pddsd->dwFlags & DDSD_WIDTH) &&
(dm.dmPelsWidth != pddsd->dwWidth)) ||
((pddsd->dwFlags & DDSD_HEIGHT) &&
(dm.dmPelsHeight != pddsd->dwHeight)) ||
((pddsd->dwFlags & DDSD_PIXELFORMAT) &&
(dm.dmBitsPerPel != pddsd->ddpfPixelFormat.dwRGBBitCount)) ||
((pddsd->dwFlags & DDSD_REFRESHRATE) &&
(dm.dmDisplayFrequency != pddsd->dwRefreshRate))))
{
continue; // current mode does not match criteria
}
//
// Check to see if mode is already in the list. The flag which
// affects this is DDEDM_REFRESHRATES.
//
for (i = 0; i < numModes; ++i)
{
if ((dm.dmPelsWidth == pdmi[i].wWidth) &&
(dm.dmPelsHeight == pdmi[i].wHeight) &&
(dm.dmBitsPerPel == pdmi[i].wBPP))
{
if (dwFlags & DDEDM_REFRESHRATES)
{
if (dm.dmDisplayFrequency == pdmi[i].wRefreshRate)
{
break; // found a match
}
}
else
{
break; // found a match
}
}
}
if (i < numModes)
{
continue; // mode already in list
}
pdmi[numModes].wWidth = (WORD) dm.dmPelsWidth;
pdmi[numModes].wHeight = (WORD) dm.dmPelsHeight;
pdmi[numModes].wBPP = (BYTE) dm.dmBitsPerPel;
pdmi[numModes].wRefreshRate = (dwFlags & DDEDM_REFRESHRATES) ?
(WORD) dm.dmDisplayFrequency : 0;
if (++numModes >= maxModes)
{
if (maxModes < 8192)
{
maxModes <<= 1;
pdmiTemp = LocalAlloc(LMEM_FIXED, maxModes * sizeof (DISPLAYMODEINFO));
if (pdmiTemp)
{
CopyMemory(pdmiTemp, pdmi, numModes * sizeof (DISPLAYMODEINFO));
LocalFree(pdmi);
pdmi = pdmiTemp;
}
else
{
LocalFree(pdmi);
DPF_ERR("Out of memory expanding mode list");
LEAVE_DDRAW();
return DDERR_GENERIC;
}
}
else
{
LocalFree(pdmi);
DPF_ERR("Too many display modes");
LEAVE_DDRAW();
return DDERR_GENERIC;
}
}
}
//
// Should we sort modes here? Probably not.
//
for (i = 0; i < numModes; ++i)
{
if (!EnumerateMode(
pdd_int,
pEnumCallback, pContext,
pdmi[i].wWidth,
pdmi[i].wHeight,
pdmi[i].wBPP,
pdmi[i].wRefreshRate,
dwFlags,
FALSE )) //not a modex mode
{
break;
}
}
//
// Enumerate emulated modex modes if required
//
while (1)
{
if (pdd_lcl->dwLocalFlags & DDRAWILCL_ALLOWMODEX)
{
//640x480 is necessary to turn on emulation
if ( bFound640x480x8 )
{
if ( !bFound320x200x8 )
{
if (!EnumerateMode(
pdd_int,
pEnumCallback, pContext,
MODEX_WIDTH,MODEX_HEIGHT1,MODEX_BPP,60,
dwFlags,
TRUE )) //not a modex mode
{
break;
}
}
if ( !bFound320x240x8 )
{
if (!EnumerateMode(
pdd_int,
pEnumCallback, pContext,
MODEX_WIDTH,MODEX_HEIGHT2,MODEX_BPP,60,
dwFlags,
TRUE )) //not a modex mode
{
break;
}
}
}
}
break;
}
LocalFree(pdmi);
LEAVE_DDRAW();
return DD_OK;
}