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

2108 lines
67 KiB

  1. /*========================================================================== *
  2. * Copyright (C) 1994-1995 Microsoft Corporation. All Rights Reserved.
  3. *
  4. * File: ddmode.c
  5. * Content: DirectDraw mode support
  6. * History:
  7. * Date By Reason
  8. * ==== == ======
  9. * 31-jan-95 craige split out of ddraw.c and enhanced
  10. * 27-feb-95 craige new sync. macros
  11. * 01-mar-95 craige Win95 mode stuff
  12. * 19-mar-95 craige use HRESULTs
  13. * 28-mar-95 craige made modeset work again
  14. * 01-apr-95 craige happy fun joy updated header file
  15. * 19-apr-95 craige check for invalid callback in EnumDisplayModes
  16. * 14-may-95 craige allow BPP change; validate EnumDisplayModes modes
  17. * 15-may-95 craige keep track of who changes the mode
  18. * 02-jun-95 craige keep track of the mode set by a process
  19. * 06-jun-95 craige added internal fn RestoreDisplayMode
  20. * 11-jun-95 craige don't allow mode switch if surfaces locked
  21. * 12-jun-95 craige new process list stuff
  22. * 25-jun-95 craige one ddraw mutex
  23. * 28-jun-95 craige ENTER_DDRAW at very start of fns
  24. * 30-jun-95 craige turned off > 16bpp
  25. * 01-jul-95 craige bug 106 - always went to last mode if mode not found
  26. * 02-jul-95 craige RestoreDisplayMode needs to call HEL too
  27. * 04-jul-95 craige YEEHAW: new driver struct; SEH
  28. * 05-jul-95 craige crank up priority during mode change
  29. * 13-jul-95 craige first step in mode set fix; made it work
  30. * 19-jul-95 craige bug 189 - graphics mode change being ignored sometimes
  31. * 20-jul-95 craige internal reorg to prevent thunking during modeset
  32. * 22-jul-95 craige bug 216 - random hang switching bpp - fixed by
  33. * using apps hwnd to hide things.
  34. * bug 230 - unsupported starting modes
  35. * 29-jul-95 toddla allways call HEL for SetMode for display driver
  36. * 10-aug-95 toddla EnumDisplayModes changed to take a lp not a lplp
  37. * 02-sep-95 craige bug 854: disable > 640x480 modes for rel 1
  38. * 04-sep-95 craige bug 894: allow forcing of mode set
  39. * 08-sep-95 craige bug 932: set preferred mode after RestoreDisplayMode
  40. * 05-jan-96 kylej add interface structures
  41. * 09-jan-96 kylej enable >640x480 modes for rel 2
  42. * 27-feb-96 colinmc ensured that bits-per-pixel is always tested for
  43. * when enumerating display modes and that enumeration
  44. * always assumes you will be in exclusive mode when
  45. * you actually do the mode switch
  46. * 11-mar-96 jeffno Dynamic mode switch stuff for NT
  47. * 24-mar-96 kylej Check modes with monitor profile
  48. * 26-mar-96 jeffno Added ModeChangedOnENTERDDRAW
  49. * 15-sep-96 craige modex only work
  50. * 05-oct-96 colinmc Work Item: Removing the restriction on taking Win16
  51. * lock on VRAM surfaces (not including the primary)
  52. * 12-oct-96 colinmc Improvements to Win16 locking code to reduce virtual
  53. * memory usage
  54. * 15-dec-96 jeffno Added more modex modes
  55. * 29-jan-97 jeffno Mode13 support
  56. * 30-jan-97 colinmc Bug 5555: Bad DPF
  57. * 01-feb-97 colinmc Bug 5594: New ModeX modes are dangerous
  58. * 02-feb-97 toddla pass driver name to DD16_GetMonitor functions
  59. * 03-may-98 johnstep NT-specific mode code moved to ddmodent.c
  60. *
  61. ***************************************************************************/
  62. #include "ddrawpr.h"
  63. #include "dx8priv.h"
  64. // DX7 introduced a new style of refresh rate testing (for stereo), but we
  65. // had to back away from it in DX8, so rather then using the LOWERTHANDDRAW7
  66. // macro, we have to create our own that takes DX8 into account.
  67. #define NEW_STYLE_REFRESH(x) \
  68. (!LOWERTHANDDRAW7(x) && !((x)->lpLcl->dwLocalFlags & DDRAWILCL_DIRECTDRAW8))
  69. static DDHALMODEINFO ddmiModeXModes[] =
  70. {
  71. #ifdef EXTENDED_MODEX
  72. {
  73. 320, // width (in pixels) of mode
  74. 175, // height (in pixels) of mode
  75. 320, // pitch (in bytes) of mode
  76. 8, // bits per pixel
  77. (WORD)(DDMODEINFO_PALETTIZED | DDMODEINFO_MODEX), // flags
  78. 0, // refresh rate
  79. 0, // red bit mask
  80. 0, // green bit mask
  81. 0, // blue bit mask
  82. 0 // alpha bit mask
  83. },
  84. #endif // EXTENDED_MODEX
  85. {
  86. 320, // width (in pixels) of mode
  87. 200, // height (in pixels) of mode
  88. 320, // pitch (in bytes) of mode
  89. 8, // bits per pixel
  90. (WORD)(DDMODEINFO_PALETTIZED | DDMODEINFO_MODEX), // flags
  91. 0, // refresh rate
  92. 0, // red bit mask
  93. 0, // green bit mask
  94. 0, // blue bit mask
  95. 0 // alpha bit mask
  96. },
  97. {
  98. 320, // width (in pixels) of mode
  99. 240, // height (in pixels) of mode
  100. 320, // pitch (in bytes) of mode
  101. 8, // bits per pixel
  102. (WORD)(DDMODEINFO_PALETTIZED | DDMODEINFO_MODEX), // flags
  103. 0, // refresh rate
  104. 0, // red bit mask
  105. 0, // green bit mask
  106. 0, // blue bit mask
  107. 0 // alpha bit mask
  108. },
  109. #ifdef EXTENDED_MODEX
  110. {
  111. 320, // width (in pixels) of mode
  112. 350, // height (in pixels) of mode
  113. 320, // pitch (in bytes) of mode
  114. 8, // bits per pixel
  115. (WORD)(DDMODEINFO_PALETTIZED | DDMODEINFO_MODEX), // flags
  116. 0, // refresh rate
  117. 0, // red bit mask
  118. 0, // green bit mask
  119. 0, // blue bit mask
  120. 0 // alpha bit mask
  121. },
  122. {
  123. 320, // width (in pixels) of mode
  124. 400, // height (in pixels) of mode
  125. 320, // pitch (in bytes) of mode
  126. 8, // bits per pixel
  127. (WORD)(DDMODEINFO_PALETTIZED | DDMODEINFO_MODEX), // flags
  128. 0, // refresh rate
  129. 0, // red bit mask
  130. 0, // green bit mask
  131. 0, // blue bit mask
  132. 0 // alpha bit mask
  133. },
  134. {
  135. 320, // width (in pixels) of mode
  136. 480, // height (in pixels) of mode
  137. 320, // pitch (in bytes) of mode
  138. 8, // bits per pixel
  139. (WORD)(DDMODEINFO_PALETTIZED | DDMODEINFO_MODEX), // flags
  140. 0, // refresh rate
  141. 0, // red bit mask
  142. 0, // green bit mask
  143. 0, // blue bit mask
  144. 0 // alpha bit mask
  145. },
  146. #endif // EXTENDED_MODEX
  147. /*
  148. * This is the standard VGA 320x200 linear mode. This mode must stay at the
  149. * end of the modex mode list, or else makeModeXModeIfNeeded might trip up
  150. * and pick this mode first. We want makeModeXModeIfNeeded to continue to
  151. * force modex and only modex.
  152. */
  153. {
  154. 320, // width (in pixels) of mode
  155. 200, // height (in pixels) of mode
  156. 320, // pitch (in bytes) of mode
  157. 8, // bits per pixel
  158. (WORD)(DDMODEINFO_PALETTIZED | DDMODEINFO_MODEX | DDMODEINFO_STANDARDVGA), // flags
  159. 0, // refresh rate
  160. 0, // red bit mask
  161. 0, // green bit mask
  162. 0, // blue bit mask
  163. 0 // alpha bit mask
  164. }
  165. };
  166. #define NUM_MODEX_MODES (sizeof( ddmiModeXModes ) / sizeof( ddmiModeXModes[0] ) )
  167. /*
  168. * makeModeXModeIfNeeded
  169. */
  170. static LPDDHALMODEINFO makeModeXModeIfNeeded(
  171. LPDDHALMODEINFO pmi,
  172. LPDDRAWI_DIRECTDRAW_LCL this_lcl )
  173. {
  174. int j;
  175. LPDDHALMODEINFO pmi_j;
  176. /*
  177. * The app compat flags which mean ModeX mode only still mean ModeX mode
  178. * only. This routine will not substitute a standard VGA mode for a ModeX
  179. * mode by virtue of the order of these modes in the modex mode table.
  180. */
  181. if( (this_lcl->dwAppHackFlags & DDRAW_APPCOMPAT_MODEXONLY) ||
  182. (dwRegFlags & DDRAW_REGFLAGS_MODEXONLY) )
  183. {
  184. for( j=0;j<NUM_MODEX_MODES; j++ )
  185. {
  186. pmi_j = &ddmiModeXModes[j];
  187. if( (pmi->dwWidth == pmi_j->dwWidth) &&
  188. (pmi->dwHeight == pmi_j->dwHeight) &&
  189. (pmi->dwBPP == pmi_j->dwBPP) &&
  190. ((pmi->wFlags & pmi_j->wFlags) & DDMODEINFO_PALETTIZED ) )
  191. {
  192. DPF(2,"Forcing mode %dx%d into modex", pmi->dwWidth,pmi->dwHeight );
  193. return pmi_j;
  194. }
  195. }
  196. }
  197. return pmi;
  198. } /* makeModeXModeIfNeeded */
  199. /*
  200. * makeDEVMODE
  201. *
  202. * create a DEVMODE struct (and flags) from mode info
  203. *
  204. * NOTE: We now always set the exclusive bit here and
  205. * we always set the bpp. This is because we were
  206. * previously not setting the bpp when not exclusive
  207. * so the checking code was always passing the surface
  208. * if it could do a mode of that size regardless of
  209. * color depth.
  210. *
  211. * The new semantics of EnumDisplayModes is that it
  212. * gives you a list of all display modes you could
  213. * switch into if you were exclusive.
  214. */
  215. void makeDEVMODE(
  216. LPDDRAWI_DIRECTDRAW_GBL this,
  217. LPDDHALMODEINFO pmi,
  218. BOOL inexcl,
  219. BOOL useRefreshRate,
  220. LPDWORD pcds_flags,
  221. LPDEVMODE pdm )
  222. {
  223. ZeroMemory( pdm, sizeof(*pdm) );
  224. pdm->dmSize = sizeof( *pdm );
  225. pdm->dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL;
  226. if( useRefreshRate && (pmi->wRefreshRate != 0) )
  227. pdm->dmFields |= DM_DISPLAYFREQUENCY;
  228. pdm->dmPelsWidth = pmi->dwWidth;
  229. pdm->dmPelsHeight = pmi->dwHeight;
  230. pdm->dmBitsPerPel = pmi->dwBPP;
  231. pdm->dmDisplayFrequency = pmi->wRefreshRate;
  232. *pcds_flags = CDS_EXCLUSIVE | CDS_FULLSCREEN;
  233. } /* makeDEVMODE */
  234. /*
  235. * AddModeXModes
  236. */
  237. void AddModeXModes( LPDDRAWI_DIRECTDRAW_GBL pdrv )
  238. {
  239. DWORD i;
  240. DWORD j;
  241. LPDDHALMODEINFO pmi_i;
  242. LPDDHALMODEINFO pmi_j;
  243. BOOL hasmode[NUM_MODEX_MODES];
  244. DWORD newmodecnt;
  245. LPDDHALMODEINFO pmi;
  246. for( j=0;j<NUM_MODEX_MODES; j++ )
  247. {
  248. hasmode[j] = FALSE;
  249. }
  250. /*
  251. * find out what modes are already supported
  252. */
  253. for( i=0;i<pdrv->dwNumModes;i++ )
  254. {
  255. pmi_i = &pdrv->lpModeInfo[i];
  256. for( j=0;j<NUM_MODEX_MODES; j++ )
  257. {
  258. pmi_j = &ddmiModeXModes[j];
  259. if( (pmi_i->dwWidth == pmi_j->dwWidth) &&
  260. (pmi_i->dwHeight == pmi_j->dwHeight) &&
  261. (pmi_i->dwBPP == pmi_j->dwBPP) &&
  262. ((pmi_i->wFlags & pmi_j->wFlags) & DDMODEINFO_PALETTIZED ) )
  263. {
  264. // There is a mode already in the mode table the same as the modeX mode.
  265. // check to make sure that the driver really supports it
  266. DWORD cds_flags;
  267. DEVMODE dm;
  268. int cds_rc;
  269. makeDEVMODE( pdrv, pmi_i, TRUE, FALSE, &cds_flags, &dm );
  270. cds_flags |= CDS_TEST;
  271. cds_rc = ChangeDisplaySettings( &dm, cds_flags );
  272. if( cds_rc != 0)
  273. {
  274. // The driver does not support this mode even though it is in the mode table.
  275. // Mark the mode as unsupported and go ahead and add the ModeX mode.
  276. DPF( 2, "Mode %d not supported (%dx%dx%d), rc = %d, marking invalid", i,
  277. pmi_i->dwWidth, pmi_i->dwHeight, pmi_i->dwBPP,
  278. cds_rc );
  279. pmi_i->wFlags |= DDMODEINFO_UNSUPPORTED;
  280. }
  281. else
  282. {
  283. // Don't add the ModeX mode, the driver supports a linear mode.
  284. hasmode[j] = TRUE;
  285. }
  286. }
  287. }
  288. }
  289. /*
  290. * count how many new modes we need
  291. */
  292. newmodecnt = 0;
  293. for( j=0;j<NUM_MODEX_MODES; j++ )
  294. {
  295. if( !hasmode[j] )
  296. {
  297. newmodecnt++;
  298. }
  299. }
  300. /*
  301. * create new struct
  302. */
  303. if( newmodecnt > 0 )
  304. {
  305. pmi = MemAlloc( (newmodecnt + pdrv->dwNumModes) * sizeof( DDHALMODEINFO ) );
  306. if( pmi != NULL )
  307. {
  308. memcpy( pmi, pdrv->lpModeInfo, pdrv->dwNumModes * sizeof( DDHALMODEINFO ) );
  309. for( j=0;j<NUM_MODEX_MODES; j++ )
  310. {
  311. if( !hasmode[j] )
  312. {
  313. DPF( 2, "Adding ModeX mode %ldx%ldx%ld (standard VGA flag is %d)",
  314. ddmiModeXModes[j].dwWidth,
  315. ddmiModeXModes[j].dwHeight,
  316. ddmiModeXModes[j].dwBPP,
  317. (ddmiModeXModes[j].wFlags &DDMODEINFO_STANDARDVGA) ? 1 : 0);
  318. pmi[ pdrv->dwNumModes ] = ddmiModeXModes[j];
  319. pdrv->dwNumModes++;
  320. }
  321. }
  322. MemFree( pdrv->lpModeInfo );
  323. pdrv->lpModeInfo = pmi;
  324. }
  325. }
  326. //
  327. // make sure the last mode we validate is the current mode
  328. // this works around a Win95 VDD bug.
  329. //
  330. (void) ChangeDisplaySettings( NULL, CDS_TEST );
  331. } /* AddModeXModes */
  332. BOOL MonitorCanHandleMode(LPDDRAWI_DIRECTDRAW_GBL this, DWORD width, DWORD height, WORD refreshRate )
  333. {
  334. DWORD max_monitor_x;
  335. DWORD min_refresh;
  336. DWORD max_refresh;
  337. max_monitor_x = (DWORD)DD16_GetMonitorMaxSize(this->cDriverName);
  338. if( ( max_monitor_x != 0 ) && ( width > max_monitor_x ) )
  339. {
  340. DPF(1, "Mode's width greater than monitor maximum width (%d)", max_monitor_x);
  341. return FALSE;
  342. }
  343. if( refreshRate == 0 )
  344. {
  345. // default refresh rate specified, no need to verify it
  346. return TRUE;
  347. }
  348. // a refresh rate was specified, we'd better make sure the monitor can handle it
  349. if(DD16_GetMonitorRefreshRateRanges(this->cDriverName, (int)width, (int) height, &min_refresh, &max_refresh))
  350. {
  351. if( (min_refresh != -1) && (min_refresh != 0) && (refreshRate < min_refresh) )
  352. {
  353. DPF(1, "Requested refresh rate < monitor's minimum refresh rate (%d)", min_refresh);
  354. return FALSE;
  355. }
  356. if( (min_refresh != -1) && (max_refresh != 0) && (refreshRate > max_refresh) )
  357. {
  358. DPF(1, "Requested refresh rate > monitor's maximum refresh rate (%d)", max_refresh);
  359. return FALSE;
  360. }
  361. }
  362. // The monitor likes it.
  363. return TRUE;
  364. }
  365. /*
  366. * setSurfaceDescFromMode
  367. */
  368. static void setSurfaceDescFromMode(
  369. LPDDRAWI_DIRECTDRAW_LCL this_lcl,
  370. LPDDHALMODEINFO pmi,
  371. LPDDSURFACEDESC pddsd
  372. )
  373. {
  374. memset( pddsd, 0, sizeof( DDSURFACEDESC ) );
  375. pddsd->dwSize = sizeof( DDSURFACEDESC );
  376. pddsd->dwFlags = DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT |
  377. DDSD_PITCH | DDSD_REFRESHRATE;
  378. pddsd->dwHeight = pmi->dwHeight;
  379. pddsd->dwWidth = pmi->dwWidth;
  380. pddsd->lPitch = pmi->lPitch;
  381. pddsd->dwRefreshRate = (DWORD)pmi->wRefreshRate;
  382. pddsd->ddpfPixelFormat.dwSize = sizeof( DDPIXELFORMAT );
  383. pddsd->ddpfPixelFormat.dwFlags = DDPF_RGB;
  384. pddsd->ddpfPixelFormat.dwRGBBitCount = (DWORD)pmi->dwBPP;
  385. if( pmi->wFlags & DDMODEINFO_PALETTIZED )
  386. {
  387. pddsd->ddpfPixelFormat.dwFlags |= DDPF_PALETTEINDEXED8;
  388. }
  389. else
  390. {
  391. pddsd->ddpfPixelFormat.dwRBitMask = pmi->dwRBitMask;
  392. pddsd->ddpfPixelFormat.dwGBitMask = pmi->dwGBitMask;
  393. pddsd->ddpfPixelFormat.dwBBitMask = pmi->dwBBitMask;
  394. pddsd->ddpfPixelFormat.dwRGBAlphaBitMask = pmi->dwAlphaBitMask;
  395. }
  396. if (pmi->wFlags & DDMODEINFO_MODEX)
  397. {
  398. /*
  399. * We only turn on these flags if the app is not hacked to turn them off and
  400. * the registry hasn't been set to turn them off.
  401. */
  402. if ( (!(dwRegFlags & DDRAW_REGFLAGS_NODDSCAPSINDDSD)) && (!(this_lcl->dwAppHackFlags & DDRAW_APPCOMPAT_NODDSCAPSINDDSD)) )
  403. {
  404. pddsd->dwFlags |= DDSD_CAPS;
  405. /*
  406. * If both MODEX and STANDARDVGA are set in the mode info, then it's
  407. * a regular VGA mode (i.e. mode 0x13)
  408. */
  409. if (pmi->wFlags & DDMODEINFO_STANDARDVGA )
  410. {
  411. pddsd->ddsCaps.dwCaps |= DDSCAPS_STANDARDVGAMODE;
  412. }
  413. else
  414. {
  415. pddsd->ddsCaps.dwCaps |= DDSCAPS_MODEX;
  416. }
  417. }
  418. }
  419. } /* setSurfaceDescFromMode */
  420. #undef DPF_MODNAME
  421. #define DPF_MODNAME "GetDisplayMode"
  422. HRESULT DDAPI DD_GetDisplayMode(
  423. LPDIRECTDRAW lpDD,
  424. LPDDSURFACEDESC lpSurfaceDesc )
  425. {
  426. LPDDRAWI_DIRECTDRAW_INT this_int;
  427. LPDDRAWI_DIRECTDRAW_LCL this_lcl;
  428. LPDDRAWI_DIRECTDRAW_GBL this;
  429. LPDDHALMODEINFO pmi;
  430. ENTER_DDRAW();
  431. DPF(2,A,"ENTERAPI: DD_GetDisplayMode");
  432. TRY
  433. {
  434. this_int = (LPDDRAWI_DIRECTDRAW_INT) lpDD;
  435. if( !VALID_DIRECTDRAW_PTR( this_int ) )
  436. {
  437. LEAVE_DDRAW();
  438. return DDERR_INVALIDOBJECT;
  439. }
  440. this_lcl = this_int->lpLcl;
  441. this = this_lcl->lpGbl;
  442. if( !VALIDEX_DDSURFACEDESC2_PTR( lpSurfaceDesc ) &&
  443. !VALIDEX_DDSURFACEDESC_PTR( lpSurfaceDesc ) )
  444. {
  445. LEAVE_DDRAW();
  446. return DDERR_INVALIDPARAMS;
  447. }
  448. if( this->dwModeIndex == DDUNSUPPORTEDMODE)
  449. {
  450. DPF_ERR( "Driver is in an unsupported mode" );
  451. LEAVE_DDRAW();
  452. return DDERR_UNSUPPORTEDMODE;
  453. }
  454. pmi = &this->lpModeInfo[ this->dwModeIndex ];
  455. pmi = makeModeXModeIfNeeded( pmi, this_lcl );
  456. ZeroMemory(lpSurfaceDesc,lpSurfaceDesc->dwSize);
  457. setSurfaceDescFromMode( this_lcl, pmi, lpSurfaceDesc );
  458. /*
  459. * Maintain old behavior..
  460. */
  461. if (LOWERTHANDDRAW4(this_int))
  462. {
  463. lpSurfaceDesc->dwSize = sizeof(DDSURFACEDESC);
  464. }
  465. else
  466. {
  467. lpSurfaceDesc->dwSize = sizeof(DDSURFACEDESC2);
  468. }
  469. /*
  470. * set stereo surface caps bits if driver marks mode as stereo mode
  471. *
  472. */
  473. if ( pmi->wFlags & DDMODEINFO_STEREO &&
  474. !LOWERTHANDDRAW7(this_int) &&
  475. VALIDEX_DDSURFACEDESC2_PTR(lpSurfaceDesc)
  476. )
  477. {
  478. LPDDSURFACEDESC2 pddsd2=(LPDDSURFACEDESC2) lpSurfaceDesc;
  479. pddsd2->ddsCaps.dwCaps2 |= DDSCAPS2_STEREOSURFACELEFT;
  480. }
  481. }
  482. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  483. {
  484. DPF_ERR( "Exception encountered validating parameters" );
  485. LEAVE_DDRAW();
  486. return DDERR_INVALIDPARAMS;
  487. }
  488. LEAVE_DDRAW();
  489. return DD_OK;
  490. } /* DD_GetDisplayMode */
  491. #undef DPF_MODNAME
  492. #define DPF_MODNAME "SetDisplayMode"
  493. /*
  494. * bumpPriority
  495. */
  496. static DWORD bumpPriority( void )
  497. {
  498. DWORD oldclass;
  499. HANDLE hprocess;
  500. hprocess = GetCurrentProcess();
  501. oldclass = GetPriorityClass( hprocess );
  502. SetPriorityClass( hprocess, HIGH_PRIORITY_CLASS );
  503. return oldclass;
  504. } /* bumpPriority */
  505. /*
  506. * restorePriority
  507. */
  508. static void restorePriority( DWORD oldclass )
  509. {
  510. HANDLE hprocess;
  511. hprocess = GetCurrentProcess();
  512. SetPriorityClass( hprocess, oldclass );
  513. } /* restorePriority */
  514. #if 0
  515. static char szClassName[] = "DirectDrawFullscreenWindow";
  516. static HWND hWndTmp;
  517. static HCURSOR hSaveClassCursor;
  518. static HCURSOR hSaveCursor;
  519. static LONG lWindowLong;
  520. static RECT rWnd;
  521. #define OCR_WAIT_DEFAULT 102
  522. /*
  523. * curtainsUp
  524. */
  525. void curtainsUp( LPDDRAWI_DIRECTDRAW_LCL pdrv_lcl )
  526. {
  527. HCURSOR hcursor= (HCURSOR)LoadImage(NULL,MAKEINTRESOURCE(OCR_WAIT_DEFAULT),IMAGE_CURSOR,0,0,0);
  528. if( (pdrv_lcl->hWnd != 0) && IsWindow( (HWND) pdrv_lcl->hWnd ) )
  529. {
  530. lWindowLong = GetWindowLong( (HWND) pdrv_lcl->hWnd, GWL_EXSTYLE );
  531. SetWindowLong( (HWND) pdrv_lcl->hWnd, GWL_EXSTYLE, lWindowLong |
  532. (WS_EX_TOOLWINDOW) );
  533. hSaveClassCursor = (HCURSOR) GetClassLong( (HWND) pdrv_lcl->hWnd, GCL_HCURSOR );
  534. SetClassLong( (HWND) pdrv_lcl->hWnd, GCL_HCURSOR, (LONG) hcursor );
  535. GetWindowRect( (HWND) pdrv_lcl->hWnd, (LPRECT) &rWnd );
  536. SetWindowPos( (HWND) pdrv_lcl->hWnd, NULL, 0, 0,
  537. 10000, 10000,
  538. SWP_NOZORDER | SWP_NOACTIVATE );
  539. SetForegroundWindow( (HWND) pdrv_lcl->hWnd );
  540. }
  541. else
  542. {
  543. WNDCLASS cls;
  544. pdrv_lcl->hWnd = 0;
  545. cls.lpszClassName = szClassName;
  546. cls.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
  547. cls.hInstance = hModule;
  548. cls.hIcon = NULL;
  549. cls.hCursor = hcursor;
  550. cls.lpszMenuName = NULL;
  551. cls.style = CS_BYTEALIGNCLIENT | CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS;
  552. cls.lpfnWndProc = DefWindowProc;
  553. cls.cbWndExtra = 0;
  554. cls.cbClsExtra = 0;
  555. RegisterClass(&cls);
  556. DPF( 4, "*** CREATEWINDOW" );
  557. hWndTmp = CreateWindowEx(WS_EX_TOPMOST|WS_EX_TOOLWINDOW,
  558. szClassName, szClassName,
  559. WS_POPUP|WS_VISIBLE, 0, 0, 10000, 10000,
  560. NULL, NULL, hModule, NULL);
  561. DPF( 5, "*** BACK FROM CREATEWINDOW, hwnd=%08lx", hWndTmp );
  562. if( hWndTmp != NULL)
  563. {
  564. SetForegroundWindow( hWndTmp );
  565. }
  566. }
  567. hSaveCursor = SetCursor( hcursor );
  568. } /* curtainsUp */
  569. /*
  570. * curtainsDown
  571. */
  572. void curtainsDown( LPDDRAWI_DIRECTDRAW_LCL pdrv_lcl )
  573. {
  574. if( (pdrv_lcl->hWnd != 0) && IsWindow( (HWND) pdrv_lcl->hWnd ) )
  575. {
  576. SetWindowLong( (HWND) pdrv_lcl->hWnd, GWL_EXSTYLE, lWindowLong );
  577. SetClassLong( (HWND) pdrv_lcl->hWnd, GCL_HCURSOR, (LONG) hSaveClassCursor );
  578. SetCursor( hSaveCursor );
  579. SetWindowPos( (HWND) pdrv_lcl->hWnd, NULL,
  580. rWnd.left, rWnd.top,
  581. rWnd.right-rWnd.left,
  582. rWnd.bottom-rWnd.top,
  583. SWP_NOZORDER | SWP_NOACTIVATE );
  584. }
  585. else
  586. {
  587. SetCursor( hSaveCursor );
  588. pdrv_lcl->hWnd = 0;
  589. if( hWndTmp != NULL )
  590. {
  591. DestroyWindow( hWndTmp );
  592. UnregisterClass( szClassName, hModule );
  593. }
  594. }
  595. hWndTmp = NULL;
  596. } /* curtainsDown */
  597. #endif
  598. /*
  599. * stopModeX
  600. */
  601. static void stopModeX( LPDDRAWI_DIRECTDRAW_GBL pdrv )
  602. {
  603. DPF( 4, "***************** Turning off ModeX or standard VGA *****************" );
  604. ModeX_RestoreMode();
  605. pdrv->dwFlags &= ~(DDRAWI_MODEX|DDRAWI_STANDARDVGA);
  606. DPF( 4, "**************** DONE Turning off ModeX or standard VGA *************" );
  607. } /* stopModeX */
  608. /*
  609. * SetDisplayMode
  610. */
  611. HRESULT SetDisplayMode(
  612. LPDDRAWI_DIRECTDRAW_LCL this_lcl,
  613. DWORD modeidx,
  614. BOOL force,
  615. BOOL useRefreshRate)
  616. {
  617. DWORD rc;
  618. DDHAL_SETMODEDATA smd;
  619. LPDDHAL_SETMODE smfn;
  620. LPDDHAL_SETMODE smhalfn;
  621. LPDDHALMODEINFO pmi;
  622. LPDDHALMODEINFO orig_pmi;
  623. BOOL inexcl;
  624. BOOL emulation;
  625. LPDDRAWI_DIRECTDRAW_GBL this;
  626. DWORD oldclass;
  627. BOOL use_modex;
  628. BOOL was_modex;
  629. DWORD real_modeidx;
  630. /*
  631. * Signify that the app at least tried to set a mode.
  632. * Redrawing of the desktop will only happen if this flag is set.
  633. */
  634. this_lcl->dwLocalFlags |= DDRAWILCL_MODEHASBEENCHANGED;
  635. this = this_lcl->lpGbl;
  636. /*
  637. * don't allow if surfaces open
  638. */
  639. if( !force )
  640. {
  641. #ifdef USE_ALIAS
  642. /*
  643. * See comment on alias stuff in DD_SetDisplayMode2()
  644. */
  645. if( this->dwWin16LockCnt > 0 )
  646. {
  647. DPF_ERR( "Can't switch modes with locked surfaces holding Win16 lock!" );
  648. return DDERR_SURFACEBUSY;
  649. }
  650. #else /* USE_ALIAS */
  651. if( this->dwSurfaceLockCount > 0 )
  652. {
  653. DPF_ERR( "Can't switch modes with locked surfaces!" );
  654. return DDERR_SURFACEBUSY;
  655. }
  656. #endif /* USE_ALIAS */
  657. }
  658. if( modeidx == DDUNSUPPORTEDMODE )
  659. {
  660. DPF_ERR( "Trying to set to an unsupported mode" );
  661. return DDERR_UNSUPPORTEDMODE;
  662. }
  663. /*
  664. * is our current mode a disp dib mode?
  665. */
  666. was_modex = FALSE;
  667. orig_pmi = NULL;
  668. if( this->dwModeIndex != DDUNSUPPORTEDMODE )
  669. {
  670. orig_pmi = &this->lpModeInfo[ this->dwModeIndex ];
  671. orig_pmi = makeModeXModeIfNeeded( orig_pmi, this_lcl );
  672. if( orig_pmi->wFlags & DDMODEINFO_MODEX )
  673. {
  674. was_modex = TRUE;
  675. }
  676. }
  677. /*
  678. * is the new mode a mode x mode
  679. */
  680. pmi = &this->lpModeInfo[ modeidx ];
  681. pmi = makeModeXModeIfNeeded( pmi, this_lcl );
  682. if( pmi->wFlags & DDMODEINFO_MODEX )
  683. {
  684. DPF( 5, "Mode %ld is a ModeX or standard VGA mode", modeidx);
  685. use_modex = TRUE;
  686. }
  687. else
  688. {
  689. use_modex = FALSE;
  690. }
  691. /*
  692. * don't re-set the mode to the same one...
  693. * NOTE: we ALWAYS set the mode in emulation on Win95 since our index could be wrong
  694. */
  695. if( modeidx == this->dwModeIndex && !(this->dwFlags & DDRAWI_NOHARDWARE) )
  696. {
  697. DPF( 5, "%08lx: Current Mode match: %ldx%ld, %dbpp", GetCurrentProcessId(),
  698. pmi->dwWidth, pmi->dwHeight, pmi->dwBPP );
  699. return DD_OK;
  700. }
  701. DPF( 5, "***********************************************" );
  702. DPF( 5, "*** SETDISPLAYMODE: %ldx%ld, %dbpp", pmi->dwWidth, pmi->dwHeight, pmi->dwBPP );
  703. DPF( 5, "*** dwModeIndex (current) = %ld", this->dwModeIndex );
  704. DPF( 5, "*** modeidx (new) = %ld", modeidx );
  705. DPF( 5, "*** use_modex = %ld", use_modex );
  706. DPF( 5, "*** was_modex = %ld", was_modex );
  707. DPF( 5, "***********************************************" );
  708. /*
  709. * check if in exclusive mode
  710. */
  711. inexcl = (this->lpExclusiveOwner == this_lcl);
  712. /*
  713. * check bpp
  714. */
  715. if( (this->dwFlags & DDRAWI_DISPLAYDRV) && !force )
  716. {
  717. DWORD dwBPP;
  718. if( NULL == orig_pmi )
  719. {
  720. /*
  721. * This is branch is taken if we are currently running in an unsupported
  722. * mode.
  723. */
  724. DDASSERT( 0UL != this_lcl->hDC );
  725. dwBPP = ( GetDeviceCaps( (HDC)( this_lcl->hDC ), BITSPIXEL ) *
  726. GetDeviceCaps( (HDC)( this_lcl->hDC ), PLANES ) );
  727. }
  728. else
  729. {
  730. dwBPP = orig_pmi->dwBPP;
  731. }
  732. if( (dwBPP != pmi->dwBPP) || ((dwBPP == pmi->dwBPP) && use_modex ) )
  733. {
  734. if( !inexcl || !(this->dwFlags & DDRAWI_FULLSCREEN) )
  735. {
  736. DPF_ERR( "Can't change BPP if not in exclusive fullscreen mode" );
  737. return DDERR_NOEXCLUSIVEMODE;
  738. }
  739. }
  740. }
  741. /*
  742. * see if we need to shutdown modex mode
  743. */
  744. if( was_modex )
  745. {
  746. stopModeX( this );
  747. }
  748. /*
  749. * see if we need to set a modex mode
  750. */
  751. if( use_modex )
  752. {
  753. DWORD i;
  754. LPDDHALMODEINFO tmp_pmi;
  755. real_modeidx = modeidx;
  756. for( i=0;i<this->dwNumModes;i++ )
  757. {
  758. tmp_pmi = &this->lpModeInfo[ i ];
  759. if( (tmp_pmi->dwWidth == 640) &&
  760. (tmp_pmi->dwHeight == 480) &&
  761. (tmp_pmi->dwBPP == 8) &&
  762. (tmp_pmi->wFlags & DDMODEINFO_PALETTIZED) )
  763. {
  764. DPF( 5, "MODEX or Standard VGA: Setting to 640x480x8 first (index=%ld)", i );
  765. modeidx = i;
  766. break;
  767. }
  768. }
  769. if( i == this->dwNumModes )
  770. {
  771. DPF( 0, "Mode not supported" );
  772. return DDERR_INVALIDMODE;
  773. }
  774. }
  775. /*
  776. * get the driver to set the new mode...
  777. */
  778. if( ( this->dwFlags & DDRAWI_DISPLAYDRV ) ||
  779. ( this->dwFlags & DDRAWI_NOHARDWARE ) ||
  780. ( this_lcl->lpDDCB->cbDDCallbacks.SetMode == NULL ) )
  781. {
  782. smfn = this_lcl->lpDDCB->HELDD.SetMode;
  783. smhalfn = smfn;
  784. emulation = TRUE;
  785. // If this DDraw object was created for a particular device, explicitly,
  786. // and we're using the HEL (which we will be except on non-display
  787. // devices), then stuff the this_lcl pointer into ddRVal so we can
  788. // check the EXPLICITMONITOR flag from mySetMode.
  789. smd.ddRVal = (HRESULT) this_lcl;
  790. DPF( 4, "Calling HEL SetMode" );
  791. }
  792. else
  793. {
  794. smhalfn = this_lcl->lpDDCB->cbDDCallbacks.SetMode;
  795. smfn = this_lcl->lpDDCB->HALDD.SetMode;
  796. emulation = FALSE;
  797. }
  798. if( smhalfn != NULL )
  799. {
  800. DWORD oldmode;
  801. BOOL didsetmode;
  802. /*
  803. * set the mode if this isn't a modex mode, or if it is a modex
  804. * mode but wasn't one before
  805. */
  806. if( !use_modex || (use_modex && !was_modex) )
  807. {
  808. smd.SetMode = smhalfn;
  809. smd.lpDD = this;
  810. smd.dwModeIndex = modeidx;
  811. smd.inexcl = inexcl;
  812. smd.useRefreshRate = useRefreshRate;
  813. this->dwFlags |= DDRAWI_CHANGINGMODE;
  814. oldclass = bumpPriority();
  815. DOHALCALL( SetMode, smfn, smd, rc, emulation );
  816. restorePriority( oldclass );
  817. this->dwFlags &= ~DDRAWI_CHANGINGMODE;
  818. didsetmode = TRUE;
  819. }
  820. else
  821. {
  822. rc = DDHAL_DRIVER_HANDLED;
  823. smd.ddRVal = DD_OK;
  824. didsetmode = FALSE;
  825. }
  826. if( rc == DDHAL_DRIVER_HANDLED )
  827. {
  828. if( smd.ddRVal == DD_OK )
  829. {
  830. oldmode = this->dwModeIndexOrig; // save original mode index
  831. if( didsetmode )
  832. {
  833. CleanupD3D8(this, FALSE, 0);
  834. FetchDirectDrawData( this, TRUE, 0, GETDDVXDHANDLE( this_lcl ), NULL, 0 , this_lcl );
  835. this->dwModeIndex = modeidx;
  836. this_lcl->dwPreferredMode = modeidx;
  837. DPF(5,"Preferred mode index is %d, desired mode is %d",this_lcl->dwPreferredMode,modeidx);
  838. this->dwModeIndexOrig = oldmode;
  839. /*
  840. * Some drivers will re-init the gamma ramp on a mode
  841. * change, so if we previously set a new gamma ramp,
  842. * we'll set it again.
  843. */
  844. if( ( this_lcl->lpPrimary != NULL ) &&
  845. ( this_lcl->lpPrimary->lpLcl->lpSurfMore->lpGammaRamp != NULL ) &&
  846. ( this_lcl->lpPrimary->lpLcl->dwFlags & DDRAWISURF_SETGAMMA ) )
  847. {
  848. SetGamma( this_lcl->lpPrimary->lpLcl, this_lcl );
  849. }
  850. /*
  851. * It is possible that calling ChangeDisplaySettings could
  852. * generate a WM_ACTIVATE app message to the app telling
  853. * it to deactivate, which would cause RestoreDisplaymode
  854. * to be called before we setup the new mode index. In this
  855. * case, it would not actually restore the mode but it would
  856. * clear the MODEHASBEENCHANGEDFLAG, insuring that we could
  857. * never restore the original mode. The simple workaround
  858. * it to set this flag again.
  859. */
  860. this_lcl->dwLocalFlags |= DDRAWILCL_MODEHASBEENCHANGED;
  861. /*
  862. * The driver local's DC will have been invalidated (DCX_CLIPCHILDREN set) by the
  863. * mode switch, if it occurred via ChangeDisplaySettigs. Record this fact so the emulation
  864. * code can decide to reinit the device DC.
  865. */
  866. this_lcl->dwLocalFlags |= DDRAWILCL_DIRTYDC;
  867. }
  868. /*
  869. * now set modex mode
  870. */
  871. if( use_modex )
  872. {
  873. extern void HELStopDCI( void );
  874. DPF( 4, "********************** Setting MODEX or STANDARD VGA MODE **********************" );
  875. if( this->dwFlags & DDRAWI_ATTACHEDTODESKTOP )
  876. {
  877. HELStopDCI();
  878. }
  879. ModeX_SetMode( (UINT)pmi->dwWidth, (UINT)pmi->dwHeight, (UINT) (pmi->wFlags & DDMODEINFO_STANDARDVGA) );
  880. /*
  881. * ModeX now active, program our driver object and return
  882. */
  883. /*
  884. * We know this code can only ever be called from an application
  885. * thread so we don't have to worry about using DDHELP's VXD handle.
  886. */
  887. fetchModeXData( this, pmi, (HANDLE) this_lcl->hDDVxd );
  888. this->dwModeIndex = real_modeidx;
  889. this_lcl->dwPreferredMode = real_modeidx;
  890. this->dwModeIndexOrig = oldmode;
  891. DPF( 4, "********************** Done Setting MODEX MODE **********************" );
  892. /*
  893. * It is possible that calling ChangeDisplaySettings could
  894. * generate a WM_ACTIVATE app message to the app telling
  895. * it to deactivate, which would cause RestoreDisplaymode
  896. * to be called before we setup the new mode index. In this
  897. * case, it would not actually restore the mode but it would
  898. * clear the MODEHASBEENCHANGEDFLAG, insuring that we could
  899. * never restore the origainl mode. The simple workaround
  900. * it to set this flag again.
  901. */
  902. this_lcl->dwLocalFlags |= DDRAWILCL_MODEHASBEENCHANGED;
  903. return DD_OK;
  904. }
  905. }
  906. return smd.ddRVal;
  907. }
  908. }
  909. return DDERR_UNSUPPORTED;
  910. } /* SetDisplayMode */
  911. /*
  912. * DD_SetDisplayMode
  913. */
  914. HRESULT DDAPI DD_SetDisplayMode(
  915. LPDIRECTDRAW lpDD,
  916. DWORD dwWidth,
  917. DWORD dwHeight,
  918. DWORD dwBPP )
  919. {
  920. DPF(2,A,"ENTERAPI: DD_SetDisplayMode");
  921. DPF(4,"DD1 setdisplay mode called");
  922. return DD_SetDisplayMode2(lpDD,dwWidth,dwHeight,dwBPP,0,0);
  923. } /* DD_SetDisplayMode */
  924. /*
  925. * DD_SetDisplayMode2
  926. */
  927. HRESULT DDAPI DD_SetDisplayMode2(
  928. LPDIRECTDRAW lpDD,
  929. DWORD dwWidth,
  930. DWORD dwHeight,
  931. DWORD dwBPP,
  932. DWORD dwRefreshRate,
  933. DWORD dwFlags)
  934. {
  935. LPDDRAWI_DIRECTDRAW_INT this_int;
  936. LPDDRAWI_DIRECTDRAW_LCL this_lcl;
  937. LPDDRAWI_DIRECTDRAW_GBL this;
  938. int i;
  939. int j;
  940. LPDDHALMODEINFO pmi;
  941. HRESULT ddrval;
  942. int iChosenMode;
  943. DWORD dwNumberOfTempModes;
  944. typedef struct
  945. {
  946. DDHALMODEINFO mi;
  947. int iIndex;
  948. }TEMP_MODE_LIST;
  949. TEMP_MODE_LIST * pTempList=0;
  950. ENTER_DDRAW();
  951. DPF(2,A,"ENTERAPI: DD_SetDisplayMode2");
  952. TRY
  953. {
  954. this_int = (LPDDRAWI_DIRECTDRAW_INT) lpDD;
  955. if( !VALID_DIRECTDRAW_PTR( this_int ) )
  956. {
  957. LEAVE_DDRAW();
  958. return DDERR_INVALIDOBJECT;
  959. }
  960. this_lcl = this_int->lpLcl;
  961. this = this_lcl->lpGbl;
  962. /*
  963. * Check for invalid flags
  964. */
  965. if( dwFlags & ~ DDSDM_VALID)
  966. {
  967. DPF_ERR( "Invalid flags specified" );
  968. LEAVE_DDRAW();
  969. return DDERR_INVALIDPARAMS;
  970. }
  971. #ifdef USE_ALIAS
  972. /*
  973. * Behaviour change. Previously we did not allow a mode switch
  974. * if any video memory (or implicit system memory) surfaces
  975. * were locked. However, we not allow mode switches for
  976. * locked VRAM surfaces as long as they don't have the Win16
  977. * lock (in which case this code is irrelevant as the DirectDraw
  978. * critical section will prevent them ever hitting this code).
  979. * So the behaviour is now that if vram surface are locked but
  980. * are not holding the Win16 lock they can mode switch away.
  981. * If however, we have Win16 locked VRAM surfaces then they can't
  982. * mode switch. This should only have any effect if the application
  983. * holding the locks attempts the mode switch. In which case,
  984. * previously it would fail if it had any VRAM or implicit system
  985. * memory surfaces locked whereas now it will only fail if it has
  986. * the primary or other unaliased VRAM surface locked.
  987. */
  988. if( this->dwWin16LockCnt > 0 )
  989. {
  990. DPF_ERR( "Can't switch modes with locked surfaces holding Win16 lock!" );
  991. LEAVE_DDRAW();
  992. return DDERR_SURFACEBUSY;
  993. }
  994. #else /* USE_ALIAS */
  995. /*
  996. * don't allow change if surfaces are locked
  997. */
  998. if( this->dwSurfaceLockCount )
  999. {
  1000. DPF_ERR( "Surfaces are locked, can't switch the mode" );
  1001. LEAVE_DDRAW();
  1002. return DDERR_SURFACEBUSY;
  1003. }
  1004. #endif /* USE_ALIAS */
  1005. /*
  1006. * don't allow change if some other process has exclusive mode
  1007. */
  1008. if( (this->lpExclusiveOwner != NULL) &&
  1009. (this->lpExclusiveOwner != this_lcl ) )
  1010. {
  1011. DPF_ERR( "Can't change mode; exclusive mode not owned" );
  1012. LEAVE_DDRAW();
  1013. return DDERR_NOEXCLUSIVEMODE;
  1014. }
  1015. /*
  1016. * Modes are now chosen in a 3-step process:
  1017. * -Build a temporary list of modes which match the desired spatial and color resolutions
  1018. * -Sort this list into ascending refresh rate order.
  1019. * -Select from this list the rate which best matches what we want.
  1020. */
  1021. if( (this_lcl->dwAppHackFlags & DDRAW_APPCOMPAT_MODEXONLY) ||
  1022. (dwRegFlags & DDRAW_REGFLAGS_MODEXONLY) )
  1023. {
  1024. /*
  1025. * Don't allow VGA mode if ModeX only.
  1026. * Note if either of these flags are set, there won't actually be a VGA mode in the
  1027. * table, so we wouldn't match it anyway. The problem comes in when makeModeXModeIfNeeded
  1028. * overrides an accelerated mode. The duplication-check loop below will attempt to
  1029. * skip the newly modex 320x200x8 since it doesn't match the VGA 320x200x8 which it is expecting later in
  1030. * the table. That VGA mode won't be in the table, so the dupe check code skips the mode we
  1031. * actually wanted (since we are forcing to modex). If we turn off the app's request for
  1032. * VGA, then that dupe check won't be made, and we should pick up the modex mode.
  1033. */
  1034. DPF(2,"Turning off request for standard VGA due to ModeX override");
  1035. dwFlags &= ~DDSDM_STANDARDVGAMODE;
  1036. }
  1037. /*
  1038. * Step 1. Build a list of modes which match the desired spatial and color resolutions
  1039. */
  1040. pTempList = (TEMP_MODE_LIST*) MemAlloc(this->dwNumModes * sizeof(TEMP_MODE_LIST));
  1041. if (0 == pTempList)
  1042. {
  1043. LEAVE_DDRAW();
  1044. return DDERR_OUTOFMEMORY;
  1045. }
  1046. dwNumberOfTempModes=0;
  1047. DPF( 5, "Looking for %ldx%ldx%ld", dwWidth, dwHeight, dwBPP );
  1048. for(i = 0;i <(int) (this->dwNumModes);i++)
  1049. {
  1050. pmi = &this->lpModeInfo[i];
  1051. pmi = makeModeXModeIfNeeded( pmi, this_lcl );
  1052. DPF( 5, "Found %ldx%ldx%ldx (flags = %ld)", pmi->dwWidth, pmi->dwHeight, pmi->dwBPP, pmi->wFlags );
  1053. if( (pmi->dwWidth == dwWidth) &&
  1054. (pmi->dwHeight == dwHeight) &&
  1055. ((DWORD)pmi->dwBPP == dwBPP) &&
  1056. ((pmi->wFlags & DDMODEINFO_UNSUPPORTED) == 0) &&
  1057. (!LOWERTHANDDRAW7(this_int) || !(pmi->wFlags & DDMODEINFO_DX7ONLY)) )
  1058. {
  1059. /*
  1060. * The behaviour is that linear modes override ModeX modes
  1061. * and standard VGA modes. If the app sets
  1062. * DDSDM_STANDARDVGAMODE even when a linear mode has replaced
  1063. * both the modex and mode13 modes, then we will IGNORE the app's
  1064. * request for VGA and run with the linear mode. This most closely
  1065. * matches the ModeX behaviour.
  1066. * If there's an accelerated 320x200 mode, then there will be neither
  1067. * the modex nor the VGA mode in the mode table. If there's no accelerated
  1068. * mode, then there will be both modex and vga modes in the list.
  1069. * Therefore, if the app specified VGA, we only pay attention to them
  1070. * and ignore a 320x200x8 mode if it is a modex mode.
  1071. */
  1072. if ( (dwFlags & DDSDM_STANDARDVGAMODE)
  1073. && (pmi->wFlags & DDMODEINFO_MODEX) && ((pmi->wFlags & DDMODEINFO_STANDARDVGA)==0) )
  1074. {
  1075. /*
  1076. * App wants a standard VGA mode, but this mode is mode X. Move on.
  1077. */
  1078. continue;
  1079. }
  1080. if(!(this->dwFlags & DDRAWI_DISPLAYDRV ))
  1081. {
  1082. if (pmi->wFlags & DDMODEINFO_DX7ONLY)
  1083. {
  1084. //
  1085. // Can't pass generated modes to non-display drivers
  1086. // because they actually get the index, and a generated
  1087. // mode's index would be beyond the end of their table.
  1088. //
  1089. continue;
  1090. }
  1091. }
  1092. pTempList[dwNumberOfTempModes].mi = *pmi;
  1093. pTempList[dwNumberOfTempModes].iIndex = i;
  1094. dwNumberOfTempModes++;
  1095. }
  1096. }
  1097. if (0 == dwNumberOfTempModes)
  1098. {
  1099. MemFree(pTempList);
  1100. LEAVE_DDRAW();
  1101. DPF( 0,"Mode not found... No match amongst available spatial and color resolutions (wanted %dx%dx%d)",dwWidth,dwHeight,dwBPP );
  1102. return DDERR_INVALIDMODE;
  1103. }
  1104. for(i=0;i<(int)dwNumberOfTempModes;i++)
  1105. DPF(5,"Copied mode list element %d:%dx%dx%d@%d",i,
  1106. pTempList[i].mi.dwWidth,
  1107. pTempList[i].mi.dwHeight,
  1108. pTempList[i].mi.dwBPP,
  1109. pTempList[i].mi.wRefreshRate);
  1110. /*
  1111. * Step 2. Sort list into ascending refresh order
  1112. * Bubble sort
  1113. * Note this does nothing if there's only one surviving mode.
  1114. */
  1115. for (i=0;i<(int)dwNumberOfTempModes;i++)
  1116. {
  1117. for (j=(int)dwNumberOfTempModes-1;j>i;j--)
  1118. {
  1119. if (pTempList[i].mi.wRefreshRate > pTempList[j].mi.wRefreshRate)
  1120. {
  1121. TEMP_MODE_LIST temp = pTempList[i];
  1122. pTempList[i] = pTempList[j];
  1123. pTempList[j] = temp;
  1124. }
  1125. }
  1126. }
  1127. for(i=0;i<(int)dwNumberOfTempModes;i++)
  1128. DPF(5,"Sorted mode list element %d:%dx%dx%d@%d",i,
  1129. pTempList[i].mi.dwWidth,
  1130. pTempList[i].mi.dwHeight,
  1131. pTempList[i].mi.dwBPP,
  1132. pTempList[i].mi.wRefreshRate);
  1133. /*
  1134. * Step 3. Find the rate we're looking for.
  1135. * There are three cases.
  1136. * 1:Looking for a specific refresh
  1137. * 2a:Not looking for a specific refresh and stepping down in spatial resolution
  1138. * 2a:Not looking for a specific refresh and stepping up in spatial resolution
  1139. */
  1140. iChosenMode = -1;
  1141. if (dwRefreshRate)
  1142. {
  1143. /* case 1 */
  1144. DPF(5,"App wants rate of %d",dwRefreshRate);
  1145. for (i=0;i<(int)dwNumberOfTempModes;i++)
  1146. {
  1147. /*
  1148. * We'll never match a zero (hardware default) rate here,
  1149. * but if there's only one rate which has refresh=0
  1150. * the app will never ask for a non-zero rate, because it will
  1151. * never have seen one at enumerate time.
  1152. */
  1153. if ( (DWORD) (pTempList[i].mi.wRefreshRate) == dwRefreshRate )
  1154. {
  1155. iChosenMode=pTempList[i].iIndex;
  1156. break;
  1157. }
  1158. }
  1159. }
  1160. else
  1161. {
  1162. /*
  1163. * Case 2b: Going up in spatial resolution, so just pick the
  1164. * lowest rate (earliest in list) which isn't a hardware
  1165. * default, unless no such rate exists.
  1166. */
  1167. iChosenMode=pTempList[0].iIndex;
  1168. }
  1169. if (-1 == iChosenMode)
  1170. {
  1171. MemFree(pTempList);
  1172. LEAVE_DDRAW();
  1173. DPF( 0,"Mode not found... No match amongst available refresh rates (wanted %dx%dx%d@%d)",dwWidth,dwHeight,dwBPP,dwRefreshRate);
  1174. return DDERR_INVALIDMODE;
  1175. }
  1176. MemFree(pTempList);
  1177. pmi = &this->lpModeInfo[iChosenMode];
  1178. /*
  1179. * only allow ModeX modes if the cooplevel is ok
  1180. */
  1181. if( (pmi->wFlags & DDMODEINFO_MODEX) && !(this_lcl->dwLocalFlags & DDRAWILCL_ALLOWMODEX) )
  1182. {
  1183. LEAVE_DDRAW();
  1184. DPF( 0,"must set DDSCL_ALLOWMODEX to use ModeX or Standard VGA modes" );
  1185. return DDERR_INVALIDMODE;
  1186. }
  1187. }
  1188. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  1189. {
  1190. DPF_ERR( "Exception encountered validating parameters" );
  1191. LEAVE_DDRAW();
  1192. return DDERR_INVALIDPARAMS;
  1193. }
  1194. // See if the monitor likes it. If using an interface older than DX7,
  1195. // we check using the old way; otherwise, we check using the new way
  1196. if( !NEW_STYLE_REFRESH( this_int ) )
  1197. {
  1198. if( !(pmi->wFlags & DDMODEINFO_MODEX) && !MonitorCanHandleMode(this, pmi->dwWidth, pmi->dwHeight, pmi->wRefreshRate) )
  1199. {
  1200. // Monitor doesn't like it
  1201. LEAVE_DDRAW();
  1202. DPF_ERR("Mode not compatible with monitor");
  1203. return DDERR_INVALIDMODE;
  1204. }
  1205. }
  1206. else if( !(pmi->wFlags & DDMODEINFO_MODEX) )
  1207. {
  1208. if( !MonitorCanHandleMode(this, pmi->dwWidth, pmi->dwHeight, 0) ||
  1209. !CanMonitorHandleRefreshRate( this, pmi->dwWidth, pmi->dwHeight,
  1210. //Only pass a refresh rate if the app asked for one (otherwise, asking for 0
  1211. //will cause us to pass the first wRefreshRate in the mode table).
  1212. dwRefreshRate ? pmi->wRefreshRate : 0 ) )
  1213. {
  1214. // Monitor doesn't like it
  1215. LEAVE_DDRAW();
  1216. DPF_ERR("Mode not compatible with monitor");
  1217. return DDERR_INVALIDMODE;
  1218. }
  1219. }
  1220. /*
  1221. * set the display mode, and pay attention to refresh rate if we were asked to.
  1222. * Always pay attention to rate on NT.
  1223. * NOTE!!! This is a very slight change from what we did in released DX2!!!
  1224. * - This function is now called from DD_SetDisplayMode with a refresh rate of 0,
  1225. * so we check for that circumstance and use it to say to the driver wether
  1226. * or not to pay attention to the refresh rate. Fine. However, now when
  1227. * someone calls DD_SetDisplayMode2 with a refresh rate of 0, we tell
  1228. * the driver to ignore the rate, when before we were telling the driver
  1229. * to force to some rate we found in the mode table (which would have been
  1230. * the first mode which matched resolution in the list... probably the lowest
  1231. * refresh rate).
  1232. */
  1233. #if 1 //def WIN95
  1234. if (0 == dwRefreshRate)
  1235. ddrval = SetDisplayMode( this_lcl, iChosenMode, FALSE, FALSE );
  1236. else
  1237. #endif
  1238. ddrval = SetDisplayMode( this_lcl, iChosenMode, FALSE, TRUE );
  1239. LEAVE_DDRAW();
  1240. return ddrval;
  1241. } /* DD_SetDisplayMode2 */
  1242. #undef DPF_MODNAME
  1243. #define DPF_MODNAME "RestoreDisplayMode"
  1244. /*
  1245. * RestoreDisplayMode
  1246. *
  1247. * For use by DD_RestoreDisplayMode & internally.
  1248. * Must be called with driver lock taken
  1249. */
  1250. HRESULT RestoreDisplayMode( LPDDRAWI_DIRECTDRAW_LCL this_lcl, BOOL force )
  1251. {
  1252. DWORD rc;
  1253. DDHAL_SETMODEDATA smd;
  1254. BOOL inexcl;
  1255. DWORD pid;
  1256. LPDDHAL_SETMODE smfn;
  1257. LPDDHAL_SETMODE smhalfn;
  1258. BOOL emulation;
  1259. LPDDRAWI_DIRECTDRAW_GBL this;
  1260. DWORD oldclass;
  1261. BOOL was_modex;
  1262. LPDDHALMODEINFO pmi;
  1263. DPF(2,A,"ENTERAPI: DD_RestoreDisplayMode");
  1264. this = this_lcl->lpGbl;
  1265. #ifdef DEBUG
  1266. if( DDUNSUPPORTEDMODE != this->dwModeIndexOrig )
  1267. {
  1268. DPF(5,"Restoring Display mode to index %d, %dx%dx%d@%d",this->dwModeIndexOrig,
  1269. this->lpModeInfo[this->dwModeIndexOrig].dwWidth,
  1270. this->lpModeInfo[this->dwModeIndexOrig].dwHeight,
  1271. this->lpModeInfo[this->dwModeIndexOrig].dwBPP,
  1272. this->lpModeInfo[this->dwModeIndexOrig].wRefreshRate);
  1273. }
  1274. else
  1275. {
  1276. DPF(5,"Restoring Display mode to a non-DirectDraw mode");
  1277. }
  1278. #endif /* DEBUG */
  1279. if (0 == (this_lcl->dwLocalFlags & DDRAWILCL_MODEHASBEENCHANGED) )
  1280. {
  1281. /*
  1282. * This app never made a mode change, so we ignore the restore, in case someone switch desktop
  1283. * modes while playing a movie in a window, for instance. We do it before the redraw window
  1284. * so that we don't flash icons when a windowed app exits.
  1285. */
  1286. DPF( 2, "Mode was never changed by this app" );
  1287. return DD_OK;
  1288. }
  1289. /*
  1290. * we ALWAYS set the mode in emulation on Win95 since our index could be wrong
  1291. */
  1292. if( ( (this->dwModeIndex == this->dwModeIndexOrig) &&
  1293. !(this->dwFlags & DDRAWI_NOHARDWARE) ) || (this->lpModeInfo==NULL) )
  1294. {
  1295. DPF( 2, "Mode wasn't changed" );
  1296. RedrawWindow( NULL, NULL, NULL, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
  1297. /*
  1298. * Scenario: Start an app that can do windowed<->fullscreen transitions. Start windowed.
  1299. * Go fullscreen (sets MODEHASBEENCHANGED). Go windowed. Use control panel to
  1300. * change display settings. Exit app. Original mode will be restored.
  1301. * If we reset this flag, that won't happen.
  1302. */
  1303. this_lcl->dwLocalFlags &= ~DDRAWILCL_MODEHASBEENCHANGED;
  1304. return DD_OK;
  1305. }
  1306. DPF( 4, "In RestoreDisplayMode" );
  1307. pid = GetCurrentProcessId();
  1308. /*
  1309. * don't allow mode change if surfaces are locked
  1310. */
  1311. if( !force )
  1312. {
  1313. #ifdef USE_ALIAS
  1314. /*
  1315. * See comment on aliasing in DD_ResetDisplayMode()
  1316. */
  1317. if( this->dwWin16LockCnt > 0 )
  1318. {
  1319. DPF_ERR( "Can't switch modes with locked surfaces holding Win16 lock!" );
  1320. return DDERR_SURFACEBUSY;
  1321. }
  1322. #else /* USE_ALIAS */
  1323. if( this->dwSurfaceLockCount > 0 )
  1324. {
  1325. DPF( 0, "Can't switch modes with locked surfaces!" );
  1326. return DDERR_SURFACEBUSY;
  1327. }
  1328. #endif /* USE_ALIAS */
  1329. }
  1330. /*
  1331. * see if we're in exclusive mode
  1332. */
  1333. if( force )
  1334. {
  1335. inexcl = TRUE;
  1336. }
  1337. else
  1338. {
  1339. inexcl = (this->lpExclusiveOwner == this_lcl);
  1340. }
  1341. /*
  1342. * check bpp
  1343. */
  1344. pmi = &this->lpModeInfo[ this->dwModeIndex ];
  1345. pmi = makeModeXModeIfNeeded( pmi, this_lcl );
  1346. if( pmi->wFlags & DDMODEINFO_MODEX )
  1347. {
  1348. was_modex = TRUE;
  1349. }
  1350. else
  1351. {
  1352. was_modex = FALSE;
  1353. }
  1354. /*
  1355. * turn off modex first...
  1356. */
  1357. if( was_modex )
  1358. {
  1359. stopModeX( this );
  1360. }
  1361. /*
  1362. * get the driver to restore the mode...
  1363. */
  1364. if( ( this->dwFlags & DDRAWI_DISPLAYDRV ) ||
  1365. ( this->dwFlags & DDRAWI_NOHARDWARE ) ||
  1366. ( this_lcl->lpDDCB->cbDDCallbacks.SetMode == NULL ) )
  1367. {
  1368. smfn = this_lcl->lpDDCB->HELDD.SetMode;
  1369. smhalfn = smfn;
  1370. emulation = TRUE;
  1371. // Store the this_lcl so we can check for multimon-aware in mySetMode
  1372. smd.ddRVal = (HRESULT) this_lcl;
  1373. }
  1374. else
  1375. {
  1376. smhalfn = this_lcl->lpDDCB->cbDDCallbacks.SetMode;
  1377. smfn = this_lcl->lpDDCB->HALDD.SetMode;
  1378. emulation = FALSE;
  1379. }
  1380. if( smhalfn != NULL )
  1381. {
  1382. smd.SetMode = smhalfn;
  1383. smd.lpDD = this;
  1384. smd.dwModeIndex = (DWORD) -1;
  1385. smd.inexcl = inexcl;
  1386. smd.useRefreshRate = TRUE;
  1387. this->dwFlags |= DDRAWI_CHANGINGMODE;
  1388. oldclass = bumpPriority();
  1389. // Store the this_lcl so we can check for multimon-aware in mySetMode
  1390. smd.ddRVal = (HRESULT) this_lcl;
  1391. DOHALCALL( SetMode, smfn, smd, rc, emulation );
  1392. restorePriority( oldclass );
  1393. this->dwFlags &= ~DDRAWI_CHANGINGMODE;
  1394. if( rc == DDHAL_DRIVER_HANDLED )
  1395. {
  1396. if( smd.ddRVal != DD_OK )
  1397. {
  1398. /*
  1399. * Scenario: Laptop boots w/ external monitor, switch to
  1400. * 10x7 mode. Shutdown, unplug the monitor, reboot. Mode
  1401. * is 640x480 but registry says it's 10x7. Run a low-res
  1402. * game, we call ChangeDisplaySettings(NULL), which tries
  1403. * to restore things according to the registry, so it
  1404. * fails. The result is we stay in low-res mode, which
  1405. * pretty much means we have to reboot.
  1406. *
  1407. * To work around this, we will explixitly set the mode that
  1408. * we started in.
  1409. */
  1410. smd.dwModeIndex = this->dwModeIndexOrig;
  1411. this->dwFlags |= DDRAWI_CHANGINGMODE;
  1412. oldclass = bumpPriority();
  1413. smd.lpDD = this;
  1414. DOHALCALL( SetMode, smfn, smd, rc, emulation );
  1415. restorePriority( oldclass );
  1416. this->dwFlags &= ~DDRAWI_CHANGINGMODE;
  1417. }
  1418. if( smd.ddRVal == DD_OK )
  1419. {
  1420. DPF( 5, "RestoreDisplayMode: Process %08lx Mode = %ld", GETCURRPID(), this->dwModeIndex );
  1421. CleanupD3D8(this, FALSE, 0);
  1422. FetchDirectDrawData( this, TRUE, 0, GETDDVXDHANDLE( this_lcl ), NULL, 0 , this_lcl );
  1423. /*
  1424. * Some drivers will re-init the gamma ramp on a mode
  1425. * change, so if we previously set a new gamma ramp,
  1426. * we'll set it again.
  1427. */
  1428. if( ( this_lcl->lpPrimary != NULL ) &&
  1429. ( this_lcl->lpPrimary->lpLcl->lpSurfMore->lpGammaRamp != NULL ) &&
  1430. ( this_lcl->lpPrimary->lpLcl->dwFlags & DDRAWISURF_SETGAMMA ) )
  1431. {
  1432. SetGamma( this_lcl->lpPrimary->lpLcl, this_lcl );
  1433. }
  1434. /*
  1435. * Scenario: Start an app that can do windowed<->fullscreen transitions. Start windowed.
  1436. * Go fullscreen (sets MODEHASBEENCHANGED). Go windowed. Use control panel to
  1437. * change display settings. Exit app. Original mode will be restored.
  1438. * If we reset this flag, that won't happen.
  1439. */
  1440. this_lcl->dwLocalFlags &= ~DDRAWILCL_MODEHASBEENCHANGED;
  1441. /*
  1442. * The driver local's DC will have been invalidated (DCX_CLIPCHILDREN set) by the
  1443. * mode switch, if it occurred via ChangeDisplaySettigs. Record this fact so the emulation
  1444. * code can decide to reinit the device DC.
  1445. */
  1446. this_lcl->dwLocalFlags |= DDRAWILCL_DIRTYDC;
  1447. if( this->dwFlags & DDRAWI_DISPLAYDRV )
  1448. {
  1449. DPF(4,"Redrawing all windows");
  1450. RedrawWindow( NULL, NULL, NULL, RDW_INVALIDATE | RDW_ERASE |
  1451. RDW_ALLCHILDREN );
  1452. }
  1453. }
  1454. return smd.ddRVal;
  1455. }
  1456. }
  1457. return DDERR_UNSUPPORTED;
  1458. } /* RestoreDisplayMode */
  1459. /*
  1460. * DD_RestoreDisplayMode
  1461. *
  1462. * restore mode
  1463. */
  1464. HRESULT DDAPI DD_RestoreDisplayMode( LPDIRECTDRAW lpDD )
  1465. {
  1466. LPDDRAWI_DIRECTDRAW_INT this_int;
  1467. LPDDRAWI_DIRECTDRAW_LCL this_lcl;
  1468. LPDDRAWI_DIRECTDRAW_GBL this;
  1469. HRESULT ddrval;
  1470. ENTER_DDRAW();
  1471. DPF(2,A,"ENTERAPI: DD_RestoreDisplayMode");
  1472. TRY
  1473. {
  1474. this_int = (LPDDRAWI_DIRECTDRAW_INT) lpDD;
  1475. if( !VALID_DIRECTDRAW_PTR( this_int ) )
  1476. {
  1477. LEAVE_DDRAW();
  1478. return DDERR_INVALIDOBJECT;
  1479. }
  1480. this_lcl = this_int->lpLcl;
  1481. this = this_lcl->lpGbl;
  1482. /*
  1483. * switching to the same mode?
  1484. */
  1485. if( this->dwModeIndex == this->dwModeIndexOrig )
  1486. {
  1487. LEAVE_DDRAW();
  1488. return DD_OK;
  1489. }
  1490. /*
  1491. * don't allow change if some other process has exclusive mode
  1492. */
  1493. if( (this->lpExclusiveOwner != NULL) &&
  1494. (this->lpExclusiveOwner != this_lcl ) )
  1495. {
  1496. DPF_ERR( "Can't change mode; exclusive mode owned" );
  1497. LEAVE_DDRAW();
  1498. return DDERR_NOEXCLUSIVEMODE;
  1499. }
  1500. #ifdef USE_ALIAS
  1501. /*
  1502. * Behaviour change. Previously we did not allow a mode switch
  1503. * if any video memory (or implicit system memory) surfaces
  1504. * were locked. However, we not allow mode switches for
  1505. * locked VRAM surfaces as long as they don't have the Win16
  1506. * lock (in which case this code is irrelevant as the DirectDraw
  1507. * critical section will prevent them ever hitting this code).
  1508. * So the behaviour is now that if vram surface are locked but
  1509. * are not holding the Win16 lock they can mode switch away.
  1510. * If however, we have Win16 locked VRAM surfaces then they can't
  1511. * mode switch. This should only have any effect if the application
  1512. * holding the locks attempts the mode switch. In which case,
  1513. * previously it would fail if it had any VRAM or implicit system
  1514. * memory surfaces locked whereas now it will only fail if it has
  1515. * the primary or other unaliased VRAM surface locked.
  1516. *
  1517. * !!! NOTE: My gut feeling is that this should have no impact on
  1518. * anyone. However, we need to pull it and see.
  1519. */
  1520. if( this->dwWin16LockCnt > 0 )
  1521. {
  1522. DPF_ERR( "Can't switch modes with locked surfaces holding Win16 lock!" );
  1523. LEAVE_DDRAW();
  1524. return DDERR_SURFACEBUSY;
  1525. }
  1526. #else /* USE_ALIAS */
  1527. /*
  1528. * don't allow change if surfaces are locked
  1529. */
  1530. if( this->dwSurfaceLockCount )
  1531. {
  1532. DPF_ERR( "Surfaces are locked, can't switch the mode" );
  1533. LEAVE_DDRAW();
  1534. return DDERR_SURFACEBUSY;
  1535. }
  1536. #endif /* USE_ALIAS */
  1537. }
  1538. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  1539. {
  1540. DPF_ERR( "Exception encountered validating parameters" );
  1541. LEAVE_DDRAW();
  1542. return DDERR_INVALIDPARAMS;
  1543. }
  1544. ddrval = RestoreDisplayMode( this_lcl, FALSE );
  1545. if( ddrval == DD_OK )
  1546. {
  1547. this_lcl->dwPreferredMode = this->dwModeIndex;
  1548. DPF( 5, "Preferred mode is now %ld", this_lcl->dwPreferredMode );
  1549. }
  1550. LEAVE_DDRAW();
  1551. return ddrval;
  1552. } /* DD_RestoreDisplayMode */
  1553. #undef DPF_MODNAME
  1554. #define DPF_MODNAME "EnumDisplayModes"
  1555. /*
  1556. * DD_EnumDisplayModes
  1557. */
  1558. HRESULT DDAPI DD_EnumDisplayModes(
  1559. LPDIRECTDRAW lpDD,
  1560. DWORD dwFlags,
  1561. LPDDSURFACEDESC lpDDSurfaceDesc,
  1562. LPVOID lpContext,
  1563. LPDDENUMMODESCALLBACK lpEnumCallback )
  1564. {
  1565. DPF(2,A,"ENTERAPI: DD_EnumDisplayModes");
  1566. if( lpDDSurfaceDesc != NULL )
  1567. {
  1568. DDSURFACEDESC2 ddsd2 = {sizeof(ddsd2)};
  1569. ZeroMemory(&ddsd2,sizeof(ddsd2));
  1570. TRY
  1571. {
  1572. if( !VALID_DIRECTDRAW_PTR( ((LPDDRAWI_DIRECTDRAW_INT)lpDD) ) )
  1573. {
  1574. return DDERR_INVALIDOBJECT;
  1575. }
  1576. if( !VALID_DDSURFACEDESC_PTR( lpDDSurfaceDesc ) )
  1577. {
  1578. DPF_ERR( "Invalid surface description. Did you set the dwSize member?" );
  1579. DPF_APIRETURNS(DDERR_INVALIDPARAMS);
  1580. return DDERR_INVALIDPARAMS;
  1581. }
  1582. memcpy(&ddsd2,lpDDSurfaceDesc,sizeof(*lpDDSurfaceDesc));
  1583. }
  1584. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  1585. {
  1586. DPF_ERR( "Exception encountered validating parameters: Bad LPDDSURFACEDESC" );
  1587. DPF_APIRETURNS(DDERR_INVALIDPARAMS);
  1588. return DDERR_INVALIDPARAMS;
  1589. }
  1590. ddsd2.dwSize = sizeof(ddsd2);
  1591. return DD_EnumDisplayModes4(lpDD,dwFlags,&ddsd2,lpContext, (LPDDENUMMODESCALLBACK2) lpEnumCallback);
  1592. }
  1593. return DD_EnumDisplayModes4(lpDD,dwFlags,NULL,lpContext,(LPDDENUMMODESCALLBACK2)lpEnumCallback);
  1594. }
  1595. HRESULT DDAPI DD_EnumDisplayModes4(
  1596. LPDIRECTDRAW lpDD,
  1597. DWORD dwFlags,
  1598. LPDDSURFACEDESC2 lpDDSurfaceDesc,
  1599. LPVOID lpContext,
  1600. LPDDENUMMODESCALLBACK2 lpEnumCallback )
  1601. {
  1602. LPDDRAWI_DIRECTDRAW_INT this_int;
  1603. LPDDRAWI_DIRECTDRAW_LCL this_lcl;
  1604. LPDDRAWI_DIRECTDRAW_GBL this;
  1605. DWORD rc;
  1606. DDSURFACEDESC2 ddsd;
  1607. LPDDHALMODEINFO pmi;
  1608. int i, j;
  1609. BOOL inexcl;
  1610. BOOL bUseRefreshRate = FALSE;
  1611. ENTER_DDRAW();
  1612. DPF(2,A,"ENTERAPI: DD_EnumDisplayModes4");
  1613. TRY
  1614. {
  1615. this_int = (LPDDRAWI_DIRECTDRAW_INT) lpDD;
  1616. if( !VALID_DIRECTDRAW_PTR( this_int ) )
  1617. {
  1618. LEAVE_DDRAW();
  1619. return DDERR_INVALIDOBJECT;
  1620. }
  1621. this_lcl = this_int->lpLcl;
  1622. this = this_lcl->lpGbl;
  1623. if( lpDDSurfaceDesc != NULL )
  1624. {
  1625. if( !VALID_DDSURFACEDESC2_PTR(lpDDSurfaceDesc) )
  1626. {
  1627. DPF_ERR( "Invalid surface description" );
  1628. LEAVE_DDRAW();
  1629. return DDERR_INVALIDPARAMS;
  1630. }
  1631. }
  1632. if ( dwFlags & ~DDEDM_VALID)
  1633. {
  1634. DPF_ERR( "Invalid flags") ;
  1635. LEAVE_DDRAW();
  1636. return DDERR_INVALIDPARAMS;
  1637. }
  1638. if( !VALIDEX_CODE_PTR( lpEnumCallback ) )
  1639. {
  1640. DPF_ERR( "Invalid enum. callback routine" );
  1641. LEAVE_DDRAW();
  1642. return DDERR_INVALIDPARAMS;
  1643. }
  1644. }
  1645. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  1646. {
  1647. DPF_ERR( "Exception encountered validating parameters" );
  1648. LEAVE_DDRAW();
  1649. return DDERR_INVALIDPARAMS;
  1650. }
  1651. /*
  1652. * see if we're in exclusive mode
  1653. */
  1654. inexcl = (this->lpExclusiveOwner == this_lcl);
  1655. if( (this_lcl->dwAppHackFlags & DDRAW_APPCOMPAT_MODEXONLY) ||
  1656. (dwRegFlags & DDRAW_REGFLAGS_MODEXONLY) )
  1657. {
  1658. /*
  1659. * Don't allow VGA mode if ModeX only.
  1660. * Note if either of these flags are set, there won't actually be a VGA mode in the
  1661. * table, so we wouldn't match it anyway. The problem comes in when makeModeXModeIfNeeded
  1662. * overrides an accelerated mode. The duplication-check loop below will attempt to
  1663. * skip the newly modex 320x200x8 since it doesn't match the VGA 320x200x8 which it is expecting later in
  1664. * the table. That VGA mode won't be in the table, so the dupe check code skips the mode we
  1665. * actually wanted (since we are forcing to modex). If we turn off the app's request for
  1666. * VGA, then that dupe check won't be made, and we should pick up the modex mode.
  1667. */
  1668. DPF(2,"Turning off request for standard VGA due to ModeX override");
  1669. dwFlags &= ~DDEDM_STANDARDVGAMODES;
  1670. }
  1671. /*
  1672. * go through all possible modes...
  1673. */
  1674. for( i=0;i<(int)this->dwNumModes;i++ )
  1675. {
  1676. pmi = &this->lpModeInfo[i];
  1677. pmi = makeModeXModeIfNeeded( pmi, this_lcl );
  1678. DPF(5,"Enumerating mode %d. %dx%d",i,pmi->dwWidth,pmi->dwHeight);
  1679. if( ( pmi->wFlags & DDMODEINFO_DX7ONLY ) &&
  1680. LOWERTHANDDRAW7( this_int ) )
  1681. {
  1682. continue;
  1683. }
  1684. /*
  1685. * check to see if this is a duplicate mode
  1686. */
  1687. for (j=0; j<i; j++)
  1688. {
  1689. // if we find a duplicate, break out early
  1690. if( (this->lpModeInfo[j].dwHeight == pmi->dwHeight) &&
  1691. (this->lpModeInfo[j].dwWidth == pmi->dwWidth) &&
  1692. (this->lpModeInfo[j].dwBPP == pmi->dwBPP) )
  1693. {
  1694. // basic mode matches, what about refresh rate?
  1695. if( dwFlags & DDEDM_REFRESHRATES )
  1696. {
  1697. // if refresh rate is not unique then the modes match
  1698. if( this->lpModeInfo[j].wRefreshRate == pmi->wRefreshRate )
  1699. {
  1700. DPF(5, "matched: %d %d", this->lpModeInfo[j].wRefreshRate, pmi->wRefreshRate);
  1701. /*
  1702. * We have an identical mode, unless one is standard VGA and the other is not
  1703. */
  1704. if( dwFlags & DDEDM_STANDARDVGAMODES )
  1705. {
  1706. /*
  1707. * If the app cares about VGA modes, then a difference in the vganess
  1708. * of the two modes means they don't match.
  1709. */
  1710. if ( (this->lpModeInfo[j].wFlags ^ pmi->wFlags) & DDMODEINFO_STANDARDVGA )
  1711. {
  1712. /*
  1713. * One mode is standard VGA and the other is not. Since
  1714. * the app asked to enumerate standard VGA modes, we don't
  1715. * consider this a match.
  1716. */
  1717. continue;
  1718. }
  1719. }
  1720. /*
  1721. * Found identical refresh rate, and either app didn't care that
  1722. * modes are different in terms of VGAness or they are the same in
  1723. * terms of VGAness. Consider this a match.
  1724. */
  1725. break;
  1726. }
  1727. // unique refresh rate and the app cares, the modes don't match
  1728. continue;
  1729. }
  1730. else
  1731. {
  1732. // the app doesn't care about refresh rates
  1733. if( dwFlags & DDEDM_STANDARDVGAMODES )
  1734. {
  1735. if ( (this->lpModeInfo[j].wFlags ^ pmi->wFlags) & DDMODEINFO_STANDARDVGA )
  1736. {
  1737. /*
  1738. * One mode is standard VGA and the other is not. Since
  1739. * the app asked to enumerate standard VGA modes, we don't
  1740. * consider this a match.
  1741. */
  1742. continue;
  1743. }
  1744. /*
  1745. * Modes are the same as far as VGAness goes. drop through and break
  1746. * since they match
  1747. */
  1748. }
  1749. /*
  1750. * The app specified neither refresh rates nor VGA, so any mode which is
  1751. * duplicated at least on resolution (spatial and color) is skipped
  1752. */
  1753. break;
  1754. }
  1755. }
  1756. }
  1757. if( j != i)
  1758. {
  1759. // broke out early, mode i is not unique, move on to the next one.
  1760. continue;
  1761. }
  1762. /*
  1763. * check if surface description matches mode
  1764. */
  1765. if ( lpDDSurfaceDesc )
  1766. {
  1767. if( lpDDSurfaceDesc->dwFlags & DDSD_HEIGHT )
  1768. {
  1769. if( lpDDSurfaceDesc->dwHeight != pmi->dwHeight )
  1770. {
  1771. continue;
  1772. }
  1773. }
  1774. if( lpDDSurfaceDesc->dwFlags & DDSD_WIDTH )
  1775. {
  1776. if( lpDDSurfaceDesc->dwWidth != pmi->dwWidth )
  1777. {
  1778. continue;
  1779. }
  1780. }
  1781. if( lpDDSurfaceDesc->dwFlags & DDSD_PIXELFORMAT )
  1782. {
  1783. if( lpDDSurfaceDesc->ddpfPixelFormat.dwRGBBitCount != pmi->dwBPP )
  1784. {
  1785. continue;
  1786. }
  1787. }
  1788. if( lpDDSurfaceDesc->dwFlags & DDSD_REFRESHRATE )
  1789. {
  1790. bUseRefreshRate = TRUE;
  1791. if( lpDDSurfaceDesc->dwRefreshRate != (DWORD)pmi->wRefreshRate )
  1792. {
  1793. continue;
  1794. }
  1795. }
  1796. else
  1797. {
  1798. bUseRefreshRate = FALSE;
  1799. }
  1800. }
  1801. /*
  1802. * see if driver will allow this
  1803. */
  1804. if (!(pmi->wFlags & DDMODEINFO_MODEX) )
  1805. {
  1806. if(this->dwFlags & DDRAWI_DISPLAYDRV)
  1807. {
  1808. DWORD cds_flags;
  1809. DEVMODE dm;
  1810. int cds_rc;
  1811. makeDEVMODE( this, pmi, inexcl, bUseRefreshRate, &cds_flags, &dm );
  1812. cds_flags |= CDS_TEST;
  1813. cds_rc = xxxChangeDisplaySettingsExA(this->cDriverName, &dm, NULL, cds_flags, 0);
  1814. if( cds_rc != 0 )
  1815. {
  1816. if( bUseRefreshRate )
  1817. {
  1818. DPF( 1, "Mode %d not supported (%ldx%ldx%ld rr=%d), rc = %d", i,
  1819. pmi->dwWidth, pmi->dwHeight, pmi->dwBPP, pmi->wRefreshRate, cds_rc );
  1820. }
  1821. else
  1822. {
  1823. DPF( 1, "Mode %d not supported (%ldx%ldx%ld), rc = %d", i,
  1824. pmi->dwWidth, pmi->dwHeight, pmi->dwBPP, cds_rc );
  1825. }
  1826. continue;
  1827. }
  1828. }
  1829. if( !NEW_STYLE_REFRESH( this_int ) )
  1830. {
  1831. // We check for a display driver, merely to maintain identical behaviour to DX6-:
  1832. // We never used to do the Monitor check on voodoos.
  1833. if (this->dwFlags & DDRAWI_DISPLAYDRV)
  1834. {
  1835. if( !MonitorCanHandleMode( this, pmi->dwWidth, pmi->dwHeight, pmi->wRefreshRate ) )
  1836. {
  1837. DPF( 1, "Monitor can't handle mode %d: (%ldx%ld rr=%d)", i,
  1838. pmi->dwWidth, pmi->dwHeight, pmi->wRefreshRate);
  1839. continue;
  1840. }
  1841. }
  1842. }
  1843. else
  1844. {
  1845. // Call MonitorcanHandleMode to verify that that the size works,
  1846. // but we'll use our own hacked mechanism to determine if the
  1847. // refresh is supported
  1848. if( !MonitorCanHandleMode( this, pmi->dwWidth, pmi->dwHeight, 0 ) )
  1849. {
  1850. DPF( 1, "Monitor can't handle mode %d: (%ldx%ld rr=%d)", i,
  1851. pmi->dwWidth, pmi->dwHeight, pmi->wRefreshRate);
  1852. continue;
  1853. }
  1854. if( ( pmi->wRefreshRate > 0 ) &&
  1855. (dwFlags & DDEDM_REFRESHRATES) )
  1856. {
  1857. if( !CanMonitorHandleRefreshRate( this, pmi->dwWidth, pmi->dwHeight, pmi->wRefreshRate ) )
  1858. {
  1859. DPF( 1, "Monitor can't handle mode %d: (%ldx%ld rr=%d)", i,
  1860. pmi->dwWidth, pmi->dwHeight, pmi->wRefreshRate);
  1861. continue;
  1862. }
  1863. }
  1864. }
  1865. }
  1866. if( (this->dwFlags & DDRAWI_DISPLAYDRV) &&
  1867. (pmi->wFlags & DDMODEINFO_MODEX) &&
  1868. !(this_lcl->dwLocalFlags & DDRAWILCL_ALLOWMODEX) )
  1869. {
  1870. DPF( 2, "skipping ModeX or standard VGA mode" );
  1871. continue;
  1872. }
  1873. /*
  1874. * invoke callback with surface desc.
  1875. */
  1876. ZeroMemory(&ddsd,sizeof(ddsd));
  1877. setSurfaceDescFromMode( this_lcl, pmi, (LPDDSURFACEDESC)&ddsd );
  1878. if (LOWERTHANDDRAW4(this_int))
  1879. {
  1880. ddsd.dwSize = sizeof(DDSURFACEDESC);
  1881. }
  1882. else
  1883. {
  1884. ddsd.dwSize = sizeof(DDSURFACEDESC2);
  1885. }
  1886. if ((pmi->wFlags & DDMODEINFO_STEREO) &&
  1887. !LOWERTHANDDRAW7(this_int)
  1888. )
  1889. {
  1890. ddsd.ddsCaps.dwCaps2 |= DDSCAPS2_STEREOSURFACELEFT;
  1891. }
  1892. /*
  1893. * Hardware default rates on NT are signified as 1Hz. We translate this to
  1894. * 0Hz for DDraw apps. At SetDisplayMode time, 0Hz is translated back to 1Hz.
  1895. */
  1896. if(0==(dwFlags & DDEDM_REFRESHRATES))
  1897. {
  1898. ddsd.dwRefreshRate = 0;
  1899. }
  1900. rc = lpEnumCallback( (LPDDSURFACEDESC2) &ddsd, lpContext );
  1901. if( rc == 0 )
  1902. {
  1903. break;
  1904. }
  1905. }
  1906. LEAVE_DDRAW();
  1907. return DD_OK;
  1908. } /* DD_EnumDisplayModes */