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
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;
|
|
}
|