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.
2108 lines
67 KiB
2108 lines
67 KiB
/*========================================================================== *
|
|
* Copyright (C) 1994-1995 Microsoft Corporation. All Rights Reserved.
|
|
*
|
|
* File: ddmode.c
|
|
* Content: DirectDraw mode support
|
|
* History:
|
|
* Date By Reason
|
|
* ==== == ======
|
|
* 31-jan-95 craige split out of ddraw.c and enhanced
|
|
* 27-feb-95 craige new sync. macros
|
|
* 01-mar-95 craige Win95 mode stuff
|
|
* 19-mar-95 craige use HRESULTs
|
|
* 28-mar-95 craige made modeset work again
|
|
* 01-apr-95 craige happy fun joy updated header file
|
|
* 19-apr-95 craige check for invalid callback in EnumDisplayModes
|
|
* 14-may-95 craige allow BPP change; validate EnumDisplayModes modes
|
|
* 15-may-95 craige keep track of who changes the mode
|
|
* 02-jun-95 craige keep track of the mode set by a process
|
|
* 06-jun-95 craige added internal fn RestoreDisplayMode
|
|
* 11-jun-95 craige don't allow mode switch if surfaces locked
|
|
* 12-jun-95 craige new process list stuff
|
|
* 25-jun-95 craige one ddraw mutex
|
|
* 28-jun-95 craige ENTER_DDRAW at very start of fns
|
|
* 30-jun-95 craige turned off > 16bpp
|
|
* 01-jul-95 craige bug 106 - always went to last mode if mode not found
|
|
* 02-jul-95 craige RestoreDisplayMode needs to call HEL too
|
|
* 04-jul-95 craige YEEHAW: new driver struct; SEH
|
|
* 05-jul-95 craige crank up priority during mode change
|
|
* 13-jul-95 craige first step in mode set fix; made it work
|
|
* 19-jul-95 craige bug 189 - graphics mode change being ignored sometimes
|
|
* 20-jul-95 craige internal reorg to prevent thunking during modeset
|
|
* 22-jul-95 craige bug 216 - random hang switching bpp - fixed by
|
|
* using apps hwnd to hide things.
|
|
* bug 230 - unsupported starting modes
|
|
* 29-jul-95 toddla allways call HEL for SetMode for display driver
|
|
* 10-aug-95 toddla EnumDisplayModes changed to take a lp not a lplp
|
|
* 02-sep-95 craige bug 854: disable > 640x480 modes for rel 1
|
|
* 04-sep-95 craige bug 894: allow forcing of mode set
|
|
* 08-sep-95 craige bug 932: set preferred mode after RestoreDisplayMode
|
|
* 05-jan-96 kylej add interface structures
|
|
* 09-jan-96 kylej enable >640x480 modes for rel 2
|
|
* 27-feb-96 colinmc ensured that bits-per-pixel is always tested for
|
|
* when enumerating display modes and that enumeration
|
|
* always assumes you will be in exclusive mode when
|
|
* you actually do the mode switch
|
|
* 11-mar-96 jeffno Dynamic mode switch stuff for NT
|
|
* 24-mar-96 kylej Check modes with monitor profile
|
|
* 26-mar-96 jeffno Added ModeChangedOnENTERDDRAW
|
|
* 15-sep-96 craige modex only work
|
|
* 05-oct-96 colinmc Work Item: Removing the restriction on taking Win16
|
|
* lock on VRAM surfaces (not including the primary)
|
|
* 12-oct-96 colinmc Improvements to Win16 locking code to reduce virtual
|
|
* memory usage
|
|
* 15-dec-96 jeffno Added more modex modes
|
|
* 29-jan-97 jeffno Mode13 support
|
|
* 30-jan-97 colinmc Bug 5555: Bad DPF
|
|
* 01-feb-97 colinmc Bug 5594: New ModeX modes are dangerous
|
|
* 02-feb-97 toddla pass driver name to DD16_GetMonitor functions
|
|
* 03-may-98 johnstep NT-specific mode code moved to ddmodent.c
|
|
*
|
|
***************************************************************************/
|
|
#include "ddrawpr.h"
|
|
#include "dx8priv.h"
|
|
|
|
|
|
// DX7 introduced a new style of refresh rate testing (for stereo), but we
|
|
// had to back away from it in DX8, so rather then using the LOWERTHANDDRAW7
|
|
// macro, we have to create our own that takes DX8 into account.
|
|
|
|
#define NEW_STYLE_REFRESH(x) \
|
|
(!LOWERTHANDDRAW7(x) && !((x)->lpLcl->dwLocalFlags & DDRAWILCL_DIRECTDRAW8))
|
|
|
|
|
|
static DDHALMODEINFO ddmiModeXModes[] =
|
|
{
|
|
#ifdef EXTENDED_MODEX
|
|
{
|
|
320, // width (in pixels) of mode
|
|
175, // height (in pixels) of mode
|
|
320, // pitch (in bytes) of mode
|
|
8, // 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
|
|
},
|
|
#endif // EXTENDED_MODEX
|
|
{
|
|
320, // width (in pixels) of mode
|
|
200, // height (in pixels) of mode
|
|
320, // pitch (in bytes) of mode
|
|
8, // 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
|
|
},
|
|
{
|
|
320, // width (in pixels) of mode
|
|
240, // height (in pixels) of mode
|
|
320, // pitch (in bytes) of mode
|
|
8, // 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
|
|
},
|
|
#ifdef EXTENDED_MODEX
|
|
{
|
|
320, // width (in pixels) of mode
|
|
350, // height (in pixels) of mode
|
|
320, // pitch (in bytes) of mode
|
|
8, // 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
|
|
},
|
|
{
|
|
320, // width (in pixels) of mode
|
|
400, // height (in pixels) of mode
|
|
320, // pitch (in bytes) of mode
|
|
8, // 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
|
|
},
|
|
{
|
|
320, // width (in pixels) of mode
|
|
480, // height (in pixels) of mode
|
|
320, // pitch (in bytes) of mode
|
|
8, // 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
|
|
},
|
|
#endif // EXTENDED_MODEX
|
|
/*
|
|
* This is the standard VGA 320x200 linear mode. This mode must stay at the
|
|
* end of the modex mode list, or else makeModeXModeIfNeeded might trip up
|
|
* and pick this mode first. We want makeModeXModeIfNeeded to continue to
|
|
* force modex and only modex.
|
|
*/
|
|
{
|
|
320, // width (in pixels) of mode
|
|
200, // height (in pixels) of mode
|
|
320, // pitch (in bytes) of mode
|
|
8, // bits per pixel
|
|
(WORD)(DDMODEINFO_PALETTIZED | DDMODEINFO_MODEX | DDMODEINFO_STANDARDVGA), // flags
|
|
0, // refresh rate
|
|
0, // red bit mask
|
|
0, // green bit mask
|
|
0, // blue bit mask
|
|
0 // alpha bit mask
|
|
}
|
|
};
|
|
#define NUM_MODEX_MODES (sizeof( ddmiModeXModes ) / sizeof( ddmiModeXModes[0] ) )
|
|
|
|
|
|
/*
|
|
* makeModeXModeIfNeeded
|
|
*/
|
|
static LPDDHALMODEINFO makeModeXModeIfNeeded(
|
|
LPDDHALMODEINFO pmi,
|
|
LPDDRAWI_DIRECTDRAW_LCL this_lcl )
|
|
{
|
|
int j;
|
|
LPDDHALMODEINFO pmi_j;
|
|
|
|
/*
|
|
* The app compat flags which mean ModeX mode only still mean ModeX mode
|
|
* only. This routine will not substitute a standard VGA mode for a ModeX
|
|
* mode by virtue of the order of these modes in the modex mode table.
|
|
*/
|
|
if( (this_lcl->dwAppHackFlags & DDRAW_APPCOMPAT_MODEXONLY) ||
|
|
(dwRegFlags & DDRAW_REGFLAGS_MODEXONLY) )
|
|
{
|
|
for( j=0;j<NUM_MODEX_MODES; j++ )
|
|
{
|
|
pmi_j = &ddmiModeXModes[j];
|
|
if( (pmi->dwWidth == pmi_j->dwWidth) &&
|
|
(pmi->dwHeight == pmi_j->dwHeight) &&
|
|
(pmi->dwBPP == pmi_j->dwBPP) &&
|
|
((pmi->wFlags & pmi_j->wFlags) & DDMODEINFO_PALETTIZED ) )
|
|
{
|
|
DPF(2,"Forcing mode %dx%d into modex", pmi->dwWidth,pmi->dwHeight );
|
|
return pmi_j;
|
|
}
|
|
}
|
|
}
|
|
return pmi;
|
|
|
|
} /* makeModeXModeIfNeeded */
|
|
|
|
|
|
/*
|
|
* makeDEVMODE
|
|
*
|
|
* create a DEVMODE struct (and flags) from mode info
|
|
*
|
|
* NOTE: We now always set the exclusive bit here and
|
|
* we always set the bpp. This is because we were
|
|
* previously not setting the bpp when not exclusive
|
|
* so the checking code was always passing the surface
|
|
* if it could do a mode of that size regardless of
|
|
* color depth.
|
|
*
|
|
* The new semantics of EnumDisplayModes is that it
|
|
* gives you a list of all display modes you could
|
|
* switch into if you were exclusive.
|
|
*/
|
|
void makeDEVMODE(
|
|
LPDDRAWI_DIRECTDRAW_GBL this,
|
|
LPDDHALMODEINFO pmi,
|
|
BOOL inexcl,
|
|
BOOL useRefreshRate,
|
|
LPDWORD pcds_flags,
|
|
LPDEVMODE pdm )
|
|
{
|
|
ZeroMemory( pdm, sizeof(*pdm) );
|
|
pdm->dmSize = sizeof( *pdm );
|
|
pdm->dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL;
|
|
if( useRefreshRate && (pmi->wRefreshRate != 0) )
|
|
pdm->dmFields |= DM_DISPLAYFREQUENCY;
|
|
pdm->dmPelsWidth = pmi->dwWidth;
|
|
pdm->dmPelsHeight = pmi->dwHeight;
|
|
pdm->dmBitsPerPel = pmi->dwBPP;
|
|
pdm->dmDisplayFrequency = pmi->wRefreshRate;
|
|
|
|
*pcds_flags = CDS_EXCLUSIVE | CDS_FULLSCREEN;
|
|
|
|
} /* makeDEVMODE */
|
|
|
|
/*
|
|
* AddModeXModes
|
|
*/
|
|
void AddModeXModes( LPDDRAWI_DIRECTDRAW_GBL pdrv )
|
|
{
|
|
DWORD i;
|
|
DWORD j;
|
|
LPDDHALMODEINFO pmi_i;
|
|
LPDDHALMODEINFO pmi_j;
|
|
BOOL hasmode[NUM_MODEX_MODES];
|
|
DWORD newmodecnt;
|
|
LPDDHALMODEINFO pmi;
|
|
|
|
for( j=0;j<NUM_MODEX_MODES; j++ )
|
|
{
|
|
hasmode[j] = FALSE;
|
|
}
|
|
|
|
/*
|
|
* find out what modes are already supported
|
|
*/
|
|
for( i=0;i<pdrv->dwNumModes;i++ )
|
|
{
|
|
pmi_i = &pdrv->lpModeInfo[i];
|
|
for( j=0;j<NUM_MODEX_MODES; j++ )
|
|
{
|
|
pmi_j = &ddmiModeXModes[j];
|
|
if( (pmi_i->dwWidth == pmi_j->dwWidth) &&
|
|
(pmi_i->dwHeight == pmi_j->dwHeight) &&
|
|
(pmi_i->dwBPP == pmi_j->dwBPP) &&
|
|
((pmi_i->wFlags & pmi_j->wFlags) & DDMODEINFO_PALETTIZED ) )
|
|
{
|
|
// There is a mode already in the mode table the same as the modeX mode.
|
|
// check to make sure that the driver really supports it
|
|
DWORD cds_flags;
|
|
DEVMODE dm;
|
|
int cds_rc;
|
|
|
|
makeDEVMODE( pdrv, pmi_i, TRUE, FALSE, &cds_flags, &dm );
|
|
|
|
cds_flags |= CDS_TEST;
|
|
cds_rc = ChangeDisplaySettings( &dm, cds_flags );
|
|
if( cds_rc != 0)
|
|
{
|
|
// The driver does not support this mode even though it is in the mode table.
|
|
// Mark the mode as unsupported and go ahead and add the ModeX mode.
|
|
DPF( 2, "Mode %d not supported (%dx%dx%d), rc = %d, marking invalid", i,
|
|
pmi_i->dwWidth, pmi_i->dwHeight, pmi_i->dwBPP,
|
|
cds_rc );
|
|
pmi_i->wFlags |= DDMODEINFO_UNSUPPORTED;
|
|
}
|
|
else
|
|
{
|
|
// Don't add the ModeX mode, the driver supports a linear mode.
|
|
hasmode[j] = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* count how many new modes we need
|
|
*/
|
|
newmodecnt = 0;
|
|
for( j=0;j<NUM_MODEX_MODES; j++ )
|
|
{
|
|
if( !hasmode[j] )
|
|
{
|
|
newmodecnt++;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* create new struct
|
|
*/
|
|
if( newmodecnt > 0 )
|
|
{
|
|
pmi = MemAlloc( (newmodecnt + pdrv->dwNumModes) * sizeof( DDHALMODEINFO ) );
|
|
if( pmi != NULL )
|
|
{
|
|
memcpy( pmi, pdrv->lpModeInfo, pdrv->dwNumModes * sizeof( DDHALMODEINFO ) );
|
|
for( j=0;j<NUM_MODEX_MODES; j++ )
|
|
{
|
|
if( !hasmode[j] )
|
|
{
|
|
DPF( 2, "Adding ModeX mode %ldx%ldx%ld (standard VGA flag is %d)",
|
|
ddmiModeXModes[j].dwWidth,
|
|
ddmiModeXModes[j].dwHeight,
|
|
ddmiModeXModes[j].dwBPP,
|
|
(ddmiModeXModes[j].wFlags &DDMODEINFO_STANDARDVGA) ? 1 : 0);
|
|
pmi[ pdrv->dwNumModes ] = ddmiModeXModes[j];
|
|
pdrv->dwNumModes++;
|
|
}
|
|
}
|
|
MemFree( pdrv->lpModeInfo );
|
|
pdrv->lpModeInfo = pmi;
|
|
}
|
|
}
|
|
//
|
|
// make sure the last mode we validate is the current mode
|
|
// this works around a Win95 VDD bug.
|
|
//
|
|
(void) ChangeDisplaySettings( NULL, CDS_TEST );
|
|
} /* AddModeXModes */
|
|
|
|
BOOL MonitorCanHandleMode(LPDDRAWI_DIRECTDRAW_GBL this, DWORD width, DWORD height, WORD refreshRate )
|
|
{
|
|
DWORD max_monitor_x;
|
|
DWORD min_refresh;
|
|
DWORD max_refresh;
|
|
|
|
max_monitor_x = (DWORD)DD16_GetMonitorMaxSize(this->cDriverName);
|
|
|
|
if( ( max_monitor_x != 0 ) && ( width > max_monitor_x ) )
|
|
{
|
|
DPF(1, "Mode's width greater than monitor maximum width (%d)", max_monitor_x);
|
|
return FALSE;
|
|
}
|
|
|
|
if( refreshRate == 0 )
|
|
{
|
|
// default refresh rate specified, no need to verify it
|
|
return TRUE;
|
|
}
|
|
|
|
// a refresh rate was specified, we'd better make sure the monitor can handle it
|
|
|
|
if(DD16_GetMonitorRefreshRateRanges(this->cDriverName, (int)width, (int) height, &min_refresh, &max_refresh))
|
|
{
|
|
if( (min_refresh != -1) && (min_refresh != 0) && (refreshRate < min_refresh) )
|
|
{
|
|
DPF(1, "Requested refresh rate < monitor's minimum refresh rate (%d)", min_refresh);
|
|
return FALSE;
|
|
}
|
|
if( (min_refresh != -1) && (max_refresh != 0) && (refreshRate > max_refresh) )
|
|
{
|
|
DPF(1, "Requested refresh rate > monitor's maximum refresh rate (%d)", max_refresh);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
// The monitor likes it.
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* setSurfaceDescFromMode
|
|
*/
|
|
static void setSurfaceDescFromMode(
|
|
LPDDRAWI_DIRECTDRAW_LCL this_lcl,
|
|
LPDDHALMODEINFO pmi,
|
|
LPDDSURFACEDESC pddsd
|
|
)
|
|
{
|
|
memset( pddsd, 0, sizeof( DDSURFACEDESC ) );
|
|
pddsd->dwSize = sizeof( DDSURFACEDESC );
|
|
pddsd->dwFlags = DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT |
|
|
DDSD_PITCH | DDSD_REFRESHRATE;
|
|
pddsd->dwHeight = pmi->dwHeight;
|
|
pddsd->dwWidth = pmi->dwWidth;
|
|
pddsd->lPitch = pmi->lPitch;
|
|
pddsd->dwRefreshRate = (DWORD)pmi->wRefreshRate;
|
|
|
|
pddsd->ddpfPixelFormat.dwSize = sizeof( DDPIXELFORMAT );
|
|
pddsd->ddpfPixelFormat.dwFlags = DDPF_RGB;
|
|
pddsd->ddpfPixelFormat.dwRGBBitCount = (DWORD)pmi->dwBPP;
|
|
if( pmi->wFlags & DDMODEINFO_PALETTIZED )
|
|
{
|
|
pddsd->ddpfPixelFormat.dwFlags |= DDPF_PALETTEINDEXED8;
|
|
}
|
|
else
|
|
{
|
|
pddsd->ddpfPixelFormat.dwRBitMask = pmi->dwRBitMask;
|
|
pddsd->ddpfPixelFormat.dwGBitMask = pmi->dwGBitMask;
|
|
pddsd->ddpfPixelFormat.dwBBitMask = pmi->dwBBitMask;
|
|
pddsd->ddpfPixelFormat.dwRGBAlphaBitMask = pmi->dwAlphaBitMask;
|
|
}
|
|
|
|
if (pmi->wFlags & DDMODEINFO_MODEX)
|
|
{
|
|
/*
|
|
* We only turn on these flags if the app is not hacked to turn them off and
|
|
* the registry hasn't been set to turn them off.
|
|
*/
|
|
if ( (!(dwRegFlags & DDRAW_REGFLAGS_NODDSCAPSINDDSD)) && (!(this_lcl->dwAppHackFlags & DDRAW_APPCOMPAT_NODDSCAPSINDDSD)) )
|
|
{
|
|
pddsd->dwFlags |= DDSD_CAPS;
|
|
/*
|
|
* If both MODEX and STANDARDVGA are set in the mode info, then it's
|
|
* a regular VGA mode (i.e. mode 0x13)
|
|
*/
|
|
if (pmi->wFlags & DDMODEINFO_STANDARDVGA )
|
|
{
|
|
pddsd->ddsCaps.dwCaps |= DDSCAPS_STANDARDVGAMODE;
|
|
}
|
|
else
|
|
{
|
|
pddsd->ddsCaps.dwCaps |= DDSCAPS_MODEX;
|
|
}
|
|
}
|
|
}
|
|
|
|
} /* setSurfaceDescFromMode */
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "GetDisplayMode"
|
|
|
|
HRESULT DDAPI DD_GetDisplayMode(
|
|
LPDIRECTDRAW lpDD,
|
|
LPDDSURFACEDESC lpSurfaceDesc )
|
|
{
|
|
LPDDRAWI_DIRECTDRAW_INT this_int;
|
|
LPDDRAWI_DIRECTDRAW_LCL this_lcl;
|
|
LPDDRAWI_DIRECTDRAW_GBL this;
|
|
LPDDHALMODEINFO pmi;
|
|
|
|
ENTER_DDRAW();
|
|
|
|
DPF(2,A,"ENTERAPI: DD_GetDisplayMode");
|
|
|
|
TRY
|
|
{
|
|
this_int = (LPDDRAWI_DIRECTDRAW_INT) lpDD;
|
|
if( !VALID_DIRECTDRAW_PTR( this_int ) )
|
|
{
|
|
LEAVE_DDRAW();
|
|
return DDERR_INVALIDOBJECT;
|
|
}
|
|
this_lcl = this_int->lpLcl;
|
|
this = this_lcl->lpGbl;
|
|
if( !VALIDEX_DDSURFACEDESC2_PTR( lpSurfaceDesc ) &&
|
|
!VALIDEX_DDSURFACEDESC_PTR( lpSurfaceDesc ) )
|
|
{
|
|
LEAVE_DDRAW();
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
if( this->dwModeIndex == DDUNSUPPORTEDMODE)
|
|
{
|
|
DPF_ERR( "Driver is in an unsupported mode" );
|
|
LEAVE_DDRAW();
|
|
return DDERR_UNSUPPORTEDMODE;
|
|
}
|
|
pmi = &this->lpModeInfo[ this->dwModeIndex ];
|
|
pmi = makeModeXModeIfNeeded( pmi, this_lcl );
|
|
|
|
ZeroMemory(lpSurfaceDesc,lpSurfaceDesc->dwSize);
|
|
setSurfaceDescFromMode( this_lcl, pmi, lpSurfaceDesc );
|
|
|
|
/*
|
|
* Maintain old behavior..
|
|
*/
|
|
if (LOWERTHANDDRAW4(this_int))
|
|
{
|
|
lpSurfaceDesc->dwSize = sizeof(DDSURFACEDESC);
|
|
}
|
|
else
|
|
{
|
|
lpSurfaceDesc->dwSize = sizeof(DDSURFACEDESC2);
|
|
|
|
|
|
}
|
|
|
|
/*
|
|
* set stereo surface caps bits if driver marks mode as stereo mode
|
|
*
|
|
*/
|
|
if ( pmi->wFlags & DDMODEINFO_STEREO &&
|
|
!LOWERTHANDDRAW7(this_int) &&
|
|
VALIDEX_DDSURFACEDESC2_PTR(lpSurfaceDesc)
|
|
)
|
|
{
|
|
LPDDSURFACEDESC2 pddsd2=(LPDDSURFACEDESC2) lpSurfaceDesc;
|
|
pddsd2->ddsCaps.dwCaps2 |= DDSCAPS2_STEREOSURFACELEFT;
|
|
}
|
|
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
DPF_ERR( "Exception encountered validating parameters" );
|
|
LEAVE_DDRAW();
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
LEAVE_DDRAW();
|
|
return DD_OK;
|
|
|
|
} /* DD_GetDisplayMode */
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "SetDisplayMode"
|
|
|
|
/*
|
|
* bumpPriority
|
|
*/
|
|
static DWORD bumpPriority( void )
|
|
{
|
|
DWORD oldclass;
|
|
HANDLE hprocess;
|
|
|
|
hprocess = GetCurrentProcess();
|
|
oldclass = GetPriorityClass( hprocess );
|
|
SetPriorityClass( hprocess, HIGH_PRIORITY_CLASS );
|
|
return oldclass;
|
|
|
|
} /* bumpPriority */
|
|
|
|
/*
|
|
* restorePriority
|
|
*/
|
|
static void restorePriority( DWORD oldclass )
|
|
{
|
|
HANDLE hprocess;
|
|
|
|
hprocess = GetCurrentProcess();
|
|
SetPriorityClass( hprocess, oldclass );
|
|
|
|
} /* restorePriority */
|
|
|
|
#if 0
|
|
static char szClassName[] = "DirectDrawFullscreenWindow";
|
|
static HWND hWndTmp;
|
|
static HCURSOR hSaveClassCursor;
|
|
static HCURSOR hSaveCursor;
|
|
static LONG lWindowLong;
|
|
static RECT rWnd;
|
|
|
|
#define OCR_WAIT_DEFAULT 102
|
|
|
|
/*
|
|
* curtainsUp
|
|
*/
|
|
void curtainsUp( LPDDRAWI_DIRECTDRAW_LCL pdrv_lcl )
|
|
{
|
|
HCURSOR hcursor= (HCURSOR)LoadImage(NULL,MAKEINTRESOURCE(OCR_WAIT_DEFAULT),IMAGE_CURSOR,0,0,0);
|
|
|
|
if( (pdrv_lcl->hWnd != 0) && IsWindow( (HWND) pdrv_lcl->hWnd ) )
|
|
{
|
|
lWindowLong = GetWindowLong( (HWND) pdrv_lcl->hWnd, GWL_EXSTYLE );
|
|
SetWindowLong( (HWND) pdrv_lcl->hWnd, GWL_EXSTYLE, lWindowLong |
|
|
(WS_EX_TOOLWINDOW) );
|
|
hSaveClassCursor = (HCURSOR) GetClassLong( (HWND) pdrv_lcl->hWnd, GCL_HCURSOR );
|
|
SetClassLong( (HWND) pdrv_lcl->hWnd, GCL_HCURSOR, (LONG) hcursor );
|
|
GetWindowRect( (HWND) pdrv_lcl->hWnd, (LPRECT) &rWnd );
|
|
SetWindowPos( (HWND) pdrv_lcl->hWnd, NULL, 0, 0,
|
|
10000, 10000,
|
|
SWP_NOZORDER | SWP_NOACTIVATE );
|
|
SetForegroundWindow( (HWND) pdrv_lcl->hWnd );
|
|
}
|
|
else
|
|
{
|
|
WNDCLASS cls;
|
|
pdrv_lcl->hWnd = 0;
|
|
cls.lpszClassName = szClassName;
|
|
cls.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
|
|
cls.hInstance = hModule;
|
|
cls.hIcon = NULL;
|
|
cls.hCursor = hcursor;
|
|
cls.lpszMenuName = NULL;
|
|
cls.style = CS_BYTEALIGNCLIENT | CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS;
|
|
cls.lpfnWndProc = DefWindowProc;
|
|
cls.cbWndExtra = 0;
|
|
cls.cbClsExtra = 0;
|
|
|
|
RegisterClass(&cls);
|
|
|
|
DPF( 4, "*** CREATEWINDOW" );
|
|
hWndTmp = CreateWindowEx(WS_EX_TOPMOST|WS_EX_TOOLWINDOW,
|
|
szClassName, szClassName,
|
|
WS_POPUP|WS_VISIBLE, 0, 0, 10000, 10000,
|
|
NULL, NULL, hModule, NULL);
|
|
DPF( 5, "*** BACK FROM CREATEWINDOW, hwnd=%08lx", hWndTmp );
|
|
|
|
if( hWndTmp != NULL)
|
|
{
|
|
SetForegroundWindow( hWndTmp );
|
|
}
|
|
}
|
|
hSaveCursor = SetCursor( hcursor );
|
|
|
|
} /* curtainsUp */
|
|
|
|
/*
|
|
* curtainsDown
|
|
*/
|
|
void curtainsDown( LPDDRAWI_DIRECTDRAW_LCL pdrv_lcl )
|
|
{
|
|
if( (pdrv_lcl->hWnd != 0) && IsWindow( (HWND) pdrv_lcl->hWnd ) )
|
|
{
|
|
SetWindowLong( (HWND) pdrv_lcl->hWnd, GWL_EXSTYLE, lWindowLong );
|
|
SetClassLong( (HWND) pdrv_lcl->hWnd, GCL_HCURSOR, (LONG) hSaveClassCursor );
|
|
SetCursor( hSaveCursor );
|
|
SetWindowPos( (HWND) pdrv_lcl->hWnd, NULL,
|
|
rWnd.left, rWnd.top,
|
|
rWnd.right-rWnd.left,
|
|
rWnd.bottom-rWnd.top,
|
|
SWP_NOZORDER | SWP_NOACTIVATE );
|
|
}
|
|
else
|
|
{
|
|
SetCursor( hSaveCursor );
|
|
pdrv_lcl->hWnd = 0;
|
|
if( hWndTmp != NULL )
|
|
{
|
|
DestroyWindow( hWndTmp );
|
|
UnregisterClass( szClassName, hModule );
|
|
}
|
|
}
|
|
hWndTmp = NULL;
|
|
|
|
} /* curtainsDown */
|
|
#endif
|
|
|
|
/*
|
|
* stopModeX
|
|
*/
|
|
static void stopModeX( LPDDRAWI_DIRECTDRAW_GBL pdrv )
|
|
{
|
|
DPF( 4, "***************** Turning off ModeX or standard VGA *****************" );
|
|
ModeX_RestoreMode();
|
|
|
|
pdrv->dwFlags &= ~(DDRAWI_MODEX|DDRAWI_STANDARDVGA);
|
|
DPF( 4, "**************** DONE Turning off ModeX or standard VGA *************" );
|
|
|
|
} /* stopModeX */
|
|
|
|
/*
|
|
* SetDisplayMode
|
|
*/
|
|
HRESULT SetDisplayMode(
|
|
LPDDRAWI_DIRECTDRAW_LCL this_lcl,
|
|
DWORD modeidx,
|
|
BOOL force,
|
|
BOOL useRefreshRate)
|
|
{
|
|
DWORD rc;
|
|
DDHAL_SETMODEDATA smd;
|
|
LPDDHAL_SETMODE smfn;
|
|
LPDDHAL_SETMODE smhalfn;
|
|
LPDDHALMODEINFO pmi;
|
|
LPDDHALMODEINFO orig_pmi;
|
|
BOOL inexcl;
|
|
BOOL emulation;
|
|
LPDDRAWI_DIRECTDRAW_GBL this;
|
|
DWORD oldclass;
|
|
BOOL use_modex;
|
|
BOOL was_modex;
|
|
DWORD real_modeidx;
|
|
|
|
/*
|
|
* Signify that the app at least tried to set a mode.
|
|
* Redrawing of the desktop will only happen if this flag is set.
|
|
*/
|
|
this_lcl->dwLocalFlags |= DDRAWILCL_MODEHASBEENCHANGED;
|
|
|
|
this = this_lcl->lpGbl;
|
|
|
|
/*
|
|
* don't allow if surfaces open
|
|
*/
|
|
if( !force )
|
|
{
|
|
#ifdef USE_ALIAS
|
|
/*
|
|
* See comment on alias stuff in DD_SetDisplayMode2()
|
|
*/
|
|
if( this->dwWin16LockCnt > 0 )
|
|
{
|
|
DPF_ERR( "Can't switch modes with locked surfaces holding Win16 lock!" );
|
|
return DDERR_SURFACEBUSY;
|
|
}
|
|
#else /* USE_ALIAS */
|
|
if( this->dwSurfaceLockCount > 0 )
|
|
{
|
|
DPF_ERR( "Can't switch modes with locked surfaces!" );
|
|
return DDERR_SURFACEBUSY;
|
|
}
|
|
#endif /* USE_ALIAS */
|
|
}
|
|
|
|
if( modeidx == DDUNSUPPORTEDMODE )
|
|
{
|
|
DPF_ERR( "Trying to set to an unsupported mode" );
|
|
return DDERR_UNSUPPORTEDMODE;
|
|
}
|
|
|
|
/*
|
|
* is our current mode a disp dib mode?
|
|
*/
|
|
was_modex = FALSE;
|
|
orig_pmi = NULL;
|
|
if( this->dwModeIndex != DDUNSUPPORTEDMODE )
|
|
{
|
|
orig_pmi = &this->lpModeInfo[ this->dwModeIndex ];
|
|
orig_pmi = makeModeXModeIfNeeded( orig_pmi, this_lcl );
|
|
if( orig_pmi->wFlags & DDMODEINFO_MODEX )
|
|
{
|
|
was_modex = TRUE;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* is the new mode a mode x mode
|
|
*/
|
|
pmi = &this->lpModeInfo[ modeidx ];
|
|
pmi = makeModeXModeIfNeeded( pmi, this_lcl );
|
|
if( pmi->wFlags & DDMODEINFO_MODEX )
|
|
{
|
|
DPF( 5, "Mode %ld is a ModeX or standard VGA mode", modeidx);
|
|
use_modex = TRUE;
|
|
}
|
|
else
|
|
{
|
|
use_modex = FALSE;
|
|
}
|
|
|
|
/*
|
|
* don't re-set the mode to the same one...
|
|
* NOTE: we ALWAYS set the mode in emulation on Win95 since our index could be wrong
|
|
*/
|
|
if( modeidx == this->dwModeIndex && !(this->dwFlags & DDRAWI_NOHARDWARE) )
|
|
{
|
|
DPF( 5, "%08lx: Current Mode match: %ldx%ld, %dbpp", GetCurrentProcessId(),
|
|
pmi->dwWidth, pmi->dwHeight, pmi->dwBPP );
|
|
return DD_OK;
|
|
}
|
|
|
|
DPF( 5, "***********************************************" );
|
|
DPF( 5, "*** SETDISPLAYMODE: %ldx%ld, %dbpp", pmi->dwWidth, pmi->dwHeight, pmi->dwBPP );
|
|
DPF( 5, "*** dwModeIndex (current) = %ld", this->dwModeIndex );
|
|
DPF( 5, "*** modeidx (new) = %ld", modeidx );
|
|
DPF( 5, "*** use_modex = %ld", use_modex );
|
|
DPF( 5, "*** was_modex = %ld", was_modex );
|
|
DPF( 5, "***********************************************" );
|
|
|
|
/*
|
|
* check if in exclusive mode
|
|
*/
|
|
inexcl = (this->lpExclusiveOwner == this_lcl);
|
|
|
|
/*
|
|
* check bpp
|
|
*/
|
|
if( (this->dwFlags & DDRAWI_DISPLAYDRV) && !force )
|
|
{
|
|
DWORD dwBPP;
|
|
|
|
if( NULL == orig_pmi )
|
|
{
|
|
/*
|
|
* This is branch is taken if we are currently running in an unsupported
|
|
* mode.
|
|
*/
|
|
DDASSERT( 0UL != this_lcl->hDC );
|
|
dwBPP = ( GetDeviceCaps( (HDC)( this_lcl->hDC ), BITSPIXEL ) *
|
|
GetDeviceCaps( (HDC)( this_lcl->hDC ), PLANES ) );
|
|
}
|
|
else
|
|
{
|
|
dwBPP = orig_pmi->dwBPP;
|
|
}
|
|
|
|
if( (dwBPP != pmi->dwBPP) || ((dwBPP == pmi->dwBPP) && use_modex ) )
|
|
{
|
|
if( !inexcl || !(this->dwFlags & DDRAWI_FULLSCREEN) )
|
|
{
|
|
DPF_ERR( "Can't change BPP if not in exclusive fullscreen mode" );
|
|
return DDERR_NOEXCLUSIVEMODE;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* see if we need to shutdown modex mode
|
|
*/
|
|
if( was_modex )
|
|
{
|
|
stopModeX( this );
|
|
}
|
|
|
|
/*
|
|
* see if we need to set a modex mode
|
|
*/
|
|
if( use_modex )
|
|
{
|
|
DWORD i;
|
|
LPDDHALMODEINFO tmp_pmi;
|
|
|
|
real_modeidx = modeidx;
|
|
for( i=0;i<this->dwNumModes;i++ )
|
|
{
|
|
tmp_pmi = &this->lpModeInfo[ i ];
|
|
if( (tmp_pmi->dwWidth == 640) &&
|
|
(tmp_pmi->dwHeight == 480) &&
|
|
(tmp_pmi->dwBPP == 8) &&
|
|
(tmp_pmi->wFlags & DDMODEINFO_PALETTIZED) )
|
|
{
|
|
DPF( 5, "MODEX or Standard VGA: Setting to 640x480x8 first (index=%ld)", i );
|
|
modeidx = i;
|
|
break;
|
|
}
|
|
}
|
|
if( i == this->dwNumModes )
|
|
{
|
|
DPF( 0, "Mode not supported" );
|
|
return DDERR_INVALIDMODE;
|
|
}
|
|
}
|
|
/*
|
|
* get the driver to set the new mode...
|
|
*/
|
|
if( ( this->dwFlags & DDRAWI_DISPLAYDRV ) ||
|
|
( this->dwFlags & DDRAWI_NOHARDWARE ) ||
|
|
( this_lcl->lpDDCB->cbDDCallbacks.SetMode == NULL ) )
|
|
{
|
|
smfn = this_lcl->lpDDCB->HELDD.SetMode;
|
|
smhalfn = smfn;
|
|
emulation = TRUE;
|
|
|
|
// If this DDraw object was created for a particular device, explicitly,
|
|
// and we're using the HEL (which we will be except on non-display
|
|
// devices), then stuff the this_lcl pointer into ddRVal so we can
|
|
// check the EXPLICITMONITOR flag from mySetMode.
|
|
smd.ddRVal = (HRESULT) this_lcl;
|
|
|
|
DPF( 4, "Calling HEL SetMode" );
|
|
}
|
|
else
|
|
{
|
|
smhalfn = this_lcl->lpDDCB->cbDDCallbacks.SetMode;
|
|
smfn = this_lcl->lpDDCB->HALDD.SetMode;
|
|
emulation = FALSE;
|
|
}
|
|
if( smhalfn != NULL )
|
|
{
|
|
DWORD oldmode;
|
|
BOOL didsetmode;
|
|
|
|
/*
|
|
* set the mode if this isn't a modex mode, or if it is a modex
|
|
* mode but wasn't one before
|
|
*/
|
|
if( !use_modex || (use_modex && !was_modex) )
|
|
{
|
|
smd.SetMode = smhalfn;
|
|
smd.lpDD = this;
|
|
smd.dwModeIndex = modeidx;
|
|
smd.inexcl = inexcl;
|
|
smd.useRefreshRate = useRefreshRate;
|
|
this->dwFlags |= DDRAWI_CHANGINGMODE;
|
|
oldclass = bumpPriority();
|
|
DOHALCALL( SetMode, smfn, smd, rc, emulation );
|
|
restorePriority( oldclass );
|
|
this->dwFlags &= ~DDRAWI_CHANGINGMODE;
|
|
didsetmode = TRUE;
|
|
}
|
|
else
|
|
{
|
|
rc = DDHAL_DRIVER_HANDLED;
|
|
smd.ddRVal = DD_OK;
|
|
didsetmode = FALSE;
|
|
}
|
|
if( rc == DDHAL_DRIVER_HANDLED )
|
|
{
|
|
if( smd.ddRVal == DD_OK )
|
|
{
|
|
oldmode = this->dwModeIndexOrig; // save original mode index
|
|
if( didsetmode )
|
|
{
|
|
CleanupD3D8(this, FALSE, 0);
|
|
FetchDirectDrawData( this, TRUE, 0, GETDDVXDHANDLE( this_lcl ), NULL, 0 , this_lcl );
|
|
this->dwModeIndex = modeidx;
|
|
this_lcl->dwPreferredMode = modeidx;
|
|
DPF(5,"Preferred mode index is %d, desired mode is %d",this_lcl->dwPreferredMode,modeidx);
|
|
this->dwModeIndexOrig = oldmode;
|
|
|
|
/*
|
|
* Some drivers will re-init the gamma ramp on a mode
|
|
* change, so if we previously set a new gamma ramp,
|
|
* we'll set it again.
|
|
*/
|
|
if( ( this_lcl->lpPrimary != NULL ) &&
|
|
( this_lcl->lpPrimary->lpLcl->lpSurfMore->lpGammaRamp != NULL ) &&
|
|
( this_lcl->lpPrimary->lpLcl->dwFlags & DDRAWISURF_SETGAMMA ) )
|
|
{
|
|
SetGamma( this_lcl->lpPrimary->lpLcl, this_lcl );
|
|
}
|
|
|
|
/*
|
|
* It is possible that calling ChangeDisplaySettings could
|
|
* generate a WM_ACTIVATE app message to the app telling
|
|
* it to deactivate, which would cause RestoreDisplaymode
|
|
* to be called before we setup the new mode index. In this
|
|
* case, it would not actually restore the mode but it would
|
|
* clear the MODEHASBEENCHANGEDFLAG, insuring that we could
|
|
* never restore the original mode. The simple workaround
|
|
* it to set this flag again.
|
|
*/
|
|
this_lcl->dwLocalFlags |= DDRAWILCL_MODEHASBEENCHANGED;
|
|
/*
|
|
* The driver local's DC will have been invalidated (DCX_CLIPCHILDREN set) by the
|
|
* mode switch, if it occurred via ChangeDisplaySettigs. Record this fact so the emulation
|
|
* code can decide to reinit the device DC.
|
|
*/
|
|
this_lcl->dwLocalFlags |= DDRAWILCL_DIRTYDC;
|
|
}
|
|
|
|
/*
|
|
* now set modex mode
|
|
*/
|
|
if( use_modex )
|
|
{
|
|
extern void HELStopDCI( void );
|
|
DPF( 4, "********************** Setting MODEX or STANDARD VGA MODE **********************" );
|
|
|
|
if( this->dwFlags & DDRAWI_ATTACHEDTODESKTOP )
|
|
{
|
|
HELStopDCI();
|
|
}
|
|
|
|
ModeX_SetMode( (UINT)pmi->dwWidth, (UINT)pmi->dwHeight, (UINT) (pmi->wFlags & DDMODEINFO_STANDARDVGA) );
|
|
/*
|
|
* ModeX now active, program our driver object and return
|
|
*/
|
|
/*
|
|
* We know this code can only ever be called from an application
|
|
* thread so we don't have to worry about using DDHELP's VXD handle.
|
|
*/
|
|
fetchModeXData( this, pmi, (HANDLE) this_lcl->hDDVxd );
|
|
this->dwModeIndex = real_modeidx;
|
|
this_lcl->dwPreferredMode = real_modeidx;
|
|
this->dwModeIndexOrig = oldmode;
|
|
DPF( 4, "********************** Done Setting MODEX MODE **********************" );
|
|
|
|
/*
|
|
* It is possible that calling ChangeDisplaySettings could
|
|
* generate a WM_ACTIVATE app message to the app telling
|
|
* it to deactivate, which would cause RestoreDisplaymode
|
|
* to be called before we setup the new mode index. In this
|
|
* case, it would not actually restore the mode but it would
|
|
* clear the MODEHASBEENCHANGEDFLAG, insuring that we could
|
|
* never restore the origainl mode. The simple workaround
|
|
* it to set this flag again.
|
|
*/
|
|
this_lcl->dwLocalFlags |= DDRAWILCL_MODEHASBEENCHANGED;
|
|
|
|
return DD_OK;
|
|
|
|
}
|
|
}
|
|
return smd.ddRVal;
|
|
}
|
|
}
|
|
|
|
return DDERR_UNSUPPORTED;
|
|
|
|
} /* SetDisplayMode */
|
|
|
|
/*
|
|
* DD_SetDisplayMode
|
|
*/
|
|
HRESULT DDAPI DD_SetDisplayMode(
|
|
LPDIRECTDRAW lpDD,
|
|
DWORD dwWidth,
|
|
DWORD dwHeight,
|
|
DWORD dwBPP )
|
|
{
|
|
DPF(2,A,"ENTERAPI: DD_SetDisplayMode");
|
|
|
|
DPF(4,"DD1 setdisplay mode called");
|
|
return DD_SetDisplayMode2(lpDD,dwWidth,dwHeight,dwBPP,0,0);
|
|
} /* DD_SetDisplayMode */
|
|
|
|
/*
|
|
* DD_SetDisplayMode2
|
|
*/
|
|
HRESULT DDAPI DD_SetDisplayMode2(
|
|
LPDIRECTDRAW lpDD,
|
|
DWORD dwWidth,
|
|
DWORD dwHeight,
|
|
DWORD dwBPP,
|
|
DWORD dwRefreshRate,
|
|
DWORD dwFlags)
|
|
{
|
|
LPDDRAWI_DIRECTDRAW_INT this_int;
|
|
LPDDRAWI_DIRECTDRAW_LCL this_lcl;
|
|
LPDDRAWI_DIRECTDRAW_GBL this;
|
|
int i;
|
|
int j;
|
|
LPDDHALMODEINFO pmi;
|
|
HRESULT ddrval;
|
|
int iChosenMode;
|
|
DWORD dwNumberOfTempModes;
|
|
|
|
typedef struct
|
|
{
|
|
DDHALMODEINFO mi;
|
|
int iIndex;
|
|
}TEMP_MODE_LIST;
|
|
|
|
TEMP_MODE_LIST * pTempList=0;
|
|
|
|
ENTER_DDRAW();
|
|
|
|
DPF(2,A,"ENTERAPI: DD_SetDisplayMode2");
|
|
|
|
TRY
|
|
{
|
|
this_int = (LPDDRAWI_DIRECTDRAW_INT) lpDD;
|
|
if( !VALID_DIRECTDRAW_PTR( this_int ) )
|
|
{
|
|
LEAVE_DDRAW();
|
|
return DDERR_INVALIDOBJECT;
|
|
}
|
|
this_lcl = this_int->lpLcl;
|
|
this = this_lcl->lpGbl;
|
|
|
|
/*
|
|
* Check for invalid flags
|
|
*/
|
|
if( dwFlags & ~ DDSDM_VALID)
|
|
{
|
|
DPF_ERR( "Invalid flags specified" );
|
|
LEAVE_DDRAW();
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
#ifdef USE_ALIAS
|
|
/*
|
|
* Behaviour change. Previously we did not allow a mode switch
|
|
* if any video memory (or implicit system memory) surfaces
|
|
* were locked. However, we not allow mode switches for
|
|
* locked VRAM surfaces as long as they don't have the Win16
|
|
* lock (in which case this code is irrelevant as the DirectDraw
|
|
* critical section will prevent them ever hitting this code).
|
|
* So the behaviour is now that if vram surface are locked but
|
|
* are not holding the Win16 lock they can mode switch away.
|
|
* If however, we have Win16 locked VRAM surfaces then they can't
|
|
* mode switch. This should only have any effect if the application
|
|
* holding the locks attempts the mode switch. In which case,
|
|
* previously it would fail if it had any VRAM or implicit system
|
|
* memory surfaces locked whereas now it will only fail if it has
|
|
* the primary or other unaliased VRAM surface locked.
|
|
*/
|
|
if( this->dwWin16LockCnt > 0 )
|
|
{
|
|
DPF_ERR( "Can't switch modes with locked surfaces holding Win16 lock!" );
|
|
LEAVE_DDRAW();
|
|
return DDERR_SURFACEBUSY;
|
|
}
|
|
#else /* USE_ALIAS */
|
|
/*
|
|
* don't allow change if surfaces are locked
|
|
*/
|
|
if( this->dwSurfaceLockCount )
|
|
{
|
|
DPF_ERR( "Surfaces are locked, can't switch the mode" );
|
|
LEAVE_DDRAW();
|
|
return DDERR_SURFACEBUSY;
|
|
}
|
|
#endif /* USE_ALIAS */
|
|
|
|
/*
|
|
* don't allow change if some other process has exclusive mode
|
|
*/
|
|
if( (this->lpExclusiveOwner != NULL) &&
|
|
(this->lpExclusiveOwner != this_lcl ) )
|
|
{
|
|
DPF_ERR( "Can't change mode; exclusive mode not owned" );
|
|
LEAVE_DDRAW();
|
|
return DDERR_NOEXCLUSIVEMODE;
|
|
}
|
|
|
|
/*
|
|
* Modes are now chosen in a 3-step process:
|
|
* -Build a temporary list of modes which match the desired spatial and color resolutions
|
|
* -Sort this list into ascending refresh rate order.
|
|
* -Select from this list the rate which best matches what we want.
|
|
*/
|
|
|
|
if( (this_lcl->dwAppHackFlags & DDRAW_APPCOMPAT_MODEXONLY) ||
|
|
(dwRegFlags & DDRAW_REGFLAGS_MODEXONLY) )
|
|
{
|
|
/*
|
|
* Don't allow VGA mode if ModeX only.
|
|
* Note if either of these flags are set, there won't actually be a VGA mode in the
|
|
* table, so we wouldn't match it anyway. The problem comes in when makeModeXModeIfNeeded
|
|
* overrides an accelerated mode. The duplication-check loop below will attempt to
|
|
* skip the newly modex 320x200x8 since it doesn't match the VGA 320x200x8 which it is expecting later in
|
|
* the table. That VGA mode won't be in the table, so the dupe check code skips the mode we
|
|
* actually wanted (since we are forcing to modex). If we turn off the app's request for
|
|
* VGA, then that dupe check won't be made, and we should pick up the modex mode.
|
|
*/
|
|
DPF(2,"Turning off request for standard VGA due to ModeX override");
|
|
dwFlags &= ~DDSDM_STANDARDVGAMODE;
|
|
}
|
|
|
|
/*
|
|
* Step 1. Build a list of modes which match the desired spatial and color resolutions
|
|
*/
|
|
pTempList = (TEMP_MODE_LIST*) MemAlloc(this->dwNumModes * sizeof(TEMP_MODE_LIST));
|
|
if (0 == pTempList)
|
|
{
|
|
LEAVE_DDRAW();
|
|
return DDERR_OUTOFMEMORY;
|
|
}
|
|
|
|
dwNumberOfTempModes=0;
|
|
DPF( 5, "Looking for %ldx%ldx%ld", dwWidth, dwHeight, dwBPP );
|
|
for(i = 0;i <(int) (this->dwNumModes);i++)
|
|
{
|
|
pmi = &this->lpModeInfo[i];
|
|
pmi = makeModeXModeIfNeeded( pmi, this_lcl );
|
|
|
|
DPF( 5, "Found %ldx%ldx%ldx (flags = %ld)", pmi->dwWidth, pmi->dwHeight, pmi->dwBPP, pmi->wFlags );
|
|
|
|
if( (pmi->dwWidth == dwWidth) &&
|
|
(pmi->dwHeight == dwHeight) &&
|
|
((DWORD)pmi->dwBPP == dwBPP) &&
|
|
((pmi->wFlags & DDMODEINFO_UNSUPPORTED) == 0) &&
|
|
(!LOWERTHANDDRAW7(this_int) || !(pmi->wFlags & DDMODEINFO_DX7ONLY)) )
|
|
{
|
|
/*
|
|
* The behaviour is that linear modes override ModeX modes
|
|
* and standard VGA modes. If the app sets
|
|
* DDSDM_STANDARDVGAMODE even when a linear mode has replaced
|
|
* both the modex and mode13 modes, then we will IGNORE the app's
|
|
* request for VGA and run with the linear mode. This most closely
|
|
* matches the ModeX behaviour.
|
|
* If there's an accelerated 320x200 mode, then there will be neither
|
|
* the modex nor the VGA mode in the mode table. If there's no accelerated
|
|
* mode, then there will be both modex and vga modes in the list.
|
|
* Therefore, if the app specified VGA, we only pay attention to them
|
|
* and ignore a 320x200x8 mode if it is a modex mode.
|
|
*/
|
|
if ( (dwFlags & DDSDM_STANDARDVGAMODE)
|
|
&& (pmi->wFlags & DDMODEINFO_MODEX) && ((pmi->wFlags & DDMODEINFO_STANDARDVGA)==0) )
|
|
{
|
|
/*
|
|
* App wants a standard VGA mode, but this mode is mode X. Move on.
|
|
*/
|
|
continue;
|
|
|
|
}
|
|
|
|
if(!(this->dwFlags & DDRAWI_DISPLAYDRV ))
|
|
{
|
|
if (pmi->wFlags & DDMODEINFO_DX7ONLY)
|
|
{
|
|
//
|
|
// Can't pass generated modes to non-display drivers
|
|
// because they actually get the index, and a generated
|
|
// mode's index would be beyond the end of their table.
|
|
//
|
|
|
|
continue;
|
|
}
|
|
}
|
|
|
|
pTempList[dwNumberOfTempModes].mi = *pmi;
|
|
pTempList[dwNumberOfTempModes].iIndex = i;
|
|
dwNumberOfTempModes++;
|
|
}
|
|
}
|
|
if (0 == dwNumberOfTempModes)
|
|
{
|
|
MemFree(pTempList);
|
|
LEAVE_DDRAW();
|
|
DPF( 0,"Mode not found... No match amongst available spatial and color resolutions (wanted %dx%dx%d)",dwWidth,dwHeight,dwBPP );
|
|
return DDERR_INVALIDMODE;
|
|
}
|
|
|
|
for(i=0;i<(int)dwNumberOfTempModes;i++)
|
|
DPF(5,"Copied mode list element %d:%dx%dx%d@%d",i,
|
|
pTempList[i].mi.dwWidth,
|
|
pTempList[i].mi.dwHeight,
|
|
pTempList[i].mi.dwBPP,
|
|
pTempList[i].mi.wRefreshRate);
|
|
|
|
/*
|
|
* Step 2. Sort list into ascending refresh order
|
|
* Bubble sort
|
|
* Note this does nothing if there's only one surviving mode.
|
|
*/
|
|
for (i=0;i<(int)dwNumberOfTempModes;i++)
|
|
{
|
|
for (j=(int)dwNumberOfTempModes-1;j>i;j--)
|
|
{
|
|
if (pTempList[i].mi.wRefreshRate > pTempList[j].mi.wRefreshRate)
|
|
{
|
|
TEMP_MODE_LIST temp = pTempList[i];
|
|
pTempList[i] = pTempList[j];
|
|
pTempList[j] = temp;
|
|
}
|
|
}
|
|
}
|
|
|
|
for(i=0;i<(int)dwNumberOfTempModes;i++)
|
|
DPF(5,"Sorted mode list element %d:%dx%dx%d@%d",i,
|
|
pTempList[i].mi.dwWidth,
|
|
pTempList[i].mi.dwHeight,
|
|
pTempList[i].mi.dwBPP,
|
|
pTempList[i].mi.wRefreshRate);
|
|
|
|
/*
|
|
* Step 3. Find the rate we're looking for.
|
|
* There are three cases.
|
|
* 1:Looking for a specific refresh
|
|
* 2a:Not looking for a specific refresh and stepping down in spatial resolution
|
|
* 2a:Not looking for a specific refresh and stepping up in spatial resolution
|
|
*/
|
|
iChosenMode = -1;
|
|
|
|
if (dwRefreshRate)
|
|
{
|
|
/* case 1 */
|
|
DPF(5,"App wants rate of %d",dwRefreshRate);
|
|
for (i=0;i<(int)dwNumberOfTempModes;i++)
|
|
{
|
|
/*
|
|
* We'll never match a zero (hardware default) rate here,
|
|
* but if there's only one rate which has refresh=0
|
|
* the app will never ask for a non-zero rate, because it will
|
|
* never have seen one at enumerate time.
|
|
*/
|
|
if ( (DWORD) (pTempList[i].mi.wRefreshRate) == dwRefreshRate )
|
|
{
|
|
iChosenMode=pTempList[i].iIndex;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Case 2b: Going up in spatial resolution, so just pick the
|
|
* lowest rate (earliest in list) which isn't a hardware
|
|
* default, unless no such rate exists.
|
|
*/
|
|
iChosenMode=pTempList[0].iIndex;
|
|
}
|
|
|
|
if (-1 == iChosenMode)
|
|
{
|
|
MemFree(pTempList);
|
|
LEAVE_DDRAW();
|
|
DPF( 0,"Mode not found... No match amongst available refresh rates (wanted %dx%dx%d@%d)",dwWidth,dwHeight,dwBPP,dwRefreshRate);
|
|
return DDERR_INVALIDMODE;
|
|
}
|
|
|
|
MemFree(pTempList);
|
|
|
|
pmi = &this->lpModeInfo[iChosenMode];
|
|
|
|
/*
|
|
* only allow ModeX modes if the cooplevel is ok
|
|
*/
|
|
if( (pmi->wFlags & DDMODEINFO_MODEX) && !(this_lcl->dwLocalFlags & DDRAWILCL_ALLOWMODEX) )
|
|
{
|
|
LEAVE_DDRAW();
|
|
DPF( 0,"must set DDSCL_ALLOWMODEX to use ModeX or Standard VGA modes" );
|
|
return DDERR_INVALIDMODE;
|
|
}
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
DPF_ERR( "Exception encountered validating parameters" );
|
|
LEAVE_DDRAW();
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
// See if the monitor likes it. If using an interface older than DX7,
|
|
// we check using the old way; otherwise, we check using the new way
|
|
if( !NEW_STYLE_REFRESH( this_int ) )
|
|
{
|
|
if( !(pmi->wFlags & DDMODEINFO_MODEX) && !MonitorCanHandleMode(this, pmi->dwWidth, pmi->dwHeight, pmi->wRefreshRate) )
|
|
{
|
|
// Monitor doesn't like it
|
|
LEAVE_DDRAW();
|
|
DPF_ERR("Mode not compatible with monitor");
|
|
return DDERR_INVALIDMODE;
|
|
}
|
|
}
|
|
else if( !(pmi->wFlags & DDMODEINFO_MODEX) )
|
|
{
|
|
if( !MonitorCanHandleMode(this, pmi->dwWidth, pmi->dwHeight, 0) ||
|
|
!CanMonitorHandleRefreshRate( this, pmi->dwWidth, pmi->dwHeight,
|
|
//Only pass a refresh rate if the app asked for one (otherwise, asking for 0
|
|
//will cause us to pass the first wRefreshRate in the mode table).
|
|
dwRefreshRate ? pmi->wRefreshRate : 0 ) )
|
|
{
|
|
// Monitor doesn't like it
|
|
LEAVE_DDRAW();
|
|
DPF_ERR("Mode not compatible with monitor");
|
|
return DDERR_INVALIDMODE;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* set the display mode, and pay attention to refresh rate if we were asked to.
|
|
* Always pay attention to rate on NT.
|
|
* NOTE!!! This is a very slight change from what we did in released DX2!!!
|
|
* - This function is now called from DD_SetDisplayMode with a refresh rate of 0,
|
|
* so we check for that circumstance and use it to say to the driver wether
|
|
* or not to pay attention to the refresh rate. Fine. However, now when
|
|
* someone calls DD_SetDisplayMode2 with a refresh rate of 0, we tell
|
|
* the driver to ignore the rate, when before we were telling the driver
|
|
* to force to some rate we found in the mode table (which would have been
|
|
* the first mode which matched resolution in the list... probably the lowest
|
|
* refresh rate).
|
|
*/
|
|
#if 1 //def WIN95
|
|
if (0 == dwRefreshRate)
|
|
ddrval = SetDisplayMode( this_lcl, iChosenMode, FALSE, FALSE );
|
|
else
|
|
#endif
|
|
ddrval = SetDisplayMode( this_lcl, iChosenMode, FALSE, TRUE );
|
|
|
|
LEAVE_DDRAW();
|
|
return ddrval;
|
|
|
|
} /* DD_SetDisplayMode2 */
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "RestoreDisplayMode"
|
|
|
|
/*
|
|
* RestoreDisplayMode
|
|
*
|
|
* For use by DD_RestoreDisplayMode & internally.
|
|
* Must be called with driver lock taken
|
|
*/
|
|
HRESULT RestoreDisplayMode( LPDDRAWI_DIRECTDRAW_LCL this_lcl, BOOL force )
|
|
{
|
|
DWORD rc;
|
|
DDHAL_SETMODEDATA smd;
|
|
BOOL inexcl;
|
|
DWORD pid;
|
|
LPDDHAL_SETMODE smfn;
|
|
LPDDHAL_SETMODE smhalfn;
|
|
BOOL emulation;
|
|
LPDDRAWI_DIRECTDRAW_GBL this;
|
|
DWORD oldclass;
|
|
BOOL was_modex;
|
|
LPDDHALMODEINFO pmi;
|
|
|
|
DPF(2,A,"ENTERAPI: DD_RestoreDisplayMode");
|
|
|
|
this = this_lcl->lpGbl;
|
|
#ifdef DEBUG
|
|
if( DDUNSUPPORTEDMODE != this->dwModeIndexOrig )
|
|
{
|
|
DPF(5,"Restoring Display mode to index %d, %dx%dx%d@%d",this->dwModeIndexOrig,
|
|
this->lpModeInfo[this->dwModeIndexOrig].dwWidth,
|
|
this->lpModeInfo[this->dwModeIndexOrig].dwHeight,
|
|
this->lpModeInfo[this->dwModeIndexOrig].dwBPP,
|
|
this->lpModeInfo[this->dwModeIndexOrig].wRefreshRate);
|
|
}
|
|
else
|
|
{
|
|
DPF(5,"Restoring Display mode to a non-DirectDraw mode");
|
|
}
|
|
#endif /* DEBUG */
|
|
|
|
if (0 == (this_lcl->dwLocalFlags & DDRAWILCL_MODEHASBEENCHANGED) )
|
|
{
|
|
/*
|
|
* This app never made a mode change, so we ignore the restore, in case someone switch desktop
|
|
* modes while playing a movie in a window, for instance. We do it before the redraw window
|
|
* so that we don't flash icons when a windowed app exits.
|
|
*/
|
|
DPF( 2, "Mode was never changed by this app" );
|
|
return DD_OK;
|
|
}
|
|
|
|
/*
|
|
* we ALWAYS set the mode in emulation on Win95 since our index could be wrong
|
|
*/
|
|
if( ( (this->dwModeIndex == this->dwModeIndexOrig) &&
|
|
!(this->dwFlags & DDRAWI_NOHARDWARE) ) || (this->lpModeInfo==NULL) )
|
|
{
|
|
DPF( 2, "Mode wasn't changed" );
|
|
RedrawWindow( NULL, NULL, NULL, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
|
|
/*
|
|
* Scenario: Start an app that can do windowed<->fullscreen transitions. Start windowed.
|
|
* Go fullscreen (sets MODEHASBEENCHANGED). Go windowed. Use control panel to
|
|
* change display settings. Exit app. Original mode will be restored.
|
|
* If we reset this flag, that won't happen.
|
|
*/
|
|
this_lcl->dwLocalFlags &= ~DDRAWILCL_MODEHASBEENCHANGED;
|
|
|
|
return DD_OK;
|
|
}
|
|
|
|
|
|
DPF( 4, "In RestoreDisplayMode" );
|
|
|
|
pid = GetCurrentProcessId();
|
|
|
|
/*
|
|
* don't allow mode change if surfaces are locked
|
|
*/
|
|
if( !force )
|
|
{
|
|
#ifdef USE_ALIAS
|
|
/*
|
|
* See comment on aliasing in DD_ResetDisplayMode()
|
|
*/
|
|
if( this->dwWin16LockCnt > 0 )
|
|
{
|
|
DPF_ERR( "Can't switch modes with locked surfaces holding Win16 lock!" );
|
|
return DDERR_SURFACEBUSY;
|
|
}
|
|
#else /* USE_ALIAS */
|
|
if( this->dwSurfaceLockCount > 0 )
|
|
{
|
|
DPF( 0, "Can't switch modes with locked surfaces!" );
|
|
return DDERR_SURFACEBUSY;
|
|
}
|
|
#endif /* USE_ALIAS */
|
|
}
|
|
|
|
/*
|
|
* see if we're in exclusive mode
|
|
*/
|
|
if( force )
|
|
{
|
|
inexcl = TRUE;
|
|
}
|
|
else
|
|
{
|
|
inexcl = (this->lpExclusiveOwner == this_lcl);
|
|
}
|
|
|
|
/*
|
|
* check bpp
|
|
*/
|
|
pmi = &this->lpModeInfo[ this->dwModeIndex ];
|
|
pmi = makeModeXModeIfNeeded( pmi, this_lcl );
|
|
if( pmi->wFlags & DDMODEINFO_MODEX )
|
|
{
|
|
was_modex = TRUE;
|
|
}
|
|
else
|
|
{
|
|
was_modex = FALSE;
|
|
}
|
|
|
|
/*
|
|
* turn off modex first...
|
|
*/
|
|
if( was_modex )
|
|
{
|
|
stopModeX( this );
|
|
}
|
|
|
|
/*
|
|
* get the driver to restore the mode...
|
|
*/
|
|
if( ( this->dwFlags & DDRAWI_DISPLAYDRV ) ||
|
|
( this->dwFlags & DDRAWI_NOHARDWARE ) ||
|
|
( this_lcl->lpDDCB->cbDDCallbacks.SetMode == NULL ) )
|
|
{
|
|
smfn = this_lcl->lpDDCB->HELDD.SetMode;
|
|
smhalfn = smfn;
|
|
emulation = TRUE;
|
|
|
|
// Store the this_lcl so we can check for multimon-aware in mySetMode
|
|
smd.ddRVal = (HRESULT) this_lcl;
|
|
}
|
|
else
|
|
{
|
|
smhalfn = this_lcl->lpDDCB->cbDDCallbacks.SetMode;
|
|
smfn = this_lcl->lpDDCB->HALDD.SetMode;
|
|
emulation = FALSE;
|
|
}
|
|
if( smhalfn != NULL )
|
|
{
|
|
smd.SetMode = smhalfn;
|
|
smd.lpDD = this;
|
|
smd.dwModeIndex = (DWORD) -1;
|
|
smd.inexcl = inexcl;
|
|
smd.useRefreshRate = TRUE;
|
|
this->dwFlags |= DDRAWI_CHANGINGMODE;
|
|
oldclass = bumpPriority();
|
|
|
|
// Store the this_lcl so we can check for multimon-aware in mySetMode
|
|
smd.ddRVal = (HRESULT) this_lcl;
|
|
|
|
DOHALCALL( SetMode, smfn, smd, rc, emulation );
|
|
restorePriority( oldclass );
|
|
this->dwFlags &= ~DDRAWI_CHANGINGMODE;
|
|
|
|
if( rc == DDHAL_DRIVER_HANDLED )
|
|
{
|
|
if( smd.ddRVal != DD_OK )
|
|
{
|
|
/*
|
|
* Scenario: Laptop boots w/ external monitor, switch to
|
|
* 10x7 mode. Shutdown, unplug the monitor, reboot. Mode
|
|
* is 640x480 but registry says it's 10x7. Run a low-res
|
|
* game, we call ChangeDisplaySettings(NULL), which tries
|
|
* to restore things according to the registry, so it
|
|
* fails. The result is we stay in low-res mode, which
|
|
* pretty much means we have to reboot.
|
|
*
|
|
* To work around this, we will explixitly set the mode that
|
|
* we started in.
|
|
*/
|
|
smd.dwModeIndex = this->dwModeIndexOrig;
|
|
this->dwFlags |= DDRAWI_CHANGINGMODE;
|
|
oldclass = bumpPriority();
|
|
smd.lpDD = this;
|
|
DOHALCALL( SetMode, smfn, smd, rc, emulation );
|
|
restorePriority( oldclass );
|
|
this->dwFlags &= ~DDRAWI_CHANGINGMODE;
|
|
}
|
|
if( smd.ddRVal == DD_OK )
|
|
{
|
|
DPF( 5, "RestoreDisplayMode: Process %08lx Mode = %ld", GETCURRPID(), this->dwModeIndex );
|
|
CleanupD3D8(this, FALSE, 0);
|
|
FetchDirectDrawData( this, TRUE, 0, GETDDVXDHANDLE( this_lcl ), NULL, 0 , this_lcl );
|
|
|
|
/*
|
|
* Some drivers will re-init the gamma ramp on a mode
|
|
* change, so if we previously set a new gamma ramp,
|
|
* we'll set it again.
|
|
*/
|
|
if( ( this_lcl->lpPrimary != NULL ) &&
|
|
( this_lcl->lpPrimary->lpLcl->lpSurfMore->lpGammaRamp != NULL ) &&
|
|
( this_lcl->lpPrimary->lpLcl->dwFlags & DDRAWISURF_SETGAMMA ) )
|
|
{
|
|
SetGamma( this_lcl->lpPrimary->lpLcl, this_lcl );
|
|
}
|
|
|
|
/*
|
|
* Scenario: Start an app that can do windowed<->fullscreen transitions. Start windowed.
|
|
* Go fullscreen (sets MODEHASBEENCHANGED). Go windowed. Use control panel to
|
|
* change display settings. Exit app. Original mode will be restored.
|
|
* If we reset this flag, that won't happen.
|
|
*/
|
|
this_lcl->dwLocalFlags &= ~DDRAWILCL_MODEHASBEENCHANGED;
|
|
|
|
/*
|
|
* The driver local's DC will have been invalidated (DCX_CLIPCHILDREN set) by the
|
|
* mode switch, if it occurred via ChangeDisplaySettigs. Record this fact so the emulation
|
|
* code can decide to reinit the device DC.
|
|
*/
|
|
this_lcl->dwLocalFlags |= DDRAWILCL_DIRTYDC;
|
|
|
|
if( this->dwFlags & DDRAWI_DISPLAYDRV )
|
|
{
|
|
DPF(4,"Redrawing all windows");
|
|
RedrawWindow( NULL, NULL, NULL, RDW_INVALIDATE | RDW_ERASE |
|
|
RDW_ALLCHILDREN );
|
|
}
|
|
}
|
|
return smd.ddRVal;
|
|
}
|
|
}
|
|
|
|
return DDERR_UNSUPPORTED;
|
|
|
|
} /* RestoreDisplayMode */
|
|
|
|
/*
|
|
* DD_RestoreDisplayMode
|
|
*
|
|
* restore mode
|
|
*/
|
|
HRESULT DDAPI DD_RestoreDisplayMode( LPDIRECTDRAW lpDD )
|
|
{
|
|
LPDDRAWI_DIRECTDRAW_INT this_int;
|
|
LPDDRAWI_DIRECTDRAW_LCL this_lcl;
|
|
LPDDRAWI_DIRECTDRAW_GBL this;
|
|
HRESULT ddrval;
|
|
|
|
ENTER_DDRAW();
|
|
|
|
DPF(2,A,"ENTERAPI: DD_RestoreDisplayMode");
|
|
|
|
TRY
|
|
{
|
|
this_int = (LPDDRAWI_DIRECTDRAW_INT) lpDD;
|
|
if( !VALID_DIRECTDRAW_PTR( this_int ) )
|
|
{
|
|
LEAVE_DDRAW();
|
|
return DDERR_INVALIDOBJECT;
|
|
}
|
|
this_lcl = this_int->lpLcl;
|
|
this = this_lcl->lpGbl;
|
|
|
|
/*
|
|
* switching to the same mode?
|
|
*/
|
|
if( this->dwModeIndex == this->dwModeIndexOrig )
|
|
{
|
|
LEAVE_DDRAW();
|
|
return DD_OK;
|
|
}
|
|
|
|
/*
|
|
* don't allow change if some other process has exclusive mode
|
|
*/
|
|
if( (this->lpExclusiveOwner != NULL) &&
|
|
(this->lpExclusiveOwner != this_lcl ) )
|
|
{
|
|
DPF_ERR( "Can't change mode; exclusive mode owned" );
|
|
LEAVE_DDRAW();
|
|
return DDERR_NOEXCLUSIVEMODE;
|
|
}
|
|
|
|
#ifdef USE_ALIAS
|
|
/*
|
|
* Behaviour change. Previously we did not allow a mode switch
|
|
* if any video memory (or implicit system memory) surfaces
|
|
* were locked. However, we not allow mode switches for
|
|
* locked VRAM surfaces as long as they don't have the Win16
|
|
* lock (in which case this code is irrelevant as the DirectDraw
|
|
* critical section will prevent them ever hitting this code).
|
|
* So the behaviour is now that if vram surface are locked but
|
|
* are not holding the Win16 lock they can mode switch away.
|
|
* If however, we have Win16 locked VRAM surfaces then they can't
|
|
* mode switch. This should only have any effect if the application
|
|
* holding the locks attempts the mode switch. In which case,
|
|
* previously it would fail if it had any VRAM or implicit system
|
|
* memory surfaces locked whereas now it will only fail if it has
|
|
* the primary or other unaliased VRAM surface locked.
|
|
*
|
|
* !!! NOTE: My gut feeling is that this should have no impact on
|
|
* anyone. However, we need to pull it and see.
|
|
*/
|
|
if( this->dwWin16LockCnt > 0 )
|
|
{
|
|
DPF_ERR( "Can't switch modes with locked surfaces holding Win16 lock!" );
|
|
LEAVE_DDRAW();
|
|
return DDERR_SURFACEBUSY;
|
|
}
|
|
#else /* USE_ALIAS */
|
|
/*
|
|
* don't allow change if surfaces are locked
|
|
*/
|
|
if( this->dwSurfaceLockCount )
|
|
{
|
|
DPF_ERR( "Surfaces are locked, can't switch the mode" );
|
|
LEAVE_DDRAW();
|
|
return DDERR_SURFACEBUSY;
|
|
}
|
|
#endif /* USE_ALIAS */
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
DPF_ERR( "Exception encountered validating parameters" );
|
|
LEAVE_DDRAW();
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
|
|
ddrval = RestoreDisplayMode( this_lcl, FALSE );
|
|
if( ddrval == DD_OK )
|
|
{
|
|
this_lcl->dwPreferredMode = this->dwModeIndex;
|
|
DPF( 5, "Preferred mode is now %ld", this_lcl->dwPreferredMode );
|
|
}
|
|
|
|
LEAVE_DDRAW();
|
|
return ddrval;
|
|
|
|
} /* DD_RestoreDisplayMode */
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "EnumDisplayModes"
|
|
|
|
/*
|
|
* DD_EnumDisplayModes
|
|
*/
|
|
HRESULT DDAPI DD_EnumDisplayModes(
|
|
LPDIRECTDRAW lpDD,
|
|
DWORD dwFlags,
|
|
LPDDSURFACEDESC lpDDSurfaceDesc,
|
|
LPVOID lpContext,
|
|
LPDDENUMMODESCALLBACK lpEnumCallback )
|
|
{
|
|
DPF(2,A,"ENTERAPI: DD_EnumDisplayModes");
|
|
|
|
if( lpDDSurfaceDesc != NULL )
|
|
{
|
|
DDSURFACEDESC2 ddsd2 = {sizeof(ddsd2)};
|
|
|
|
ZeroMemory(&ddsd2,sizeof(ddsd2));
|
|
|
|
TRY
|
|
{
|
|
if( !VALID_DIRECTDRAW_PTR( ((LPDDRAWI_DIRECTDRAW_INT)lpDD) ) )
|
|
{
|
|
return DDERR_INVALIDOBJECT;
|
|
}
|
|
if( !VALID_DDSURFACEDESC_PTR( lpDDSurfaceDesc ) )
|
|
{
|
|
DPF_ERR( "Invalid surface description. Did you set the dwSize member?" );
|
|
DPF_APIRETURNS(DDERR_INVALIDPARAMS);
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
memcpy(&ddsd2,lpDDSurfaceDesc,sizeof(*lpDDSurfaceDesc));
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
DPF_ERR( "Exception encountered validating parameters: Bad LPDDSURFACEDESC" );
|
|
DPF_APIRETURNS(DDERR_INVALIDPARAMS);
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
ddsd2.dwSize = sizeof(ddsd2);
|
|
return DD_EnumDisplayModes4(lpDD,dwFlags,&ddsd2,lpContext, (LPDDENUMMODESCALLBACK2) lpEnumCallback);
|
|
}
|
|
|
|
return DD_EnumDisplayModes4(lpDD,dwFlags,NULL,lpContext,(LPDDENUMMODESCALLBACK2)lpEnumCallback);
|
|
}
|
|
HRESULT DDAPI DD_EnumDisplayModes4(
|
|
LPDIRECTDRAW lpDD,
|
|
DWORD dwFlags,
|
|
LPDDSURFACEDESC2 lpDDSurfaceDesc,
|
|
LPVOID lpContext,
|
|
LPDDENUMMODESCALLBACK2 lpEnumCallback )
|
|
{
|
|
LPDDRAWI_DIRECTDRAW_INT this_int;
|
|
LPDDRAWI_DIRECTDRAW_LCL this_lcl;
|
|
LPDDRAWI_DIRECTDRAW_GBL this;
|
|
DWORD rc;
|
|
DDSURFACEDESC2 ddsd;
|
|
LPDDHALMODEINFO pmi;
|
|
int i, j;
|
|
BOOL inexcl;
|
|
BOOL bUseRefreshRate = FALSE;
|
|
|
|
ENTER_DDRAW();
|
|
|
|
DPF(2,A,"ENTERAPI: DD_EnumDisplayModes4");
|
|
|
|
TRY
|
|
{
|
|
this_int = (LPDDRAWI_DIRECTDRAW_INT) lpDD;
|
|
if( !VALID_DIRECTDRAW_PTR( this_int ) )
|
|
{
|
|
LEAVE_DDRAW();
|
|
return DDERR_INVALIDOBJECT;
|
|
}
|
|
this_lcl = this_int->lpLcl;
|
|
this = this_lcl->lpGbl;
|
|
|
|
if( lpDDSurfaceDesc != NULL )
|
|
{
|
|
if( !VALID_DDSURFACEDESC2_PTR(lpDDSurfaceDesc) )
|
|
{
|
|
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( lpEnumCallback ) )
|
|
{
|
|
DPF_ERR( "Invalid enum. callback routine" );
|
|
LEAVE_DDRAW();
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
}
|
|
EXCEPT( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
DPF_ERR( "Exception encountered validating parameters" );
|
|
LEAVE_DDRAW();
|
|
return DDERR_INVALIDPARAMS;
|
|
}
|
|
|
|
/*
|
|
* see if we're in exclusive mode
|
|
*/
|
|
inexcl = (this->lpExclusiveOwner == this_lcl);
|
|
|
|
if( (this_lcl->dwAppHackFlags & DDRAW_APPCOMPAT_MODEXONLY) ||
|
|
(dwRegFlags & DDRAW_REGFLAGS_MODEXONLY) )
|
|
{
|
|
/*
|
|
* Don't allow VGA mode if ModeX only.
|
|
* Note if either of these flags are set, there won't actually be a VGA mode in the
|
|
* table, so we wouldn't match it anyway. The problem comes in when makeModeXModeIfNeeded
|
|
* overrides an accelerated mode. The duplication-check loop below will attempt to
|
|
* skip the newly modex 320x200x8 since it doesn't match the VGA 320x200x8 which it is expecting later in
|
|
* the table. That VGA mode won't be in the table, so the dupe check code skips the mode we
|
|
* actually wanted (since we are forcing to modex). If we turn off the app's request for
|
|
* VGA, then that dupe check won't be made, and we should pick up the modex mode.
|
|
*/
|
|
DPF(2,"Turning off request for standard VGA due to ModeX override");
|
|
dwFlags &= ~DDEDM_STANDARDVGAMODES;
|
|
}
|
|
|
|
|
|
/*
|
|
* go through all possible modes...
|
|
*/
|
|
for( i=0;i<(int)this->dwNumModes;i++ )
|
|
{
|
|
pmi = &this->lpModeInfo[i];
|
|
pmi = makeModeXModeIfNeeded( pmi, this_lcl );
|
|
DPF(5,"Enumerating mode %d. %dx%d",i,pmi->dwWidth,pmi->dwHeight);
|
|
|
|
if( ( pmi->wFlags & DDMODEINFO_DX7ONLY ) &&
|
|
LOWERTHANDDRAW7( this_int ) )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* check to see if this is a duplicate mode
|
|
*/
|
|
for (j=0; j<i; j++)
|
|
{
|
|
// if we find a duplicate, break out early
|
|
if( (this->lpModeInfo[j].dwHeight == pmi->dwHeight) &&
|
|
(this->lpModeInfo[j].dwWidth == pmi->dwWidth) &&
|
|
(this->lpModeInfo[j].dwBPP == pmi->dwBPP) )
|
|
{
|
|
// basic mode matches, what about refresh rate?
|
|
if( dwFlags & DDEDM_REFRESHRATES )
|
|
{
|
|
// if refresh rate is not unique then the modes match
|
|
if( this->lpModeInfo[j].wRefreshRate == pmi->wRefreshRate )
|
|
{
|
|
DPF(5, "matched: %d %d", this->lpModeInfo[j].wRefreshRate, pmi->wRefreshRate);
|
|
/*
|
|
* We have an identical mode, unless one is standard VGA and the other is not
|
|
*/
|
|
if( dwFlags & DDEDM_STANDARDVGAMODES )
|
|
{
|
|
/*
|
|
* If the app cares about VGA modes, then a difference in the vganess
|
|
* of the two modes means they don't match.
|
|
*/
|
|
if ( (this->lpModeInfo[j].wFlags ^ pmi->wFlags) & DDMODEINFO_STANDARDVGA )
|
|
{
|
|
/*
|
|
* One mode is standard VGA and the other is not. Since
|
|
* the app asked to enumerate standard VGA modes, we don't
|
|
* consider this a match.
|
|
*/
|
|
continue;
|
|
}
|
|
}
|
|
/*
|
|
* Found identical refresh rate, and either app didn't care that
|
|
* modes are different in terms of VGAness or they are the same in
|
|
* terms of VGAness. Consider this a match.
|
|
*/
|
|
break;
|
|
}
|
|
// unique refresh rate and the app cares, the modes don't match
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
// the app doesn't care about refresh rates
|
|
if( dwFlags & DDEDM_STANDARDVGAMODES )
|
|
{
|
|
if ( (this->lpModeInfo[j].wFlags ^ pmi->wFlags) & DDMODEINFO_STANDARDVGA )
|
|
{
|
|
/*
|
|
* One mode is standard VGA and the other is not. Since
|
|
* the app asked to enumerate standard VGA modes, we don't
|
|
* consider this a match.
|
|
*/
|
|
continue;
|
|
}
|
|
/*
|
|
* Modes are the same as far as VGAness goes. drop through and break
|
|
* since they match
|
|
*/
|
|
}
|
|
/*
|
|
* The app specified neither refresh rates nor VGA, so any mode which is
|
|
* duplicated at least on resolution (spatial and color) is skipped
|
|
*/
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( j != i)
|
|
{
|
|
// broke out early, mode i is not unique, move on to the next one.
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* check if surface description matches mode
|
|
*/
|
|
if ( lpDDSurfaceDesc )
|
|
{
|
|
if( lpDDSurfaceDesc->dwFlags & DDSD_HEIGHT )
|
|
{
|
|
if( lpDDSurfaceDesc->dwHeight != pmi->dwHeight )
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
if( lpDDSurfaceDesc->dwFlags & DDSD_WIDTH )
|
|
{
|
|
if( lpDDSurfaceDesc->dwWidth != pmi->dwWidth )
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
if( lpDDSurfaceDesc->dwFlags & DDSD_PIXELFORMAT )
|
|
{
|
|
if( lpDDSurfaceDesc->ddpfPixelFormat.dwRGBBitCount != pmi->dwBPP )
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
if( lpDDSurfaceDesc->dwFlags & DDSD_REFRESHRATE )
|
|
{
|
|
bUseRefreshRate = TRUE;
|
|
if( lpDDSurfaceDesc->dwRefreshRate != (DWORD)pmi->wRefreshRate )
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bUseRefreshRate = FALSE;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* see if driver will allow this
|
|
*/
|
|
if (!(pmi->wFlags & DDMODEINFO_MODEX) )
|
|
{
|
|
if(this->dwFlags & DDRAWI_DISPLAYDRV)
|
|
{
|
|
|
|
DWORD cds_flags;
|
|
DEVMODE dm;
|
|
int cds_rc;
|
|
|
|
makeDEVMODE( this, pmi, inexcl, bUseRefreshRate, &cds_flags, &dm );
|
|
|
|
cds_flags |= CDS_TEST;
|
|
cds_rc = xxxChangeDisplaySettingsExA(this->cDriverName, &dm, NULL, cds_flags, 0);
|
|
if( cds_rc != 0 )
|
|
{
|
|
if( bUseRefreshRate )
|
|
{
|
|
DPF( 1, "Mode %d not supported (%ldx%ldx%ld rr=%d), rc = %d", i,
|
|
pmi->dwWidth, pmi->dwHeight, pmi->dwBPP, pmi->wRefreshRate, cds_rc );
|
|
}
|
|
else
|
|
{
|
|
DPF( 1, "Mode %d not supported (%ldx%ldx%ld), rc = %d", i,
|
|
pmi->dwWidth, pmi->dwHeight, pmi->dwBPP, cds_rc );
|
|
}
|
|
continue;
|
|
}
|
|
}
|
|
if( !NEW_STYLE_REFRESH( this_int ) )
|
|
{
|
|
// We check for a display driver, merely to maintain identical behaviour to DX6-:
|
|
// We never used to do the Monitor check on voodoos.
|
|
if (this->dwFlags & DDRAWI_DISPLAYDRV)
|
|
{
|
|
if( !MonitorCanHandleMode( this, pmi->dwWidth, pmi->dwHeight, pmi->wRefreshRate ) )
|
|
{
|
|
DPF( 1, "Monitor can't handle mode %d: (%ldx%ld rr=%d)", i,
|
|
pmi->dwWidth, pmi->dwHeight, pmi->wRefreshRate);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Call MonitorcanHandleMode to verify that that the size works,
|
|
// but we'll use our own hacked mechanism to determine if the
|
|
// refresh is supported
|
|
|
|
if( !MonitorCanHandleMode( this, pmi->dwWidth, pmi->dwHeight, 0 ) )
|
|
{
|
|
DPF( 1, "Monitor can't handle mode %d: (%ldx%ld rr=%d)", i,
|
|
pmi->dwWidth, pmi->dwHeight, pmi->wRefreshRate);
|
|
continue;
|
|
}
|
|
if( ( pmi->wRefreshRate > 0 ) &&
|
|
(dwFlags & DDEDM_REFRESHRATES) )
|
|
{
|
|
if( !CanMonitorHandleRefreshRate( this, pmi->dwWidth, pmi->dwHeight, pmi->wRefreshRate ) )
|
|
{
|
|
DPF( 1, "Monitor can't handle mode %d: (%ldx%ld rr=%d)", i,
|
|
pmi->dwWidth, pmi->dwHeight, pmi->wRefreshRate);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if( (this->dwFlags & DDRAWI_DISPLAYDRV) &&
|
|
(pmi->wFlags & DDMODEINFO_MODEX) &&
|
|
!(this_lcl->dwLocalFlags & DDRAWILCL_ALLOWMODEX) )
|
|
{
|
|
DPF( 2, "skipping ModeX or standard VGA mode" );
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
* invoke callback with surface desc.
|
|
*/
|
|
ZeroMemory(&ddsd,sizeof(ddsd));
|
|
setSurfaceDescFromMode( this_lcl, pmi, (LPDDSURFACEDESC)&ddsd );
|
|
if (LOWERTHANDDRAW4(this_int))
|
|
{
|
|
ddsd.dwSize = sizeof(DDSURFACEDESC);
|
|
}
|
|
else
|
|
{
|
|
ddsd.dwSize = sizeof(DDSURFACEDESC2);
|
|
}
|
|
|
|
if ((pmi->wFlags & DDMODEINFO_STEREO) &&
|
|
!LOWERTHANDDRAW7(this_int)
|
|
)
|
|
{
|
|
ddsd.ddsCaps.dwCaps2 |= DDSCAPS2_STEREOSURFACELEFT;
|
|
}
|
|
|
|
/*
|
|
* Hardware default rates on NT are signified as 1Hz. We translate this to
|
|
* 0Hz for DDraw apps. At SetDisplayMode time, 0Hz is translated back to 1Hz.
|
|
*/
|
|
if(0==(dwFlags & DDEDM_REFRESHRATES))
|
|
{
|
|
ddsd.dwRefreshRate = 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
rc = lpEnumCallback( (LPDDSURFACEDESC2) &ddsd, lpContext );
|
|
if( rc == 0 )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
LEAVE_DDRAW();
|
|
return DD_OK;
|
|
|
|
} /* DD_EnumDisplayModes */
|