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.

1737 lines
54 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 1994-1999 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: ddrefrsh.c
  6. * Content: DirectDraw Refresh Rate support
  7. *
  8. * On Win98, we don't have detailed information regarding what
  9. * refresh rates the montor supports. We can get some information
  10. * from the monitor (EDID data), but we cannot absolutely rely on
  11. * it, so we require that the user manually verify each refresh
  12. * rate before we allow it to be used.
  13. *
  14. * History:
  15. * Date By Reason
  16. * ==== == ======
  17. * 02-apr-99 smac Created it
  18. *
  19. ***************************************************************************/
  20. #include "ddrawpr.h"
  21. #include "edid.h"
  22. #undef DPF_MODNAME
  23. #define DPF_MODNAME "Refresh"
  24. #ifdef WIN95
  25. static WORD SupportedRefreshRates[] = {60, 75, 85, 100, 120};
  26. #define NUM_SUPPORTED_REFRESH_RATES ( sizeof( SupportedRefreshRates ) / sizeof( WORD ) )
  27. /*
  28. * GetEDIDData
  29. */
  30. HRESULT GetEDIDData( LPDDRAWI_DIRECTDRAW_GBL pddd, VESA_EDID * pEDIDData )
  31. {
  32. memset( pEDIDData, 0, sizeof( VESA_EDID ) );
  33. if( DD16_GetMonitorEDIDData( pddd->cDriverName, (LPVOID)pEDIDData) )
  34. {
  35. return DD_OK;
  36. }
  37. if( !( pddd->dwFlags & DDRAWI_DISPLAYDRV ) )
  38. {
  39. // HACK: Use primary display EDID data for passthrough devices
  40. if( DD16_GetMonitorEDIDData( g_szPrimaryDisplay, (LPVOID)pEDIDData) )
  41. {
  42. return DD_OK;
  43. }
  44. }
  45. return DDERR_UNSUPPORTED;
  46. }
  47. /*
  48. * CheckEdidBandiwdth
  49. *
  50. * Takes a resoltion/refrsh rate and calculates the bandwidth required for
  51. * this, and then updates lpHighestRefresh and lpHighestBandwidth to keep
  52. * track of the highest refresh rate and badnwidth info that we've encountered.
  53. */
  54. void CheckEdidBandwidth( DWORD dwWidth, DWORD dwHeight, DWORD dwRefreshRate,
  55. LPDWORD lpHighestRefresh, LPDWORD lpHighestBandwidth )
  56. {
  57. DWORD dwBandwidth;
  58. dwBandwidth = dwWidth * dwHeight * dwRefreshRate;
  59. if( dwBandwidth > *lpHighestBandwidth )
  60. {
  61. *lpHighestBandwidth = dwBandwidth;
  62. }
  63. if( dwRefreshRate > *lpHighestRefresh )
  64. {
  65. *lpHighestRefresh = dwRefreshRate;
  66. }
  67. }
  68. /*
  69. * StdTimeXRES
  70. */
  71. int StdTimeXRES(WORD StdTime)
  72. {
  73. if (StdTime == 0 || StdTime == 0x0101)
  74. return 0;
  75. else
  76. return ((StdTime & veStdTime_HorzResMask) + 31) * 8;
  77. }
  78. /*
  79. * StdTimeYRES
  80. */
  81. int StdTimeYRES(WORD StdTime)
  82. {
  83. if (StdTime == 0 || StdTime == 0x0101)
  84. return 0;
  85. switch (StdTime & veStdTime_AspectRatioMask)
  86. {
  87. case veStdTime_AspectRatio1to1: return StdTimeXRES(StdTime);
  88. case veStdTime_AspectRatio4to3: return StdTimeXRES(StdTime) * 3 / 4;
  89. case veStdTime_AspectRatio5to4: return StdTimeXRES(StdTime) * 4 / 5;
  90. case veStdTime_AspectRatio16to9: return StdTimeXRES(StdTime) * 9 / 16;
  91. }
  92. return 0;
  93. }
  94. /*
  95. * StdTimeRATE
  96. */
  97. int StdTimeRATE(WORD StdTime)
  98. {
  99. if (StdTime == 0 || StdTime == 0x0101)
  100. return 0;
  101. else
  102. return ((StdTime & veStdTime_RefreshRateMask) >> 8) + 60;
  103. }
  104. __inline UINT DetTimeXRES(BYTE *DetTime)
  105. {
  106. return (UINT)DetTime[2] + (((UINT)DetTime[4] & 0xF0) << 4);
  107. }
  108. __inline UINT DetTimeYRES(BYTE *DetTime)
  109. {
  110. return (UINT)DetTime[5] + (((UINT)DetTime[7] & 0xF0) << 4);
  111. }
  112. __inline UINT DetTimeXBLANK(BYTE *DetTime)
  113. {
  114. return (UINT)DetTime[3] + (((UINT)DetTime[4] & 0x0F) << 4);
  115. }
  116. __inline UINT DetTimeYBLANK(BYTE *DetTime)
  117. {
  118. return (UINT)DetTime[6] + (((UINT)DetTime[7] & 0x0F) << 0);
  119. }
  120. int DetTimeRATE(BYTE *DetTime)
  121. {
  122. ULONG clk;
  123. ULONG x;
  124. ULONG y;
  125. clk = *(WORD*)DetTime;
  126. x = DetTimeXRES(DetTime) + DetTimeXBLANK(DetTime);
  127. y = DetTimeYRES(DetTime) + DetTimeYBLANK(DetTime);
  128. if (clk == 0 || x == 0 || y == 0)
  129. return 0;
  130. return (int)((clk * 10000) / (x * y));
  131. }
  132. /*
  133. * GetDetailedTime
  134. */
  135. void GetDetailedTime(BYTE *DetTime, LPDWORD lpHighestRefresh, LPDWORD lpHighestBandwidth )
  136. {
  137. char ach[14];
  138. int i;
  139. DWORD dw;
  140. dw = *(DWORD *)DetTime;
  141. if( dw == 0xFD000000 ) // Monitor limits
  142. {
  143. if( (DWORD)(DetTime[6]) > *lpHighestRefresh )
  144. {
  145. *lpHighestRefresh = (DWORD)(DetTime[6]);
  146. }
  147. }
  148. else if (dw == 0xFA000000) // more standard timings
  149. {
  150. WORD * StdTime = (WORD *)&DetTime[5];
  151. CheckEdidBandwidth( StdTimeXRES( StdTime[0] ),
  152. StdTimeYRES( StdTime[0] ),
  153. StdTimeRATE( StdTime[0] ),
  154. lpHighestRefresh, lpHighestBandwidth );
  155. CheckEdidBandwidth( StdTimeXRES( StdTime[1] ),
  156. StdTimeYRES( StdTime[1] ),
  157. StdTimeRATE( StdTime[1] ),
  158. lpHighestRefresh, lpHighestBandwidth );
  159. CheckEdidBandwidth( StdTimeXRES( StdTime[2] ),
  160. StdTimeYRES( StdTime[2] ),
  161. StdTimeRATE( StdTime[2] ),
  162. lpHighestRefresh, lpHighestBandwidth );
  163. CheckEdidBandwidth( StdTimeXRES( StdTime[3] ),
  164. StdTimeYRES( StdTime[3] ),
  165. StdTimeRATE( StdTime[3] ),
  166. lpHighestRefresh, lpHighestBandwidth );
  167. CheckEdidBandwidth( StdTimeXRES( StdTime[4] ),
  168. StdTimeYRES( StdTime[4] ),
  169. StdTimeRATE( StdTime[4] ),
  170. lpHighestRefresh, lpHighestBandwidth );
  171. CheckEdidBandwidth( StdTimeXRES( StdTime[5] ),
  172. StdTimeYRES( StdTime[5] ),
  173. StdTimeRATE( StdTime[5] ),
  174. lpHighestRefresh, lpHighestBandwidth );
  175. }
  176. else if( ( dw != 0xFF000000 ) && // Serial number
  177. ( dw != 0xFE000000 ) && // Monitor String
  178. ( dw != 0xFC000000 ) && // Monitor Name
  179. ( dw != 0xFB000000 ) && // ColorPoint data
  180. ( DetTimeRATE( DetTime) ) )
  181. {
  182. CheckEdidBandwidth( DetTimeXRES( DetTime ),
  183. DetTimeYRES( DetTime ),
  184. DetTimeRATE( DetTime ),
  185. lpHighestRefresh, lpHighestBandwidth );
  186. }
  187. }
  188. /*
  189. * EvaluateMonitor
  190. *
  191. * Determines the amount of bandwidth that the monitor can handle.
  192. */
  193. void EvaluateMonitor( VESA_EDID *lpEdidData, DWORD *lpHighestRefresh, DWORD *lpHighestBandwidth )
  194. {
  195. BYTE chk;
  196. int i;
  197. *lpHighestRefresh = 0;
  198. *lpHighestBandwidth = 0;
  199. /*
  200. * Do some sanity checking to make sure that the EDID data looks sane
  201. */
  202. for( chk = i = 0; i < 128; i++)
  203. {
  204. chk += ((BYTE *)lpEdidData)[i];
  205. }
  206. if (chk != 0)
  207. {
  208. // Bad checksum
  209. return;
  210. }
  211. /*
  212. * First get the bandwidth from the established timings
  213. */
  214. if( lpEdidData->veEstTime1 & veEstTime1_720x400x70Hz)
  215. {
  216. CheckEdidBandwidth( 720, 400, 70, lpHighestRefresh, lpHighestBandwidth );
  217. }
  218. if( lpEdidData->veEstTime1 & veEstTime1_720x400x88Hz)
  219. {
  220. CheckEdidBandwidth( 720, 400, 88, lpHighestRefresh, lpHighestBandwidth );
  221. }
  222. if( lpEdidData->veEstTime1 & veEstTime1_640x480x60Hz)
  223. {
  224. CheckEdidBandwidth( 640, 480, 60, lpHighestRefresh, lpHighestBandwidth );
  225. }
  226. if( lpEdidData->veEstTime1 & veEstTime1_640x480x67Hz)
  227. {
  228. CheckEdidBandwidth( 640, 480, 67, lpHighestRefresh, lpHighestBandwidth );
  229. }
  230. if( lpEdidData->veEstTime1 & veEstTime1_640x480x72Hz)
  231. {
  232. CheckEdidBandwidth( 640, 480, 72, lpHighestRefresh, lpHighestBandwidth );
  233. }
  234. if( lpEdidData->veEstTime1 & veEstTime1_640x480x75Hz)
  235. {
  236. CheckEdidBandwidth( 640, 480, 75, lpHighestRefresh, lpHighestBandwidth );
  237. }
  238. if( lpEdidData->veEstTime1 & veEstTime1_800x600x60Hz)
  239. {
  240. CheckEdidBandwidth( 800, 600, 60, lpHighestRefresh, lpHighestBandwidth );
  241. }
  242. if( lpEdidData->veEstTime2 & veEstTime2_800x600x72Hz)
  243. {
  244. CheckEdidBandwidth( 800, 600, 72, lpHighestRefresh, lpHighestBandwidth );
  245. }
  246. if( lpEdidData->veEstTime2 & veEstTime2_800x600x75Hz)
  247. {
  248. CheckEdidBandwidth( 800, 600, 75, lpHighestRefresh, lpHighestBandwidth );
  249. }
  250. if( lpEdidData->veEstTime2 & veEstTime2_1024x768x60Hz)
  251. {
  252. CheckEdidBandwidth( 1024, 768, 60, lpHighestRefresh, lpHighestBandwidth );
  253. }
  254. if( lpEdidData->veEstTime2 & veEstTime2_1024x768x70Hz)
  255. {
  256. CheckEdidBandwidth( 1024, 768, 70, lpHighestRefresh, lpHighestBandwidth );
  257. }
  258. if( lpEdidData->veEstTime2 & veEstTime2_1024x768x75Hz)
  259. {
  260. CheckEdidBandwidth( 1024, 768, 75, lpHighestRefresh, lpHighestBandwidth );
  261. }
  262. if( lpEdidData->veEstTime2 & veEstTime2_1280x1024x75Hz)
  263. {
  264. CheckEdidBandwidth( 1280, 1024, 75, lpHighestRefresh, lpHighestBandwidth );
  265. }
  266. if( lpEdidData->veEstTime3 & veEstTime3_1152x870x75Hz)
  267. {
  268. CheckEdidBandwidth( 1152, 870, 75, lpHighestRefresh, lpHighestBandwidth );
  269. }
  270. /*
  271. * Now get the bandwidth from the standard timings
  272. */
  273. CheckEdidBandwidth( StdTimeXRES( lpEdidData->veStdTimeID1 ),
  274. StdTimeYRES( lpEdidData->veStdTimeID1 ),
  275. StdTimeRATE( lpEdidData->veStdTimeID1 ),
  276. lpHighestRefresh, lpHighestBandwidth );
  277. CheckEdidBandwidth( StdTimeXRES( lpEdidData->veStdTimeID2 ),
  278. StdTimeYRES( lpEdidData->veStdTimeID2 ),
  279. StdTimeRATE( lpEdidData->veStdTimeID2 ),
  280. lpHighestRefresh, lpHighestBandwidth );
  281. CheckEdidBandwidth( StdTimeXRES( lpEdidData->veStdTimeID3 ),
  282. StdTimeYRES( lpEdidData->veStdTimeID3 ),
  283. StdTimeRATE( lpEdidData->veStdTimeID3 ),
  284. lpHighestRefresh, lpHighestBandwidth );
  285. CheckEdidBandwidth( StdTimeXRES( lpEdidData->veStdTimeID4 ),
  286. StdTimeYRES( lpEdidData->veStdTimeID4 ),
  287. StdTimeRATE( lpEdidData->veStdTimeID4 ),
  288. lpHighestRefresh, lpHighestBandwidth );
  289. CheckEdidBandwidth( StdTimeXRES( lpEdidData->veStdTimeID5 ),
  290. StdTimeYRES( lpEdidData->veStdTimeID5 ),
  291. StdTimeRATE( lpEdidData->veStdTimeID5 ),
  292. lpHighestRefresh, lpHighestBandwidth );
  293. CheckEdidBandwidth( StdTimeXRES( lpEdidData->veStdTimeID6 ),
  294. StdTimeYRES( lpEdidData->veStdTimeID6 ),
  295. StdTimeRATE( lpEdidData->veStdTimeID6 ),
  296. lpHighestRefresh, lpHighestBandwidth );
  297. CheckEdidBandwidth( StdTimeXRES( lpEdidData->veStdTimeID7 ),
  298. StdTimeYRES( lpEdidData->veStdTimeID7 ),
  299. StdTimeRATE( lpEdidData->veStdTimeID7 ),
  300. lpHighestRefresh, lpHighestBandwidth );
  301. CheckEdidBandwidth( StdTimeXRES( lpEdidData->veStdTimeID8 ),
  302. StdTimeYRES( lpEdidData->veStdTimeID8 ),
  303. StdTimeRATE( lpEdidData->veStdTimeID8 ),
  304. lpHighestRefresh, lpHighestBandwidth );
  305. /*
  306. * Now get the detailed timing information
  307. */
  308. GetDetailedTime( lpEdidData->veDetailTime1, lpHighestRefresh, lpHighestBandwidth );
  309. GetDetailedTime( lpEdidData->veDetailTime2, lpHighestRefresh, lpHighestBandwidth );
  310. GetDetailedTime( lpEdidData->veDetailTime3, lpHighestRefresh, lpHighestBandwidth );
  311. GetDetailedTime( lpEdidData->veDetailTime4, lpHighestRefresh, lpHighestBandwidth );
  312. }
  313. //=============================================================================
  314. //
  315. // Function Description:
  316. //
  317. // Finds an item in a registry-based most recently used (MRU) list, and
  318. // either retrieves the contents of that item, or updates (add if it doesn't
  319. // exist) the item.
  320. //
  321. // Arguments:
  322. //
  323. // [IN/OUT] item - Contains at least the unique portion of the item to
  324. // search for [IN/OUT]. If writing the item, should contain
  325. // the entire item [IN].
  326. // [IN] writeItem - Set to TRUE if updating/adding an item to the MRU list.
  327. //
  328. // Return Value:
  329. //
  330. // TRUE - If writeItem is TRUE, then the item was written to the registry.
  331. // Otherwise the item was found and its contents stored in findItem.
  332. // FALSE - Failure; no more information available.
  333. //
  334. // Created:
  335. //
  336. // 04/08/1999 johnstep
  337. //
  338. //=============================================================================
  339. //-----------------------------------------------------------------------------
  340. // Define global MRU list values here, for simplicity:
  341. //
  342. // gMruRegKey - Registry key where MRU list is stored
  343. // gMruRegOrderValue - Name of MRU list order value
  344. // gMruBaseChar - Base index into MRU list
  345. // gMruMaxChar - Maximum index into MRU list
  346. // gMruItemSize - Size of findItem.
  347. // gMruUniqueOffset - Offset of unique portion of item. This unique portion
  348. // is what will be used to compare items.
  349. // gMruUniqueSize - Size of unique portion of item.
  350. //-----------------------------------------------------------------------------
  351. static const CHAR *gMruRegKey =
  352. REGSTR_PATH_DDRAW "\\" REGSTR_KEY_RECENTMONITORS;
  353. static const CHAR *gMruRegOrderValue = REGSTR_VAL_DDRAW_MONITORSORDER;
  354. #define gMruBaseChar '0'
  355. #define gMruMaxChar '9'
  356. #define gMruItemSize sizeof (DDMONITORINFO)
  357. #define gMruUniqueOffset 0
  358. #define gMruUniqueSize offsetof(DDMONITORINFO, Mode640x480)
  359. BOOL
  360. MruList(
  361. VOID *item,
  362. const BOOL writeItem
  363. )
  364. {
  365. BOOL success = FALSE;
  366. HKEY hkey;
  367. // Create or open the root key, with permission to query and set values;
  368. // only continue if successful:
  369. if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, gMruRegKey,
  370. 0, NULL, 0, KEY_QUERY_VALUE | KEY_SET_VALUE,
  371. NULL, &hkey, NULL) == ERROR_SUCCESS)
  372. {
  373. CHAR mruOrder[gMruMaxChar - gMruBaseChar + 2];
  374. DWORD type;
  375. DWORD count = sizeof mruOrder;
  376. UINT i;
  377. {
  378. CHAR temp[sizeof mruOrder];
  379. // If we read the order value successfully, copy the valid chars
  380. // into mruOrder, removing duplicates:
  381. if (RegQueryValueEx(hkey, gMruRegOrderValue, NULL, &type,
  382. (BYTE *) temp, &count) == ERROR_SUCCESS)
  383. {
  384. UINT j = 0;
  385. for (--count, i = 0; i < count; i++)
  386. {
  387. if ((temp[i] >= gMruBaseChar) &&
  388. (temp[i] <= gMruMaxChar))
  389. {
  390. UINT k;
  391. for (k = 0; k < j; k++)
  392. {
  393. if (mruOrder[k] == temp[i])
  394. {
  395. break;
  396. }
  397. }
  398. if (k == j)
  399. {
  400. mruOrder[j++] = temp[i];
  401. }
  402. }
  403. }
  404. count = j;
  405. }
  406. else
  407. {
  408. count = 0;
  409. }
  410. }
  411. // Only continue if we found at least one valid value in the order
  412. // list, or if we're writing the item:
  413. if ((count > 0) || writeItem)
  414. {
  415. CHAR regValue[2];
  416. BYTE regItem[gMruItemSize];
  417. regValue[1] = '\0';
  418. // Search for the item in the MRU list:
  419. for (i = 0; i < count; i++)
  420. {
  421. DWORD size = sizeof regItem;
  422. regValue[0] = mruOrder[i];
  423. if ((RegQueryValueEx(hkey, regValue, NULL, &type,
  424. (BYTE *) &regItem, &size) == ERROR_SUCCESS) &&
  425. (size == sizeof regItem))
  426. {
  427. if (memcmp(
  428. (BYTE *) &regItem + gMruUniqueOffset,
  429. (BYTE *) item + gMruUniqueOffset,
  430. gMruUniqueSize) == 0)
  431. {
  432. break;
  433. }
  434. }
  435. }
  436. // Keep going if we found the item or in any case if we need to
  437. // write the item:
  438. if ((i < count) || writeItem)
  439. {
  440. UINT j;
  441. // If we didn't find the item, then we must be writing, so
  442. // adjust the index appropriately. If the list is already
  443. // full, we just use the last item (LRU item), otherwise, add
  444. // a new item:
  445. if (i == count)
  446. {
  447. if (count == (gMruMaxChar - gMruBaseChar + 1))
  448. {
  449. i--;
  450. }
  451. else
  452. {
  453. // Adding a new item; search for the lowest unused
  454. // valid char:
  455. for (mruOrder[i] = gMruBaseChar;
  456. mruOrder[i] < gMruMaxChar;
  457. mruOrder[i]++)
  458. {
  459. for (j = 0; j < i; j++)
  460. {
  461. if (mruOrder[j] == mruOrder[i])
  462. {
  463. break;
  464. }
  465. }
  466. if (j == i)
  467. {
  468. break;
  469. }
  470. }
  471. count++;
  472. }
  473. }
  474. // Update the MRU order list if necessary. We update if we
  475. // found or are adding an item after the first, or if this is
  476. // the first item in the list:
  477. if (i > 0 || (count == 1))
  478. {
  479. // Bubble found item to head of order list:
  480. for (j = i; j > 0; j--)
  481. {
  482. CHAR temp = mruOrder[j];
  483. mruOrder[j] = mruOrder[j - 1];
  484. mruOrder[j - 1] = temp;
  485. }
  486. // Write the order list:
  487. mruOrder[count] = '\0';
  488. RegSetValueEx(hkey, gMruRegOrderValue, 0,
  489. REG_SZ, (BYTE *) mruOrder, count + 1);
  490. }
  491. // If we want to write the item, do it now. We will always
  492. // write to the first item in the order list. If not writing,
  493. // copy what was read from the registry into item:
  494. if (writeItem)
  495. {
  496. regValue[0] = mruOrder[0];
  497. if (RegSetValueEx(hkey, regValue, 0,
  498. REG_BINARY, (BYTE *) item, sizeof regItem) ==
  499. ERROR_SUCCESS)
  500. {
  501. success = TRUE;
  502. }
  503. }
  504. else
  505. {
  506. memcpy(
  507. (BYTE *) item + gMruUniqueOffset,
  508. regItem + gMruUniqueOffset,
  509. sizeof regItem);
  510. success = TRUE;
  511. }
  512. }
  513. }
  514. // Always close the registry key when finished:
  515. RegCloseKey(hkey);
  516. }
  517. return success;
  518. }
  519. //-----------------------------------------------------------------------------
  520. /*
  521. * DDSaveMonitorInfo
  522. *
  523. * Writes the monitor info to the registry.
  524. */
  525. HRESULT DDSaveMonitorInfo( LPDDRAWI_DIRECTDRAW_INT lpDD_int )
  526. {
  527. return MruList( (VOID *) lpDD_int->lpLcl->lpGbl->lpMonitorInfo, TRUE ) ?
  528. DD_OK : DDERR_GENERIC;
  529. }
  530. __inline IsValidRefreshRate( DWORD dwWidth, DWORD dwHeight, int refreshRate,
  531. DWORD dwHighestBandwidth )
  532. {
  533. return
  534. ( ( refreshRate >= 0 ) &&
  535. ( ( dwWidth * dwHeight * (DWORD) refreshRate ) <= dwHighestBandwidth ) );
  536. }
  537. /*
  538. * DDGetMonitorInfo
  539. *
  540. * Reads the monitor info from the registry and verifies that it still applies.
  541. */
  542. HRESULT DDGetMonitorInfo(
  543. LPDDRAWI_DIRECTDRAW_INT lpDD_int )
  544. {
  545. LPDDMONITORINFO pInfo;
  546. static DDDEVICEIDENTIFIER DeviceIdentifier;
  547. HRESULT hr;
  548. if( ( lpDD_int->lpVtbl == &dd7Callbacks ) &&
  549. ( lpDD_int->lpLcl->lpGbl->lpMonitorInfo == NULL ) )
  550. {
  551. VESA_EDID EDIDData;
  552. DWORD dwHighestRefresh;
  553. DWORD dwHighestBandwidth;
  554. HKEY hKey;
  555. BOOL bGotLastMonitor = FALSE;
  556. hr = GetEDIDData( lpDD_int->lpLcl->lpGbl, &EDIDData );
  557. if( hr != DD_OK )
  558. {
  559. // There is no EDID data
  560. return DDERR_GENERIC;
  561. }
  562. EvaluateMonitor( &EDIDData, &dwHighestRefresh, &dwHighestBandwidth );
  563. hr = DD_GetDeviceIdentifier( (LPDIRECTDRAW) lpDD_int, &DeviceIdentifier, 0 );
  564. if( hr != DD_OK )
  565. {
  566. // Failed to get device identifier for monitor info
  567. return hr;
  568. }
  569. pInfo = (LPDDMONITORINFO) MemAlloc( sizeof( DDMONITORINFO ) );
  570. if( pInfo == NULL )
  571. {
  572. // Out of memory allocating monitor info structure
  573. return DDERR_OUTOFMEMORY;
  574. }
  575. pInfo->Manufacturer = *(WORD *)&EDIDData.veManufactID[0];
  576. pInfo->Product = *(WORD *)&EDIDData.veProductCode[0];
  577. pInfo->SerialNumber = EDIDData.veSerialNbr;
  578. pInfo->DeviceIdentifier = DeviceIdentifier.guidDeviceIdentifier;
  579. // Read monitor information from registry, if available. We need to
  580. // compare this to the EDID data to see if the monitor or adapter
  581. // changed and verify the selected refresh rates are sane:
  582. if( MruList( (VOID *) pInfo, FALSE ) )
  583. {
  584. // Validate modes here against EDID data:
  585. if( !IsValidRefreshRate( 640, 480,
  586. pInfo->Mode640x480, dwHighestBandwidth ) )
  587. {
  588. pInfo->Mode640x480 = -1;
  589. }
  590. if( !IsValidRefreshRate( 800, 600,
  591. pInfo->Mode800x600, dwHighestBandwidth ) )
  592. {
  593. pInfo->Mode800x600 = -1;
  594. }
  595. if( !IsValidRefreshRate( 1024, 768,
  596. pInfo->Mode1024x768, dwHighestBandwidth ) )
  597. {
  598. pInfo->Mode1024x768 = -1;
  599. }
  600. if( !IsValidRefreshRate( 1280, 1024,
  601. pInfo->Mode1280x1024, dwHighestBandwidth ) )
  602. {
  603. pInfo->Mode1280x1024 = -1;
  604. }
  605. if( !IsValidRefreshRate( 1600, 1200,
  606. pInfo->Mode1600x1200, dwHighestBandwidth ) )
  607. {
  608. pInfo->Mode1600x1200 = -1;
  609. }
  610. bGotLastMonitor = TRUE;
  611. }
  612. if( !bGotLastMonitor )
  613. {
  614. pInfo->Mode640x480 = -1;
  615. pInfo->Mode800x600 = -1;
  616. pInfo->Mode1024x768 = -1;
  617. pInfo->Mode1280x1024 = -1;
  618. pInfo->Mode1600x1200 = -1;
  619. }
  620. pInfo->ModeReserved1 = -1;
  621. pInfo->ModeReserved2 = -1;
  622. pInfo->ModeReserved3 = -1;
  623. lpDD_int->lpLcl->lpGbl->lpMonitorInfo = pInfo;
  624. }
  625. return DD_OK;
  626. }
  627. /*
  628. * ExpandModeTable
  629. *
  630. * On Win9X, drivers can specify their maximum refresh rate for each mode,
  631. * allowing DDraw to add modes for each refresh rate that we care about.
  632. * This allows drivers to add refresh rate easily without having to
  633. * maintain huge tables. This also allows us to avoid regressions by allowing
  634. * us to only enumerate these refresh rates on newer interfaces.
  635. */
  636. HRESULT ExpandModeTable( LPDDRAWI_DIRECTDRAW_GBL pddd )
  637. {
  638. DWORD i;
  639. DWORD j;
  640. DWORD iNumModes = 0;
  641. LPDDHALMODEINFO pNewModeTable;
  642. DWORD iModeIndex;
  643. WORD wMaxRefresh;
  644. /*
  645. * Count the number of entries that we'll need
  646. */
  647. if( pddd->lpModeInfo != NULL )
  648. {
  649. for( i = 0; i < pddd->dwNumModes; i++ )
  650. {
  651. iNumModes++;
  652. if( pddd->lpModeInfo[i].wFlags & DDMODEINFO_MAXREFRESH )
  653. {
  654. for( j = 0; j < NUM_SUPPORTED_REFRESH_RATES; j++ )
  655. {
  656. if( SupportedRefreshRates[j] <= pddd->lpModeInfo[i].wRefreshRate )
  657. {
  658. iNumModes++;
  659. }
  660. }
  661. }
  662. }
  663. if( iNumModes > pddd->dwNumModes )
  664. {
  665. /*
  666. * We do have to add modes and allocate a new table
  667. */
  668. pNewModeTable = (LPDDHALMODEINFO) MemAlloc( sizeof( DDHALMODEINFO ) * iNumModes );
  669. if( pNewModeTable == NULL )
  670. {
  671. /*
  672. * Instead of failing here, we'll just clear all of the MAXREFRESHRATE
  673. * flags and set the rate to 0.
  674. */
  675. for( i = 0; i < pddd->dwNumModes; i++ )
  676. {
  677. if( pddd->lpModeInfo[i].wFlags & DDMODEINFO_MAXREFRESH )
  678. {
  679. pddd->lpModeInfo[i].wFlags &= ~DDMODEINFO_MAXREFRESH;
  680. pddd->lpModeInfo[i].wRefreshRate = 0;
  681. }
  682. }
  683. }
  684. else
  685. {
  686. memcpy( pNewModeTable, pddd->lpModeInfo, pddd->dwNumModes * sizeof( DDHALMODEINFO ) );
  687. /*
  688. * Now add the new refresh rates
  689. */
  690. iModeIndex = pddd->dwNumModes;
  691. for( i = 0; i < pddd->dwNumModes; i++ )
  692. {
  693. if( pddd->lpModeInfo[i].wFlags & DDMODEINFO_MAXREFRESH )
  694. {
  695. pNewModeTable[i].wFlags &= ~DDMODEINFO_MAXREFRESH;
  696. wMaxRefresh = pNewModeTable[i].wRefreshRate;
  697. pNewModeTable[i].wRefreshRate = 0;
  698. for( j = 0; j < NUM_SUPPORTED_REFRESH_RATES; j++ )
  699. {
  700. if( SupportedRefreshRates[j] <= wMaxRefresh )
  701. {
  702. memcpy( &(pNewModeTable[iModeIndex]), &(pNewModeTable[i]), sizeof( DDHALMODEINFO ) );
  703. pNewModeTable[iModeIndex].wFlags |= DDMODEINFO_DX7ONLY;
  704. pNewModeTable[iModeIndex++].wRefreshRate = SupportedRefreshRates[j];
  705. }
  706. }
  707. }
  708. }
  709. MemFree( pddd->lpModeInfo );
  710. pddd->lpModeInfo = pNewModeTable;
  711. pddd->dwNumModes = iModeIndex;
  712. }
  713. }
  714. }
  715. return DD_OK;
  716. }
  717. /*
  718. * CanMonitorHandleRefreshRate
  719. *
  720. * Has the specified refresh rate been tested and verified that it works?
  721. */
  722. BOOL CanMonitorHandleRefreshRate( LPDDRAWI_DIRECTDRAW_GBL pddd, DWORD dwWidth, DWORD dwHeight, int wRefresh )
  723. {
  724. if( wRefresh == 0 )
  725. {
  726. return TRUE;
  727. }
  728. if( pddd->lpMonitorInfo == NULL )
  729. {
  730. return FALSE;
  731. }
  732. /*
  733. * If we are setting this mode because we are testing it, then we should
  734. * allow it so the user can verify whether it worked or not.
  735. */
  736. if( pddd->dwFlags & DDRAWI_TESTINGMODES )
  737. {
  738. return TRUE;
  739. }
  740. if( ( dwWidth <= 640 ) && ( dwHeight <= 480 ) )
  741. {
  742. if( pddd->lpMonitorInfo->Mode640x480 >= wRefresh )
  743. {
  744. return TRUE;
  745. }
  746. }
  747. if( ( dwWidth <= 800 ) && ( dwHeight <= 600 ) )
  748. {
  749. if( pddd->lpMonitorInfo->Mode800x600 >= wRefresh )
  750. {
  751. return TRUE;
  752. }
  753. }
  754. if( ( dwWidth <= 1024 ) && ( dwHeight <= 768 ) )
  755. {
  756. if( pddd->lpMonitorInfo->Mode1024x768 >= wRefresh )
  757. {
  758. return TRUE;
  759. }
  760. }
  761. if( ( dwWidth <= 1280 ) && ( dwHeight <= 1024 ) )
  762. {
  763. if( pddd->lpMonitorInfo->Mode1280x1024 >= wRefresh )
  764. {
  765. return TRUE;
  766. }
  767. }
  768. if( ( dwWidth <= 1600 ) && ( dwHeight <= 1200 ) )
  769. {
  770. if( pddd->lpMonitorInfo->Mode1600x1200 >= wRefresh )
  771. {
  772. return TRUE;
  773. }
  774. }
  775. return FALSE;
  776. }
  777. /*
  778. * IsModeTested
  779. *
  780. * Determines if we already have data for the requested mode.
  781. */
  782. BOOL IsModeTested( LPDDRAWI_DIRECTDRAW_GBL pddd, DWORD dwWidth, DWORD dwHeight )
  783. {
  784. if( pddd->lpMonitorInfo == NULL )
  785. {
  786. return FALSE;
  787. }
  788. if( ( dwWidth <= 640 ) && ( dwHeight <= 480 ) )
  789. {
  790. if( pddd->lpMonitorInfo->Mode640x480 != -1 )
  791. {
  792. return TRUE;
  793. }
  794. }
  795. else if( ( dwWidth <= 800 ) && ( dwHeight <= 600 ) )
  796. {
  797. if( pddd->lpMonitorInfo->Mode800x600 != -1 )
  798. {
  799. return TRUE;
  800. }
  801. }
  802. else if( ( dwWidth <= 1024 ) && ( dwHeight <= 768 ) )
  803. {
  804. if( pddd->lpMonitorInfo->Mode1024x768 != -1 )
  805. {
  806. return TRUE;
  807. }
  808. }
  809. else if( ( dwWidth <= 1280 ) && ( dwHeight <= 1024 ) )
  810. {
  811. if( pddd->lpMonitorInfo->Mode1280x1024 != -1 )
  812. {
  813. return TRUE;
  814. }
  815. }
  816. else if( ( dwWidth <= 1600 ) && ( dwHeight <= 1200 ) )
  817. {
  818. if( pddd->lpMonitorInfo->Mode1600x1200 != -1 )
  819. {
  820. return TRUE;
  821. }
  822. }
  823. return FALSE;
  824. }
  825. /*
  826. * UpdateMonitorInfo
  827. */
  828. void UpdateMonitorInfo( LPDDRAWI_DIRECTDRAW_GBL pddd, DWORD dwWidth, DWORD dwHeight, int iRefreshRate )
  829. {
  830. if( pddd->lpMonitorInfo == NULL )
  831. {
  832. return;
  833. }
  834. if( ( dwWidth <= 640 ) && ( dwHeight <= 480 ) )
  835. {
  836. pddd->lpMonitorInfo->Mode640x480 = iRefreshRate;
  837. }
  838. else if( ( dwWidth <= 800 ) && ( dwHeight <= 600 ) )
  839. {
  840. pddd->lpMonitorInfo->Mode800x600 = iRefreshRate;
  841. }
  842. else if( ( dwWidth <= 1024 ) && ( dwHeight <= 768 ) )
  843. {
  844. pddd->lpMonitorInfo->Mode1024x768 = iRefreshRate;
  845. }
  846. else if( ( dwWidth <= 1280 ) && ( dwHeight <= 1024 ) )
  847. {
  848. pddd->lpMonitorInfo->Mode1280x1024 = iRefreshRate;
  849. }
  850. else if( ( dwWidth <= 1600 ) && ( dwHeight <= 1200 ) )
  851. {
  852. pddd->lpMonitorInfo->Mode1600x1200 = iRefreshRate;
  853. }
  854. }
  855. /*
  856. * GetModeToTest
  857. */
  858. HRESULT GetModeToTest( DWORD dwInWidth, DWORD dwInHeight,
  859. LPDWORD lpdwOutWidth, LPDWORD lpdwOutHeight )
  860. {
  861. if( ( dwInWidth <= 640 ) && ( dwInHeight <= 480 ) )
  862. {
  863. *lpdwOutWidth = 640;
  864. *lpdwOutHeight = 480;
  865. }
  866. else if( ( dwInWidth <= 800 ) && ( dwInHeight <= 600 ) )
  867. {
  868. *lpdwOutWidth = 800;
  869. *lpdwOutHeight = 600;
  870. }
  871. else if( ( dwInWidth <= 1024 ) && ( dwInHeight <= 768 ) )
  872. {
  873. *lpdwOutWidth = 1024;
  874. *lpdwOutHeight = 768;
  875. }
  876. else if( ( dwInWidth <= 1280 ) && ( dwInHeight <= 1024 ) )
  877. {
  878. *lpdwOutWidth = 1280;
  879. *lpdwOutHeight = 1024;
  880. }
  881. else if( ( dwInWidth <= 1600 ) && ( dwInHeight <= 1200 ) )
  882. {
  883. *lpdwOutWidth = 1600;
  884. *lpdwOutHeight = 1200;
  885. }
  886. else
  887. {
  888. return DDERR_GENERIC;
  889. }
  890. return DD_OK;
  891. }
  892. /*
  893. * GuestimateRefreshRate
  894. */
  895. int GuestimateRefreshRate( LPDDRAWI_DIRECTDRAW_GBL pddd, DWORD dwWidth, DWORD dwHeight,
  896. DWORD dwHighestRefresh, DWORD dwHighestBandwidth )
  897. {
  898. int i;
  899. DWORD dwBandwidth;
  900. if( ( pddd->lpMonitorInfo == NULL ) ||
  901. ( dwHighestRefresh == 0 ) )
  902. {
  903. return 0;
  904. }
  905. // Sanity check to see if the monitor can handle the resolution
  906. if( !MonitorCanHandleMode( pddd, dwWidth, dwHeight, 0 ) )
  907. {
  908. return 0;
  909. }
  910. // If the monitor did not return any refresh rates higher than 60,
  911. // something is up so we'd better stick to it.
  912. if( dwHighestRefresh == 60 )
  913. {
  914. return 60;
  915. }
  916. // Likwise, we will only go after the 100+ refresh rates if the monitor
  917. // enumerated a refresh rate of at least 85hz. This may be an unnecesary
  918. // restiction, but it seems safe.
  919. for( i = NUM_SUPPORTED_REFRESH_RATES - 1; i >= 0; i-- )
  920. {
  921. if( ( SupportedRefreshRates[i] <= 85 ) ||
  922. ( dwHighestRefresh >= 85 ) )
  923. {
  924. dwBandwidth = dwWidth * dwHeight * SupportedRefreshRates[i];
  925. if( dwBandwidth <= dwHighestBandwidth )
  926. {
  927. return SupportedRefreshRates[i];
  928. }
  929. }
  930. }
  931. return 0;
  932. }
  933. /*
  934. * SetTheMode
  935. */
  936. HRESULT SetTheMode( LPDIRECTDRAW7 lpDD, LPMODETESTCONTEXT pContext )
  937. {
  938. HRESULT hr;
  939. DWORD dwBPP;
  940. /*
  941. * We set an internal flag indicating that we are running a mode test.
  942. * This lets CanMonitorHandleRefreshRate know that the requested mode
  943. * should be used, even though it hasb't successfully been tested yet.
  944. */
  945. ((LPDDRAWI_DIRECTDRAW_INT)lpDD)->lpLcl->lpGbl->dwFlags |= DDRAWI_TESTINGMODES;
  946. //
  947. // There might be a case in which we decided that the lowest BPP the driver
  948. // could do for this mode was, say, 8bpp. But that didn't take into consideration
  949. // what rates the driver said it could do. E.g. if the driver (for whatever
  950. // reason) doesn't advertise 8bpp at 60Hz, but DOES advertise 16bpp at 60Hz
  951. // then we can go ahead and use the 16bpp mode. We are here to test monitor
  952. // bandwidth, not the DAC. The monitor's bandwidth is entirely determined
  953. // by the spatial resolution and refresh rate. If we bump the driver to
  954. // a higher BPP (one that it says it can do), then we are still testing
  955. // the correct monitor setup.
  956. // We do this in a really dumb way: just keep cranking up from the lowest BPP
  957. // (which is in the context mode list) in steps of 8 until we succeed the
  958. // mode change, or exceed 32bpp.
  959. //
  960. dwBPP = pContext->lpModeList[pContext->dwCurrentMode].dwBPP;
  961. do
  962. {
  963. hr = DD_SetDisplayMode2( (LPDIRECTDRAW)lpDD,
  964. pContext->lpModeList[pContext->dwCurrentMode].dwWidth,
  965. pContext->lpModeList[pContext->dwCurrentMode].dwHeight,
  966. dwBPP,
  967. pContext->lpModeList[pContext->dwCurrentMode].dwRefreshRate,
  968. DDSDM_STANDARDVGAMODE );
  969. dwBPP += 8;
  970. } while(FAILED(hr) && (dwBPP <= 32) );
  971. ((LPDDRAWI_DIRECTDRAW_INT)lpDD)->lpLcl->lpGbl->dwFlags &= ~DDRAWI_TESTINGMODES;
  972. return hr;
  973. }
  974. /*
  975. * SetupNextTest
  976. */
  977. void SetupNextTest( LPDIRECTDRAW7 lpDD, LPMODETESTCONTEXT pContext )
  978. {
  979. int i;
  980. /*
  981. * Drop back to the next refrsh rate if there is one, otherwise
  982. * move on to the next mode.
  983. */
  984. for( i = NUM_SUPPORTED_REFRESH_RATES - 1; i >= 0; i-- )
  985. {
  986. if( SupportedRefreshRates[i] <
  987. pContext->lpModeList[pContext->dwCurrentMode].dwRefreshRate )
  988. {
  989. pContext->lpModeList[pContext->dwCurrentMode].dwRefreshRate =
  990. SupportedRefreshRates[i];
  991. break;
  992. }
  993. }
  994. if( i < 0 )
  995. {
  996. // We've tried everything in this mode, so move on
  997. UpdateMonitorInfo( ((LPDDRAWI_DIRECTDRAW_INT)lpDD)->lpLcl->lpGbl,
  998. pContext->lpModeList[pContext->dwCurrentMode].dwWidth,
  999. pContext->lpModeList[pContext->dwCurrentMode].dwHeight,
  1000. 0 );
  1001. pContext->dwCurrentMode++;
  1002. }
  1003. }
  1004. /*
  1005. * RunNextTest
  1006. */
  1007. HRESULT RunNextTest( LPDIRECTDRAW7 lpDD, LPMODETESTCONTEXT pContext )
  1008. {
  1009. HRESULT hr;
  1010. LPDDRAWI_DIRECTDRAW_GBL pddd;
  1011. do
  1012. {
  1013. if( pContext->dwCurrentMode >= pContext->dwNumModes )
  1014. {
  1015. // Restore the mode if we've changed it
  1016. pddd = ((LPDDRAWI_DIRECTDRAW_INT)lpDD)->lpLcl->lpGbl;
  1017. if( pContext->dwOrigModeIndex != pddd->dwModeIndex )
  1018. {
  1019. DD_SetDisplayMode2( (LPDIRECTDRAW)lpDD,
  1020. pddd->lpModeInfo[pContext->dwOrigModeIndex].dwWidth,
  1021. pddd->lpModeInfo[pContext->dwOrigModeIndex].dwHeight,
  1022. pddd->lpModeInfo[pContext->dwOrigModeIndex].dwBPP,
  1023. pddd->lpModeInfo[pContext->dwOrigModeIndex].wRefreshRate,
  1024. 0 );
  1025. }
  1026. DDSaveMonitorInfo( (LPDDRAWI_DIRECTDRAW_INT)lpDD );
  1027. MemFree( pContext->lpModeList );
  1028. MemFree( pContext );
  1029. ((LPDDRAWI_DIRECTDRAW_INT)lpDD)->lpLcl->lpModeTestContext = NULL;
  1030. return DDERR_TESTFINISHED;
  1031. }
  1032. hr = SetTheMode( lpDD, pContext );
  1033. if( hr != DD_OK )
  1034. {
  1035. SetupNextTest( lpDD, pContext );
  1036. }
  1037. } while( ( hr != DD_OK ) && (hr != DDERR_TESTFINISHED ) );
  1038. if( hr != DDERR_TESTFINISHED )
  1039. {
  1040. pContext->dwTimeStamp = GetTickCount();
  1041. }
  1042. return hr;
  1043. }
  1044. #endif
  1045. /*
  1046. * DD_StartModeTest
  1047. *
  1048. * Indicates that the app wants to start testing a mode (or modes).
  1049. */
  1050. HRESULT DDAPI DD_StartModeTest( LPDIRECTDRAW7 lpDD, LPSIZE lpModesToTest, DWORD dwNumEntries, DWORD dwFlags )
  1051. {
  1052. #ifdef WIN95
  1053. LPDDRAWI_DIRECTDRAW_INT this_int;
  1054. LPDDRAWI_DIRECTDRAW_LCL this_lcl;
  1055. LPDDRAWI_DIRECTDRAW_GBL this;
  1056. BOOL excl_exists;
  1057. BOOL is_excl;
  1058. LPMODETESTCONTEXT pContext;
  1059. DWORD i;
  1060. DWORD j;
  1061. HRESULT hr;
  1062. DWORD dwRefreshRate;
  1063. DWORD dwModeWidth;
  1064. DWORD dwModeHeight;
  1065. VESA_EDID EDIDData;
  1066. DWORD dwHighestRefresh;
  1067. DWORD dwHighestBandwidth;
  1068. ENTER_DDRAW();
  1069. #endif
  1070. DPF(2,A,"ENTERAPI: DD_StartModeTest");
  1071. #ifdef WINNT
  1072. return DDERR_TESTFINISHED;
  1073. #else
  1074. TRY
  1075. {
  1076. this_int = (LPDDRAWI_DIRECTDRAW_INT) lpDD;
  1077. if( !VALID_DIRECTDRAW_PTR( this_int ) )
  1078. {
  1079. LEAVE_DDRAW();
  1080. return DDERR_INVALIDOBJECT;
  1081. }
  1082. this_lcl = this_int->lpLcl;
  1083. this = this_lcl->lpGbl;
  1084. if( this->lpMonitorInfo == NULL )
  1085. {
  1086. // There is no monitor info
  1087. LEAVE_DDRAW();
  1088. return DDERR_NOMONITORINFORMATION;
  1089. }
  1090. if( this_lcl->lpModeTestContext != NULL )
  1091. {
  1092. DPF_ERR( "Mode test already running" );
  1093. LEAVE_DDRAW();
  1094. return DDERR_INVALIDPARAMS;
  1095. }
  1096. if( dwFlags & ~DDSMT_VALID )
  1097. {
  1098. DPF_ERR( "Invalid Flags specified" );
  1099. LEAVE_DDRAW();
  1100. return DDERR_INVALIDPARAMS;
  1101. }
  1102. if( ( dwFlags & DDSMT_ISTESTREQUIRED ) &&
  1103. ( lpModesToTest == NULL ) )
  1104. {
  1105. DPF_ERR( "No modes specified to test" );
  1106. LEAVE_DDRAW();
  1107. return DDERR_INVALIDPARAMS;
  1108. }
  1109. CheckExclusiveMode( this_lcl, &excl_exists, &is_excl, FALSE, NULL, FALSE);
  1110. if( lpModesToTest != NULL )
  1111. {
  1112. if ( ( dwNumEntries == 0 ) ||
  1113. ( !VALID_BYTE_ARRAY( lpModesToTest, sizeof( SIZE ) * dwNumEntries ) ) )
  1114. {
  1115. DPF_ERR( "Invalid mode list specified" );
  1116. LEAVE_DDRAW();
  1117. return DDERR_INVALIDPARAMS;
  1118. }
  1119. /*
  1120. * The app must own exclusive mode to test the modes
  1121. */
  1122. if ( !is_excl || !(this->dwFlags & DDRAWI_FULLSCREEN) )
  1123. {
  1124. DPF_ERR( "Must be in full-screen exclusive mode to test the modes" );
  1125. LEAVE_DDRAW();
  1126. return DDERR_NOEXCLUSIVEMODE;
  1127. }
  1128. }
  1129. else
  1130. {
  1131. /*
  1132. * There must not be another app running which owns exclusive mode
  1133. */
  1134. if( !excl_exists || is_excl )
  1135. {
  1136. this->lpMonitorInfo->Mode640x480 = -1;
  1137. this->lpMonitorInfo->Mode800x600 = -1;
  1138. this->lpMonitorInfo->Mode1024x768 = -1;
  1139. this->lpMonitorInfo->Mode1280x1024 = -1;
  1140. this->lpMonitorInfo->Mode1600x1200 = -1;
  1141. this->lpMonitorInfo->ModeReserved1 = -1;
  1142. this->lpMonitorInfo->ModeReserved2 = -1;
  1143. this->lpMonitorInfo->ModeReserved3 = -1;
  1144. hr = DDSaveMonitorInfo( this_int );
  1145. LEAVE_DDRAW();
  1146. return hr;
  1147. }
  1148. else
  1149. {
  1150. DPF_ERR( "Cannot reset monitor info; another app owns exclusive mode" );
  1151. LEAVE_DDRAW();
  1152. return DDERR_NOEXCLUSIVEMODE;
  1153. }
  1154. }
  1155. }
  1156. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  1157. {
  1158. DPF_ERR( "Exception encountered validating parameters" );
  1159. LEAVE_DDRAW();
  1160. return DDERR_INVALIDPARAMS;
  1161. }
  1162. /*
  1163. * Get and evaluate the EDID data
  1164. */
  1165. hr = GetEDIDData( this, &EDIDData );
  1166. if( hr != DD_OK )
  1167. {
  1168. // There is no EDID data
  1169. LEAVE_DDRAW();
  1170. return DDERR_NOMONITORINFORMATION;
  1171. }
  1172. EvaluateMonitor( &EDIDData, &dwHighestRefresh, &dwHighestBandwidth );
  1173. for( i = 0; i < this->dwNumModes; i++ )
  1174. {
  1175. if( this->lpModeInfo[i].wRefreshRate > 0 )
  1176. {
  1177. break;
  1178. }
  1179. }
  1180. if( i == this->dwNumModes )
  1181. {
  1182. // The driver does not enumerate display mode refresh rates.
  1183. LEAVE_DDRAW();
  1184. return DDERR_NODRIVERSUPPORT;
  1185. }
  1186. /*
  1187. * Allocate a context for ourselves
  1188. */
  1189. pContext = (LPMODETESTCONTEXT) MemAlloc( sizeof( MODETESTCONTEXT ) );
  1190. if( pContext == NULL )
  1191. {
  1192. DPF_ERR( "Insufficient memory" );
  1193. LEAVE_DDRAW();
  1194. return DDERR_OUTOFMEMORY;
  1195. }
  1196. pContext->dwNumModes = 0;
  1197. pContext->dwCurrentMode = 0;
  1198. pContext->lpModeList = (LPMODETESTDATA) MemAlloc( sizeof( MODETESTDATA ) * dwNumEntries );
  1199. if( pContext->lpModeList == NULL )
  1200. {
  1201. MemFree( pContext );
  1202. LEAVE_DDRAW();
  1203. return DDERR_OUTOFMEMORY;
  1204. }
  1205. this_lcl->lpModeTestContext = pContext;
  1206. /*
  1207. * Guestimate which refresh rates we should try for each mode in the list
  1208. * based on the EDID data
  1209. */
  1210. for( i = 0; i < dwNumEntries; i++ )
  1211. {
  1212. DWORD dwLowestBPP = 0xFFFFFFFF;
  1213. /*
  1214. * Verify that the driver understands the resolution
  1215. */
  1216. for( j = 0; j < this->dwNumModes; j++ )
  1217. {
  1218. if( ( this->lpModeInfo[j].dwHeight == (DWORD) lpModesToTest[i].cy ) &&
  1219. ( this->lpModeInfo[j].dwWidth == (DWORD) lpModesToTest[i].cx ) )
  1220. {
  1221. if( this->lpModeInfo[j].dwBPP < dwLowestBPP )
  1222. {
  1223. dwLowestBPP = this->lpModeInfo[j].dwBPP;
  1224. }
  1225. }
  1226. }
  1227. if( dwLowestBPP == 0xFFFFFFFF )
  1228. {
  1229. /*
  1230. * The driver doesn't undestand this mode, so the app is dumb
  1231. * for not enumerating the modes first.
  1232. */
  1233. MemFree( pContext->lpModeList );
  1234. MemFree( pContext );
  1235. this_lcl->lpModeTestContext = NULL;
  1236. DPF_ERR( "Invalid mode specified in mode list" );
  1237. LEAVE_DDRAW();
  1238. return DDERR_INVALIDPARAMS;
  1239. }
  1240. /*
  1241. * Get the actual mode to test. For example, the app may want
  1242. * to test 320x240, 640x400, and 640x480, but we treat all of these
  1243. * modes the same so we only have to do a single test.
  1244. */
  1245. hr = GetModeToTest( lpModesToTest[i].cx,
  1246. lpModesToTest[i].cy,
  1247. &dwModeWidth,
  1248. &dwModeHeight );
  1249. if( hr != DD_OK )
  1250. {
  1251. // They are testing a mode higher the 1600x1200
  1252. continue;
  1253. }
  1254. for( j = 0; j < pContext->dwNumModes; j++ )
  1255. {
  1256. if( ( pContext->lpModeList[j].dwWidth == dwModeWidth ) &&
  1257. ( pContext->lpModeList[j].dwHeight == dwModeHeight ) )
  1258. {
  1259. break;
  1260. }
  1261. }
  1262. if( j < pContext->dwNumModes )
  1263. {
  1264. // Duplicate mode
  1265. continue;
  1266. }
  1267. if( !IsModeTested( this, dwModeWidth, dwModeHeight ) )
  1268. {
  1269. dwRefreshRate = GuestimateRefreshRate( this, dwModeWidth, dwModeHeight,
  1270. dwHighestRefresh, dwHighestBandwidth );
  1271. pContext->lpModeList[pContext->dwNumModes].dwWidth = dwModeWidth;
  1272. pContext->lpModeList[pContext->dwNumModes].dwHeight = dwModeHeight;
  1273. pContext->lpModeList[pContext->dwNumModes].dwBPP = dwLowestBPP;
  1274. pContext->lpModeList[pContext->dwNumModes].dwRefreshRate = dwRefreshRate;
  1275. pContext->dwNumModes++;
  1276. }
  1277. }
  1278. /*
  1279. * After all of that, do we still have any modes that need testing?
  1280. * If not, we can stop now
  1281. */
  1282. if( dwFlags & DDSMT_ISTESTREQUIRED )
  1283. {
  1284. hr = ( pContext->dwNumModes > 0 ) ? DDERR_NEWMODE : DDERR_TESTFINISHED;
  1285. MemFree( pContext->lpModeList );
  1286. MemFree( pContext );
  1287. this_lcl->lpModeTestContext = NULL;
  1288. }
  1289. else
  1290. {
  1291. pContext->dwOrigModeIndex = this->dwModeIndex;
  1292. hr = RunNextTest( lpDD, pContext );
  1293. }
  1294. LEAVE_DDRAW();
  1295. return hr;
  1296. #endif
  1297. }
  1298. /*
  1299. * DD_EvaluateMode
  1300. *
  1301. * Called at high frequency while the mode test is being performed. If the user has indicated
  1302. * that a mode succeeded or failed, we move on to the next moe in the test; otherwise, we will
  1303. * simply check the 15 second timeout value and fail the mode when we hit it..
  1304. */
  1305. HRESULT DDAPI DD_EvaluateMode( LPDIRECTDRAW7 lpDD, DWORD dwFlags, DWORD *pSecondsUntilTimeout)
  1306. {
  1307. #ifdef WIN95
  1308. LPDDRAWI_DIRECTDRAW_INT this_int;
  1309. LPDDRAWI_DIRECTDRAW_LCL this_lcl;
  1310. LPDDRAWI_DIRECTDRAW_GBL this;
  1311. BOOL excl_exists;
  1312. BOOL is_excl;
  1313. LPMODETESTCONTEXT pContext;
  1314. DWORD i;
  1315. DWORD j;
  1316. HRESULT hr = DD_OK;
  1317. DWORD dwTick;
  1318. ENTER_DDRAW();
  1319. #endif
  1320. DPF(2,A,"ENTERAPI: DD_EvaluateMode");
  1321. #ifdef WINNT
  1322. return DDERR_INVALIDPARAMS;
  1323. #else
  1324. TRY
  1325. {
  1326. this_int = (LPDDRAWI_DIRECTDRAW_INT) lpDD;
  1327. if( !VALID_DIRECTDRAW_PTR( this_int ) )
  1328. {
  1329. LEAVE_DDRAW();
  1330. return DDERR_INVALIDOBJECT;
  1331. }
  1332. this_lcl = this_int->lpLcl;
  1333. this = this_lcl->lpGbl;
  1334. if( this->lpMonitorInfo == NULL )
  1335. {
  1336. // There is no monitor info so we should not be here
  1337. LEAVE_DDRAW();
  1338. return DDERR_NOMONITORINFORMATION;
  1339. }
  1340. pContext = this_lcl->lpModeTestContext;
  1341. if( NULL == pContext )
  1342. {
  1343. DPF_ERR( "Must call StartModeTest before EvaulateMode" );
  1344. LEAVE_DDRAW();
  1345. return DDERR_INVALIDPARAMS;
  1346. }
  1347. if( ( NULL != pSecondsUntilTimeout ) &&
  1348. !VALID_BYTE_ARRAY( pSecondsUntilTimeout, sizeof( DWORD ) ) )
  1349. {
  1350. DPF_ERR( "Invalid pointer to timeout counter" );
  1351. LEAVE_DDRAW();
  1352. return DDERR_INVALIDPARAMS;
  1353. }
  1354. if( dwFlags & ~DDEM_VALID )
  1355. {
  1356. DPF_ERR( "Invalid Flags specified" );
  1357. LEAVE_DDRAW();
  1358. return DDERR_INVALIDPARAMS;
  1359. }
  1360. if( ( dwFlags & DDEM_MODEPASSED ) &&
  1361. ( dwFlags & DDEM_MODEFAILED ) )
  1362. {
  1363. DPF_ERR( "Invalid Flags specified" );
  1364. LEAVE_DDRAW();
  1365. return DDERR_INVALIDPARAMS;
  1366. }
  1367. /*
  1368. * If we lost exclusive mode, we should stop the test now
  1369. */
  1370. CheckExclusiveMode( this_lcl, &excl_exists, &is_excl, FALSE, NULL, FALSE);
  1371. if (!is_excl || !(this->dwFlags & DDRAWI_FULLSCREEN) )
  1372. {
  1373. DPF_ERR( "Exclusive mode lost" );
  1374. MemFree( pContext->lpModeList );
  1375. MemFree( pContext );
  1376. this_lcl->lpModeTestContext = NULL;
  1377. LEAVE_DDRAW();
  1378. return DDERR_TESTFINISHED;
  1379. }
  1380. }
  1381. EXCEPT( EXCEPTION_EXECUTE_HANDLER )
  1382. {
  1383. DPF_ERR( "Exception encountered validating parameters" );
  1384. LEAVE_DDRAW();
  1385. return DDERR_INVALIDPARAMS;
  1386. }
  1387. if( dwFlags & DDEM_MODEPASSED )
  1388. {
  1389. // The current data is good, so save it
  1390. UpdateMonitorInfo( this,
  1391. pContext->lpModeList[pContext->dwCurrentMode].dwWidth,
  1392. pContext->lpModeList[pContext->dwCurrentMode].dwHeight,
  1393. pContext->lpModeList[pContext->dwCurrentMode].dwRefreshRate );
  1394. // Move on to the next test, if there is one
  1395. pContext->dwCurrentMode++;
  1396. hr = RunNextTest( lpDD, pContext );
  1397. if( hr == DD_OK )
  1398. {
  1399. hr = DDERR_NEWMODE;
  1400. }
  1401. }
  1402. else
  1403. {
  1404. // Has our timeout expired?
  1405. dwTick = GetTickCount();
  1406. if( dwTick - pContext->dwTimeStamp > 15000 )
  1407. {
  1408. dwFlags |= DDEM_MODEFAILED;
  1409. }
  1410. if( dwFlags & DDEM_MODEFAILED )
  1411. {
  1412. // Drop down to the next refresh rate or the next mode
  1413. SetupNextTest( lpDD, pContext );
  1414. hr = RunNextTest( lpDD, pContext );
  1415. if( hr == DD_OK )
  1416. {
  1417. hr = DDERR_NEWMODE;
  1418. }
  1419. dwTick = GetTickCount();
  1420. }
  1421. }
  1422. if( pSecondsUntilTimeout != NULL )
  1423. {
  1424. if( hr == DDERR_TESTFINISHED )
  1425. {
  1426. *pSecondsUntilTimeout = 0;
  1427. }
  1428. else
  1429. {
  1430. *pSecondsUntilTimeout = 15 - ( ( dwTick - pContext->dwTimeStamp) / 1000 );
  1431. }
  1432. }
  1433. LEAVE_DDRAW();
  1434. return hr;
  1435. #endif
  1436. }
  1437. //
  1438. // This function is designed to allow DX7 apps to see some modes that would otherwise be
  1439. // incorrectly masked by the mode enumeration thing.
  1440. //
  1441. // If a driver exposes a list of modes with full-on refresh rates in EVERY entry in the mode table,
  1442. // then we will enum exactly NONE of them to the app, since any rate with a rate cannot be enumerated
  1443. // until the mode test has run. Apps that don't run the mode test will see NO modes at all.
  1444. //
  1445. // The s3 savage 4 is a case in point: it fills in the refresh rate for the current display mode,
  1446. // (and no other mode) and doesn't dupe the entry to one with a zero refresh rate.
  1447. //
  1448. // What we do is: every time we find an instance of a mode (size, bitdepth, masks) that has no
  1449. // zero-rate entry, we append a zero-rate entry to the end of the mode list.
  1450. //
  1451. //No need to massage on winNT
  1452. #ifdef WIN95
  1453. void MassageModeTable(LPDDRAWI_DIRECTDRAW_GBL pddd)
  1454. {
  1455. DWORD iMode, iCheckZero;
  1456. if( pddd->lpModeInfo != NULL )
  1457. {
  1458. RestartLoop:
  1459. for( iMode = 0; iMode < pddd->dwNumModes; iMode++ )
  1460. {
  1461. if (pddd->lpModeInfo[iMode].wRefreshRate != 0)
  1462. {
  1463. // Found a mode with non-zero rate. Check to see if the mode is also represented
  1464. // by a zero-rate entry. If it is not, then append such an entry
  1465. for( iCheckZero = 0; iCheckZero < pddd->dwNumModes; iCheckZero++ )
  1466. {
  1467. if( (pddd->lpModeInfo[iCheckZero].dwWidth == pddd->lpModeInfo[iMode].dwWidth) &&
  1468. (pddd->lpModeInfo[iCheckZero].dwHeight == pddd->lpModeInfo[iMode].dwHeight) &&
  1469. (pddd->lpModeInfo[iCheckZero].dwBPP == pddd->lpModeInfo[iMode].dwBPP) &&
  1470. (pddd->lpModeInfo[iCheckZero].dwRBitMask == pddd->lpModeInfo[iMode].dwRBitMask) &&
  1471. (pddd->lpModeInfo[iCheckZero].dwGBitMask == pddd->lpModeInfo[iMode].dwGBitMask) &&
  1472. (pddd->lpModeInfo[iCheckZero].dwBBitMask == pddd->lpModeInfo[iMode].dwBBitMask))
  1473. {
  1474. // found a matching mode, in terms of size and depth.
  1475. // If the refresh rate is zero, then we can break out and go on to the next iMode
  1476. if (pddd->lpModeInfo[iCheckZero].wRefreshRate == 0)
  1477. {
  1478. goto NextMode;
  1479. }
  1480. }
  1481. }
  1482. // If we got here, then there was no entry in the mode list for this size+depth
  1483. // that had a zero refresh rate. Append one now.
  1484. // Note how expanding the mode list like this means that if the driver (as it typically
  1485. // will) offers several rates for a given mode, we'll expand the table on the first
  1486. // hit of that mode, but then the expanded table will satisfy us for every subsequent
  1487. // rate of that mode (i.e. now there WILL be a zero-rated entry for that mode (since
  1488. // we just added it)).
  1489. {
  1490. LPDDHALMODEINFO pmi;
  1491. pmi = (LPDDHALMODEINFO) MemAlloc(sizeof(*pmi) * (pddd->dwNumModes+1));
  1492. if (pmi == NULL)
  1493. {
  1494. //oh just give up....
  1495. return;
  1496. }
  1497. memcpy(pmi, pddd->lpModeInfo, sizeof(*pmi)*pddd->dwNumModes );
  1498. MemFree(pddd->lpModeInfo);
  1499. pddd->lpModeInfo = pmi;
  1500. // Now put the zero-rated mode in there
  1501. memcpy( &pddd->lpModeInfo[pddd->dwNumModes], &pddd->lpModeInfo[iMode], sizeof(*pmi));
  1502. pddd->lpModeInfo[pddd->dwNumModes].wRefreshRate = 0;
  1503. pddd->lpModeInfo[pddd->dwNumModes].wFlags |= DDMODEINFO_DX7ONLY;
  1504. pddd->dwNumModes++;
  1505. //Now we have to restart the whole loop because we changed the lpModeInfo pointer:
  1506. goto RestartLoop;
  1507. }
  1508. }
  1509. NextMode:;
  1510. }
  1511. }
  1512. }
  1513. #endif //WIN95