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.

3331 lines
122 KiB

  1. //-----------------------------------------------------------------------------
  2. // File: D3DSaver.cpp
  3. //
  4. // Desc: Framework for screensavers that use Direct3D 8.0.
  5. //
  6. // Copyright (c) 2000-2001 Microsoft Corporation. All rights reserved.
  7. //-----------------------------------------------------------------------------
  8. #include <Windows.h>
  9. #include <windowsx.h>
  10. #include <commctrl.h>
  11. #include <stdio.h>
  12. #include <tchar.h>
  13. #include <regstr.h>
  14. #define COMPILE_MULTIMON_STUBS
  15. #include <multimon.h>
  16. #include <mmsystem.h>
  17. #include <D3DX8.h>
  18. #include "D3DSaver.h"
  19. #include "dxutil.h"
  20. // Resource IDs. D3DSaver assumes that you will create resources with
  21. // these IDs that it can use. The easiest way to do this is to copy
  22. // the resources from the rc file of an existing D3DSaver-based program.
  23. #define IDI_MAIN_ICON 101
  24. #define IDD_SINGLEMONITORSETTINGS 200
  25. #define IDD_MULTIMONITORSETTINGS 201
  26. #define IDC_MONITORSTAB 2000
  27. #define IDC_TABNAMEFMT 2001
  28. #define IDC_ADAPTERNAME 2002
  29. #define IDC_RENDERING 2003
  30. #define IDC_MOREINFO 2004
  31. #define IDC_DISABLEHW 2005
  32. #define IDC_SCREENUSAGEBOX 2006
  33. #define IDC_RENDER 2007
  34. #define IDC_LEAVEBLACK 2008
  35. #define IDC_DISPLAYMODEBOX 2009
  36. #define IDC_MODESSTATIC 2010
  37. #define IDC_MODESCOMBO 2011
  38. #define IDC_AUTOMATIC 2012
  39. #define IDC_DISPLAYMODENOTE 2013
  40. #define IDC_GENERALBOX 2014
  41. #define IDC_SAME 2015
  42. #define IDC_MODEFMT 2016
  43. #define IDS_ERR_GENERIC 2100
  44. #define IDS_ERR_NODIRECT3D 2101
  45. #define IDS_ERR_NOWINDOWEDHAL 2102
  46. #define IDS_ERR_CREATEDEVICEFAILED 2103
  47. #define IDS_ERR_NOCOMPATIBLEDEVICES 2104
  48. #define IDS_ERR_NOHARDWAREDEVICE 2105
  49. #define IDS_ERR_HALNOTCOMPATIBLE 2106
  50. #define IDS_ERR_NOHALTHISMODE 2107
  51. #define IDS_ERR_MEDIANOTFOUND 2108
  52. #define IDS_ERR_RESIZEFAILED 2109
  53. #define IDS_ERR_OUTOFMEMORY 2110
  54. #define IDS_ERR_OUTOFVIDEOMEMORY 2111
  55. #define IDS_ERR_NOPREVIEW 2112
  56. #define IDS_INFO_GOODHAL 2200
  57. #define IDS_INFO_BADHAL_GOODSW 2201
  58. #define IDS_INFO_BADHAL_BADSW 2202
  59. #define IDS_INFO_BADHAL_NOSW 2203
  60. #define IDS_INFO_NOHAL_GOODSW 2204
  61. #define IDS_INFO_NOHAL_BADSW 2205
  62. #define IDS_INFO_NOHAL_NOSW 2206
  63. #define IDS_INFO_DISABLEDHAL_GOODSW 2207
  64. #define IDS_INFO_DISABLEDHAL_BADSW 2208
  65. #define IDS_INFO_DISABLEDHAL_NOSW 2209
  66. #define IDS_RENDERING_HAL 2210
  67. #define IDS_RENDERING_SW 2211
  68. #define IDS_RENDERING_NONE 2212
  69. // Use the following structure rather than DISPLAY_DEVICE, since some old
  70. // versions of DISPLAY_DEVICE are missing the last two fields and this can
  71. // cause problems with EnumDisplayDevices on Windows 2000.
  72. struct DISPLAY_DEVICE_FULL
  73. {
  74. DWORD cb;
  75. TCHAR DeviceName[32];
  76. TCHAR DeviceString[128];
  77. DWORD StateFlags;
  78. TCHAR DeviceID[128];
  79. TCHAR DeviceKey[128];
  80. };
  81. static CD3DScreensaver* s_pD3DScreensaver = NULL;
  82. //-----------------------------------------------------------------------------
  83. // Name: CD3DScreensaver()
  84. // Desc: Constructor
  85. //-----------------------------------------------------------------------------
  86. CD3DScreensaver::CD3DScreensaver()
  87. {
  88. s_pD3DScreensaver = this;
  89. m_bCheckingSaverPassword = FALSE;
  90. m_bIs9x = FALSE;
  91. m_dwSaverMouseMoveCount = 0;
  92. m_hWndParent = NULL;
  93. m_hPasswordDLL = NULL;
  94. m_hWnd = NULL;
  95. m_VerifySaverPassword = NULL;
  96. m_bAllScreensSame = FALSE;
  97. m_pD3D = NULL;
  98. m_pd3dDevice = NULL;
  99. m_bWindowed = FALSE;
  100. m_bWaitForInputIdle = FALSE;
  101. m_bErrorMode = FALSE;
  102. m_hrError = S_OK;
  103. m_szError[0] = TEXT('\0');
  104. m_fFPS = 0.0f;
  105. m_strDeviceStats[0] = TEXT('\0');
  106. m_strFrameStats[0] = TEXT('\0');
  107. // Note: clients should load a resource into m_strWindowTitle to localize this string
  108. lstrcpy( m_strWindowTitle, TEXT("Screen Saver") );
  109. m_bAllowRef = FALSE;
  110. m_bUseDepthBuffer = FALSE;
  111. m_bMultithreaded = FALSE;
  112. m_bOneScreenOnly = FALSE;
  113. m_strRegPath[0] = TEXT('\0');
  114. m_dwMinDepthBits = 16;
  115. m_dwMinStencilBits = 0;
  116. m_SwapEffectFullscreen = D3DSWAPEFFECT_DISCARD;
  117. m_SwapEffectWindowed = D3DSWAPEFFECT_COPY_VSYNC;
  118. SetRectEmpty( &m_rcRenderTotal );
  119. SetRectEmpty( &m_rcRenderCurDevice );
  120. ZeroMemory( m_Monitors, sizeof(m_Monitors) );
  121. m_dwNumMonitors = 0;
  122. ZeroMemory( m_Adapters, sizeof(m_Adapters) );
  123. m_dwNumAdapters = 0;
  124. ZeroMemory( m_RenderUnits, sizeof(m_RenderUnits) );
  125. m_dwNumRenderUnits = 0;
  126. m_fTime = 0.0f;
  127. }
  128. //-----------------------------------------------------------------------------
  129. // Name: Create()
  130. // Desc: Have the client program call this function before calling Run().
  131. //-----------------------------------------------------------------------------
  132. HRESULT CD3DScreensaver::Create( HINSTANCE hInstance )
  133. {
  134. HRESULT hr;
  135. SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_IDLE );
  136. m_hInstance = hInstance;
  137. // Parse the command line and do the appropriate thing
  138. TCHAR* pstrCmdLine = GetCommandLine();
  139. m_SaverMode = ParseCommandLine( pstrCmdLine );
  140. EnumMonitors();
  141. // Create the screen saver window(s)
  142. if( m_SaverMode == sm_preview ||
  143. m_SaverMode == sm_test ||
  144. m_SaverMode == sm_full )
  145. {
  146. if( FAILED( hr = CreateSaverWindow() ) )
  147. {
  148. m_bErrorMode = TRUE;
  149. m_hrError = hr;
  150. }
  151. }
  152. if( m_SaverMode == sm_preview )
  153. {
  154. // In preview mode, "pause" (enter a limited message loop) briefly
  155. // before proceeding, so the display control panel knows to update itself.
  156. m_bWaitForInputIdle = TRUE;
  157. // Post a message to mark the end of the initial group of window messages
  158. PostMessage( m_hWnd, WM_USER, 0, 0 );
  159. MSG msg;
  160. while( m_bWaitForInputIdle )
  161. {
  162. // If GetMessage returns FALSE, it's quitting time.
  163. if( !GetMessage( &msg, m_hWnd, 0, 0 ) )
  164. {
  165. // Post the quit message to handle it later
  166. PostQuitMessage(0);
  167. break;
  168. }
  169. TranslateMessage( &msg );
  170. DispatchMessage( &msg );
  171. }
  172. }
  173. // Create Direct3D object
  174. if( (m_pD3D = Direct3DCreate8( D3D_SDK_VERSION ) ) == NULL )
  175. {
  176. m_bErrorMode = TRUE;
  177. m_hrError = D3DAPPERR_NODIRECT3D;
  178. return S_OK;
  179. }
  180. // Give the app the opportunity to register a pluggable SW D3D Device.
  181. if( FAILED( hr = RegisterSoftwareDevice() ) )
  182. {
  183. m_bErrorMode = TRUE;
  184. m_hrError = hr;
  185. return S_OK;
  186. }
  187. // Build a list of Direct3D adapters, modes and devices. The
  188. // ConfirmDevice() callback is used to confirm that only devices that
  189. // meet the app's requirements are considered.
  190. if( FAILED( hr = BuildDeviceList() ) )
  191. {
  192. m_bErrorMode = TRUE;
  193. m_hrError = hr;
  194. return S_OK;
  195. }
  196. // Make sure that at least one valid usable D3D device was found
  197. BOOL bCompatibleDeviceFound = FALSE;
  198. for( DWORD iAdapter = 0; iAdapter < m_dwNumAdapters; iAdapter++ )
  199. {
  200. if( m_Adapters[iAdapter]->bHasAppCompatHAL ||
  201. m_Adapters[iAdapter]->bHasAppCompatSW )
  202. {
  203. bCompatibleDeviceFound = TRUE;
  204. break;
  205. }
  206. }
  207. if( !bCompatibleDeviceFound )
  208. {
  209. m_bErrorMode = TRUE;
  210. m_hrError = D3DAPPERR_NOCOMPATIBLEDEVICES;
  211. return S_OK;
  212. }
  213. // Read any settings we need
  214. ReadSettings();
  215. return S_OK;
  216. }
  217. //-----------------------------------------------------------------------------
  218. // Name: EnumMonitors()
  219. // Desc: Determine HMONITOR, desktop rect, and other info for each monitor.
  220. // Note that EnumDisplayDevices enumerates monitors in the order
  221. // indicated on the Settings page of the Display control panel, which
  222. // is the order we want to list monitors in, as opposed to the order
  223. // used by D3D's GetAdapterInfo.
  224. //-----------------------------------------------------------------------------
  225. VOID CD3DScreensaver::EnumMonitors( VOID )
  226. {
  227. DWORD iDevice = 0;
  228. DISPLAY_DEVICE_FULL dispdev;
  229. DISPLAY_DEVICE_FULL dispdev2;
  230. DEVMODE devmode;
  231. dispdev.cb = sizeof(dispdev);
  232. dispdev2.cb = sizeof(dispdev2);
  233. devmode.dmSize = sizeof(devmode);
  234. devmode.dmDriverExtra = 0;
  235. MonitorInfo* pMonitorInfoNew;
  236. while( EnumDisplayDevices(NULL, iDevice, (DISPLAY_DEVICE*)&dispdev, 0) )
  237. {
  238. // Ignore NetMeeting's mirrored displays
  239. if( (dispdev.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) == 0 )
  240. {
  241. // To get monitor info for a display device, call EnumDisplayDevices
  242. // a second time, passing dispdev.DeviceName (from the first call) as
  243. // the first parameter.
  244. EnumDisplayDevices(dispdev.DeviceName, 0, (DISPLAY_DEVICE*)&dispdev2, 0);
  245. pMonitorInfoNew = &m_Monitors[m_dwNumMonitors];
  246. ZeroMemory( pMonitorInfoNew, sizeof(MonitorInfo) );
  247. lstrcpy( pMonitorInfoNew->strDeviceName, dispdev.DeviceString );
  248. lstrcpy( pMonitorInfoNew->strMonitorName, dispdev2.DeviceString );
  249. pMonitorInfoNew->iAdapter = NO_ADAPTER;
  250. if( dispdev.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP )
  251. {
  252. EnumDisplaySettings( dispdev.DeviceName, ENUM_CURRENT_SETTINGS, &devmode );
  253. if( dispdev.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE )
  254. {
  255. // For some reason devmode.dmPosition is not always (0, 0)
  256. // for the primary display, so force it.
  257. pMonitorInfoNew->rcScreen.left = 0;
  258. pMonitorInfoNew->rcScreen.top = 0;
  259. }
  260. else
  261. {
  262. pMonitorInfoNew->rcScreen.left = devmode.dmPosition.x;
  263. pMonitorInfoNew->rcScreen.top = devmode.dmPosition.y;
  264. }
  265. pMonitorInfoNew->rcScreen.right = pMonitorInfoNew->rcScreen.left + devmode.dmPelsWidth;
  266. pMonitorInfoNew->rcScreen.bottom = pMonitorInfoNew->rcScreen.top + devmode.dmPelsHeight;
  267. pMonitorInfoNew->hMonitor = MonitorFromRect( &pMonitorInfoNew->rcScreen, MONITOR_DEFAULTTONULL );
  268. }
  269. m_dwNumMonitors++;
  270. if( m_dwNumMonitors == MAX_DISPLAYS )
  271. break;
  272. }
  273. iDevice++;
  274. }
  275. }
  276. //-----------------------------------------------------------------------------
  277. // Name: Run()
  278. // Desc: Starts main execution of the screen saver.
  279. //-----------------------------------------------------------------------------
  280. INT CD3DScreensaver::Run()
  281. {
  282. HRESULT hr;
  283. // Parse the command line and do the appropriate thing
  284. switch ( m_SaverMode )
  285. {
  286. case sm_config:
  287. {
  288. if( m_bErrorMode )
  289. {
  290. DisplayErrorMsg( m_hrError, 0 );
  291. }
  292. else
  293. {
  294. DoConfig();
  295. }
  296. break;
  297. }
  298. case sm_preview:
  299. case sm_test:
  300. case sm_full:
  301. {
  302. if( FAILED( hr = DoSaver() ) )
  303. DisplayErrorMsg( hr, 0 );
  304. break;
  305. }
  306. case sm_passwordchange:
  307. {
  308. ChangePassword();
  309. break;
  310. }
  311. }
  312. for( DWORD iAdapter = 0; iAdapter < m_dwNumAdapters; iAdapter++ )
  313. SAFE_DELETE( m_Adapters[iAdapter] );
  314. SAFE_RELEASE( m_pD3D );
  315. return 0;
  316. }
  317. //-----------------------------------------------------------------------------
  318. // Name: ParseCommandLine()
  319. // Desc: Interpret command-line parameters passed to this app.
  320. //-----------------------------------------------------------------------------
  321. SaverMode CD3DScreensaver::ParseCommandLine( TCHAR* pstrCommandLine )
  322. {
  323. m_hWndParent = NULL;
  324. // Skip the first part of the command line, which is the full path
  325. // to the exe. If it contains spaces, it will be contained in quotes.
  326. if (*pstrCommandLine == TEXT('\"'))
  327. {
  328. pstrCommandLine++;
  329. while (*pstrCommandLine != TEXT('\0') && *pstrCommandLine != TEXT('\"'))
  330. pstrCommandLine++;
  331. if( *pstrCommandLine == TEXT('\"') )
  332. pstrCommandLine++;
  333. }
  334. else
  335. {
  336. while (*pstrCommandLine != TEXT('\0') && *pstrCommandLine != TEXT(' '))
  337. pstrCommandLine++;
  338. if( *pstrCommandLine == TEXT(' ') )
  339. pstrCommandLine++;
  340. }
  341. // Skip along to the first option delimiter "/" or "-"
  342. while ( *pstrCommandLine != TEXT('\0') && *pstrCommandLine != TEXT('/') && *pstrCommandLine != TEXT('-') )
  343. pstrCommandLine++;
  344. // If there wasn't one, then must be config mode
  345. if ( *pstrCommandLine == TEXT('\0') )
  346. return sm_config;
  347. // Otherwise see what the option was
  348. switch ( *(++pstrCommandLine) )
  349. {
  350. case 'c':
  351. case 'C':
  352. pstrCommandLine++;
  353. while ( *pstrCommandLine && !isdigit(*pstrCommandLine) )
  354. pstrCommandLine++;
  355. if ( isdigit(*pstrCommandLine) )
  356. {
  357. #ifdef _WIN64
  358. CHAR strCommandLine[2048];
  359. DXUtil_ConvertGenericStringToAnsi(strCommandLine, pstrCommandLine, 2048);
  360. m_hWndParent = HWND(_atoi64(strCommandLine));
  361. #else
  362. m_hWndParent = HWND(_ttol(pstrCommandLine));
  363. #endif
  364. }
  365. else
  366. {
  367. m_hWndParent = NULL;
  368. }
  369. return sm_config;
  370. case 't':
  371. case 'T':
  372. return sm_test;
  373. case 'p':
  374. case 'P':
  375. // Preview-mode, so option is followed by the parent HWND in decimal
  376. pstrCommandLine++;
  377. while ( *pstrCommandLine && !isdigit(*pstrCommandLine) )
  378. pstrCommandLine++;
  379. if ( isdigit(*pstrCommandLine) )
  380. {
  381. #ifdef _WIN64
  382. CHAR strCommandLine[2048];
  383. DXUtil_ConvertGenericStringToAnsi(strCommandLine, pstrCommandLine, 2048);
  384. m_hWndParent = HWND(_atoi64(strCommandLine));
  385. #else
  386. m_hWndParent = HWND(_ttol(pstrCommandLine));
  387. #endif
  388. }
  389. return sm_preview;
  390. case 'a':
  391. case 'A':
  392. // Password change mode, so option is followed by parent HWND in decimal
  393. pstrCommandLine++;
  394. while ( *pstrCommandLine && !isdigit(*pstrCommandLine) )
  395. pstrCommandLine++;
  396. if ( isdigit(*pstrCommandLine) )
  397. {
  398. #ifdef _WIN64
  399. CHAR strCommandLine[2048];
  400. DXUtil_ConvertGenericStringToAnsi(strCommandLine, pstrCommandLine, 2048);
  401. m_hWndParent = HWND(_atoi64(strCommandLine));
  402. #else
  403. m_hWndParent = HWND(_ttol(pstrCommandLine));
  404. #endif
  405. }
  406. return sm_passwordchange;
  407. default:
  408. // All other options => run the screensaver (typically this is "/s")
  409. return sm_full;
  410. }
  411. }
  412. //-----------------------------------------------------------------------------
  413. // Name: CreateSaverWindow
  414. // Desc: Register and create the appropriate window(s)
  415. //-----------------------------------------------------------------------------
  416. HRESULT CD3DScreensaver::CreateSaverWindow()
  417. {
  418. /*
  419. // Uncomment this code to allow stepping thru code in the preview case
  420. if( m_SaverMode == sm_preview )
  421. {
  422. WNDCLASS cls;
  423. cls.hCursor = NULL;
  424. cls.hIcon = NULL;
  425. cls.lpszMenuName = NULL;
  426. cls.lpszClassName = TEXT("Parent");
  427. cls.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
  428. cls.hInstance = m_hInstance;
  429. cls.style = CS_VREDRAW|CS_HREDRAW|CS_SAVEBITS|CS_DBLCLKS;
  430. cls.lpfnWndProc = DefWindowProc;
  431. cls.cbWndExtra = 0;
  432. cls.cbClsExtra = 0;
  433. RegisterClass( &cls );
  434. // Create the window
  435. RECT rect;
  436. HWND hwnd;
  437. rect.left = rect.top = 40;
  438. rect.right = rect.left+200;
  439. rect.bottom = rect.top+200;
  440. AdjustWindowRect( &rect, WS_VISIBLE|WS_OVERLAPPED|WS_CAPTION|WS_POPUP, FALSE );
  441. hwnd = CreateWindow( TEXT("Parent"), TEXT("FakeShell"),
  442. WS_VISIBLE|WS_OVERLAPPED|WS_CAPTION|WS_POPUP, rect.left, rect.top,
  443. rect.right-rect.left, rect.bottom-rect.top, NULL,
  444. NULL, m_hInstance, NULL );
  445. m_hWndParent = hwnd;
  446. }
  447. */
  448. // Register an appropriate window class
  449. WNDCLASS cls;
  450. cls.hCursor = LoadCursor( NULL, IDC_ARROW );
  451. cls.hIcon = LoadIcon( m_hInstance, MAKEINTRESOURCE(IDI_MAIN_ICON) );
  452. cls.lpszMenuName = NULL;
  453. cls.lpszClassName = TEXT("D3DSaverWndClass");
  454. cls.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
  455. cls.hInstance = m_hInstance;
  456. cls.style = CS_VREDRAW|CS_HREDRAW;
  457. cls.lpfnWndProc = SaverProcStub;
  458. cls.cbWndExtra = 0;
  459. cls.cbClsExtra = 0;
  460. RegisterClass( &cls );
  461. // Create the window
  462. RECT rc;
  463. DWORD dwStyle;
  464. switch ( m_SaverMode )
  465. {
  466. case sm_preview:
  467. GetClientRect( m_hWndParent, &rc );
  468. dwStyle = WS_VISIBLE | WS_CHILD;
  469. AdjustWindowRect( &rc, dwStyle, FALSE );
  470. m_hWnd = CreateWindow( TEXT("D3DSaverWndClass"), m_strWindowTitle, dwStyle,
  471. rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top,
  472. m_hWndParent, NULL, m_hInstance, this );
  473. m_Monitors[0].hWnd = m_hWnd;
  474. GetClientRect( m_hWnd, &m_rcRenderTotal );
  475. GetClientRect( m_hWnd, &m_rcRenderCurDevice );
  476. break;
  477. case sm_test:
  478. rc.left = rc.top = 50;
  479. rc.right = rc.left+600;
  480. rc.bottom = rc.top+400;
  481. dwStyle = WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU;
  482. AdjustWindowRect( &rc, dwStyle, FALSE );
  483. m_hWnd = CreateWindow( TEXT("D3DSaverWndClass"), m_strWindowTitle, dwStyle,
  484. rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top,
  485. NULL, NULL, m_hInstance, this );
  486. m_Monitors[0].hWnd = m_hWnd;
  487. GetClientRect( m_hWnd, &m_rcRenderTotal );
  488. GetClientRect( m_hWnd, &m_rcRenderCurDevice );
  489. break;
  490. case sm_full:
  491. // Create windows for each monitor. Note that m_hWnd is NULL when CreateWindowEx
  492. // is called for the first monitor, so that window has no parent. Windows for
  493. // additional monitors are created as children of the window for the first monitor.
  494. dwStyle = WS_VISIBLE | WS_POPUP;
  495. m_hWnd = NULL;
  496. for( DWORD iMonitor = 0; iMonitor < m_dwNumMonitors; iMonitor++ )
  497. {
  498. MonitorInfo* pMonitorInfo;
  499. pMonitorInfo = &m_Monitors[iMonitor];
  500. if( pMonitorInfo->hMonitor == NULL )
  501. continue;
  502. rc = pMonitorInfo->rcScreen;
  503. pMonitorInfo->hWnd = CreateWindowEx( WS_EX_TOPMOST, TEXT("D3DSaverWndClass"),
  504. m_strWindowTitle, dwStyle, rc.left, rc.top, rc.right - rc.left,
  505. rc.bottom - rc.top, m_hWnd, NULL, m_hInstance, this );
  506. if( pMonitorInfo->hWnd == NULL )
  507. return E_FAIL;
  508. if( m_hWnd == NULL )
  509. m_hWnd = pMonitorInfo->hWnd;
  510. }
  511. }
  512. if ( m_hWnd == NULL )
  513. return E_FAIL;
  514. return S_OK;
  515. }
  516. //-----------------------------------------------------------------------------
  517. // Name: DoSaver()
  518. // Desc: Run the screensaver graphics - may be preview, test or full-on mode
  519. //-----------------------------------------------------------------------------
  520. HRESULT CD3DScreensaver::DoSaver()
  521. {
  522. HRESULT hr;
  523. // Figure out if we're on Win9x
  524. OSVERSIONINFO osvi;
  525. osvi.dwOSVersionInfoSize = sizeof(osvi);
  526. GetVersionEx( &osvi );
  527. m_bIs9x = (osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
  528. // If we're in full on mode, and on 9x, then need to load the password DLL
  529. if ( m_SaverMode == sm_full && m_bIs9x )
  530. {
  531. // Only do this if the password is set - check registry:
  532. HKEY hKey;
  533. if ( RegOpenKey( HKEY_CURRENT_USER , REGSTR_PATH_SCREENSAVE , &hKey ) == ERROR_SUCCESS )
  534. {
  535. DWORD dwVal;
  536. DWORD dwSize = sizeof(dwVal);
  537. if ( (RegQueryValueEx( hKey, REGSTR_VALUE_USESCRPASSWORD, NULL, NULL,
  538. (BYTE *)&dwVal, &dwSize ) == ERROR_SUCCESS) && dwVal )
  539. {
  540. m_hPasswordDLL = LoadLibrary( TEXT("PASSWORD.CPL") );
  541. if ( m_hPasswordDLL )
  542. m_VerifySaverPassword = (VERIFYPWDPROC)GetProcAddress( m_hPasswordDLL, "VerifyScreenSavePwd" );
  543. RegCloseKey( hKey );
  544. }
  545. }
  546. }
  547. // Initialize the application timer
  548. DXUtil_Timer( TIMER_START );
  549. if( !m_bErrorMode )
  550. {
  551. // Initialize the app's custom scene stuff
  552. if( FAILED( hr = OneTimeSceneInit() ) )
  553. return DisplayErrorMsg( hr, MSGERR_APPMUSTEXIT );
  554. // Do graphical init stuff
  555. if ( FAILED(hr = Initialize3DEnvironment()) )
  556. return hr;
  557. }
  558. // Flag as screensaver running if in full on mode
  559. if ( m_SaverMode == sm_full )
  560. {
  561. BOOL bUnused;
  562. SystemParametersInfo( SPI_SCREENSAVERRUNNING, TRUE, &bUnused, 0 );
  563. }
  564. // Message pump
  565. BOOL bGotMsg;
  566. MSG msg;
  567. msg.message = WM_NULL;
  568. while ( msg.message != WM_QUIT )
  569. {
  570. bGotMsg = PeekMessage( &msg, NULL, 0, 0, PM_REMOVE );
  571. if( bGotMsg )
  572. {
  573. TranslateMessage( &msg );
  574. DispatchMessage( &msg );
  575. }
  576. else
  577. {
  578. Sleep(10);
  579. if( m_bErrorMode )
  580. {
  581. UpdateErrorBox();
  582. }
  583. else
  584. {
  585. Render3DEnvironment();
  586. }
  587. }
  588. }
  589. return S_OK;
  590. }
  591. //-----------------------------------------------------------------------------
  592. // Name: ShutdownSaver()
  593. // Desc:
  594. //-----------------------------------------------------------------------------
  595. VOID CD3DScreensaver::ShutdownSaver()
  596. {
  597. // Unflag screensaver running if in full on mode
  598. if ( m_SaverMode == sm_full )
  599. {
  600. BOOL bUnused;
  601. SystemParametersInfo( SPI_SCREENSAVERRUNNING, FALSE, &bUnused, 0 );
  602. }
  603. // Kill graphical stuff
  604. Cleanup3DEnvironment();
  605. // Let client app clean up its resources
  606. FinalCleanup();
  607. // Unload the password DLL (if we loaded it)
  608. if ( m_hPasswordDLL != NULL )
  609. {
  610. FreeLibrary( m_hPasswordDLL );
  611. m_hPasswordDLL = NULL;
  612. }
  613. // Post message to drop out of message loop
  614. PostQuitMessage( 0 );
  615. }
  616. //-----------------------------------------------------------------------------
  617. // Name: SaverProcStub()
  618. // Desc: This function forwards all window messages to SaverProc, which has
  619. // access to the "this" pointer.
  620. //-----------------------------------------------------------------------------
  621. LRESULT CALLBACK CD3DScreensaver::SaverProcStub( HWND hWnd, UINT uMsg,
  622. WPARAM wParam, LPARAM lParam )
  623. {
  624. return s_pD3DScreensaver->SaverProc( hWnd, uMsg, wParam, lParam );
  625. }
  626. //-----------------------------------------------------------------------------
  627. // Name: SaverProc()
  628. // Desc: Handle window messages for main screensaver windows (one per screen).
  629. //-----------------------------------------------------------------------------
  630. LRESULT CD3DScreensaver::SaverProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
  631. {
  632. switch ( uMsg )
  633. {
  634. case WM_USER:
  635. // All initialization messages have gone through. Allow
  636. // 500ms of idle time, then proceed with initialization.
  637. SetTimer( hWnd, 1, 500, NULL );
  638. break;
  639. case WM_TIMER:
  640. // Initial idle time is done, proceed with initialization.
  641. m_bWaitForInputIdle = FALSE;
  642. KillTimer( hWnd, 1 );
  643. break;
  644. case WM_DESTROY:
  645. if( m_SaverMode == sm_preview || m_SaverMode == sm_test )
  646. ShutdownSaver();
  647. break;
  648. case WM_SETCURSOR:
  649. if ( m_SaverMode == sm_full && !m_bCheckingSaverPassword )
  650. {
  651. // Hide cursor
  652. SetCursor( NULL );
  653. return TRUE;
  654. }
  655. break;
  656. case WM_PAINT:
  657. {
  658. // Show error message, if there is one
  659. PAINTSTRUCT ps;
  660. BeginPaint( hWnd, &ps );
  661. // In preview mode, just fill
  662. // the preview window with black.
  663. if( !m_bErrorMode && m_SaverMode == sm_preview )
  664. {
  665. RECT rc;
  666. GetClientRect(hWnd,&rc);
  667. HBRUSH hbrBlack = (HBRUSH)GetStockObject(BLACK_BRUSH);
  668. if( hbrBlack != NULL )
  669. FillRect(ps.hdc, &rc, hbrBlack );
  670. }
  671. else
  672. {
  673. DoPaint( hWnd, ps.hdc );
  674. }
  675. EndPaint( hWnd, &ps );
  676. return 0;
  677. }
  678. case WM_ERASEBKGND:
  679. // Erase background if checking password or if window is not
  680. // assigned to a render unit
  681. if( !m_bCheckingSaverPassword )
  682. {
  683. RenderUnit* pRenderUnit;
  684. D3DAdapterInfo* pD3DAdapterInfo;
  685. for( DWORD iRenderUnit = 0; iRenderUnit < m_dwNumRenderUnits; iRenderUnit++ )
  686. {
  687. pRenderUnit = &m_RenderUnits[iRenderUnit];
  688. pD3DAdapterInfo = m_Adapters[pRenderUnit->iAdapter];
  689. if( pD3DAdapterInfo->hWndDevice == hWnd )
  690. return TRUE; // don't erase this window
  691. }
  692. }
  693. break;
  694. case WM_MOUSEMOVE:
  695. if( m_SaverMode != sm_test )
  696. {
  697. static INT xPrev = -1;
  698. static INT yPrev = -1;
  699. INT xCur = GET_X_LPARAM(lParam);
  700. INT yCur = GET_Y_LPARAM(lParam);
  701. if( xCur != xPrev || yCur != yPrev )
  702. {
  703. xPrev = xCur;
  704. yPrev = yCur;
  705. m_dwSaverMouseMoveCount++;
  706. if ( m_dwSaverMouseMoveCount > 5 )
  707. InterruptSaver();
  708. }
  709. }
  710. break;
  711. case WM_KEYDOWN:
  712. case WM_LBUTTONDOWN:
  713. case WM_RBUTTONDOWN:
  714. case WM_MBUTTONDOWN:
  715. if( m_SaverMode != sm_test )
  716. InterruptSaver();
  717. break;
  718. case WM_ACTIVATEAPP:
  719. if( wParam == FALSE && m_SaverMode != sm_test )
  720. InterruptSaver();
  721. break;
  722. case WM_POWERBROADCAST:
  723. if( wParam == PBT_APMSUSPEND && m_VerifySaverPassword == NULL )
  724. InterruptSaver();
  725. break;
  726. case WM_SYSCOMMAND:
  727. if ( m_SaverMode == sm_full )
  728. {
  729. switch ( wParam )
  730. {
  731. case SC_NEXTWINDOW:
  732. case SC_PREVWINDOW:
  733. case SC_SCREENSAVE:
  734. case SC_CLOSE:
  735. return FALSE;
  736. break;
  737. case SC_MONITORPOWER:
  738. //
  739. // The monitor is shutting down. Tell our client that he needs to
  740. // cleanup and exit.
  741. //
  742. InterruptSaver();
  743. break;
  744. };
  745. }
  746. break;
  747. }
  748. return DefWindowProc( hWnd, uMsg, wParam, lParam );
  749. }
  750. //-----------------------------------------------------------------------------
  751. // Name: InterruptSaver()
  752. // Desc: A message was received (mouse move, keydown, etc.) that may mean
  753. // the screen saver should show the password dialog and/or shut down.
  754. //-----------------------------------------------------------------------------
  755. VOID CD3DScreensaver::InterruptSaver()
  756. {
  757. HRESULT hr;
  758. DWORD iRenderUnit;
  759. RenderUnit* pRenderUnit;
  760. BOOL bPasswordOkay = FALSE;
  761. if( m_SaverMode == sm_test ||
  762. m_SaverMode == sm_full && !m_bCheckingSaverPassword )
  763. {
  764. if( m_bIs9x && m_SaverMode == sm_full )
  765. {
  766. // If no VerifyPassword function, then no password is set
  767. // or we're not on 9x.
  768. if ( m_VerifySaverPassword != NULL )
  769. {
  770. // Shut down all D3D devices so we can show a Windows dialog
  771. for( iRenderUnit = 0; iRenderUnit < m_dwNumRenderUnits; iRenderUnit++ )
  772. {
  773. pRenderUnit = &m_RenderUnits[iRenderUnit];
  774. SwitchToRenderUnit(iRenderUnit);
  775. if( pRenderUnit->bDeviceObjectsRestored )
  776. {
  777. InvalidateDeviceObjects();
  778. pRenderUnit->bDeviceObjectsRestored = FALSE;
  779. }
  780. if( pRenderUnit->bDeviceObjectsInited )
  781. {
  782. DeleteDeviceObjects();
  783. pRenderUnit->bDeviceObjectsInited = FALSE;
  784. }
  785. SAFE_RELEASE(pRenderUnit->pd3dDevice);
  786. }
  787. // Make sure all adapter windows cover the whole screen,
  788. // even after deleting D3D devices (which may have caused
  789. // mode changes)
  790. D3DAdapterInfo* pD3DAdapterInfo;
  791. for( DWORD iAdapter = 0; iAdapter < m_dwNumAdapters; iAdapter++ )
  792. {
  793. pD3DAdapterInfo = m_Adapters[iAdapter];
  794. ShowWindow( pD3DAdapterInfo->hWndDevice, SW_RESTORE );
  795. ShowWindow( pD3DAdapterInfo->hWndDevice, SW_MAXIMIZE );
  796. }
  797. m_bCheckingSaverPassword = TRUE;
  798. bPasswordOkay = m_VerifySaverPassword( m_hWnd );
  799. m_bCheckingSaverPassword = FALSE;
  800. if ( bPasswordOkay )
  801. {
  802. // D3D devices are all torn down, so it's safe
  803. // to discard all render units now (so we don't
  804. // try to clean them up again later).
  805. m_dwNumRenderUnits = 0;
  806. }
  807. else
  808. {
  809. // Back to screen saving...
  810. SetCursor( NULL );
  811. m_dwSaverMouseMoveCount = 0;
  812. // Recreate all D3D devices
  813. for( iRenderUnit = 0; iRenderUnit < m_dwNumRenderUnits; iRenderUnit++ )
  814. {
  815. pRenderUnit = &m_RenderUnits[iRenderUnit];
  816. hr = m_pD3D->CreateDevice(pRenderUnit->iAdapter,
  817. pRenderUnit->DeviceType, m_hWnd,
  818. pRenderUnit->dwBehavior, &pRenderUnit->d3dpp,
  819. &pRenderUnit->pd3dDevice );
  820. if( FAILED( hr ) )
  821. {
  822. m_bErrorMode = TRUE;
  823. m_hrError = D3DAPPERR_CREATEDEVICEFAILED;
  824. }
  825. else
  826. {
  827. SwitchToRenderUnit(iRenderUnit);
  828. if( FAILED(hr = InitDeviceObjects() ) )
  829. {
  830. m_bErrorMode = TRUE;
  831. m_hrError = D3DAPPERR_INITDEVICEOBJECTSFAILED;
  832. }
  833. else
  834. {
  835. pRenderUnit->bDeviceObjectsInited = TRUE;
  836. if( FAILED(hr = RestoreDeviceObjects() ) )
  837. {
  838. m_bErrorMode = TRUE;
  839. m_hrError = D3DAPPERR_INITDEVICEOBJECTSFAILED;
  840. }
  841. else
  842. {
  843. pRenderUnit->bDeviceObjectsRestored = TRUE;
  844. }
  845. }
  846. }
  847. }
  848. return;
  849. }
  850. }
  851. }
  852. ShutdownSaver();
  853. }
  854. }
  855. //-----------------------------------------------------------------------------
  856. // Name: Initialize3DEnvironment()
  857. // Desc: Set up D3D device(s)
  858. //-----------------------------------------------------------------------------
  859. HRESULT CD3DScreensaver::Initialize3DEnvironment()
  860. {
  861. HRESULT hr;
  862. DWORD iAdapter;
  863. DWORD iMonitor;
  864. D3DAdapterInfo* pD3DAdapterInfo;
  865. MonitorInfo* pMonitorInfo;
  866. DWORD iRenderUnit;
  867. RenderUnit* pRenderUnit;
  868. MONITORINFO monitorInfo;
  869. if ( m_SaverMode == sm_full )
  870. {
  871. // Fullscreen mode. Create a RenderUnit for each monitor (unless
  872. // the user wants it black)
  873. m_bWindowed = FALSE;
  874. if( m_bOneScreenOnly )
  875. {
  876. // Set things up to only create a RenderUnit on the best device
  877. for( iAdapter = 0; iAdapter < m_dwNumAdapters; iAdapter++ )
  878. {
  879. pD3DAdapterInfo = m_Adapters[iAdapter];
  880. pD3DAdapterInfo->bLeaveBlack = TRUE;
  881. }
  882. GetBestAdapter( &iAdapter );
  883. if( iAdapter == NO_ADAPTER )
  884. {
  885. m_bErrorMode = TRUE;
  886. m_hrError = D3DAPPERR_NOCOMPATIBLEDEVICES;
  887. }
  888. else
  889. {
  890. pD3DAdapterInfo = m_Adapters[iAdapter];
  891. pD3DAdapterInfo->bLeaveBlack = FALSE;
  892. }
  893. }
  894. for( iMonitor = 0; iMonitor < m_dwNumMonitors; iMonitor++ )
  895. {
  896. pMonitorInfo = &m_Monitors[iMonitor];
  897. iAdapter = pMonitorInfo->iAdapter;
  898. if( iAdapter == NO_ADAPTER )
  899. continue;
  900. pD3DAdapterInfo = m_Adapters[iAdapter];
  901. if( !pD3DAdapterInfo->bLeaveBlack && pD3DAdapterInfo->dwNumDevices > 0 )
  902. {
  903. pD3DAdapterInfo->hWndDevice = pMonitorInfo->hWnd;
  904. pRenderUnit = &m_RenderUnits[m_dwNumRenderUnits++];
  905. ZeroMemory( pRenderUnit, sizeof(RenderUnit) );
  906. pRenderUnit->iAdapter = iAdapter;
  907. if( FAILED( hr = CreateFullscreenRenderUnit( pRenderUnit ) ) )
  908. {
  909. // skip this render unit and leave screen blank
  910. m_dwNumRenderUnits--;
  911. m_bErrorMode = TRUE;
  912. m_hrError = D3DAPPERR_CREATEDEVICEFAILED;
  913. }
  914. }
  915. }
  916. }
  917. else
  918. {
  919. // Windowed mode, for test mode or preview window. Just need one RenderUnit.
  920. m_bWindowed = TRUE;
  921. GetClientRect( m_hWnd, &m_rcRenderTotal );
  922. GetClientRect( m_hWnd, &m_rcRenderCurDevice );
  923. GetBestAdapter( &iAdapter );
  924. if( iAdapter == NO_ADAPTER )
  925. {
  926. m_bErrorMode = TRUE;
  927. m_hrError = D3DAPPERR_CREATEDEVICEFAILED;
  928. }
  929. else
  930. {
  931. pD3DAdapterInfo = m_Adapters[iAdapter];
  932. pD3DAdapterInfo->hWndDevice = m_hWnd;
  933. }
  934. if( !m_bErrorMode )
  935. {
  936. pRenderUnit = &m_RenderUnits[m_dwNumRenderUnits++];
  937. ZeroMemory( pRenderUnit, sizeof(RenderUnit) );
  938. pRenderUnit->iAdapter = iAdapter;
  939. if( FAILED( hr = CreateWindowedRenderUnit( pRenderUnit ) ) )
  940. {
  941. m_dwNumRenderUnits--;
  942. m_bErrorMode = TRUE;
  943. if( m_SaverMode == sm_preview )
  944. m_hrError = D3DAPPERR_NOPREVIEW;
  945. else
  946. m_hrError = D3DAPPERR_CREATEDEVICEFAILED;
  947. }
  948. }
  949. }
  950. // Once all mode changes are done, (re-)determine coordinates of all
  951. // screens, and make sure windows still cover each screen
  952. for( iMonitor = 0; iMonitor < m_dwNumMonitors; iMonitor++ )
  953. {
  954. pMonitorInfo = &m_Monitors[iMonitor];
  955. monitorInfo.cbSize = sizeof(MONITORINFO);
  956. GetMonitorInfo( pMonitorInfo->hMonitor, &monitorInfo );
  957. pMonitorInfo->rcScreen = monitorInfo.rcMonitor;
  958. if( !m_bWindowed )
  959. {
  960. SetWindowPos( pMonitorInfo->hWnd, HWND_TOPMOST, monitorInfo.rcMonitor.left,
  961. monitorInfo.rcMonitor.top, monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left,
  962. monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top, SWP_NOACTIVATE );
  963. }
  964. }
  965. // For fullscreen, determine bounds of the virtual screen containing all
  966. // screens that are rendering. Don't just use SM_XVIRTUALSCREEN, because
  967. // we don't want to count screens that are just black
  968. if( !m_bWindowed )
  969. {
  970. for( iRenderUnit = 0; iRenderUnit < m_dwNumRenderUnits; iRenderUnit++ )
  971. {
  972. pRenderUnit = &m_RenderUnits[iRenderUnit];
  973. pMonitorInfo = &m_Monitors[pRenderUnit->iMonitor];
  974. UnionRect( &m_rcRenderTotal, &m_rcRenderTotal, &pMonitorInfo->rcScreen );
  975. }
  976. }
  977. if( !m_bErrorMode )
  978. {
  979. // Initialize D3D devices for all render units
  980. for( iRenderUnit = 0; iRenderUnit < m_dwNumRenderUnits; iRenderUnit++ )
  981. {
  982. pRenderUnit = &m_RenderUnits[iRenderUnit];
  983. SwitchToRenderUnit( iRenderUnit );
  984. if ( FAILED(hr = InitDeviceObjects() ) )
  985. {
  986. m_bErrorMode = TRUE;
  987. m_hrError = D3DAPPERR_INITDEVICEOBJECTSFAILED;
  988. }
  989. else
  990. {
  991. pRenderUnit->bDeviceObjectsInited = TRUE;
  992. if ( FAILED(hr = RestoreDeviceObjects() ) )
  993. {
  994. m_bErrorMode = TRUE;
  995. m_hrError = D3DAPPERR_INITDEVICEOBJECTSFAILED;
  996. }
  997. else
  998. {
  999. pRenderUnit->bDeviceObjectsRestored = TRUE;
  1000. }
  1001. }
  1002. }
  1003. UpdateDeviceStats();
  1004. }
  1005. // Make sure all those display changes don't count as user mouse moves
  1006. m_dwSaverMouseMoveCount = 0;
  1007. return S_OK;
  1008. }
  1009. //-----------------------------------------------------------------------------
  1010. // Name: GetBestAdapter()
  1011. // Desc: To decide which adapter to use, loop through monitors until you find
  1012. // one whose adapter has a compatible HAL. If none, use the first
  1013. // monitor that has an compatible SW device.
  1014. //-----------------------------------------------------------------------------
  1015. BOOL CD3DScreensaver::GetBestAdapter( DWORD* piAdapter )
  1016. {
  1017. DWORD iAdapterBest = NO_ADAPTER;
  1018. DWORD iAdapter;
  1019. DWORD iMonitor;
  1020. MonitorInfo* pMonitorInfo;
  1021. D3DAdapterInfo* pD3DAdapterInfo;
  1022. for( iMonitor = 0; iMonitor < m_dwNumMonitors; iMonitor++ )
  1023. {
  1024. pMonitorInfo = &m_Monitors[iMonitor];
  1025. iAdapter = pMonitorInfo->iAdapter;
  1026. if( iAdapter == NO_ADAPTER )
  1027. continue;
  1028. pD3DAdapterInfo = m_Adapters[iAdapter];
  1029. if( pD3DAdapterInfo->bHasAppCompatHAL )
  1030. {
  1031. iAdapterBest = iAdapter;
  1032. break;
  1033. }
  1034. if( pD3DAdapterInfo->bHasAppCompatSW )
  1035. {
  1036. iAdapterBest = iAdapter;
  1037. // but keep looking...
  1038. }
  1039. }
  1040. *piAdapter = iAdapterBest;
  1041. return (iAdapterBest != NO_ADAPTER);
  1042. }
  1043. //-----------------------------------------------------------------------------
  1044. // Name: CreateFullscreenRenderUnit()
  1045. // Desc:
  1046. //-----------------------------------------------------------------------------
  1047. HRESULT CD3DScreensaver::CreateFullscreenRenderUnit( RenderUnit* pRenderUnit )
  1048. {
  1049. HRESULT hr;
  1050. UINT iAdapter = pRenderUnit->iAdapter;
  1051. D3DAdapterInfo* pD3DAdapterInfo = m_Adapters[iAdapter];
  1052. DWORD iMonitor = pD3DAdapterInfo->iMonitor;
  1053. D3DDeviceInfo* pD3DDeviceInfo;
  1054. D3DModeInfo* pD3DModeInfo;
  1055. DWORD dwCurrentDevice;
  1056. D3DDEVTYPE curType;
  1057. if( iAdapter >= m_dwNumAdapters )
  1058. return E_FAIL;
  1059. if( pD3DAdapterInfo->dwNumDevices == 0 )
  1060. return E_FAIL;
  1061. // Find the best device for the adapter. Use HAL
  1062. // if it's there, otherwise SW, otherwise REF.
  1063. dwCurrentDevice = 0xffff;
  1064. curType = D3DDEVTYPE_FORCE_DWORD;
  1065. for( DWORD iDevice = 0; iDevice < pD3DAdapterInfo->dwNumDevices; iDevice++)
  1066. {
  1067. pD3DDeviceInfo = &pD3DAdapterInfo->devices[iDevice];
  1068. if( pD3DDeviceInfo->DeviceType == D3DDEVTYPE_HAL && !pD3DAdapterInfo->bDisableHW )
  1069. {
  1070. dwCurrentDevice = iDevice;
  1071. curType = D3DDEVTYPE_HAL;
  1072. break; // stop looking
  1073. }
  1074. else if( pD3DDeviceInfo->DeviceType == D3DDEVTYPE_SW )
  1075. {
  1076. dwCurrentDevice = iDevice;
  1077. curType = D3DDEVTYPE_SW;
  1078. // but keep looking
  1079. }
  1080. else if( pD3DDeviceInfo->DeviceType == D3DDEVTYPE_REF && m_bAllowRef && curType != D3DDEVTYPE_SW )
  1081. {
  1082. dwCurrentDevice = iDevice;
  1083. curType = D3DDEVTYPE_REF;
  1084. // but keep looking
  1085. }
  1086. }
  1087. if( dwCurrentDevice == 0xffff )
  1088. return D3DAPPERR_NOHARDWAREDEVICE;
  1089. pD3DDeviceInfo = &pD3DAdapterInfo->devices[dwCurrentDevice];
  1090. pD3DDeviceInfo->dwCurrentMode = 0xffff;
  1091. if( pD3DAdapterInfo->dwUserPrefWidth != 0 )
  1092. {
  1093. // Try to find mode that matches user preference
  1094. for( DWORD iMode = 0; iMode < pD3DDeviceInfo->dwNumModes; iMode++)
  1095. {
  1096. pD3DModeInfo = &pD3DDeviceInfo->modes[iMode];
  1097. if( pD3DModeInfo->Width == pD3DAdapterInfo->dwUserPrefWidth &&
  1098. pD3DModeInfo->Height == pD3DAdapterInfo->dwUserPrefHeight &&
  1099. pD3DModeInfo->Format == pD3DAdapterInfo->d3dfmtUserPrefFormat )
  1100. {
  1101. pD3DDeviceInfo->dwCurrentMode = iMode;
  1102. break;
  1103. }
  1104. }
  1105. }
  1106. // If user-preferred mode is not specified or not found,
  1107. // use "Automatic" technique:
  1108. if( pD3DDeviceInfo->dwCurrentMode == 0xffff )
  1109. {
  1110. if( pD3DDeviceInfo->DeviceType == D3DDEVTYPE_SW )
  1111. {
  1112. // If using a SW rast then try to find a low resolution and 16-bpp.
  1113. BOOL bFound16BitMode = FALSE;
  1114. DWORD dwSmallestHeight = -1;
  1115. pD3DDeviceInfo->dwCurrentMode = 0; // unless we find something better
  1116. for( DWORD iMode = 0; iMode < pD3DDeviceInfo->dwNumModes; iMode++)
  1117. {
  1118. pD3DModeInfo = &pD3DDeviceInfo->modes[iMode];
  1119. // Skip 640x400 because 640x480 is better
  1120. if( pD3DModeInfo->Height == 400 )
  1121. continue;
  1122. if( pD3DModeInfo->Height < dwSmallestHeight ||
  1123. (pD3DModeInfo->Height == dwSmallestHeight && !bFound16BitMode) )
  1124. {
  1125. dwSmallestHeight = pD3DModeInfo->Height;
  1126. pD3DDeviceInfo->dwCurrentMode = iMode;
  1127. bFound16BitMode = FALSE;
  1128. if( ( pD3DModeInfo->Format == D3DFMT_R5G6B5 ||
  1129. pD3DModeInfo->Format == D3DFMT_X1R5G5B5 ||
  1130. pD3DModeInfo->Format == D3DFMT_A1R5G5B5 ||
  1131. pD3DModeInfo->Format == D3DFMT_A4R4G4B4 ||
  1132. pD3DModeInfo->Format == D3DFMT_X4R4G4B4 ) )
  1133. {
  1134. bFound16BitMode = TRUE;
  1135. }
  1136. }
  1137. }
  1138. }
  1139. else
  1140. {
  1141. // Try to find mode matching desktop resolution and 32-bpp.
  1142. BOOL bMatchedSize = FALSE;
  1143. BOOL bGot32Bit = FALSE;
  1144. pD3DDeviceInfo->dwCurrentMode = 0; // unless we find something better
  1145. for( DWORD iMode = 0; iMode < pD3DDeviceInfo->dwNumModes; iMode++)
  1146. {
  1147. pD3DModeInfo = &pD3DDeviceInfo->modes[iMode];
  1148. if( pD3DModeInfo->Width == pD3DAdapterInfo->d3ddmDesktop.Width &&
  1149. pD3DModeInfo->Height == pD3DAdapterInfo->d3ddmDesktop.Height )
  1150. {
  1151. if( !bMatchedSize )
  1152. pD3DDeviceInfo->dwCurrentMode = iMode;
  1153. bMatchedSize = TRUE;
  1154. if( !bGot32Bit &&
  1155. ( pD3DModeInfo->Format == D3DFMT_X8R8G8B8 ||
  1156. pD3DModeInfo->Format == D3DFMT_A8R8G8B8 ) )
  1157. {
  1158. pD3DDeviceInfo->dwCurrentMode = iMode;
  1159. bGot32Bit = TRUE;
  1160. break;
  1161. }
  1162. }
  1163. }
  1164. }
  1165. }
  1166. // If desktop mode not found, pick highest mode available
  1167. if( pD3DDeviceInfo->dwCurrentMode == 0xffff )
  1168. {
  1169. DWORD dwWidthMax = 0;
  1170. DWORD dwHeightMax = 0;
  1171. DWORD dwBppMax = 0;
  1172. DWORD dwWidthCur = 0;
  1173. DWORD dwHeightCur = 0;
  1174. DWORD dwBppCur = 0;
  1175. for( DWORD iMode = 0; iMode < pD3DDeviceInfo->dwNumModes; iMode++)
  1176. {
  1177. pD3DModeInfo = &pD3DDeviceInfo->modes[iMode];
  1178. dwWidthCur = pD3DModeInfo->Width;
  1179. dwHeightCur = pD3DModeInfo->Height;
  1180. if( pD3DModeInfo->Format == D3DFMT_X8R8G8B8 ||
  1181. pD3DModeInfo->Format == D3DFMT_A8R8G8B8 )
  1182. {
  1183. dwBppCur = 32;
  1184. }
  1185. else
  1186. {
  1187. dwBppCur = 16;
  1188. }
  1189. if( dwWidthCur > dwWidthMax ||
  1190. dwHeightCur > dwHeightMax ||
  1191. dwWidthCur == dwWidthMax && dwHeightCur == dwHeightMax && dwBppCur > dwBppMax )
  1192. {
  1193. dwWidthMax = dwWidthCur;
  1194. dwHeightMax = dwHeightCur;
  1195. dwBppMax = dwBppCur;
  1196. pD3DDeviceInfo->dwCurrentMode = iMode;
  1197. }
  1198. }
  1199. }
  1200. // Try to create the D3D device, falling back to lower-res modes if it fails
  1201. BOOL bAtLeastOneFailure = FALSE;
  1202. while( TRUE )
  1203. {
  1204. pD3DModeInfo = &pD3DDeviceInfo->modes[pD3DDeviceInfo->dwCurrentMode];
  1205. pRenderUnit->DeviceType = pD3DDeviceInfo->DeviceType;
  1206. pRenderUnit->dwBehavior = pD3DModeInfo->dwBehavior;
  1207. pRenderUnit->iMonitor = iMonitor;
  1208. pRenderUnit->d3dpp.BackBufferFormat = pD3DModeInfo->Format;
  1209. pRenderUnit->d3dpp.BackBufferWidth = pD3DModeInfo->Width;
  1210. pRenderUnit->d3dpp.BackBufferHeight = pD3DModeInfo->Height;
  1211. pRenderUnit->d3dpp.Windowed = FALSE;
  1212. pRenderUnit->d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
  1213. pRenderUnit->d3dpp.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_ONE;
  1214. pRenderUnit->d3dpp.AutoDepthStencilFormat = pD3DModeInfo->DepthStencilFormat;
  1215. pRenderUnit->d3dpp.BackBufferCount = 1;
  1216. pRenderUnit->d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
  1217. pRenderUnit->d3dpp.SwapEffect = m_SwapEffectFullscreen;
  1218. pRenderUnit->d3dpp.hDeviceWindow = pD3DAdapterInfo->hWndDevice;
  1219. pRenderUnit->d3dpp.EnableAutoDepthStencil = m_bUseDepthBuffer;
  1220. pRenderUnit->d3dpp.Flags = 0;
  1221. // Create device
  1222. hr = m_pD3D->CreateDevice( iAdapter, pRenderUnit->DeviceType,
  1223. m_hWnd, // (this is the focus window)
  1224. pRenderUnit->dwBehavior, &pRenderUnit->d3dpp,
  1225. &pRenderUnit->pd3dDevice );
  1226. if( SUCCEEDED( hr ) )
  1227. {
  1228. // Give the client app an opportunity to reject this mode
  1229. // due to not enough video memory, or any other reason
  1230. if( SUCCEEDED( hr = ConfirmMode( pRenderUnit->pd3dDevice ) ) )
  1231. break;
  1232. else
  1233. SAFE_RELEASE( pRenderUnit->pd3dDevice );
  1234. }
  1235. // If we get here, remember that CreateDevice or ConfirmMode failed, so
  1236. // we can change the default mode next time
  1237. bAtLeastOneFailure = TRUE;
  1238. if( !FindNextLowerMode( pD3DDeviceInfo ) )
  1239. break;
  1240. }
  1241. if( SUCCEEDED( hr ) && bAtLeastOneFailure && m_strRegPath[0] != TEXT('\0') )
  1242. {
  1243. // Record the mode that succeeded in the registry so we can
  1244. // default to it next time
  1245. TCHAR strKey[100];
  1246. HKEY hkeyParent;
  1247. HKEY hkey;
  1248. pD3DAdapterInfo->dwUserPrefWidth = pRenderUnit->d3dpp.BackBufferWidth;
  1249. pD3DAdapterInfo->dwUserPrefHeight = pRenderUnit->d3dpp.BackBufferHeight;
  1250. pD3DAdapterInfo->d3dfmtUserPrefFormat = pRenderUnit->d3dpp.BackBufferFormat;
  1251. if( ERROR_SUCCESS == RegCreateKeyEx( HKEY_CURRENT_USER, m_strRegPath,
  1252. 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkeyParent, NULL ) )
  1253. {
  1254. wsprintf( strKey, TEXT("Screen %d"), iMonitor + 1 );
  1255. if( ERROR_SUCCESS == RegCreateKeyEx( hkeyParent, strKey,
  1256. 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL ) )
  1257. {
  1258. RegSetValueEx( hkey, TEXT("Width"), NULL, REG_DWORD,
  1259. (BYTE*)&pD3DAdapterInfo->dwUserPrefWidth, sizeof(DWORD) );
  1260. RegSetValueEx( hkey, TEXT("Height"), NULL, REG_DWORD,
  1261. (BYTE*)&pD3DAdapterInfo->dwUserPrefHeight, sizeof(DWORD) );
  1262. RegSetValueEx( hkey, TEXT("Format"), NULL, REG_DWORD,
  1263. (BYTE*)&pD3DAdapterInfo->d3dfmtUserPrefFormat, sizeof(DWORD) );
  1264. RegSetValueEx( hkey, TEXT("Adapter ID"), NULL, REG_BINARY,
  1265. (BYTE*)&pD3DAdapterInfo->d3dAdapterIdentifier.DeviceIdentifier, sizeof(GUID) );
  1266. RegCloseKey( hkey );
  1267. }
  1268. RegCloseKey( hkeyParent );
  1269. }
  1270. }
  1271. return hr;
  1272. }
  1273. //-----------------------------------------------------------------------------
  1274. // Name: FindNextLowerMode()
  1275. // Desc:
  1276. //-----------------------------------------------------------------------------
  1277. BOOL CD3DScreensaver::FindNextLowerMode( D3DDeviceInfo* pD3DDeviceInfo )
  1278. {
  1279. DWORD iModeCur = pD3DDeviceInfo->dwCurrentMode;
  1280. D3DModeInfo* pD3DModeInfoCur = &pD3DDeviceInfo->modes[iModeCur];
  1281. DWORD dwWidthCur = pD3DModeInfoCur->Width;
  1282. DWORD dwHeightCur = pD3DModeInfoCur->Height;
  1283. DWORD dwNumPixelsCur = dwWidthCur * dwHeightCur;
  1284. D3DFORMAT d3dfmtCur = pD3DModeInfoCur->Format;
  1285. BOOL b32BitCur = (d3dfmtCur == D3DFMT_A8R8G8B8 ||
  1286. d3dfmtCur == D3DFMT_X8R8G8B8);
  1287. DWORD iModeNew;
  1288. D3DModeInfo* pD3DModeInfoNew;
  1289. DWORD dwWidthNew;
  1290. DWORD dwHeightNew;
  1291. DWORD dwNumPixelsNew;
  1292. D3DFORMAT d3dfmtNew = D3DFMT_UNKNOWN;
  1293. BOOL b32BitNew;
  1294. DWORD dwWidthBest = 0;
  1295. DWORD dwHeightBest = 0;
  1296. DWORD dwNumPixelsBest = 0;
  1297. BOOL b32BitBest = FALSE;
  1298. DWORD iModeBest = 0xffff;
  1299. for( iModeNew = 0; iModeNew < pD3DDeviceInfo->dwNumModes; iModeNew++ )
  1300. {
  1301. // Don't pick the same mode we currently have
  1302. if( iModeNew == iModeCur )
  1303. continue;
  1304. // Get info about new mode
  1305. pD3DModeInfoNew = &pD3DDeviceInfo->modes[iModeNew];
  1306. dwWidthNew = pD3DModeInfoNew->Width;
  1307. dwHeightNew = pD3DModeInfoNew->Height;
  1308. dwNumPixelsNew = dwWidthNew * dwHeightNew;
  1309. d3dfmtNew = pD3DModeInfoNew->Format;
  1310. b32BitNew = (d3dfmtNew == D3DFMT_A8R8G8B8 ||
  1311. d3dfmtNew == D3DFMT_X8R8G8B8);
  1312. // If we're currently 32-bit and new mode is same width/height and 16-bit, take it
  1313. if( b32BitCur &&
  1314. !b32BitNew &&
  1315. pD3DModeInfoNew->Width == dwWidthCur &&
  1316. pD3DModeInfoNew->Height == dwHeightCur)
  1317. {
  1318. pD3DDeviceInfo->dwCurrentMode = iModeNew;
  1319. return TRUE;
  1320. }
  1321. // If new mode is smaller than current mode, see if it's our best so far
  1322. if( dwNumPixelsNew < dwNumPixelsCur )
  1323. {
  1324. // If current best is 32-bit, new mode needs to be bigger to be best
  1325. if( b32BitBest && (dwNumPixelsNew < dwNumPixelsBest ) )
  1326. continue;
  1327. // If new mode is bigger or equal to best, make it the best
  1328. if( (dwNumPixelsNew > dwNumPixelsBest) ||
  1329. (!b32BitBest && b32BitNew) )
  1330. {
  1331. dwWidthBest = dwWidthNew;
  1332. dwHeightBest = dwHeightNew;
  1333. dwNumPixelsBest = dwNumPixelsNew;
  1334. iModeBest = iModeNew;
  1335. b32BitBest = b32BitNew;
  1336. }
  1337. }
  1338. }
  1339. if( iModeBest == 0xffff )
  1340. return FALSE; // no smaller mode found
  1341. pD3DDeviceInfo->dwCurrentMode = iModeBest;
  1342. return TRUE;
  1343. }
  1344. //-----------------------------------------------------------------------------
  1345. // Name: CreateWindowedRenderUnit()
  1346. // Desc:
  1347. //-----------------------------------------------------------------------------
  1348. HRESULT CD3DScreensaver::CreateWindowedRenderUnit( RenderUnit* pRenderUnit )
  1349. {
  1350. HRESULT hr;
  1351. UINT iAdapter = pRenderUnit->iAdapter;
  1352. D3DAdapterInfo* pD3DAdapterInfo = m_Adapters[iAdapter];
  1353. DWORD iMonitor = pD3DAdapterInfo->iMonitor;
  1354. D3DDeviceInfo* pD3DDeviceInfo;
  1355. D3DDEVTYPE curType;
  1356. // Find the best device for the primary adapter. Use HAL
  1357. // if it's there, otherwise SW, otherwise REF.
  1358. pD3DAdapterInfo->dwCurrentDevice = 0xffff; // unless we find something better
  1359. curType = D3DDEVTYPE_FORCE_DWORD;
  1360. for( DWORD iDevice = 0; iDevice < pD3DAdapterInfo->dwNumDevices; iDevice++)
  1361. {
  1362. pD3DDeviceInfo = &pD3DAdapterInfo->devices[iDevice];
  1363. if( pD3DDeviceInfo->DeviceType == D3DDEVTYPE_HAL && !pD3DAdapterInfo->bDisableHW &&
  1364. pD3DDeviceInfo->bCanDoWindowed )
  1365. {
  1366. pD3DAdapterInfo->dwCurrentDevice = iDevice;
  1367. curType = D3DDEVTYPE_HAL;
  1368. break;
  1369. }
  1370. else if( pD3DDeviceInfo->DeviceType == D3DDEVTYPE_SW &&
  1371. pD3DDeviceInfo->bCanDoWindowed )
  1372. {
  1373. pD3DAdapterInfo->dwCurrentDevice = iDevice;
  1374. curType = D3DDEVTYPE_SW;
  1375. // but keep looking
  1376. }
  1377. else if( pD3DDeviceInfo->DeviceType == D3DDEVTYPE_REF && m_bAllowRef && curType != D3DDEVTYPE_SW )
  1378. {
  1379. pD3DAdapterInfo->dwCurrentDevice = iDevice;
  1380. curType = D3DDEVTYPE_REF;
  1381. // but keep looking
  1382. }
  1383. }
  1384. if( pD3DAdapterInfo->dwCurrentDevice == 0xffff )
  1385. return D3DAPPERR_NOHARDWAREDEVICE;
  1386. pD3DDeviceInfo = &pD3DAdapterInfo->devices[pD3DAdapterInfo->dwCurrentDevice];
  1387. D3DWindowedModeInfo D3DWindowedModeInfo;
  1388. D3DWindowedModeInfo.DisplayFormat = pD3DAdapterInfo->d3ddmDesktop.Format;
  1389. D3DWindowedModeInfo.BackBufferFormat = pD3DAdapterInfo->d3ddmDesktop.Format;
  1390. if( FAILED( CheckWindowedFormat( iAdapter, &D3DWindowedModeInfo ) ) )
  1391. {
  1392. D3DWindowedModeInfo.BackBufferFormat = D3DFMT_A8R8G8B8;
  1393. if( FAILED( CheckWindowedFormat( iAdapter, &D3DWindowedModeInfo ) ) )
  1394. {
  1395. D3DWindowedModeInfo.BackBufferFormat = D3DFMT_X8R8G8B8;
  1396. if( FAILED( CheckWindowedFormat( iAdapter, &D3DWindowedModeInfo ) ) )
  1397. {
  1398. D3DWindowedModeInfo.BackBufferFormat = D3DFMT_A1R5G5B5;
  1399. if( FAILED( CheckWindowedFormat( iAdapter, &D3DWindowedModeInfo ) ) )
  1400. {
  1401. D3DWindowedModeInfo.BackBufferFormat = D3DFMT_R5G6B5;
  1402. if( FAILED( CheckWindowedFormat( iAdapter, &D3DWindowedModeInfo ) ) )
  1403. {
  1404. return E_FAIL;
  1405. }
  1406. }
  1407. }
  1408. }
  1409. }
  1410. pRenderUnit->DeviceType = pD3DDeviceInfo->DeviceType;
  1411. pRenderUnit->dwBehavior = D3DWindowedModeInfo.dwBehavior;
  1412. pRenderUnit->iMonitor = iMonitor;
  1413. pRenderUnit->d3dpp.BackBufferWidth = 0;
  1414. pRenderUnit->d3dpp.BackBufferHeight = 0;
  1415. pRenderUnit->d3dpp.Windowed = TRUE;
  1416. pRenderUnit->d3dpp.FullScreen_RefreshRateInHz = 0;
  1417. pRenderUnit->d3dpp.FullScreen_PresentationInterval = 0;
  1418. pRenderUnit->d3dpp.BackBufferFormat = D3DWindowedModeInfo.BackBufferFormat;
  1419. pRenderUnit->d3dpp.AutoDepthStencilFormat = D3DWindowedModeInfo.DepthStencilFormat;
  1420. pRenderUnit->d3dpp.BackBufferCount = 1;
  1421. pRenderUnit->d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
  1422. pRenderUnit->d3dpp.SwapEffect = m_SwapEffectWindowed;
  1423. pRenderUnit->d3dpp.hDeviceWindow = pD3DAdapterInfo->hWndDevice;
  1424. pRenderUnit->d3dpp.EnableAutoDepthStencil = m_bUseDepthBuffer;
  1425. pRenderUnit->d3dpp.Flags = 0;
  1426. // Create device
  1427. hr = m_pD3D->CreateDevice( iAdapter, pRenderUnit->DeviceType, m_hWnd,
  1428. pRenderUnit->dwBehavior, &pRenderUnit->d3dpp, &pRenderUnit->pd3dDevice );
  1429. if ( FAILED(hr) )
  1430. {
  1431. return hr;
  1432. }
  1433. return S_OK;
  1434. }
  1435. //-----------------------------------------------------------------------------
  1436. // Name: UpdateDeviceStats()
  1437. // Desc: Store device description
  1438. //-----------------------------------------------------------------------------
  1439. VOID CD3DScreensaver::UpdateDeviceStats()
  1440. {
  1441. DWORD iRenderUnit;
  1442. RenderUnit* pRenderUnit;
  1443. for( iRenderUnit = 0; iRenderUnit < m_dwNumRenderUnits; iRenderUnit++ )
  1444. {
  1445. pRenderUnit = &m_RenderUnits[iRenderUnit];
  1446. if( pRenderUnit->DeviceType == D3DDEVTYPE_REF )
  1447. lstrcpy( pRenderUnit->strDeviceStats, TEXT("REF") );
  1448. else if( pRenderUnit->DeviceType == D3DDEVTYPE_HAL )
  1449. lstrcpy( pRenderUnit->strDeviceStats, TEXT("HAL") );
  1450. else if( pRenderUnit->DeviceType == D3DDEVTYPE_SW )
  1451. lstrcpy( pRenderUnit->strDeviceStats, TEXT("SW") );
  1452. if( pRenderUnit->dwBehavior & D3DCREATE_HARDWARE_VERTEXPROCESSING &&
  1453. pRenderUnit->dwBehavior & D3DCREATE_PUREDEVICE )
  1454. {
  1455. if( pRenderUnit->DeviceType == D3DDEVTYPE_HAL )
  1456. lstrcat( pRenderUnit->strDeviceStats, TEXT(" (pure hw vp)") );
  1457. else
  1458. lstrcat( pRenderUnit->strDeviceStats, TEXT(" (simulated pure hw vp)") );
  1459. }
  1460. else if( pRenderUnit->dwBehavior & D3DCREATE_HARDWARE_VERTEXPROCESSING )
  1461. {
  1462. if( pRenderUnit->DeviceType == D3DDEVTYPE_HAL )
  1463. lstrcat( pRenderUnit->strDeviceStats, TEXT(" (hw vp)") );
  1464. else
  1465. lstrcat( pRenderUnit->strDeviceStats, TEXT(" (simulated hw vp)") );
  1466. }
  1467. else if( pRenderUnit->dwBehavior & D3DCREATE_MIXED_VERTEXPROCESSING )
  1468. {
  1469. if( pRenderUnit->DeviceType == D3DDEVTYPE_HAL )
  1470. lstrcat( pRenderUnit->strDeviceStats, TEXT(" (mixed vp)") );
  1471. else
  1472. lstrcat( pRenderUnit->strDeviceStats, TEXT(" (simulated mixed vp)") );
  1473. }
  1474. else if( pRenderUnit->dwBehavior & D3DCREATE_SOFTWARE_VERTEXPROCESSING )
  1475. {
  1476. lstrcat( pRenderUnit->strDeviceStats, TEXT(" (sw vp)") );
  1477. }
  1478. if( pRenderUnit->DeviceType == D3DDEVTYPE_HAL )
  1479. {
  1480. lstrcat( pRenderUnit->strDeviceStats, TEXT(": ") );
  1481. TCHAR szDescription[300];
  1482. DXUtil_ConvertAnsiStringToGeneric( szDescription,
  1483. m_Adapters[pRenderUnit->iAdapter]->d3dAdapterIdentifier.Description, 300 );
  1484. lstrcat( pRenderUnit->strDeviceStats, szDescription );
  1485. }
  1486. }
  1487. }
  1488. //-----------------------------------------------------------------------------
  1489. // Name: SwitchToRenderUnit()
  1490. // Desc: Updates internal variables and notifies client that we are switching
  1491. // to a new RenderUnit / D3D device.
  1492. //-----------------------------------------------------------------------------
  1493. VOID CD3DScreensaver::SwitchToRenderUnit( UINT iRenderUnit )
  1494. {
  1495. RenderUnit* pRenderUnit = &m_RenderUnits[iRenderUnit];
  1496. MonitorInfo* pMonitorInfo = &m_Monitors[pRenderUnit->iMonitor];
  1497. m_pd3dDevice = pRenderUnit->pd3dDevice;
  1498. if( !m_bWindowed )
  1499. m_rcRenderCurDevice = pMonitorInfo->rcScreen;
  1500. if( m_pd3dDevice != NULL )
  1501. {
  1502. // Store render target surface desc
  1503. LPDIRECT3DSURFACE8 pBackBuffer;
  1504. m_pd3dDevice->GetBackBuffer( 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer );
  1505. pBackBuffer->GetDesc( &m_d3dsdBackBuffer );
  1506. pBackBuffer->Release();
  1507. }
  1508. lstrcpy( m_strDeviceStats, pRenderUnit->strDeviceStats );
  1509. lstrcpy( m_strFrameStats, pRenderUnit->strFrameStats );
  1510. // Notify the client to switch to this device
  1511. SetDevice(iRenderUnit);
  1512. }
  1513. //-----------------------------------------------------------------------------
  1514. // Name: SetProjectionMatrix()
  1515. // Desc: This function sets up an appropriate projection matrix to support
  1516. // rendering the appropriate parts of the scene to each screen.
  1517. //-----------------------------------------------------------------------------
  1518. HRESULT CD3DScreensaver::SetProjectionMatrix( FLOAT fNear, FLOAT fFar )
  1519. {
  1520. D3DXMATRIX mat;
  1521. INT cx, cy;
  1522. INT dx, dy;
  1523. INT dd;
  1524. FLOAT l,r,t,b;
  1525. if( m_bAllScreensSame )
  1526. {
  1527. cx = (m_rcRenderCurDevice.right + m_rcRenderCurDevice.left) / 2;
  1528. cy = (m_rcRenderCurDevice.bottom + m_rcRenderCurDevice.top) / 2;
  1529. dx = m_rcRenderCurDevice.right - m_rcRenderCurDevice.left;
  1530. dy = m_rcRenderCurDevice.bottom - m_rcRenderCurDevice.top;
  1531. }
  1532. else
  1533. {
  1534. cx = (m_rcRenderTotal.right + m_rcRenderTotal.left) / 2;
  1535. cy = (m_rcRenderTotal.bottom + m_rcRenderTotal.top) / 2;
  1536. dx = m_rcRenderTotal.right - m_rcRenderTotal.left;
  1537. dy = m_rcRenderTotal.bottom - m_rcRenderTotal.top;
  1538. }
  1539. dd = (dx > dy ? dy : dx);
  1540. l = FLOAT(m_rcRenderCurDevice.left - cx) / (FLOAT)(dd);
  1541. r = FLOAT(m_rcRenderCurDevice.right - cx) / (FLOAT)(dd);
  1542. t = FLOAT(m_rcRenderCurDevice.top - cy) / (FLOAT)(dd);
  1543. b = FLOAT(m_rcRenderCurDevice.bottom - cy) / (FLOAT)(dd);
  1544. l = fNear * l;
  1545. r = fNear * r;
  1546. t = fNear * t;
  1547. b = fNear * b;
  1548. D3DXMatrixPerspectiveOffCenterLH( &mat, l, r, t, b, fNear, fFar );
  1549. return m_pd3dDevice->SetTransform( D3DTS_PROJECTION, &mat );
  1550. }
  1551. //-----------------------------------------------------------------------------
  1552. // Name: SortModesCallback()
  1553. // Desc: Callback function for sorting display modes (used by BuildDeviceList).
  1554. //-----------------------------------------------------------------------------
  1555. static int SortModesCallback( const VOID* arg1, const VOID* arg2 )
  1556. {
  1557. D3DDISPLAYMODE* p1 = (D3DDISPLAYMODE*)arg1;
  1558. D3DDISPLAYMODE* p2 = (D3DDISPLAYMODE*)arg2;
  1559. if( p1->Width < p2->Width ) return -1;
  1560. if( p1->Width > p2->Width ) return +1;
  1561. if( p1->Height < p2->Height ) return -1;
  1562. if( p1->Height > p2->Height ) return +1;
  1563. if( p1->Format > p2->Format ) return -1;
  1564. if( p1->Format < p2->Format ) return +1;
  1565. return 0;
  1566. }
  1567. //-----------------------------------------------------------------------------
  1568. // Name: BuildDeviceList()
  1569. // Desc: Builds a list of all available adapters, devices, and modes.
  1570. //-----------------------------------------------------------------------------
  1571. HRESULT CD3DScreensaver::BuildDeviceList()
  1572. {
  1573. DWORD dwNumDeviceTypes;
  1574. const TCHAR* strDeviceDescs[] = { TEXT("HAL"), TEXT("SW"), TEXT("REF") };
  1575. const D3DDEVTYPE DeviceTypes[] = { D3DDEVTYPE_HAL, D3DDEVTYPE_SW, D3DDEVTYPE_REF };
  1576. if( m_bAllowRef )
  1577. dwNumDeviceTypes = 3;
  1578. else
  1579. dwNumDeviceTypes = 2;
  1580. HMONITOR hMonitor = NULL;
  1581. BOOL bHALExists = FALSE;
  1582. BOOL bHALIsWindowedCompatible = FALSE;
  1583. BOOL bHALIsDesktopCompatible = FALSE;
  1584. BOOL bHALIsSampleCompatible = FALSE;
  1585. // Loop through all the adapters on the system (usually, there's just one
  1586. // unless more than one graphics card is present).
  1587. for( UINT iAdapter = 0; iAdapter < m_pD3D->GetAdapterCount(); iAdapter++ )
  1588. {
  1589. // Fill in adapter info
  1590. if( m_Adapters[m_dwNumAdapters] == NULL )
  1591. {
  1592. m_Adapters[m_dwNumAdapters] = new D3DAdapterInfo;
  1593. if( m_Adapters[m_dwNumAdapters] == NULL )
  1594. return E_OUTOFMEMORY;
  1595. ZeroMemory( m_Adapters[m_dwNumAdapters], sizeof(D3DAdapterInfo) );
  1596. }
  1597. D3DAdapterInfo* pAdapter = m_Adapters[m_dwNumAdapters];
  1598. m_pD3D->GetAdapterIdentifier( iAdapter, D3DENUM_NO_WHQL_LEVEL, &pAdapter->d3dAdapterIdentifier );
  1599. m_pD3D->GetAdapterDisplayMode( iAdapter, &pAdapter->d3ddmDesktop );
  1600. pAdapter->dwNumDevices = 0;
  1601. pAdapter->dwCurrentDevice = 0;
  1602. pAdapter->bLeaveBlack = FALSE;
  1603. pAdapter->iMonitor = NO_MONITOR;
  1604. // Find the MonitorInfo that corresponds to this adapter. If the monitor
  1605. // is disabled, the adapter has a NULL HMONITOR and we cannot find the
  1606. // corresponding MonitorInfo. (Well, if one monitor was disabled, we
  1607. // could link the one MonitorInfo with a NULL HMONITOR to the one
  1608. // D3DAdapterInfo with a NULL HMONITOR, but if there are more than one,
  1609. // we can't link them, so it's safer not to ever try.)
  1610. hMonitor = m_pD3D->GetAdapterMonitor( iAdapter );
  1611. if( hMonitor != NULL )
  1612. {
  1613. for( DWORD iMonitor = 0; iMonitor < m_dwNumMonitors; iMonitor++ )
  1614. {
  1615. MonitorInfo* pMonitorInfo;
  1616. pMonitorInfo = &m_Monitors[iMonitor];
  1617. if( pMonitorInfo->hMonitor == hMonitor )
  1618. {
  1619. pAdapter->iMonitor = iMonitor;
  1620. pMonitorInfo->iAdapter = iAdapter;
  1621. break;
  1622. }
  1623. }
  1624. }
  1625. // Enumerate all display modes on this adapter
  1626. D3DDISPLAYMODE modes[100];
  1627. D3DFORMAT formats[20];
  1628. DWORD dwNumFormats = 0;
  1629. DWORD dwNumModes = 0;
  1630. DWORD dwNumAdapterModes = m_pD3D->GetAdapterModeCount( iAdapter );
  1631. // Add the adapter's current desktop format to the list of formats
  1632. formats[dwNumFormats++] = pAdapter->d3ddmDesktop.Format;
  1633. for( UINT iMode = 0; iMode < dwNumAdapterModes; iMode++ )
  1634. {
  1635. // Get the display mode attributes
  1636. D3DDISPLAYMODE DisplayMode;
  1637. m_pD3D->EnumAdapterModes( iAdapter, iMode, &DisplayMode );
  1638. // Filter out low-resolution modes
  1639. if( DisplayMode.Width < 640 || DisplayMode.Height < 400 )
  1640. continue;
  1641. // Check if the mode already exists (to filter out refresh rates)
  1642. for( DWORD m=0L; m<dwNumModes; m++ )
  1643. {
  1644. if( ( modes[m].Width == DisplayMode.Width ) &&
  1645. ( modes[m].Height == DisplayMode.Height ) &&
  1646. ( modes[m].Format == DisplayMode.Format ) )
  1647. break;
  1648. }
  1649. // If we found a new mode, add it to the list of modes
  1650. if( m == dwNumModes )
  1651. {
  1652. modes[dwNumModes].Width = DisplayMode.Width;
  1653. modes[dwNumModes].Height = DisplayMode.Height;
  1654. modes[dwNumModes].Format = DisplayMode.Format;
  1655. modes[dwNumModes].RefreshRate = 0;
  1656. dwNumModes++;
  1657. // Check if the mode's format already exists
  1658. for( DWORD f=0; f<dwNumFormats; f++ )
  1659. {
  1660. if( DisplayMode.Format == formats[f] )
  1661. break;
  1662. }
  1663. // If the format is new, add it to the list
  1664. if( f== dwNumFormats )
  1665. formats[dwNumFormats++] = DisplayMode.Format;
  1666. }
  1667. }
  1668. // Sort the list of display modes (by format, then width, then height)
  1669. qsort( modes, dwNumModes, sizeof(D3DDISPLAYMODE), SortModesCallback );
  1670. // Add devices to adapter
  1671. for( UINT iDevice = 0; iDevice < dwNumDeviceTypes; iDevice++ )
  1672. {
  1673. // Fill in device info
  1674. D3DDeviceInfo* pDevice;
  1675. pDevice = &pAdapter->devices[pAdapter->dwNumDevices];
  1676. pDevice->DeviceType = DeviceTypes[iDevice];
  1677. m_pD3D->GetDeviceCaps( iAdapter, DeviceTypes[iDevice], &pDevice->d3dCaps );
  1678. pDevice->strDesc = strDeviceDescs[iDevice];
  1679. pDevice->dwNumModes = 0;
  1680. pDevice->dwCurrentMode = 0;
  1681. pDevice->bCanDoWindowed = FALSE;
  1682. pDevice->bWindowed = FALSE;
  1683. pDevice->MultiSampleType = D3DMULTISAMPLE_NONE;
  1684. // Examine each format supported by the adapter to see if it will
  1685. // work with this device and meets the needs of the application.
  1686. BOOL bFormatConfirmed[20];
  1687. DWORD dwBehavior[20];
  1688. D3DFORMAT fmtDepthStencil[20];
  1689. for( DWORD f=0; f<dwNumFormats; f++ )
  1690. {
  1691. bFormatConfirmed[f] = FALSE;
  1692. fmtDepthStencil[f] = D3DFMT_UNKNOWN;
  1693. // Skip formats that cannot be used as render targets on this device
  1694. if( FAILED( m_pD3D->CheckDeviceType( iAdapter, pDevice->DeviceType,
  1695. formats[f], formats[f], FALSE ) ) )
  1696. continue;
  1697. if( pDevice->DeviceType == D3DDEVTYPE_SW )
  1698. {
  1699. // This system has a SW device
  1700. pAdapter->bHasSW = TRUE;
  1701. }
  1702. if( pDevice->DeviceType == D3DDEVTYPE_HAL )
  1703. {
  1704. // This system has a HAL device
  1705. bHALExists = TRUE;
  1706. pAdapter->bHasHAL = TRUE;
  1707. if( pDevice->d3dCaps.Caps2 & D3DCAPS2_CANRENDERWINDOWED )
  1708. {
  1709. // HAL can run in a window for some mode
  1710. bHALIsWindowedCompatible = TRUE;
  1711. if( f == 0 )
  1712. {
  1713. // HAL can run in a window for the current desktop mode
  1714. bHALIsDesktopCompatible = TRUE;
  1715. }
  1716. }
  1717. }
  1718. // Confirm the device/format for HW vertex processing
  1719. if( pDevice->d3dCaps.DevCaps&D3DDEVCAPS_HWTRANSFORMANDLIGHT )
  1720. {
  1721. if( pDevice->d3dCaps.DevCaps&D3DDEVCAPS_PUREDEVICE )
  1722. {
  1723. dwBehavior[f] = D3DCREATE_HARDWARE_VERTEXPROCESSING |
  1724. D3DCREATE_PUREDEVICE;
  1725. if( SUCCEEDED( ConfirmDevice( &pDevice->d3dCaps, dwBehavior[f],
  1726. formats[f] ) ) )
  1727. bFormatConfirmed[f] = TRUE;
  1728. }
  1729. if ( FALSE == bFormatConfirmed[f] )
  1730. {
  1731. dwBehavior[f] = D3DCREATE_HARDWARE_VERTEXPROCESSING;
  1732. if( SUCCEEDED( ConfirmDevice( &pDevice->d3dCaps, dwBehavior[f],
  1733. formats[f] ) ) )
  1734. bFormatConfirmed[f] = TRUE;
  1735. }
  1736. if ( FALSE == bFormatConfirmed[f] )
  1737. {
  1738. dwBehavior[f] = D3DCREATE_MIXED_VERTEXPROCESSING;
  1739. if( SUCCEEDED( ConfirmDevice( &pDevice->d3dCaps, dwBehavior[f],
  1740. formats[f] ) ) )
  1741. bFormatConfirmed[f] = TRUE;
  1742. }
  1743. }
  1744. // Confirm the device/format for SW vertex processing
  1745. if( FALSE == bFormatConfirmed[f] )
  1746. {
  1747. dwBehavior[f] = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  1748. if( SUCCEEDED( ConfirmDevice( &pDevice->d3dCaps, dwBehavior[f],
  1749. formats[f] ) ) )
  1750. bFormatConfirmed[f] = TRUE;
  1751. }
  1752. if( bFormatConfirmed[f] && m_bMultithreaded )
  1753. {
  1754. dwBehavior[f] |= D3DCREATE_MULTITHREADED;
  1755. }
  1756. // Find a suitable depth/stencil buffer format for this device/format
  1757. if( bFormatConfirmed[f] && m_bUseDepthBuffer )
  1758. {
  1759. if( !FindDepthStencilFormat( iAdapter, pDevice->DeviceType,
  1760. formats[f], &fmtDepthStencil[f] ) )
  1761. {
  1762. bFormatConfirmed[f] = FALSE;
  1763. }
  1764. }
  1765. }
  1766. // Add all enumerated display modes with confirmed formats to the
  1767. // device's list of valid modes
  1768. for( DWORD m=0L; m<dwNumModes; m++ )
  1769. {
  1770. for( DWORD f=0; f<dwNumFormats; f++ )
  1771. {
  1772. if( modes[m].Format == formats[f] )
  1773. {
  1774. if( bFormatConfirmed[f] == TRUE )
  1775. {
  1776. // Add this mode to the device's list of valid modes
  1777. pDevice->modes[pDevice->dwNumModes].Width = modes[m].Width;
  1778. pDevice->modes[pDevice->dwNumModes].Height = modes[m].Height;
  1779. pDevice->modes[pDevice->dwNumModes].Format = modes[m].Format;
  1780. pDevice->modes[pDevice->dwNumModes].dwBehavior = dwBehavior[f];
  1781. pDevice->modes[pDevice->dwNumModes].DepthStencilFormat = fmtDepthStencil[f];
  1782. pDevice->dwNumModes++;
  1783. if( pDevice->DeviceType == D3DDEVTYPE_HAL )
  1784. bHALIsSampleCompatible = TRUE;
  1785. }
  1786. }
  1787. }
  1788. }
  1789. // Select any 640x480 mode for default (but prefer a 16-bit mode)
  1790. for( m=0; m<pDevice->dwNumModes; m++ )
  1791. {
  1792. if( pDevice->modes[m].Width==640 && pDevice->modes[m].Height==480 )
  1793. {
  1794. pDevice->dwCurrentMode = m;
  1795. if( pDevice->modes[m].Format == D3DFMT_R5G6B5 ||
  1796. pDevice->modes[m].Format == D3DFMT_X1R5G5B5 ||
  1797. pDevice->modes[m].Format == D3DFMT_A1R5G5B5 )
  1798. {
  1799. break;
  1800. }
  1801. }
  1802. }
  1803. // Check if the device is compatible with the desktop display mode
  1804. // (which was added initially as formats[0])
  1805. if( bFormatConfirmed[0] && (pDevice->d3dCaps.Caps2 & D3DCAPS2_CANRENDERWINDOWED) )
  1806. {
  1807. pDevice->bCanDoWindowed = TRUE;
  1808. pDevice->bWindowed = TRUE;
  1809. }
  1810. // If valid modes were found, keep this device
  1811. if( pDevice->dwNumModes > 0 )
  1812. {
  1813. pAdapter->dwNumDevices++;
  1814. if( pDevice->DeviceType == D3DDEVTYPE_SW )
  1815. pAdapter->bHasAppCompatSW = TRUE;
  1816. else if( pDevice->DeviceType == D3DDEVTYPE_HAL )
  1817. pAdapter->bHasAppCompatHAL = TRUE;
  1818. }
  1819. }
  1820. // If valid devices were found, keep this adapter
  1821. // Count adapters even if no devices, so we can throw up blank windows on them
  1822. // if( pAdapter->dwNumDevices > 0 )
  1823. m_dwNumAdapters++;
  1824. }
  1825. /*
  1826. // Return an error if no compatible devices were found
  1827. if( 0L == m_dwNumAdapters )
  1828. return D3DAPPERR_NOCOMPATIBLEDEVICES;
  1829. // Pick a default device that can render into a window
  1830. // (This code assumes that the HAL device comes before the REF
  1831. // device in the device array).
  1832. for( DWORD a=0; a<m_dwNumAdapters; a++ )
  1833. {
  1834. for( DWORD d=0; d < m_Adapters[a]->dwNumDevices; d++ )
  1835. {
  1836. if( m_Adapters[a]->devices[d].bWindowed )
  1837. {
  1838. m_Adapters[a]->dwCurrentDevice = d;
  1839. m_dwAdapter = a;
  1840. m_bWindowed = TRUE;
  1841. // Display a warning message
  1842. if( m_Adapters[a]->devices[d].DeviceType == D3DDEVTYPE_REF )
  1843. {
  1844. if( !bHALExists )
  1845. DisplayErrorMsg( D3DAPPERR_NOHARDWAREDEVICE, MSGWARN_SWITCHEDTOREF );
  1846. else if( !bHALIsSampleCompatible )
  1847. DisplayErrorMsg( D3DAPPERR_HALNOTCOMPATIBLE, MSGWARN_SWITCHEDTOREF );
  1848. else if( !bHALIsWindowedCompatible )
  1849. DisplayErrorMsg( D3DAPPERR_NOWINDOWEDHAL, MSGWARN_SWITCHEDTOREF );
  1850. else if( !bHALIsDesktopCompatible )
  1851. DisplayErrorMsg( D3DAPPERR_NODESKTOPHAL, MSGWARN_SWITCHEDTOREF );
  1852. else // HAL is desktop compatible, but not sample compatible
  1853. DisplayErrorMsg( D3DAPPERR_NOHALTHISMODE, MSGWARN_SWITCHEDTOREF );
  1854. }
  1855. return S_OK;
  1856. }
  1857. }
  1858. }
  1859. return D3DAPPERR_NOWINDOWABLEDEVICES;
  1860. */
  1861. return S_OK;
  1862. }
  1863. //-----------------------------------------------------------------------------
  1864. // Name: CheckWindowedFormat()
  1865. // Desc:
  1866. //-----------------------------------------------------------------------------
  1867. HRESULT CD3DScreensaver::CheckWindowedFormat( UINT iAdapter, D3DWindowedModeInfo* pD3DWindowedModeInfo )
  1868. {
  1869. HRESULT hr;
  1870. D3DAdapterInfo* pD3DAdapterInfo = m_Adapters[iAdapter];
  1871. D3DDeviceInfo* pD3DDeviceInfo = &pD3DAdapterInfo->devices[pD3DAdapterInfo->dwCurrentDevice];
  1872. BOOL bFormatConfirmed = FALSE;
  1873. if( FAILED( hr = m_pD3D->CheckDeviceType( iAdapter, pD3DDeviceInfo->DeviceType,
  1874. pD3DAdapterInfo->d3ddmDesktop.Format, pD3DWindowedModeInfo->BackBufferFormat, TRUE ) ) )
  1875. {
  1876. return hr;
  1877. }
  1878. // Confirm the device/format for HW vertex processing
  1879. if( pD3DDeviceInfo->d3dCaps.DevCaps&D3DDEVCAPS_HWTRANSFORMANDLIGHT )
  1880. {
  1881. if( pD3DDeviceInfo->d3dCaps.DevCaps&D3DDEVCAPS_PUREDEVICE )
  1882. {
  1883. pD3DWindowedModeInfo->dwBehavior = D3DCREATE_HARDWARE_VERTEXPROCESSING |
  1884. D3DCREATE_PUREDEVICE;
  1885. if( SUCCEEDED( ConfirmDevice( &pD3DDeviceInfo->d3dCaps, pD3DWindowedModeInfo->dwBehavior,
  1886. pD3DWindowedModeInfo->BackBufferFormat ) ) )
  1887. bFormatConfirmed = TRUE;
  1888. }
  1889. if ( !bFormatConfirmed )
  1890. {
  1891. pD3DWindowedModeInfo->dwBehavior = D3DCREATE_HARDWARE_VERTEXPROCESSING;
  1892. if( SUCCEEDED( ConfirmDevice( &pD3DDeviceInfo->d3dCaps, pD3DWindowedModeInfo->dwBehavior,
  1893. pD3DWindowedModeInfo->BackBufferFormat ) ) )
  1894. bFormatConfirmed = TRUE;
  1895. }
  1896. if ( !bFormatConfirmed )
  1897. {
  1898. pD3DWindowedModeInfo->dwBehavior = D3DCREATE_MIXED_VERTEXPROCESSING;
  1899. if( SUCCEEDED( ConfirmDevice( &pD3DDeviceInfo->d3dCaps, pD3DWindowedModeInfo->dwBehavior,
  1900. pD3DWindowedModeInfo->BackBufferFormat ) ) )
  1901. bFormatConfirmed = TRUE;
  1902. }
  1903. }
  1904. // Confirm the device/format for SW vertex processing
  1905. if( !bFormatConfirmed )
  1906. {
  1907. pD3DWindowedModeInfo->dwBehavior = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  1908. if( SUCCEEDED( ConfirmDevice( &pD3DDeviceInfo->d3dCaps, pD3DWindowedModeInfo->dwBehavior,
  1909. pD3DWindowedModeInfo->BackBufferFormat ) ) )
  1910. bFormatConfirmed = TRUE;
  1911. }
  1912. if( bFormatConfirmed && m_bMultithreaded )
  1913. {
  1914. pD3DWindowedModeInfo->dwBehavior |= D3DCREATE_MULTITHREADED;
  1915. }
  1916. // Find a suitable depth/stencil buffer format for this device/format
  1917. if( bFormatConfirmed && m_bUseDepthBuffer )
  1918. {
  1919. if( !FindDepthStencilFormat( iAdapter, pD3DDeviceInfo->DeviceType,
  1920. pD3DWindowedModeInfo->BackBufferFormat, &pD3DWindowedModeInfo->DepthStencilFormat ) )
  1921. {
  1922. bFormatConfirmed = FALSE;
  1923. }
  1924. }
  1925. if( !bFormatConfirmed )
  1926. return E_FAIL;
  1927. return S_OK;
  1928. }
  1929. //-----------------------------------------------------------------------------
  1930. // Name: FindDepthStencilFormat()
  1931. // Desc: Finds a depth/stencil format for the given device that is compatible
  1932. // with the render target format and meets the needs of the app.
  1933. //-----------------------------------------------------------------------------
  1934. BOOL CD3DScreensaver::FindDepthStencilFormat( UINT iAdapter, D3DDEVTYPE DeviceType,
  1935. D3DFORMAT TargetFormat, D3DFORMAT* pDepthStencilFormat )
  1936. {
  1937. if( m_dwMinDepthBits <= 16 && m_dwMinStencilBits == 0 )
  1938. {
  1939. if( SUCCEEDED( m_pD3D->CheckDeviceFormat( iAdapter, DeviceType,
  1940. TargetFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D16 ) ) )
  1941. {
  1942. if( SUCCEEDED( m_pD3D->CheckDepthStencilMatch( iAdapter, DeviceType,
  1943. TargetFormat, TargetFormat, D3DFMT_D16 ) ) )
  1944. {
  1945. *pDepthStencilFormat = D3DFMT_D16;
  1946. return TRUE;
  1947. }
  1948. }
  1949. }
  1950. if( m_dwMinDepthBits <= 15 && m_dwMinStencilBits <= 1 )
  1951. {
  1952. if( SUCCEEDED( m_pD3D->CheckDeviceFormat( iAdapter, DeviceType,
  1953. TargetFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D15S1 ) ) )
  1954. {
  1955. if( SUCCEEDED( m_pD3D->CheckDepthStencilMatch( iAdapter, DeviceType,
  1956. TargetFormat, TargetFormat, D3DFMT_D15S1 ) ) )
  1957. {
  1958. *pDepthStencilFormat = D3DFMT_D15S1;
  1959. return TRUE;
  1960. }
  1961. }
  1962. }
  1963. if( m_dwMinDepthBits <= 24 && m_dwMinStencilBits == 0 )
  1964. {
  1965. if( SUCCEEDED( m_pD3D->CheckDeviceFormat( iAdapter, DeviceType,
  1966. TargetFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D24X8 ) ) )
  1967. {
  1968. if( SUCCEEDED( m_pD3D->CheckDepthStencilMatch( iAdapter, DeviceType,
  1969. TargetFormat, TargetFormat, D3DFMT_D24X8 ) ) )
  1970. {
  1971. *pDepthStencilFormat = D3DFMT_D24X8;
  1972. return TRUE;
  1973. }
  1974. }
  1975. }
  1976. if( m_dwMinDepthBits <= 24 && m_dwMinStencilBits <= 8 )
  1977. {
  1978. if( SUCCEEDED( m_pD3D->CheckDeviceFormat( iAdapter, DeviceType,
  1979. TargetFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D24S8 ) ) )
  1980. {
  1981. if( SUCCEEDED( m_pD3D->CheckDepthStencilMatch( iAdapter, DeviceType,
  1982. TargetFormat, TargetFormat, D3DFMT_D24S8 ) ) )
  1983. {
  1984. *pDepthStencilFormat = D3DFMT_D24S8;
  1985. return TRUE;
  1986. }
  1987. }
  1988. }
  1989. if( m_dwMinDepthBits <= 24 && m_dwMinStencilBits <= 4 )
  1990. {
  1991. if( SUCCEEDED( m_pD3D->CheckDeviceFormat( iAdapter, DeviceType,
  1992. TargetFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D24X4S4 ) ) )
  1993. {
  1994. if( SUCCEEDED( m_pD3D->CheckDepthStencilMatch( iAdapter, DeviceType,
  1995. TargetFormat, TargetFormat, D3DFMT_D24X4S4 ) ) )
  1996. {
  1997. *pDepthStencilFormat = D3DFMT_D24X4S4;
  1998. return TRUE;
  1999. }
  2000. }
  2001. }
  2002. if( m_dwMinDepthBits <= 32 && m_dwMinStencilBits == 0 )
  2003. {
  2004. if( SUCCEEDED( m_pD3D->CheckDeviceFormat( iAdapter, DeviceType,
  2005. TargetFormat, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, D3DFMT_D32 ) ) )
  2006. {
  2007. if( SUCCEEDED( m_pD3D->CheckDepthStencilMatch( iAdapter, DeviceType,
  2008. TargetFormat, TargetFormat, D3DFMT_D32 ) ) )
  2009. {
  2010. *pDepthStencilFormat = D3DFMT_D32;
  2011. return TRUE;
  2012. }
  2013. }
  2014. }
  2015. return FALSE;
  2016. }
  2017. //-----------------------------------------------------------------------------
  2018. // Name: Cleanup3DEnvironment()
  2019. // Desc:
  2020. //-----------------------------------------------------------------------------
  2021. VOID CD3DScreensaver::Cleanup3DEnvironment()
  2022. {
  2023. RenderUnit* pRenderUnit;
  2024. for( DWORD iRenderUnit = 0; iRenderUnit < m_dwNumRenderUnits; iRenderUnit++ )
  2025. {
  2026. pRenderUnit = &m_RenderUnits[iRenderUnit];
  2027. SwitchToRenderUnit( iRenderUnit );
  2028. if( pRenderUnit->bDeviceObjectsRestored )
  2029. {
  2030. InvalidateDeviceObjects();
  2031. pRenderUnit->bDeviceObjectsRestored = FALSE;
  2032. }
  2033. if( pRenderUnit->bDeviceObjectsInited )
  2034. {
  2035. DeleteDeviceObjects();
  2036. pRenderUnit->bDeviceObjectsInited = FALSE;
  2037. }
  2038. SAFE_RELEASE(m_pd3dDevice);
  2039. }
  2040. m_dwNumRenderUnits = 0;
  2041. SAFE_RELEASE(m_pD3D);
  2042. }
  2043. //-----------------------------------------------------------------------------
  2044. // Name: Render3DEnvironment()
  2045. // Desc:
  2046. //-----------------------------------------------------------------------------
  2047. HRESULT CD3DScreensaver::Render3DEnvironment()
  2048. {
  2049. HRESULT hr;
  2050. RenderUnit* pRenderUnit;
  2051. D3DAdapterInfo* pAdapterInfo;
  2052. m_fTime = DXUtil_Timer( TIMER_GETAPPTIME );
  2053. m_fElapsedTime = DXUtil_Timer( TIMER_GETELAPSEDTIME );
  2054. // Tell client to update the world
  2055. FrameMove();
  2056. UpdateFrameStats();
  2057. for( DWORD iRenderUnit = 0; iRenderUnit < m_dwNumRenderUnits; iRenderUnit++ )
  2058. {
  2059. pRenderUnit = &m_RenderUnits[iRenderUnit];
  2060. pAdapterInfo = m_Adapters[pRenderUnit->iAdapter];
  2061. SwitchToRenderUnit( iRenderUnit );
  2062. if( m_pd3dDevice == NULL )
  2063. continue;
  2064. // Test the cooperative level to see if it's okay to render
  2065. if( FAILED( hr = m_pd3dDevice->TestCooperativeLevel() ) )
  2066. {
  2067. // If the device was lost, do not render until we get it back
  2068. if( D3DERR_DEVICELOST == hr )
  2069. return S_OK;
  2070. // Check if the device needs to be reset.
  2071. if( D3DERR_DEVICENOTRESET == hr )
  2072. {
  2073. // If we are windowed, read the desktop mode and use the same format for
  2074. // the back buffer
  2075. if( m_bWindowed )
  2076. {
  2077. m_pD3D->GetAdapterDisplayMode( pRenderUnit->iAdapter, &pAdapterInfo->d3ddmDesktop );
  2078. // m_d3dpp.BackBufferFormat = pAdapterInfo->d3ddmDesktop.Format;
  2079. }
  2080. if( pRenderUnit->bDeviceObjectsRestored )
  2081. {
  2082. InvalidateDeviceObjects();
  2083. pRenderUnit->bDeviceObjectsRestored = FALSE;
  2084. }
  2085. if( FAILED( hr = m_pd3dDevice->Reset( &pRenderUnit->d3dpp ) ) )
  2086. {
  2087. m_bErrorMode = TRUE;
  2088. }
  2089. else
  2090. {
  2091. if( FAILED( hr = RestoreDeviceObjects() ) )
  2092. {
  2093. m_bErrorMode = TRUE;
  2094. }
  2095. else
  2096. {
  2097. pRenderUnit->bDeviceObjectsRestored = TRUE;
  2098. }
  2099. }
  2100. }
  2101. }
  2102. // Tell client to render using the current device
  2103. Render();
  2104. }
  2105. // Call Present() in a separate loop once all rendering is done
  2106. // so multiple monitors are as closely synced visually as possible
  2107. for( iRenderUnit = 0; iRenderUnit < m_dwNumRenderUnits; iRenderUnit++ )
  2108. {
  2109. pRenderUnit = &m_RenderUnits[iRenderUnit];
  2110. SwitchToRenderUnit( iRenderUnit );
  2111. // Present the results of the rendering to the screen
  2112. m_pd3dDevice->Present( NULL, NULL, NULL, NULL );
  2113. }
  2114. return S_OK;
  2115. }
  2116. //-----------------------------------------------------------------------------
  2117. // Name: UpdateErrorBox()
  2118. // Desc: Update the box that shows the error message
  2119. //-----------------------------------------------------------------------------
  2120. VOID CD3DScreensaver::UpdateErrorBox()
  2121. {
  2122. MonitorInfo* pMonitorInfo;
  2123. HWND hwnd;
  2124. RECT rcBounds;
  2125. static DWORD dwTimeLast = 0;
  2126. DWORD dwTimeNow;
  2127. FLOAT fTimeDelta;
  2128. // Make sure all the RenderUnits / D3D devices have been torn down
  2129. // so the error box is visible
  2130. if( m_bErrorMode && m_dwNumRenderUnits > 0 )
  2131. {
  2132. Cleanup3DEnvironment();
  2133. }
  2134. // Update timing to determine how much to move error box
  2135. if( dwTimeLast == 0 )
  2136. dwTimeLast = timeGetTime();
  2137. dwTimeNow = timeGetTime();
  2138. fTimeDelta = (FLOAT)(dwTimeNow - dwTimeLast) / 1000.0f;
  2139. dwTimeLast = dwTimeNow;
  2140. // Load error string if necessary
  2141. if( m_szError[0] == TEXT('\0') )
  2142. {
  2143. GetTextForError( m_hrError, m_szError, sizeof(m_szError) / sizeof(TCHAR) );
  2144. }
  2145. for( DWORD iMonitor = 0; iMonitor < m_dwNumMonitors; iMonitor++ )
  2146. {
  2147. pMonitorInfo = &m_Monitors[iMonitor];
  2148. hwnd = pMonitorInfo->hWnd;
  2149. if( hwnd == NULL )
  2150. continue;
  2151. if( m_SaverMode == sm_full )
  2152. {
  2153. rcBounds = pMonitorInfo->rcScreen;
  2154. ScreenToClient( hwnd, (POINT*)&rcBounds.left );
  2155. ScreenToClient( hwnd, (POINT*)&rcBounds.right );
  2156. }
  2157. else
  2158. {
  2159. rcBounds = m_rcRenderTotal;
  2160. }
  2161. if( pMonitorInfo->widthError == 0 )
  2162. {
  2163. if( m_SaverMode == sm_preview )
  2164. {
  2165. pMonitorInfo->widthError = (float) (rcBounds.right - rcBounds.left);
  2166. pMonitorInfo->heightError = (float) (rcBounds.bottom - rcBounds.top);
  2167. pMonitorInfo->xError = 0.0f;
  2168. pMonitorInfo->yError = 0.0f;
  2169. pMonitorInfo->xVelError = 0.0f;
  2170. pMonitorInfo->yVelError = 0.0f;
  2171. InvalidateRect( hwnd, NULL, FALSE ); // Invalidate the hwnd so it gets drawn
  2172. UpdateWindow( hwnd );
  2173. }
  2174. else
  2175. {
  2176. pMonitorInfo->widthError = 300;
  2177. pMonitorInfo->heightError = 150;
  2178. pMonitorInfo->xError = (rcBounds.right + rcBounds.left - pMonitorInfo->widthError) / 2.0f;
  2179. pMonitorInfo->yError = (rcBounds.bottom + rcBounds.top - pMonitorInfo->heightError) / 2.0f;
  2180. pMonitorInfo->xVelError = (rcBounds.right - rcBounds.left) / 10.0f;
  2181. pMonitorInfo->yVelError = (rcBounds.bottom - rcBounds.top) / 20.0f;
  2182. }
  2183. }
  2184. else
  2185. {
  2186. if( m_SaverMode != sm_preview )
  2187. {
  2188. RECT rcOld;
  2189. RECT rcNew;
  2190. SetRect( &rcOld, (INT)pMonitorInfo->xError, (INT)pMonitorInfo->yError,
  2191. (INT)(pMonitorInfo->xError + pMonitorInfo->widthError),
  2192. (INT)(pMonitorInfo->yError + pMonitorInfo->heightError) );
  2193. // Update rect velocity
  2194. if( (pMonitorInfo->xError + pMonitorInfo->xVelError * fTimeDelta +
  2195. pMonitorInfo->widthError > rcBounds.right && pMonitorInfo->xVelError > 0.0f) ||
  2196. (pMonitorInfo->xError + pMonitorInfo->xVelError * fTimeDelta <
  2197. rcBounds.left && pMonitorInfo->xVelError < 0.0f) )
  2198. {
  2199. pMonitorInfo->xVelError = -pMonitorInfo->xVelError;
  2200. }
  2201. if( (pMonitorInfo->yError + pMonitorInfo->yVelError * fTimeDelta +
  2202. pMonitorInfo->heightError > rcBounds.bottom && pMonitorInfo->yVelError > 0.0f) ||
  2203. (pMonitorInfo->yError + pMonitorInfo->yVelError * fTimeDelta <
  2204. rcBounds.top && pMonitorInfo->yVelError < 0.0f) )
  2205. {
  2206. pMonitorInfo->yVelError = -pMonitorInfo->yVelError;
  2207. }
  2208. // Update rect position
  2209. pMonitorInfo->xError += pMonitorInfo->xVelError * fTimeDelta;
  2210. pMonitorInfo->yError += pMonitorInfo->yVelError * fTimeDelta;
  2211. SetRect( &rcNew, (INT)pMonitorInfo->xError, (INT)pMonitorInfo->yError,
  2212. (INT)(pMonitorInfo->xError + pMonitorInfo->widthError),
  2213. (INT)(pMonitorInfo->yError + pMonitorInfo->heightError) );
  2214. if( rcOld.left != rcNew.left || rcOld.top != rcNew.top )
  2215. {
  2216. InvalidateRect( hwnd, &rcOld, FALSE ); // Invalidate old rect so it gets erased
  2217. InvalidateRect( hwnd, &rcNew, FALSE ); // Invalidate new rect so it gets drawn
  2218. UpdateWindow( hwnd );
  2219. }
  2220. }
  2221. }
  2222. }
  2223. }
  2224. //-----------------------------------------------------------------------------
  2225. // Name: GetTextForError()
  2226. // Desc: Translate an HRESULT error code into a string that can be displayed
  2227. // to explain the error. A class derived from CD3DScreensaver can
  2228. // provide its own version of this function that provides app-specific
  2229. // error translation instead of or in addition to calling this function.
  2230. // This function returns TRUE if a specific error was translated, or
  2231. // FALSE if no specific translation for the HRESULT was found (though
  2232. // it still puts a generic string into pszError).
  2233. //-----------------------------------------------------------------------------
  2234. BOOL CD3DScreensaver::GetTextForError( HRESULT hr, TCHAR* pszError,
  2235. DWORD dwNumChars )
  2236. {
  2237. const DWORD dwErrorMap[][2] =
  2238. {
  2239. // HRESULT, stringID
  2240. E_FAIL, IDS_ERR_GENERIC,
  2241. D3DAPPERR_NODIRECT3D, IDS_ERR_NODIRECT3D,
  2242. D3DAPPERR_NOWINDOWEDHAL, IDS_ERR_NOWINDOWEDHAL,
  2243. D3DAPPERR_CREATEDEVICEFAILED, IDS_ERR_CREATEDEVICEFAILED,
  2244. D3DAPPERR_NOCOMPATIBLEDEVICES, IDS_ERR_NOCOMPATIBLEDEVICES,
  2245. D3DAPPERR_NOHARDWAREDEVICE, IDS_ERR_NOHARDWAREDEVICE,
  2246. D3DAPPERR_HALNOTCOMPATIBLE, IDS_ERR_HALNOTCOMPATIBLE,
  2247. D3DAPPERR_NOHALTHISMODE, IDS_ERR_NOHALTHISMODE,
  2248. D3DAPPERR_MEDIANOTFOUND, IDS_ERR_MEDIANOTFOUND,
  2249. D3DAPPERR_RESIZEFAILED, IDS_ERR_RESIZEFAILED,
  2250. E_OUTOFMEMORY, IDS_ERR_OUTOFMEMORY,
  2251. D3DERR_OUTOFVIDEOMEMORY, IDS_ERR_OUTOFVIDEOMEMORY,
  2252. D3DAPPERR_NOPREVIEW, IDS_ERR_NOPREVIEW
  2253. };
  2254. const DWORD dwErrorMapSize = sizeof(dwErrorMap) / sizeof(DWORD[2]);
  2255. DWORD iError;
  2256. DWORD resid = 0;
  2257. for( iError = 0; iError < dwErrorMapSize; iError++ )
  2258. {
  2259. if( hr == (HRESULT)dwErrorMap[iError][0] )
  2260. {
  2261. resid = dwErrorMap[iError][1];
  2262. }
  2263. }
  2264. if( resid == 0 )
  2265. {
  2266. resid = IDS_ERR_GENERIC;
  2267. }
  2268. LoadString( NULL, resid, pszError, dwNumChars );
  2269. if( resid == IDS_ERR_GENERIC )
  2270. return FALSE;
  2271. else
  2272. return TRUE;
  2273. }
  2274. //-----------------------------------------------------------------------------
  2275. // Name: UpdateFrameStats()
  2276. // Desc: Keep track of the frame count
  2277. //-----------------------------------------------------------------------------
  2278. VOID CD3DScreensaver::UpdateFrameStats()
  2279. {
  2280. UINT iRenderUnit;
  2281. RenderUnit* pRenderUnit;
  2282. UINT iAdapter;
  2283. static FLOAT fLastTime = 0.0f;
  2284. static DWORD dwFrames = 0L;
  2285. FLOAT fTime = DXUtil_Timer( TIMER_GETABSOLUTETIME );
  2286. ++dwFrames;
  2287. // Update the scene stats once per second
  2288. if( fTime - fLastTime > 1.0f )
  2289. {
  2290. m_fFPS = dwFrames / (fTime - fLastTime);
  2291. fLastTime = fTime;
  2292. dwFrames = 0L;
  2293. for( iRenderUnit = 0; iRenderUnit < m_dwNumRenderUnits; iRenderUnit++ )
  2294. {
  2295. pRenderUnit = &m_RenderUnits[iRenderUnit];
  2296. iAdapter = pRenderUnit->iAdapter;
  2297. // Get adapter's current mode so we can report
  2298. // bit depth (back buffer depth may be unknown)
  2299. D3DDISPLAYMODE mode;
  2300. m_pD3D->GetAdapterDisplayMode( iAdapter, &mode );
  2301. _stprintf( pRenderUnit->strFrameStats, TEXT("%.02f fps (%dx%dx%d)"), m_fFPS,
  2302. mode.Width, mode.Height,
  2303. mode.Format==D3DFMT_X8R8G8B8?32:16 );
  2304. if( m_bUseDepthBuffer )
  2305. {
  2306. D3DAdapterInfo* pAdapterInfo = m_Adapters[iAdapter];
  2307. D3DDeviceInfo* pDeviceInfo = &pAdapterInfo->devices[pAdapterInfo->dwCurrentDevice];
  2308. D3DModeInfo* pModeInfo = &pDeviceInfo->modes[pDeviceInfo->dwCurrentMode];
  2309. switch( pModeInfo->DepthStencilFormat )
  2310. {
  2311. case D3DFMT_D16:
  2312. lstrcat( pRenderUnit->strFrameStats, TEXT(" (D16)") );
  2313. break;
  2314. case D3DFMT_D15S1:
  2315. lstrcat( pRenderUnit->strFrameStats, TEXT(" (D15S1)") );
  2316. break;
  2317. case D3DFMT_D24X8:
  2318. lstrcat( pRenderUnit->strFrameStats, TEXT(" (D24X8)") );
  2319. break;
  2320. case D3DFMT_D24S8:
  2321. lstrcat( pRenderUnit->strFrameStats, TEXT(" (D24S8)") );
  2322. break;
  2323. case D3DFMT_D24X4S4:
  2324. lstrcat( pRenderUnit->strFrameStats, TEXT(" (D24X4S4)") );
  2325. break;
  2326. case D3DFMT_D32:
  2327. lstrcat( pRenderUnit->strFrameStats, TEXT(" (D32)") );
  2328. break;
  2329. }
  2330. }
  2331. }
  2332. }
  2333. }
  2334. //-----------------------------------------------------------------------------
  2335. // Name: DoPaint()
  2336. // Desc:
  2337. //-----------------------------------------------------------------------------
  2338. VOID CD3DScreensaver::DoPaint(HWND hwnd, HDC hdc)
  2339. {
  2340. HMONITOR hMonitor = MonitorFromWindow( hwnd, MONITOR_DEFAULTTONEAREST );
  2341. MonitorInfo* pMonitorInfo = NULL;
  2342. for( DWORD iMonitor = 0; iMonitor < m_dwNumMonitors; iMonitor++)
  2343. {
  2344. pMonitorInfo = &m_Monitors[iMonitor];
  2345. if( pMonitorInfo->hMonitor == hMonitor )
  2346. break;
  2347. }
  2348. if( pMonitorInfo == NULL || iMonitor == m_dwNumMonitors )
  2349. return;
  2350. // Draw the error message box
  2351. HBRUSH hbrBlack = (HBRUSH)GetStockObject(BLACK_BRUSH);
  2352. RECT rc;
  2353. SetRect( &rc, (INT)pMonitorInfo->xError, (INT)pMonitorInfo->yError,
  2354. (INT)(pMonitorInfo->xError + pMonitorInfo->widthError),
  2355. (INT)(pMonitorInfo->yError + pMonitorInfo->heightError) );
  2356. FillRect(hdc, &rc, (HBRUSH)(COLOR_WINDOW+1));
  2357. if( hbrBlack != NULL )
  2358. FrameRect(hdc, &rc, hbrBlack);
  2359. RECT rc2;
  2360. int height;
  2361. rc2 = rc;
  2362. height = DrawText(hdc, m_szError, -1, &rc, DT_WORDBREAK | DT_CENTER | DT_CALCRECT );
  2363. rc = rc2;
  2364. rc2.top = (rc.bottom + rc.top - height) / 2;
  2365. DrawText(hdc, m_szError, -1, &rc2, DT_WORDBREAK | DT_CENTER );
  2366. // Erase everywhere except the error message box
  2367. ExcludeClipRect( hdc, rc.left, rc.top, rc.right, rc.bottom );
  2368. rc = pMonitorInfo->rcScreen;
  2369. ScreenToClient( hwnd, (POINT*)&rc.left );
  2370. ScreenToClient( hwnd, (POINT*)&rc.right );
  2371. if( hbrBlack != NULL )
  2372. FillRect(hdc, &rc, hbrBlack );
  2373. }
  2374. //-----------------------------------------------------------------------------
  2375. // Name: ChangePassword()
  2376. // Desc:
  2377. //-----------------------------------------------------------------------------
  2378. VOID CD3DScreensaver::ChangePassword()
  2379. {
  2380. // Load the password change DLL
  2381. HINSTANCE mpr = LoadLibrary( TEXT("MPR.DLL") );
  2382. if ( mpr != NULL )
  2383. {
  2384. // Grab the password change function from it
  2385. typedef DWORD (PASCAL *PWCHGPROC)( LPCSTR, HWND, DWORD, LPVOID );
  2386. PWCHGPROC pwd = (PWCHGPROC)GetProcAddress( mpr, "PwdChangePasswordA" );
  2387. // Do the password change
  2388. if ( pwd != NULL )
  2389. pwd( "SCRSAVE", m_hWndParent, 0, NULL );
  2390. // Free the library
  2391. FreeLibrary( mpr );
  2392. }
  2393. }
  2394. //-----------------------------------------------------------------------------
  2395. // Name: DisplayErrorMsg()
  2396. // Desc: Displays error messages in a message box
  2397. //-----------------------------------------------------------------------------
  2398. HRESULT CD3DScreensaver::DisplayErrorMsg( HRESULT hr, DWORD dwType )
  2399. {
  2400. TCHAR strMsg[512];
  2401. GetTextForError( hr, strMsg, 512 );
  2402. MessageBox( m_hWnd, strMsg, m_strWindowTitle, MB_ICONERROR | MB_OK );
  2403. return hr;
  2404. }
  2405. //-----------------------------------------------------------------------------
  2406. // Name: ReadScreenSettings()
  2407. // Desc: Read the registry settings that affect how the screens are set up and
  2408. // used.
  2409. //-----------------------------------------------------------------------------
  2410. VOID CD3DScreensaver::ReadScreenSettings( HKEY hkeyParent )
  2411. {
  2412. TCHAR strKey[100];
  2413. DWORD iMonitor;
  2414. MonitorInfo* pMonitorInfo;
  2415. DWORD iAdapter;
  2416. D3DAdapterInfo* pD3DAdapterInfo;
  2417. HKEY hkey;
  2418. DWORD dwType = REG_DWORD;
  2419. DWORD dwLength = sizeof(DWORD);
  2420. DWORD dwLength2 = sizeof(GUID);
  2421. GUID guidAdapterID;
  2422. GUID guidZero;
  2423. ZeroMemory( &guidAdapterID, sizeof(GUID) );
  2424. ZeroMemory( &guidZero, sizeof(GUID) );
  2425. RegQueryValueEx( hkeyParent, TEXT("AllScreensSame"), NULL, &dwType,
  2426. (BYTE*)&m_bAllScreensSame, &dwLength);
  2427. for( iMonitor = 0; iMonitor < m_dwNumMonitors; iMonitor++ )
  2428. {
  2429. pMonitorInfo = &m_Monitors[iMonitor];
  2430. iAdapter = pMonitorInfo->iAdapter;
  2431. if( iAdapter == NO_ADAPTER )
  2432. continue;
  2433. pD3DAdapterInfo = m_Adapters[iAdapter];
  2434. wsprintf( strKey, TEXT("Screen %d"), iMonitor + 1 );
  2435. if( ERROR_SUCCESS == RegCreateKeyEx( hkeyParent, strKey,
  2436. 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL ) )
  2437. {
  2438. RegQueryValueEx( hkey, TEXT("Adapter ID"), NULL, &dwType,
  2439. (BYTE*)&guidAdapterID, &dwLength2);
  2440. RegQueryValueEx( hkey, TEXT("Leave Black"), NULL, &dwType,
  2441. (BYTE*)&pD3DAdapterInfo->bLeaveBlack, &dwLength);
  2442. if( guidAdapterID == pD3DAdapterInfo->d3dAdapterIdentifier.DeviceIdentifier ||
  2443. guidAdapterID == guidZero )
  2444. {
  2445. RegQueryValueEx( hkey, TEXT("Disable Hardware"), NULL, &dwType,
  2446. (BYTE*)&pD3DAdapterInfo->bDisableHW, &dwLength);
  2447. RegQueryValueEx( hkey, TEXT("Width"), NULL, &dwType,
  2448. (BYTE*)&pD3DAdapterInfo->dwUserPrefWidth, &dwLength);
  2449. RegQueryValueEx( hkey, TEXT("Height"), NULL, &dwType,
  2450. (BYTE*)&pD3DAdapterInfo->dwUserPrefHeight, &dwLength);
  2451. RegQueryValueEx( hkey, TEXT("Format"), NULL, &dwType,
  2452. (BYTE*)&pD3DAdapterInfo->d3dfmtUserPrefFormat, &dwLength);
  2453. }
  2454. RegCloseKey( hkey);
  2455. }
  2456. }
  2457. }
  2458. //-----------------------------------------------------------------------------
  2459. // Name: WriteScreenSettings()
  2460. // Desc: Write the registry settings that affect how the screens are set up and
  2461. // used.
  2462. //-----------------------------------------------------------------------------
  2463. VOID CD3DScreensaver::WriteScreenSettings( HKEY hkeyParent )
  2464. {
  2465. TCHAR strKey[100];
  2466. DWORD iMonitor;
  2467. MonitorInfo* pMonitorInfo;
  2468. DWORD iAdapter;
  2469. D3DAdapterInfo* pD3DAdapterInfo;
  2470. HKEY hkey;
  2471. RegSetValueEx( hkeyParent, TEXT("AllScreensSame"), NULL, REG_DWORD,
  2472. (BYTE*)&m_bAllScreensSame, sizeof(DWORD) );
  2473. for( iMonitor = 0; iMonitor < m_dwNumMonitors; iMonitor++ )
  2474. {
  2475. pMonitorInfo = &m_Monitors[iMonitor];
  2476. iAdapter = pMonitorInfo->iAdapter;
  2477. if( iAdapter == NO_ADAPTER )
  2478. continue;
  2479. pD3DAdapterInfo = m_Adapters[iAdapter];
  2480. wsprintf( strKey, TEXT("Screen %d"), iMonitor + 1 );
  2481. if( ERROR_SUCCESS == RegCreateKeyEx( hkeyParent, strKey,
  2482. 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL ) )
  2483. {
  2484. RegSetValueEx( hkey, TEXT("Leave Black"), NULL, REG_DWORD,
  2485. (BYTE*)&pD3DAdapterInfo->bLeaveBlack, sizeof(DWORD) );
  2486. RegSetValueEx( hkey, TEXT("Disable Hardware"), NULL, REG_DWORD,
  2487. (BYTE*)&pD3DAdapterInfo->bDisableHW, sizeof(DWORD) );
  2488. RegSetValueEx( hkey, TEXT("Width"), NULL, REG_DWORD,
  2489. (BYTE*)&pD3DAdapterInfo->dwUserPrefWidth, sizeof(DWORD) );
  2490. RegSetValueEx( hkey, TEXT("Height"), NULL, REG_DWORD,
  2491. (BYTE*)&pD3DAdapterInfo->dwUserPrefHeight, sizeof(DWORD) );
  2492. RegSetValueEx( hkey, TEXT("Format"), NULL, REG_DWORD,
  2493. (BYTE*)&pD3DAdapterInfo->d3dfmtUserPrefFormat, sizeof(DWORD) );
  2494. RegSetValueEx( hkey, TEXT("Adapter ID"), NULL, REG_BINARY,
  2495. (BYTE*)&pD3DAdapterInfo->d3dAdapterIdentifier.DeviceIdentifier, sizeof(GUID) );
  2496. RegCloseKey( hkey);
  2497. }
  2498. }
  2499. }
  2500. //-----------------------------------------------------------------------------
  2501. // Name: DoScreenSettingsDialog()
  2502. // Desc:
  2503. //-----------------------------------------------------------------------------
  2504. VOID CD3DScreensaver::DoScreenSettingsDialog( HWND hwndParent )
  2505. {
  2506. LPCTSTR pstrTemplate;
  2507. if( m_dwNumAdapters > 1 && !m_bOneScreenOnly )
  2508. pstrTemplate = MAKEINTRESOURCE( IDD_MULTIMONITORSETTINGS );
  2509. else
  2510. pstrTemplate = MAKEINTRESOURCE( IDD_SINGLEMONITORSETTINGS );
  2511. DialogBox(m_hInstance, pstrTemplate, hwndParent, ScreenSettingsDlgProcStub );
  2512. }
  2513. //-----------------------------------------------------------------------------
  2514. // Name: ScreenSettingsDlgProcStub()
  2515. // Desc:
  2516. //-----------------------------------------------------------------------------
  2517. INT_PTR CALLBACK CD3DScreensaver::ScreenSettingsDlgProcStub( HWND hWnd, UINT uMsg,
  2518. WPARAM wParam, LPARAM lParam )
  2519. {
  2520. return s_pD3DScreensaver->ScreenSettingsDlgProc( hWnd, uMsg, wParam, lParam );
  2521. }
  2522. // We need to store a copy of the original screen settings so that the user
  2523. // can modify those settings in the dialog, then hit Cancel and have the
  2524. // original settings restored.
  2525. static D3DAdapterInfo* s_AdaptersSave[9];
  2526. static BOOL s_bAllScreensSameSave;
  2527. //-----------------------------------------------------------------------------
  2528. // Name: ScreenSettingsDlgProc()
  2529. // Desc:
  2530. //-----------------------------------------------------------------------------
  2531. INT_PTR CD3DScreensaver::ScreenSettingsDlgProc( HWND hWnd, UINT uMsg,
  2532. WPARAM wParam, LPARAM lParam )
  2533. {
  2534. HWND hwndTabs = GetDlgItem(hWnd, IDC_MONITORSTAB);
  2535. HWND hwndModeList = GetDlgItem(hWnd, IDC_MODESCOMBO);
  2536. DWORD iMonitor;
  2537. MonitorInfo* pMonitorInfo;
  2538. DWORD iAdapter;
  2539. switch (uMsg)
  2540. {
  2541. case WM_INITDIALOG:
  2542. {
  2543. INT i = 0;
  2544. TC_ITEM tie;
  2545. TCHAR szFmt[100];
  2546. TCHAR sz[100];
  2547. GetWindowText(GetDlgItem(hWnd, IDC_TABNAMEFMT), szFmt, 100);
  2548. tie.mask = TCIF_TEXT | TCIF_IMAGE;
  2549. tie.iImage = -1;
  2550. for( iMonitor = 0; iMonitor < m_dwNumMonitors; iMonitor++ )
  2551. {
  2552. wsprintf(sz, szFmt, iMonitor + 1);
  2553. tie.pszText = sz;
  2554. TabCtrl_InsertItem(hwndTabs, i++, &tie);
  2555. }
  2556. for( iAdapter = 0; iAdapter < m_dwNumAdapters; iAdapter++ )
  2557. {
  2558. s_AdaptersSave[iAdapter] = new D3DAdapterInfo;
  2559. if( s_AdaptersSave[iAdapter] != NULL )
  2560. *s_AdaptersSave[iAdapter] = *m_Adapters[iAdapter];
  2561. }
  2562. s_bAllScreensSameSave = m_bAllScreensSame;
  2563. SetupAdapterPage(hWnd);
  2564. CheckDlgButton(hWnd, IDC_SAME, (m_bAllScreensSame ? BST_CHECKED : BST_UNCHECKED));
  2565. }
  2566. return TRUE;
  2567. case WM_NOTIFY:
  2568. {
  2569. NMHDR* pnmh = (LPNMHDR)lParam;
  2570. UINT code = pnmh->code;
  2571. if (code == TCN_SELCHANGE)
  2572. {
  2573. SetupAdapterPage(hWnd);
  2574. }
  2575. }
  2576. return TRUE;
  2577. case WM_COMMAND:
  2578. switch( LOWORD( wParam ) )
  2579. {
  2580. case IDC_SAME:
  2581. m_bAllScreensSame = (IsDlgButtonChecked(hWnd, IDC_SAME) == BST_CHECKED);
  2582. break;
  2583. case IDC_LEAVEBLACK:
  2584. case IDC_RENDER:
  2585. if( m_bOneScreenOnly )
  2586. {
  2587. GetBestAdapter( &iAdapter );
  2588. iMonitor = m_Adapters[iAdapter]->iMonitor;
  2589. }
  2590. else
  2591. {
  2592. iMonitor = TabCtrl_GetCurSel(hwndTabs);
  2593. }
  2594. pMonitorInfo = &m_Monitors[iMonitor];
  2595. iAdapter = pMonitorInfo->iAdapter;
  2596. if( IsDlgButtonChecked(hWnd, IDC_LEAVEBLACK) == BST_CHECKED )
  2597. {
  2598. m_Adapters[iAdapter]->bLeaveBlack = TRUE;
  2599. EnableWindow(GetDlgItem(hWnd, IDC_MODESCOMBO), FALSE);
  2600. EnableWindow(GetDlgItem(hWnd, IDC_MODESSTATIC), FALSE);
  2601. EnableWindow(GetDlgItem(hWnd, IDC_DISPLAYMODEBOX), FALSE);
  2602. EnableWindow(GetDlgItem(hWnd, IDC_DISPLAYMODENOTE), FALSE);
  2603. }
  2604. else
  2605. {
  2606. m_Adapters[iAdapter]->bLeaveBlack = FALSE;
  2607. EnableWindow(GetDlgItem(hWnd, IDC_MODESCOMBO), TRUE);
  2608. EnableWindow(GetDlgItem(hWnd, IDC_MODESSTATIC), TRUE);
  2609. EnableWindow(GetDlgItem(hWnd, IDC_DISPLAYMODEBOX), TRUE);
  2610. EnableWindow(GetDlgItem(hWnd, IDC_DISPLAYMODENOTE), TRUE);
  2611. }
  2612. break;
  2613. case IDC_MODESCOMBO:
  2614. if (HIWORD(wParam) == CBN_SELCHANGE)
  2615. {
  2616. DWORD iSel;
  2617. DWORD iMode;
  2618. if( m_bOneScreenOnly )
  2619. {
  2620. GetBestAdapter( &iAdapter );
  2621. iMonitor = m_Adapters[iAdapter]->iMonitor;
  2622. }
  2623. else
  2624. {
  2625. iMonitor = TabCtrl_GetCurSel(hwndTabs);
  2626. }
  2627. pMonitorInfo = &m_Monitors[iMonitor];
  2628. iAdapter = pMonitorInfo->iAdapter;
  2629. iSel = ComboBox_GetCurSel( hwndModeList );
  2630. if( iSel == 0 )
  2631. {
  2632. // "Automatic"
  2633. m_Adapters[iAdapter]->dwUserPrefWidth = 0;
  2634. m_Adapters[iAdapter]->dwUserPrefHeight = 0;
  2635. m_Adapters[iAdapter]->d3dfmtUserPrefFormat = D3DFMT_UNKNOWN;
  2636. }
  2637. else
  2638. {
  2639. D3DAdapterInfo* pD3DAdapterInfo = m_Adapters[iAdapter];
  2640. D3DDeviceInfo* pD3DDeviceInfo;
  2641. D3DModeInfo* pD3DModeInfo;
  2642. pD3DDeviceInfo = &pD3DAdapterInfo->devices[pD3DAdapterInfo->dwCurrentDevice];
  2643. iMode = (DWORD)ComboBox_GetItemData( hwndModeList, iSel );
  2644. pD3DModeInfo = &pD3DDeviceInfo->modes[iMode];
  2645. m_Adapters[iAdapter]->dwUserPrefWidth = pD3DModeInfo->Width;
  2646. m_Adapters[iAdapter]->dwUserPrefHeight = pD3DModeInfo->Height;
  2647. m_Adapters[iAdapter]->d3dfmtUserPrefFormat = pD3DModeInfo->Format;
  2648. }
  2649. }
  2650. break;
  2651. case IDC_DISABLEHW:
  2652. if( m_bOneScreenOnly )
  2653. {
  2654. GetBestAdapter( &iAdapter );
  2655. iMonitor = m_Adapters[iAdapter]->iMonitor;
  2656. }
  2657. else
  2658. {
  2659. iMonitor = TabCtrl_GetCurSel(hwndTabs);
  2660. }
  2661. pMonitorInfo = &m_Monitors[iMonitor];
  2662. iAdapter = pMonitorInfo->iAdapter;
  2663. if( IsDlgButtonChecked( hWnd, IDC_DISABLEHW ) == BST_CHECKED )
  2664. m_Adapters[iAdapter]->bDisableHW = TRUE;
  2665. else
  2666. m_Adapters[iAdapter]->bDisableHW = FALSE;
  2667. SetupAdapterPage( hWnd );
  2668. break;
  2669. case IDC_MOREINFO:
  2670. {
  2671. if( m_bOneScreenOnly )
  2672. {
  2673. GetBestAdapter( &iAdapter );
  2674. iMonitor = m_Adapters[iAdapter]->iMonitor;
  2675. }
  2676. else
  2677. {
  2678. iMonitor = TabCtrl_GetCurSel(hwndTabs);
  2679. }
  2680. pMonitorInfo = &m_Monitors[iMonitor];
  2681. iAdapter = pMonitorInfo->iAdapter;
  2682. D3DAdapterInfo* pD3DAdapterInfo;
  2683. TCHAR szText[500];
  2684. if( pMonitorInfo->hMonitor == NULL )
  2685. pD3DAdapterInfo = NULL;
  2686. else
  2687. pD3DAdapterInfo = m_Adapters[pMonitorInfo->iAdapter];
  2688. // Accelerated / Unaccelerated settings
  2689. BOOL bHasHAL = FALSE;
  2690. BOOL bHasAppCompatHAL = FALSE;
  2691. BOOL bDisabledHAL = FALSE;
  2692. BOOL bHasSW = FALSE;
  2693. BOOL bHasAppCompatSW = FALSE;
  2694. if( pD3DAdapterInfo != NULL )
  2695. {
  2696. bHasHAL = pD3DAdapterInfo->bHasHAL;
  2697. bHasAppCompatHAL = pD3DAdapterInfo->bHasAppCompatHAL;
  2698. bDisabledHAL = pD3DAdapterInfo->bDisableHW;
  2699. bHasSW = pD3DAdapterInfo->bHasSW;
  2700. bHasAppCompatSW = pD3DAdapterInfo->bHasAppCompatSW;
  2701. }
  2702. if( bHasHAL && !bDisabledHAL && bHasAppCompatHAL )
  2703. {
  2704. // Good HAL
  2705. LoadString( NULL, IDS_INFO_GOODHAL, szText, 500 );
  2706. }
  2707. else if( bHasHAL && bDisabledHAL )
  2708. {
  2709. // Disabled HAL
  2710. if( bHasSW && bHasAppCompatSW )
  2711. LoadString( NULL, IDS_INFO_DISABLEDHAL_GOODSW, szText, 500 );
  2712. else if( bHasSW )
  2713. LoadString( NULL, IDS_INFO_DISABLEDHAL_BADSW, szText, 500 );
  2714. else
  2715. LoadString( NULL, IDS_INFO_DISABLEDHAL_NOSW, szText, 500 );
  2716. }
  2717. else if( bHasHAL && !bHasAppCompatHAL )
  2718. {
  2719. // Bad HAL
  2720. if( bHasSW && bHasAppCompatSW )
  2721. LoadString( NULL, IDS_INFO_BADHAL_GOODSW, szText, 500 );
  2722. else if( bHasSW )
  2723. LoadString( NULL, IDS_INFO_BADHAL_BADSW, szText, 500 );
  2724. else
  2725. LoadString( NULL, IDS_INFO_BADHAL_NOSW, szText, 500 );
  2726. }
  2727. else
  2728. {
  2729. // No HAL
  2730. if( bHasSW && bHasAppCompatSW )
  2731. LoadString( NULL, IDS_INFO_NOHAL_GOODSW, szText, 500 );
  2732. else if( bHasSW )
  2733. LoadString( NULL, IDS_INFO_NOHAL_BADSW, szText, 500 );
  2734. else
  2735. LoadString( NULL, IDS_INFO_NOHAL_NOSW, szText, 500 );
  2736. }
  2737. MessageBox( hWnd, szText, pMonitorInfo->strDeviceName, MB_OK | MB_ICONINFORMATION );
  2738. break;
  2739. }
  2740. case IDOK:
  2741. for( iAdapter = 0; iAdapter < m_dwNumAdapters; iAdapter++ )
  2742. {
  2743. SAFE_DELETE( s_AdaptersSave[iAdapter] );
  2744. }
  2745. EndDialog(hWnd, IDOK);
  2746. break;
  2747. case IDCANCEL:
  2748. // Restore member values to original state
  2749. for( iAdapter = 0; iAdapter < m_dwNumAdapters; iAdapter++ )
  2750. {
  2751. if( s_AdaptersSave[iAdapter] != NULL )
  2752. *m_Adapters[iAdapter] = *s_AdaptersSave[iAdapter];
  2753. SAFE_DELETE( s_AdaptersSave[iAdapter] );
  2754. }
  2755. m_bAllScreensSame = s_bAllScreensSameSave;
  2756. EndDialog(hWnd, IDCANCEL);
  2757. break;
  2758. }
  2759. return TRUE;
  2760. default:
  2761. return FALSE;
  2762. }
  2763. }
  2764. //-----------------------------------------------------------------------------
  2765. // Name: SetupAdapterPage()
  2766. // Desc: Set up the controls for a given page in the Screen Settings dialog.
  2767. //-----------------------------------------------------------------------------
  2768. VOID CD3DScreensaver::SetupAdapterPage( HWND hWnd )
  2769. {
  2770. HWND hwndTabs = GetDlgItem(hWnd, IDC_MONITORSTAB);
  2771. HWND hwndModeList = GetDlgItem(hWnd, IDC_MODESCOMBO);
  2772. UINT iPage = TabCtrl_GetCurFocus(hwndTabs);
  2773. HWND hwndDesc = GetDlgItem(hWnd, IDC_ADAPTERNAME);
  2774. MonitorInfo* pMonitorInfo;
  2775. D3DAdapterInfo* pD3DAdapterInfo;
  2776. D3DDeviceInfo* pD3DDeviceInfo;
  2777. D3DModeInfo* pD3DModeInfo;
  2778. if( m_bOneScreenOnly )
  2779. {
  2780. DWORD iAdapter;
  2781. GetBestAdapter( &iAdapter );
  2782. if( iAdapter != NO_ADAPTER )
  2783. {
  2784. pD3DAdapterInfo = m_Adapters[iAdapter];
  2785. iPage = pD3DAdapterInfo->iMonitor;
  2786. }
  2787. }
  2788. pMonitorInfo = &m_Monitors[iPage];
  2789. SetWindowText( hwndDesc, pMonitorInfo->strDeviceName );
  2790. if( pMonitorInfo->iAdapter == NO_ADAPTER )
  2791. pD3DAdapterInfo = NULL;
  2792. else
  2793. pD3DAdapterInfo = m_Adapters[pMonitorInfo->iAdapter];
  2794. // Accelerated / Unaccelerated settings
  2795. BOOL bHasHAL = FALSE;
  2796. BOOL bHasAppCompatHAL = FALSE;
  2797. BOOL bDisabledHAL = FALSE;
  2798. BOOL bHasSW = FALSE;
  2799. BOOL bHasAppCompatSW = FALSE;
  2800. if( pD3DAdapterInfo != NULL )
  2801. {
  2802. bHasHAL = pD3DAdapterInfo->bHasHAL;
  2803. bHasAppCompatHAL = pD3DAdapterInfo->bHasAppCompatHAL;
  2804. bDisabledHAL = pD3DAdapterInfo->bDisableHW;
  2805. bHasSW = pD3DAdapterInfo->bHasSW;
  2806. bHasAppCompatSW = pD3DAdapterInfo->bHasAppCompatSW;
  2807. }
  2808. TCHAR szStatus[200];
  2809. if( bHasHAL && !bDisabledHAL && bHasAppCompatHAL )
  2810. {
  2811. LoadString( NULL, IDS_RENDERING_HAL, szStatus, 200 );
  2812. }
  2813. else if( bHasSW && bHasAppCompatSW )
  2814. {
  2815. LoadString( NULL, IDS_RENDERING_SW, szStatus, 200 );
  2816. }
  2817. else
  2818. {
  2819. LoadString( NULL, IDS_RENDERING_NONE, szStatus, 200 );
  2820. }
  2821. SetWindowText( GetDlgItem( hWnd, IDC_RENDERING ), szStatus );
  2822. if( bHasHAL && bHasAppCompatHAL )
  2823. {
  2824. EnableWindow( GetDlgItem( hWnd, IDC_DISABLEHW ), TRUE );
  2825. CheckDlgButton( hWnd, IDC_DISABLEHW,
  2826. pD3DAdapterInfo->bDisableHW ? BST_CHECKED : BST_UNCHECKED );
  2827. }
  2828. else
  2829. {
  2830. EnableWindow( GetDlgItem( hWnd, IDC_DISABLEHW ), FALSE );
  2831. CheckDlgButton( hWnd, IDC_DISABLEHW, BST_UNCHECKED );
  2832. }
  2833. if( bHasAppCompatHAL || bHasAppCompatSW )
  2834. {
  2835. if( pD3DAdapterInfo->bLeaveBlack )
  2836. CheckRadioButton(hWnd, IDC_RENDER, IDC_LEAVEBLACK, IDC_LEAVEBLACK);
  2837. else
  2838. CheckRadioButton(hWnd, IDC_RENDER, IDC_LEAVEBLACK, IDC_RENDER);
  2839. EnableWindow(GetDlgItem(hWnd, IDC_LEAVEBLACK), TRUE);
  2840. EnableWindow(GetDlgItem(hWnd, IDC_RENDER), TRUE);
  2841. EnableWindow(GetDlgItem(hWnd, IDC_SCREENUSAGEBOX), TRUE);
  2842. }
  2843. else
  2844. {
  2845. CheckRadioButton(hWnd, IDC_RENDER, IDC_LEAVEBLACK, IDC_LEAVEBLACK);
  2846. EnableWindow(GetDlgItem(hWnd, IDC_LEAVEBLACK), FALSE);
  2847. EnableWindow(GetDlgItem(hWnd, IDC_RENDER), FALSE);
  2848. EnableWindow(GetDlgItem(hWnd, IDC_SCREENUSAGEBOX), FALSE);
  2849. }
  2850. if( IsDlgButtonChecked(hWnd, IDC_LEAVEBLACK) == BST_CHECKED )
  2851. {
  2852. EnableWindow(GetDlgItem(hWnd, IDC_MODESCOMBO), FALSE);
  2853. EnableWindow(GetDlgItem(hWnd, IDC_MODESSTATIC), FALSE);
  2854. EnableWindow(GetDlgItem(hWnd, IDC_DISPLAYMODEBOX), FALSE);
  2855. EnableWindow(GetDlgItem(hWnd, IDC_DISPLAYMODENOTE), FALSE);
  2856. }
  2857. else
  2858. {
  2859. EnableWindow(GetDlgItem(hWnd, IDC_MODESCOMBO), TRUE);
  2860. EnableWindow(GetDlgItem(hWnd, IDC_MODESSTATIC), TRUE);
  2861. EnableWindow(GetDlgItem(hWnd, IDC_DISPLAYMODEBOX), TRUE);
  2862. EnableWindow(GetDlgItem(hWnd, IDC_DISPLAYMODENOTE), TRUE);
  2863. }
  2864. // Mode list
  2865. ComboBox_ResetContent( hwndModeList );
  2866. if( pD3DAdapterInfo == NULL )
  2867. return;
  2868. TCHAR strAutomatic[100];
  2869. GetWindowText(GetDlgItem(hWnd, IDC_AUTOMATIC), strAutomatic, 100);
  2870. ComboBox_AddString( hwndModeList, strAutomatic );
  2871. ComboBox_SetItemData( hwndModeList, 0, -1 );
  2872. pD3DDeviceInfo = &pD3DAdapterInfo->devices[pD3DAdapterInfo->dwCurrentDevice];
  2873. DWORD iSelInitial = 0;
  2874. TCHAR strModeFmt[100];
  2875. GetWindowText(GetDlgItem(hWnd, IDC_MODEFMT), strModeFmt, 100);
  2876. for( DWORD iMode = 0; iMode < pD3DDeviceInfo->dwNumModes; iMode++ )
  2877. {
  2878. DWORD dwBitDepth;
  2879. TCHAR strMode[80];
  2880. DWORD dwItem;
  2881. pD3DModeInfo = &pD3DDeviceInfo->modes[iMode];
  2882. dwBitDepth = 16;
  2883. if( pD3DModeInfo->Format == D3DFMT_X8R8G8B8 ||
  2884. pD3DModeInfo->Format == D3DFMT_A8R8G8B8 ||
  2885. pD3DModeInfo->Format == D3DFMT_R8G8B8 )
  2886. {
  2887. dwBitDepth = 32;
  2888. }
  2889. wsprintf( strMode, strModeFmt, pD3DModeInfo->Width,
  2890. pD3DModeInfo->Height, dwBitDepth );
  2891. dwItem = ComboBox_AddString( hwndModeList, strMode );
  2892. ComboBox_SetItemData( hwndModeList, dwItem, iMode );
  2893. if( pD3DModeInfo->Width == pD3DAdapterInfo->dwUserPrefWidth &&
  2894. pD3DModeInfo->Height == pD3DAdapterInfo->dwUserPrefHeight &&
  2895. pD3DModeInfo->Format == pD3DAdapterInfo->d3dfmtUserPrefFormat )
  2896. {
  2897. iSelInitial = dwItem;
  2898. }
  2899. }
  2900. ComboBox_SetCurSel( hwndModeList, iSelInitial );
  2901. }