Source code of Windows XP (NT5)
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.

2316 lines
73 KiB

  1. //=============================================================================
  2. // Copyright (c) 1999 Microsoft Corporation
  3. //
  4. // swapchan.cpp
  5. //
  6. // Direct3D swap chain implementation.
  7. //
  8. // Created 11/16/1999 johnstep (John Stephens)
  9. //=============================================================================
  10. #include "ddrawpr.h"
  11. #include "swapchan.hpp"
  12. #include "pixel.hpp"
  13. #undef DPF_MODNAME
  14. #define DPF_MODNAME "CSwapChain::QueryInterface"
  15. //=============================================================================
  16. // IUnknown::QueryInterface (public)
  17. //
  18. // Created 11/16/1999 johnstep
  19. //=============================================================================
  20. STDMETHODIMP
  21. CSwapChain::QueryInterface(
  22. REFIID riid,
  23. void **ppInterface
  24. )
  25. {
  26. API_ENTER(Device());
  27. if (!VALID_PTR_PTR(ppInterface))
  28. {
  29. DPF_ERR("Invalid ppvObj parameter passed to QueryInterface for a SwapChain");
  30. return D3DERR_INVALIDCALL;
  31. }
  32. if (!VALID_PTR(&riid, sizeof(GUID)))
  33. {
  34. DPF_ERR("Invalid guid memory address to QueryInterface for a SwapChain");
  35. return D3DERR_INVALIDCALL;
  36. }
  37. if ((riid == IID_IDirect3DSwapChain8) || (riid == IID_IUnknown))
  38. {
  39. AddRef();
  40. *ppInterface =
  41. static_cast<void *>(
  42. static_cast<IDirect3DSwapChain8 *>(this));
  43. return S_OK;
  44. }
  45. DPF_ERR("Unsupported Interface identifier passed to QueryInterface for a SwapChain");
  46. // Null out param
  47. *ppInterface = NULL;
  48. return E_NOINTERFACE;
  49. } // QueryInterface
  50. #undef DPF_MODNAME
  51. #define DPF_MODNAME "CSwapChain::AddRef"
  52. //=============================================================================
  53. // IUnknown::AddRef (public)
  54. //
  55. // Created 11/16/1999 johnstep
  56. //=============================================================================
  57. STDMETHODIMP_(ULONG)
  58. CSwapChain::AddRef()
  59. {
  60. API_ENTER_NO_LOCK(Device());
  61. return AddRefImpl();
  62. } // AddRef
  63. #undef DPF_MODNAME
  64. #define DPF_MODNAME "CSwapChain::Release"
  65. //=============================================================================
  66. // IUnknown::Release (public)
  67. //
  68. // Created 11/16/1999 johnstep
  69. //=============================================================================
  70. STDMETHODIMP_(ULONG)
  71. CSwapChain::Release()
  72. {
  73. API_ENTER_SUBOBJECT_RELEASE(Device());
  74. return ReleaseImpl();
  75. } // Release
  76. #undef DPF_MODNAME
  77. #define DPF_MODNAME "CSwapChain::CSwapChain"
  78. //=============================================================================
  79. // CSwapChain::CSwapChain
  80. //
  81. // Created 11/16/1999 johnstep
  82. //=============================================================================
  83. CSwapChain::CSwapChain(
  84. CBaseDevice *pDevice,
  85. REF_TYPE refType) :
  86. CBaseObject(pDevice, refType),
  87. m_pCursor(NULL),
  88. m_hGDISurface(NULL),
  89. m_pMirrorSurface(NULL),
  90. m_pPrimarySurface(NULL),
  91. m_ppBackBuffers(NULL),
  92. m_presentnext(0),
  93. m_cBackBuffers(0),
  94. m_bExclusiveMode(FALSE),
  95. m_pCursorShadow(NULL),
  96. m_pHotTracking(NULL),
  97. m_lIMEState(0),
  98. m_lSetIME(0),
  99. m_dwFlags(0),
  100. m_dwFlipCnt(0),
  101. m_dwFlipTime(0xffffffff),
  102. m_uiErrorMode(0)
  103. {
  104. HKEY hKey;
  105. ZeroMemory(&m_BltData, sizeof m_BltData);
  106. m_BltData.hDD = Device()->GetHandle();
  107. m_BltData.bltFX.dwROP = SRCCOPY;
  108. m_BltData.ddRVal = E_FAIL;
  109. if (!RegOpenKey(HKEY_LOCAL_MACHINE, RESPATH_D3D, &hKey))
  110. {
  111. DWORD type;
  112. DWORD value;
  113. DWORD cb = sizeof(value);
  114. if (!RegQueryValueEx(hKey, REGSTR_VAL_DDRAW_SHOWFRAMERATE, NULL, &type, (CONST LPBYTE)&value, &cb))
  115. {
  116. DPF( 2, REGSTR_VAL_DDRAW_SHOWFRAMERATE" : %d", value );
  117. if (value)
  118. {
  119. m_dwFlags |= D3D_REGFLAGS_SHOWFRAMERATE;
  120. }
  121. }
  122. #ifdef WINNT
  123. cb = sizeof(value);
  124. if (!RegQueryValueEx(hKey, REGSTR_VAL_D3D_FLIPNOVSYNC, NULL, &type, (CONST LPBYTE)&value, &cb))
  125. {
  126. DPF( 2, REGSTR_VAL_D3D_FLIPNOVSYNC" : %d", value );
  127. if (value)
  128. {
  129. m_dwFlags |= D3D_REGFLAGS_FLIPNOVSYNC;
  130. }
  131. }
  132. RegCloseKey(hKey);
  133. }
  134. m_dwForceRefreshRate = 0;
  135. if( !RegOpenKey( HKEY_LOCAL_MACHINE, REGSTR_PATH_DDRAW, &hKey ) )
  136. {
  137. DWORD type;
  138. DWORD value;
  139. DWORD cb = sizeof(value);
  140. if( !RegQueryValueEx( hKey, REGSTR_VAL_DDRAW_FORCEREFRESHRATE, NULL, &type, (CONST LPBYTE)&value, &cb ) )
  141. {
  142. m_dwForceRefreshRate = value;
  143. }
  144. #endif
  145. RegCloseKey(hKey);
  146. }
  147. }
  148. void CSwapChain::Init(
  149. D3DPRESENT_PARAMETERS* pPresentationParams,
  150. HRESULT *pHr
  151. )
  152. {
  153. DXGASSERT(pHr != NULL);
  154. //the gamma ramp is initialized to 1:1
  155. for (int i=0;i<256;i++)
  156. {
  157. m_DesiredGammaRamp.red[i] =
  158. m_DesiredGammaRamp.green[i] =
  159. m_DesiredGammaRamp.blue[i] = static_cast<WORD>(i);
  160. }
  161. *pHr = Reset(
  162. pPresentationParams);
  163. return;
  164. } // CSwapChain::CSwapChain
  165. #undef DPF_MODNAME
  166. #define DPF_MODNAME "CSwapChain::~CSwapChain"
  167. //=============================================================================
  168. // CSwapChain::~CSwapChain
  169. //
  170. // Created 11/16/1999 johnstep
  171. //=============================================================================
  172. CSwapChain::~CSwapChain()
  173. {
  174. if (!m_PresentationData.Windowed)
  175. {
  176. m_PresentationData.Windowed = TRUE;
  177. // make sure we restore after a fullscreen
  178. SetCooperativeLevel();
  179. }
  180. Destroy();
  181. } // CSwapChain::~CSwapChain
  182. #undef DPF_MODNAME
  183. #define DPF_MODNAME "CSwapChain::CreateWindowed"
  184. //=============================================================================
  185. // CSwapChain::CreateWindowed
  186. //
  187. // Created 11/16/1999 johnstep
  188. //=============================================================================
  189. HRESULT
  190. CSwapChain::CreateWindowed(
  191. UINT width,
  192. UINT height,
  193. D3DFORMAT backBufferFormat,
  194. UINT cBackBuffers,
  195. D3DMULTISAMPLE_TYPE MultiSampleType,
  196. BOOL bDiscard,
  197. BOOL bLockable
  198. )
  199. {
  200. // For the windowed case, we will currently create exactly 3 surfaces
  201. // in this order:
  202. //
  203. // 1. Primary Surface
  204. // 2. Back Buffer
  205. // 3. Z Buffer (by notifying the device)
  206. //
  207. // For now, all 3 surfaces must reside in local video memory. Later,
  208. // we may allow multiple back buffers, if there is interest, to allow
  209. // simulated fullscreen-style double buffering (alternate back buffer
  210. // surfaces after presenting).
  211. //
  212. // !!! The primary surface is actually optional because we can just use
  213. // DdGetDC and then GDI BitBlt. But, presumably, there are performance
  214. // advantages to using DirectDraw Blt. Of course, the problem with using
  215. // DirectDraw Blts is keeping in sync with the window manager (so we
  216. // don't write outside of the window, etc.). GDI BitBlt will also handle
  217. // format conversion for us, though slowly.
  218. DXGASSERT(m_pPrimarySurface == NULL);
  219. DXGASSERT(m_ppBackBuffers == NULL);
  220. DXGASSERT(m_cBackBuffers == 0);
  221. HRESULT hr;
  222. if (D3DSWAPEFFECT_FLIP == m_PresentationData.SwapEffect)
  223. {
  224. cBackBuffers = m_PresentationData.BackBufferCount + 1;
  225. }
  226. // 1. Create a simple primary surface. If we already have a primary
  227. // surface, then don't bother to create a new one.
  228. if (this == Device()->SwapChain())
  229. {
  230. DWORD dwUsage = D3DUSAGE_PRIMARYSURFACE | D3DUSAGE_LOCK;
  231. DWORD Width = Device()->DisplayWidth();
  232. DWORD Height = Device()->DisplayHeight();
  233. // D3DSWAPEFFECT_NO_PRESENT is a hack to allow our D3D test framework
  234. // to create a windowed REF device after they have created a fullscreen
  235. // HAL device. We cannot create a second primary surface for the windowed
  236. // device, but we cannot leave m_pPrimarySurface equal to NULL (becaue then
  237. // we cannot cleanup the swap chain and Reset will fail), so instead we
  238. // create a dummy surface and call it the primary, with the understanding
  239. // that this device will never call Present or use the primary surface in
  240. // any way. We also don't have to do much checking since this is not an
  241. // external feature.
  242. if (D3DSWAPEFFECT_NO_PRESENT == m_PresentationData.SwapEffect)
  243. {
  244. dwUsage = D3DUSAGE_OFFSCREENPLAIN | D3DUSAGE_LOCK;
  245. Width = 256;
  246. Height = 256;
  247. }
  248. m_pPrimarySurface = new CDriverSurface(
  249. Device(),
  250. Width,
  251. Height,
  252. dwUsage,
  253. Device()->DisplayFormat(), // UserFormat
  254. Device()->DisplayFormat(), // RealFormat
  255. D3DMULTISAMPLE_NONE,//of course, when windowed
  256. 0, // hKernelHandle
  257. REF_INTERNAL,
  258. &hr);
  259. }
  260. else
  261. {
  262. // Additional SwapChain, it's already there
  263. m_pPrimarySurface = Device()->SwapChain()->PrimarySurface();
  264. hr = DD_OK;
  265. }
  266. // 2. Create the back buffer.
  267. if (m_pPrimarySurface == NULL)
  268. {
  269. return E_OUTOFMEMORY;
  270. }
  271. m_PresentUseBlt = TRUE;
  272. if (SUCCEEDED(hr))
  273. {
  274. if (m_ppBackBuffers = new CDriverSurface *[cBackBuffers])
  275. {
  276. DWORD Usage = D3DUSAGE_BACKBUFFER | D3DUSAGE_RENDERTARGET;
  277. if ((D3DMULTISAMPLE_NONE == m_PresentationData.MultiSampleType) &&
  278. bLockable)
  279. {
  280. Usage |= D3DUSAGE_LOCK;
  281. }
  282. if (bDiscard)
  283. {
  284. Usage |= D3DUSAGE_DISCARD;
  285. }
  286. for (; m_cBackBuffers < cBackBuffers; ++m_cBackBuffers)
  287. {
  288. m_ppBackBuffers[m_cBackBuffers] = new CDriverSurface(
  289. Device(),
  290. width,
  291. height,
  292. Usage,
  293. backBufferFormat, // UserFormat
  294. backBufferFormat, // RealFormat
  295. MultiSampleType,
  296. 0, // hKernelHandle
  297. REF_INTRINSIC,
  298. &hr);
  299. if (m_ppBackBuffers[m_cBackBuffers] == NULL)
  300. {
  301. hr = E_OUTOFMEMORY;
  302. break;
  303. }
  304. if (FAILED(hr))
  305. {
  306. m_ppBackBuffers[m_cBackBuffers]->DecrementUseCount();
  307. m_ppBackBuffers[m_cBackBuffers] = NULL;
  308. break;
  309. }
  310. }
  311. if (m_cBackBuffers == cBackBuffers)
  312. {
  313. m_BltData.hDestSurface = m_pPrimarySurface->KernelHandle();
  314. m_BltData.dwFlags = DDBLT_WINDOWCLIP | DDBLT_ROP | DDBLT_WAIT | DDBLT_DX8ORHIGHER;
  315. if (Device()->GetD3DCaps()->MaxStreams != 0)
  316. {
  317. m_BltData.dwFlags |= DDBLT_PRESENTATION;
  318. }
  319. if (D3DSWAPEFFECT_COPY_VSYNC == m_PresentationData.SwapEffect)
  320. {
  321. m_BltData.dwFlags |= DDBLT_COPYVSYNC;
  322. // Need to let thunk layer know current refresh rate
  323. if (Device()->DisplayRate() < 60)
  324. {
  325. // 60Hz = 16.666ms per frame
  326. // 75Hz = 13.333ms
  327. // 85Hz = 11.765ms
  328. m_BltData.threshold = 13;
  329. }
  330. else
  331. {
  332. m_BltData.threshold = (DWORD)(1000.0f / (float)Device()->DisplayRate());
  333. }
  334. }
  335. m_ClientWidth = 0; // windowed client is updated in present
  336. m_ClientHeight = 0;
  337. return hr;
  338. }
  339. // Something went wrong, so clean up now.
  340. // 2. Destroy Back Buffers, if any.
  341. while (m_cBackBuffers > 0)
  342. {
  343. m_ppBackBuffers[--m_cBackBuffers]->DecrementUseCount();
  344. }
  345. delete [] m_ppBackBuffers;
  346. m_ppBackBuffers = NULL;
  347. }
  348. else
  349. {
  350. hr = E_OUTOFMEMORY;
  351. }
  352. }
  353. // 1. Destroy Primary Surface.
  354. if (this == Device()->SwapChain())
  355. m_pPrimarySurface->DecrementUseCount();
  356. m_pPrimarySurface = NULL;
  357. return hr;
  358. } // CreateWindowed
  359. #undef DPF_MODNAME
  360. #define DPF_MODNAME "CSwapChain::CreateFullScreen"
  361. //=============================================================================
  362. // CSwapChain::CreateFullscreen
  363. //
  364. // Created 11/16/1999 johnstep
  365. //=============================================================================
  366. HRESULT
  367. CSwapChain::CreateFullscreen(
  368. UINT width,
  369. UINT height,
  370. D3DFORMAT backBufferFormat,
  371. UINT cBackBuffers,
  372. UINT PresentationRate,
  373. D3DMULTISAMPLE_TYPE MultiSampleType,
  374. BOOL bDiscard,
  375. BOOL bLockable
  376. )
  377. {
  378. HRESULT hr = E_FAIL;
  379. DWORD i;
  380. BOOL bMirrorBufferCreated, bNoDDrawSupport;
  381. UINT Usage = 0;
  382. if (bLockable)
  383. {
  384. Usage |= D3DUSAGE_LOCK;
  385. }
  386. if (bDiscard)
  387. {
  388. Usage |= D3DUSAGE_DISCARD;
  389. }
  390. // If it's a hardware device, we want to create a primary surface and a
  391. // number of backbuffers. We need to make this a single driver call,
  392. // however, in order for everything to get attached correctly. Therefore,
  393. // what we do is call the DDI to create the primary chain, and it will
  394. // return the handles for each surface in the chain. After that, we
  395. // will individually create each swap chain buffer, but we will supply
  396. // it with the required handles rather than having it call the DDI itself.
  397. // First, call the DDI to allocate the memory and the kernel handles
  398. DDSURFACEINFO SurfInfoArray[D3DPRESENT_BACK_BUFFERS_MAX + 2];
  399. ZeroMemory(SurfInfoArray, sizeof(SurfInfoArray));
  400. D3D8_CREATESURFACEDATA CreateSurfaceData;
  401. ZeroMemory(&CreateSurfaceData, sizeof(CreateSurfaceData));
  402. DXGASSERT(cBackBuffers <= D3DPRESENT_BACK_BUFFERS_MAX);
  403. for (i = 0; i < cBackBuffers + 1; i++)
  404. {
  405. SurfInfoArray[i].cpWidth = width;
  406. SurfInfoArray[i].cpHeight = height;
  407. }
  408. CreateSurfaceData.hDD = Device()->GetHandle();
  409. CreateSurfaceData.pSList = &SurfInfoArray[0];
  410. bNoDDrawSupport = Device()->Enum()->NoDDrawSupport(Device()->AdapterIndex());
  411. if (D3DDEVTYPE_HAL == Device()->GetDeviceType() &&
  412. m_PresentationData.SwapEffect == D3DSWAPEFFECT_FLIP)
  413. {
  414. m_PresentUseBlt = FALSE;
  415. bMirrorBufferCreated = FALSE;
  416. CreateSurfaceData.dwSCnt = cBackBuffers + 1;
  417. CreateSurfaceData.MultiSampleType = MultiSampleType;
  418. }
  419. else if ((m_PresentationData.SwapEffect == D3DSWAPEFFECT_COPY &&
  420. m_PresentationData.FullScreen_PresentationInterval ==
  421. D3DPRESENT_INTERVAL_IMMEDIATE) || bNoDDrawSupport
  422. )
  423. {
  424. // If we're doing a copy-swap-effect and the app
  425. // specifies interval-immediate, then we can blt directly
  426. // to the primary without a mirror.
  427. DXGASSERT(MultiSampleType == D3DMULTISAMPLE_NONE);
  428. m_PresentUseBlt = TRUE;
  429. bMirrorBufferCreated = FALSE;
  430. CreateSurfaceData.dwSCnt = 1;
  431. CreateSurfaceData.MultiSampleType = D3DMULTISAMPLE_NONE;
  432. }
  433. else
  434. {
  435. //one for m_pPrimarySurface and one for m_pMirrorSurface
  436. m_PresentUseBlt = TRUE;
  437. bMirrorBufferCreated = TRUE;
  438. CreateSurfaceData.dwSCnt = 2;
  439. CreateSurfaceData.MultiSampleType = D3DMULTISAMPLE_NONE;
  440. }
  441. CreateSurfaceData.Type = D3DRTYPE_SURFACE;
  442. CreateSurfaceData.Pool = D3DPOOL_LOCALVIDMEM;
  443. CreateSurfaceData.dwUsage = D3DUSAGE_PRIMARYSURFACE | Usage;
  444. CreateSurfaceData.Format = Device()->DisplayFormat();
  445. if(Device()->DisplayFormat() != backBufferFormat)
  446. {
  447. CreateSurfaceData.dwUsage |= D3DUSAGE_ALPHACHANNEL;
  448. }
  449. if (!bNoDDrawSupport)
  450. {
  451. hr = Device()->GetHalCallbacks()->CreateSurface(&CreateSurfaceData);
  452. if (FAILED(hr))
  453. {
  454. if (D3DDEVTYPE_HAL == Device()->GetDeviceType())
  455. {
  456. DPF_ERR("Failed to create driver primary surface chain");
  457. return hr;
  458. }
  459. else
  460. {
  461. // assume CreateSurfaceData is still intact
  462. bMirrorBufferCreated = FALSE;
  463. CreateSurfaceData.dwSCnt = 1;
  464. hr = Device()->GetHalCallbacks()->CreateSurface(&CreateSurfaceData);
  465. if (FAILED(hr))
  466. {
  467. DPF_ERR("Failed to create driver primary surface");
  468. return hr;
  469. }
  470. }
  471. }
  472. }
  473. // Now that we have the handles, create the surface interfaces
  474. // one by one
  475. // When creating passing in kernel handles to a driver
  476. // surface, the surface will assume that it was created in
  477. // LocalVidMem. We assert this here..
  478. DXGASSERT(CreateSurfaceData.Pool == D3DPOOL_LOCALVIDMEM);
  479. m_pPrimarySurface = new CDriverSurface(
  480. Device(),
  481. width,
  482. height,
  483. CreateSurfaceData.dwUsage | D3DUSAGE_LOCK,
  484. // there is a problem with thunklayer when NoDDrawSupport
  485. // DriverData.DisplayWidth and DriverData.DisplayHeight
  486. // DriverData.DisplayFormat are not getting updated
  487. // so we use backBufferFormat until Device()->DisplayFormat()
  488. bNoDDrawSupport ? backBufferFormat : Device()->DisplayFormat(), // UserFormat
  489. bNoDDrawSupport ? backBufferFormat : Device()->DisplayFormat(), // RealFormat
  490. CreateSurfaceData.MultiSampleType,
  491. SurfInfoArray[0].hKernelHandle,
  492. REF_INTERNAL,
  493. &hr);
  494. if (m_pPrimarySurface == NULL)
  495. {
  496. // We'll clean up the kernel handle(s) at the
  497. // end of the function
  498. hr = E_OUTOFMEMORY;
  499. }
  500. else
  501. {
  502. // Zero out the kernel-handle so that
  503. // we don't clean it at exit. If the CDriverSurface
  504. // function fails; it will still release the kernel
  505. // handle in its destructor.
  506. SurfInfoArray[0].hKernelHandle = 0;
  507. }
  508. if (SUCCEEDED(hr))
  509. {
  510. m_hGDISurface = m_pPrimarySurface->KernelHandle();
  511. if (bMirrorBufferCreated)
  512. {
  513. // Mirror surfaces are only useful if we're going
  514. // to do a Blt as part of the Present. (We might
  515. // also do a flip in addition.)
  516. DXGASSERT(m_PresentUseBlt);
  517. // When creating passing in kernel handles to a driver
  518. // surface, the surface will assume that it was created in
  519. // LocalVidMem. We assert this here..
  520. DXGASSERT(CreateSurfaceData.Pool == D3DPOOL_LOCALVIDMEM);
  521. m_pMirrorSurface = new CDriverSurface(
  522. Device(),
  523. width,
  524. height,
  525. D3DUSAGE_BACKBUFFER,
  526. Device()->DisplayFormat(), // UserFormat
  527. Device()->DisplayFormat(), // RealFormat
  528. D3DMULTISAMPLE_NONE,
  529. SurfInfoArray[1].hKernelHandle,
  530. REF_INTERNAL,
  531. &hr);
  532. if (NULL == m_pMirrorSurface)
  533. {
  534. //if out of memory, then destroy the driver object as well
  535. D3D8_DESTROYSURFACEDATA DestroySurfData;
  536. DestroySurfData.hDD = Device()->GetHandle();
  537. DestroySurfData.hSurface = SurfInfoArray[1].hKernelHandle;
  538. Device()->GetHalCallbacks()->DestroySurface(&DestroySurfData);
  539. bMirrorBufferCreated = FALSE;
  540. hr = S_OK; //but don't fail as m_pMirrorSurface is optional
  541. }
  542. else if (FAILED(hr))
  543. {
  544. // Release the surface
  545. m_pMirrorSurface->DecrementUseCount();
  546. m_pMirrorSurface = NULL;
  547. bMirrorBufferCreated = FALSE;
  548. hr = S_OK; //but don't fail as m_pMirrorSurface is optional
  549. }
  550. else
  551. {
  552. //blt from m_ppBackBuffers[m_presentnext] to m_pMirrorSurface
  553. //then flip from m_pPrimarySurface to m_pMirrorSurface
  554. m_BltData.hDestSurface =
  555. m_pMirrorSurface->KernelHandle();
  556. }
  557. // In all cases, zero out the kernel handle
  558. // since it has either been owned by something or freed by now
  559. SurfInfoArray[1].hKernelHandle = 0;
  560. }
  561. if (m_PresentUseBlt)
  562. {
  563. if (!bMirrorBufferCreated)
  564. {
  565. // If we're blitting and there is no
  566. // mirror surface; then the primary must be
  567. // the destination
  568. DXGASSERT(m_BltData.hDestSurface == NULL);
  569. m_BltData.hDestSurface = m_pPrimarySurface->KernelHandle();
  570. }
  571. if (D3DSWAPEFFECT_FLIP == m_PresentationData.SwapEffect)
  572. {
  573. // To emualte flip for SW drivers, create an extra backbuffer
  574. cBackBuffers = m_PresentationData.BackBufferCount + 1;
  575. }
  576. ZeroMemory(SurfInfoArray, sizeof(SurfInfoArray));
  577. for (i = 1; i < cBackBuffers + 1; i++)
  578. {
  579. SurfInfoArray[i].cpWidth = width;
  580. SurfInfoArray[i].cpHeight = height;
  581. }
  582. ZeroMemory(&CreateSurfaceData, sizeof(CreateSurfaceData));
  583. CreateSurfaceData.hDD = Device()->GetHandle();
  584. CreateSurfaceData.pSList = &SurfInfoArray[1];
  585. CreateSurfaceData.dwSCnt = cBackBuffers;
  586. CreateSurfaceData.Type = D3DRTYPE_SURFACE;
  587. CreateSurfaceData.Pool = D3DPOOL_DEFAULT;
  588. CreateSurfaceData.dwUsage = D3DUSAGE_BACKBUFFER | D3DUSAGE_RENDERTARGET;
  589. CreateSurfaceData.Format = backBufferFormat;
  590. CreateSurfaceData.MultiSampleType = MultiSampleType;
  591. hr = Device()->GetHalCallbacks()->CreateSurface(&CreateSurfaceData);
  592. }
  593. }
  594. if (SUCCEEDED(hr))
  595. {
  596. if (m_ppBackBuffers = new CDriverSurface *[cBackBuffers])
  597. {
  598. DWORD Usage = D3DUSAGE_BACKBUFFER | D3DUSAGE_RENDERTARGET;
  599. if ((D3DMULTISAMPLE_NONE == m_PresentationData.MultiSampleType) &&
  600. bLockable)
  601. {
  602. Usage |= D3DUSAGE_LOCK;
  603. }
  604. for (; m_cBackBuffers < cBackBuffers; ++m_cBackBuffers)
  605. {
  606. m_ppBackBuffers[m_cBackBuffers] = new CDriverSurface(
  607. Device(),
  608. width,
  609. height,
  610. Usage,
  611. backBufferFormat,
  612. backBufferFormat,
  613. MultiSampleType,
  614. SurfInfoArray[m_cBackBuffers + 1].hKernelHandle,
  615. REF_INTRINSIC,
  616. &hr);
  617. if (m_ppBackBuffers[m_cBackBuffers] == NULL)
  618. {
  619. // We'll clean up the kernel handle at the ned
  620. // of the function
  621. hr = E_OUTOFMEMORY;
  622. break;
  623. }
  624. else
  625. {
  626. // Zero out the kernel-handle so that
  627. // we don't clean it at exit. (Even in failure,
  628. // the m_ppBackBuffers[m_cBackBuffers] object
  629. // will free the kernel handle now
  630. SurfInfoArray[m_cBackBuffers + 1].hKernelHandle = 0;
  631. }
  632. if (FAILED(hr))
  633. {
  634. m_ppBackBuffers[m_cBackBuffers]->DecrementUseCount();
  635. m_ppBackBuffers[m_cBackBuffers] = NULL;
  636. break;
  637. }
  638. }
  639. if (m_cBackBuffers != cBackBuffers)
  640. {
  641. // Something went wrong, so clean up now.
  642. // 2. Destroy Back Buffers, if any.
  643. while (m_cBackBuffers > 0)
  644. {
  645. m_ppBackBuffers[--m_cBackBuffers]->DecrementUseCount();
  646. }
  647. delete [] m_ppBackBuffers;
  648. m_ppBackBuffers = NULL;
  649. }
  650. else
  651. {
  652. const D3D8_DRIVERCAPS* pDriverCaps = Device()->GetCoreCaps();
  653. m_dwFlipFlags = DDFLIP_WAIT;
  654. if ((D3DPRESENT_INTERVAL_IMMEDIATE == m_PresentationData.FullScreen_PresentationInterval)
  655. #ifdef WINNT
  656. || (D3D_REGFLAGS_FLIPNOVSYNC & m_dwFlags)
  657. #endif
  658. )
  659. {
  660. if (DDCAPS2_FLIPNOVSYNC & pDriverCaps->D3DCaps.Caps2)
  661. {
  662. m_dwFlipFlags |= DDFLIP_NOVSYNC;
  663. }
  664. }
  665. else if (DDCAPS2_FLIPINTERVAL & pDriverCaps->D3DCaps.Caps2)
  666. {
  667. switch(m_PresentationData.FullScreen_PresentationInterval)
  668. {
  669. case D3DPRESENT_INTERVAL_DEFAULT:
  670. case D3DPRESENT_INTERVAL_ONE:
  671. m_dwFlipFlags |= DDFLIP_INTERVAL1;
  672. break;
  673. case D3DPRESENT_INTERVAL_TWO:
  674. m_dwFlipFlags |= DDFLIP_INTERVAL2;
  675. break;
  676. case D3DPRESENT_INTERVAL_THREE:
  677. m_dwFlipFlags |= DDFLIP_INTERVAL3;
  678. break;
  679. case D3DPRESENT_INTERVAL_FOUR:
  680. m_dwFlipFlags |= DDFLIP_INTERVAL4;
  681. break;
  682. }
  683. }
  684. m_BltData.hWnd = m_PresentationData.hDeviceWindow;
  685. m_BltData.dwFlags = DDBLT_ROP | DDBLT_WAIT;
  686. m_ClientWidth = width;
  687. m_ClientHeight = height;
  688. }
  689. }
  690. else
  691. {
  692. hr = E_OUTOFMEMORY;
  693. }
  694. }
  695. // Error handling cleanup
  696. if (FAILED(hr))
  697. {
  698. // We may need to free surface handles that
  699. // were not owned by any CDriverSurface that
  700. // we failed to properly create
  701. D3D8_DESTROYSURFACEDATA DestroyData;
  702. ZeroMemory(&DestroyData, sizeof DestroyData);
  703. DestroyData.hDD = Device()->GetHandle();
  704. for (UINT i = 0; i < CreateSurfaceData.dwSCnt; i++)
  705. {
  706. if (CreateSurfaceData.pSList[i].hKernelHandle)
  707. {
  708. DestroyData.hSurface = CreateSurfaceData.pSList[i].hKernelHandle;
  709. Device()->GetHalCallbacks()->DestroySurface(&DestroyData);
  710. }
  711. }
  712. }
  713. return hr;
  714. } // CreateFullScreen
  715. #undef DPF_MODNAME
  716. #define DPF_MODNAME "CSwapChain::Destroy"
  717. //=============================================================================
  718. // CSwapChain::Destroy
  719. //
  720. // Created 11/16/1999 johnstep
  721. //=============================================================================
  722. VOID
  723. CSwapChain::Destroy()
  724. {
  725. // Destroy surfaces in reverse create order.
  726. if (m_pCursor)
  727. {
  728. delete m_pCursor;
  729. m_pCursor = NULL;
  730. }
  731. // 2. Destroy Back Buffers
  732. //
  733. // If the previous mode was windowed, we should have exactly 1
  734. // back buffer to destroy. Otherwise, there could be more than
  735. // one, and plus we may need some sort of atomic destruction.
  736. if (m_ppBackBuffers)
  737. {
  738. while (m_cBackBuffers > 0)
  739. {
  740. m_ppBackBuffers[--m_cBackBuffers]->DecrementUseCount();
  741. }
  742. delete [] m_ppBackBuffers;
  743. m_ppBackBuffers = NULL;
  744. }
  745. // 1. Destroy Mirror Surface
  746. if (m_pMirrorSurface)
  747. {
  748. m_pMirrorSurface->DecrementUseCount();
  749. m_pMirrorSurface = NULL;
  750. }
  751. // 1. Destroy Primary Surface
  752. if (m_pPrimarySurface)
  753. {
  754. if (this == Device()->SwapChain())
  755. m_pPrimarySurface->DecrementUseCount();
  756. m_pPrimarySurface = NULL;
  757. m_hGDISurface = NULL;
  758. }
  759. m_presentnext = 0;
  760. } // Destroy
  761. #undef DPF_MODNAME
  762. #define DPF_MODNAME "CSwapChain::GetBackBuffer"
  763. //=============================================================================
  764. // IDirect3DSwapChain8::GetBackBuffer (public)
  765. //
  766. // Created 11/16/1999 johnstep
  767. //=============================================================================
  768. STDMETHODIMP
  769. CSwapChain::GetBackBuffer(
  770. UINT iBackBuffer,
  771. D3DBACKBUFFER_TYPE Type,
  772. IDirect3DSurface8 **ppBackBuffer
  773. )
  774. {
  775. API_ENTER(Device());
  776. if (ppBackBuffer == NULL)
  777. {
  778. DPF_ERR("Invalid ppBackbuffer parameter passed to GetBackBuffer");
  779. return D3DERR_INVALIDCALL;
  780. }
  781. // We can't just assert we have a valid back buffer array because a
  782. // Reset may have failed, which puts the device in a disabled state
  783. // until Reset is called again. Once we have a `disabled' flag, we
  784. // can check that instead of m_ppBackBuffers.
  785. if (m_ppBackBuffers == NULL)
  786. {
  787. DPF_ERR("GetBackBuffer failed due to Device being lost");
  788. return D3DERR_INVALIDCALL;
  789. }
  790. // in case of windowed D3DSWAPEFFECT_FLIP, m_cBackBuffers
  791. // == m_PresentationData.BackBufferCount + 1 as we allocate
  792. // that extra buffer for user without its knowledge
  793. if (iBackBuffer >= m_PresentationData.BackBufferCount)
  794. {
  795. DPF_ERR("Invalid iBackBuffer parameter passed to GetBackBuffer");
  796. return D3DERR_INVALIDCALL;
  797. }
  798. *ppBackBuffer = BackBuffer(iBackBuffer);
  799. DXGASSERT(*ppBackBuffer != NULL);
  800. if (*ppBackBuffer)
  801. {
  802. (*ppBackBuffer)->AddRef();
  803. return S_OK;
  804. }
  805. else
  806. {
  807. DPF(2, "Swapchain doesn't have a BackBuffer[%d]",iBackBuffer);
  808. return D3DERR_NOTFOUND;
  809. }
  810. } // GetBackBuffer
  811. #undef DPF_MODNAME
  812. #define DPF_MODNAME "CSwapChain::Reset"
  813. //=============================================================================
  814. // IDirect3DSwapChain8::Reset (public)
  815. //
  816. // Resizes the device. If this results in a display mode change, then all
  817. // existing surfaces will be lost.
  818. //
  819. // Arguments:
  820. // width
  821. // height
  822. // pcBackBuffers (in/out) !!! Currently an (in) but will be fixed later.
  823. // backBufferFormat
  824. // fullscreen
  825. // pOptionalParams
  826. // Created 11/16/1999 johnstep
  827. //=============================================================================
  828. HRESULT
  829. CSwapChain::Reset(
  830. D3DPRESENT_PARAMETERS *pPresentationParameters
  831. )
  832. {
  833. BOOL bDeviceLost = FALSE;
  834. HRESULT hr;
  835. // Validate First before changing state
  836. switch (pPresentationParameters->SwapEffect)
  837. {
  838. case D3DSWAPEFFECT_DISCARD:
  839. case D3DSWAPEFFECT_COPY:
  840. case D3DSWAPEFFECT_COPY_VSYNC:
  841. case D3DSWAPEFFECT_FLIP:
  842. case D3DSWAPEFFECT_NO_PRESENT:
  843. break;
  844. default:
  845. DPF_ERR("Invalid parameter for SwapEffect for D3DPRESENT_PARAMETERS. "
  846. "Must be one of D3DSWAPEFFECTS_COPY, D3DSWAPEFFECTS_COPY_VSYNC, "
  847. "D3DSWAPEFFECTS_DISCARD, or D3DSWAPEFFECTS_FLIP. CreateDevice/Reset Fails.");
  848. return D3DERR_INVALIDCALL;
  849. }
  850. if (pPresentationParameters->BackBufferCount)
  851. {
  852. if ((D3DSWAPEFFECT_COPY == pPresentationParameters->SwapEffect ||
  853. D3DSWAPEFFECT_COPY_VSYNC == pPresentationParameters->SwapEffect)
  854. && (pPresentationParameters->BackBufferCount > 1))
  855. {
  856. DPF_ERR("BackBufferCount must be 1 if SwapEffect is COPY/VSYNC. CreateDevice/Reset Fails.");
  857. pPresentationParameters->BackBufferCount = 1;
  858. return D3DERR_INVALIDCALL;
  859. }
  860. if (pPresentationParameters->BackBufferCount >
  861. D3DPRESENT_BACK_BUFFERS_MAX)
  862. {
  863. DPF_ERR("BackBufferCount must be less "
  864. "than D3DPRESENT_BACK_BUFFERS_MAX. CreateDevice/Reset Fails.");
  865. pPresentationParameters->BackBufferCount =
  866. D3DPRESENT_BACK_BUFFERS_MAX;
  867. return D3DERR_INVALIDCALL;
  868. }
  869. }
  870. else
  871. {
  872. pPresentationParameters->BackBufferCount = 1;
  873. DPF(4, "BackBufferCount not specified, considered default 1 ");
  874. }
  875. if (D3DSWAPEFFECT_DISCARD != pPresentationParameters->SwapEffect)
  876. {
  877. if (pPresentationParameters->MultiSampleType != D3DMULTISAMPLE_NONE)
  878. {
  879. DPF_ERR("Multisampling requires D3DSWAPEFFECT_DISCARD. CreateDevice/Reset Fails.");
  880. return D3DERR_INVALIDCALL;
  881. }
  882. }
  883. // D3DSWAPEFFECT_NO_PRESENT is a hack that only works for windowed mode
  884. if (D3DSWAPEFFECT_NO_PRESENT == pPresentationParameters->SwapEffect)
  885. {
  886. if (!pPresentationParameters->Windowed)
  887. {
  888. DPF_ERR("D3DSWAPEFFECT_NO_PRESENT only works when the device is windowed. CreateDevice/Reset Fails.");
  889. return D3DERR_INVALIDCALL;
  890. }
  891. }
  892. memcpy(&m_PresentationData,
  893. pPresentationParameters,sizeof m_PresentationData);
  894. // Remember the original swapeffect
  895. m_UserSwapEffect = pPresentationParameters->SwapEffect;
  896. // Convert discard to flip or copy based on stuff
  897. if (D3DSWAPEFFECT_DISCARD == pPresentationParameters->SwapEffect)
  898. {
  899. if (pPresentationParameters->Windowed &&
  900. pPresentationParameters->BackBufferCount == 1)
  901. {
  902. m_PresentationData.SwapEffect = D3DSWAPEFFECT_COPY;
  903. }
  904. else
  905. {
  906. m_PresentationData.SwapEffect = D3DSWAPEFFECT_FLIP;
  907. }
  908. }
  909. if (NULL == m_PresentationData.hDeviceWindow)
  910. {
  911. m_PresentationData.hDeviceWindow= Device()->FocusWindow();
  912. }
  913. DXGASSERT( NULL != m_PresentationData.hDeviceWindow);
  914. #ifdef WINNT
  915. // On NT, SetCooperativeLevel will fail if another device has exclusive
  916. // mode, so we cannot call it. On Win9X, it will not fail, but CreateSurface
  917. // WILL fail if we don't first call it, so we need to special case this call.
  918. if (m_UserSwapEffect != D3DSWAPEFFECT_NO_PRESENT)
  919. {
  920. #endif
  921. hr = SetCooperativeLevel();
  922. if (FAILED(hr))
  923. {
  924. DPF_ERR("SetCooperativeLevel returned failure. CreateDevice/Reset Failed");
  925. return hr;
  926. }
  927. #ifdef WINNT
  928. }
  929. #endif
  930. // See if the device is lost
  931. if (D3D8IsDeviceLost(Device()->GetHandle()))
  932. {
  933. bDeviceLost = TRUE;
  934. FetchDirectDrawData(Device()->GetDeviceData(),
  935. Device()->GetInitFunction(),
  936. Device()->Enum()->GetUnknown16(Device()->AdapterIndex()),
  937. Device()->Enum()->GetHalOpList(Device()->AdapterIndex()),
  938. Device()->Enum()->GetNumHalOps(Device()->AdapterIndex()));
  939. }
  940. // Map the unknown format to a real one. If they will take any format
  941. // (i.e. the specified UNKNOWN), then we will try to give them the one
  942. // that matches the display format.
  943. if (m_PresentationData.Windowed)
  944. {
  945. // If we are windowed, we need to use the current display mode. We may be
  946. // able to relax this for new drivers.
  947. if (D3DFMT_UNKNOWN == m_PresentationData.BackBufferFormat)
  948. {
  949. m_PresentationData.BackBufferFormat = Device()->DisplayFormat();
  950. }
  951. if (CPixel::SuppressAlphaChannel(m_PresentationData.BackBufferFormat)
  952. != Device()->DisplayFormat())
  953. {
  954. DPF_ERR("Windowed BackBuffer Format must be compatible with Desktop Format. CreateDevice/Reset fails.");
  955. return D3DERR_INVALIDCALL;
  956. }
  957. }
  958. if (m_PresentationData.Windowed)
  959. {
  960. if ((m_PresentationData.BackBufferWidth < 1) ||
  961. (m_PresentationData.BackBufferHeight < 1))
  962. {
  963. RECT rc;
  964. if (GetClientRect(m_PresentationData.hDeviceWindow, &rc))
  965. {
  966. if (m_PresentationData.BackBufferWidth < 1)
  967. m_PresentationData.BackBufferWidth = rc.right;
  968. if (m_PresentationData.BackBufferHeight < 1)
  969. m_PresentationData.BackBufferHeight = rc.bottom;
  970. }
  971. else
  972. {
  973. DPF_ERR("zero width and/or height and unable to get client. CreateDevice/Reset fails.");
  974. return D3DERR_INVALIDCALL;
  975. }
  976. }
  977. // We can handle color conversion from the back buffer if we use
  978. // GDI BitBlt instead of DirectDraw Blt for presentation.
  979. switch (m_PresentationData.BackBufferFormat)
  980. {
  981. case D3DFMT_X1R5G5B5:
  982. case D3DFMT_A1R5G5B5:
  983. case D3DFMT_R5G6B5:
  984. case D3DFMT_X8R8G8B8:
  985. case D3DFMT_A8R8G8B8:
  986. break;
  987. default:
  988. DPF_ERR("Unsupported back buffer format specified.");
  989. return D3DERR_INVALIDCALL;
  990. }
  991. // Does the device support offscreen RTs of this format in the current
  992. // display mode?
  993. if (FAILED(Device()->Enum()->CheckDeviceFormat(
  994. Device()->AdapterIndex(),
  995. Device()->GetDeviceType(),
  996. Device()->DisplayFormat(),
  997. D3DUSAGE_RENDERTARGET,
  998. D3DRTYPE_SURFACE,
  999. m_PresentationData.BackBufferFormat)))
  1000. {
  1001. DPF_ERR("This back buffer format is not supported for a windowed device. CreateDevice/Reset Fails");
  1002. DPF_ERR(" Use CheckDeviceType(Adapter, DeviceType, <Current Display Format>, <Desired BackBufferFormat>, TRUE /* Windowed */)");
  1003. return D3DERR_INVALIDCALL;
  1004. }
  1005. // For now, always destroy existing surfaces and recreate. Later, we
  1006. // may reuse the surfaces. We should also add an `initialized' flag,
  1007. // but for now will just arbitrarily use m_pPrimarySurface for this
  1008. // purpose.
  1009. if (this == Device()->SwapChain())
  1010. {
  1011. Device()->UpdateRenderTarget(NULL, NULL);
  1012. if (m_pPrimarySurface != NULL)
  1013. {
  1014. Device()->ResourceManager()->DiscardBytes(0);
  1015. static_cast<CD3DBase*>(Device())->Destroy();
  1016. Destroy();
  1017. }
  1018. if (Device()->GetZStencil() != NULL)
  1019. {
  1020. Device()->GetZStencil()->DecrementUseCount();
  1021. Device()->ResetZStencil();
  1022. }
  1023. if (D3D8DoVidmemSurfacesExist(Device()->GetHandle()))
  1024. {
  1025. // user must free any video memory surfaces before doing
  1026. // fullscreen Reset, otherwise we fail.
  1027. DPF_ERR("All user created D3DPOOL_DEFAULT surfaces must be freed"
  1028. " before Reset can succeed. Reset Fails.");
  1029. return D3DERR_DEVICELOST;
  1030. }
  1031. }
  1032. // If the device is lost, we should now restore it before creating
  1033. // the new swap chain.
  1034. if (bDeviceLost)
  1035. {
  1036. D3D8RestoreDevice(Device()->GetHandle());
  1037. }
  1038. hr = CreateWindowed(
  1039. Width(),
  1040. Height(),
  1041. BackBufferFormat(),
  1042. m_PresentationData.BackBufferCount,
  1043. m_PresentationData.MultiSampleType,
  1044. (D3DSWAPEFFECT_DISCARD == m_UserSwapEffect),
  1045. (pPresentationParameters->Flags & D3DPRESENTFLAG_LOCKABLE_BACKBUFFER)
  1046. );
  1047. }
  1048. else
  1049. {
  1050. D3DFORMAT FormatWithoutAlpha;
  1051. #ifdef WINNT
  1052. // Pick the best refresh rate
  1053. m_PresentationData.FullScreen_RefreshRateInHz = PickRefreshRate(
  1054. Width(),
  1055. Height(),
  1056. m_PresentationData.FullScreen_RefreshRateInHz,
  1057. m_PresentationData.BackBufferFormat);
  1058. #endif
  1059. // If they specified a mode, does the mode exist?
  1060. if (Width() != Device()->DisplayWidth()
  1061. || Height() != Device()->DisplayHeight()
  1062. || BackBufferFormat() != Device()->DisplayFormat()
  1063. || ((m_PresentationData.FullScreen_RefreshRateInHz != 0) &&
  1064. (m_PresentationData.FullScreen_RefreshRateInHz !=
  1065. Device()->DisplayRate()))
  1066. )
  1067. {
  1068. D3DDISPLAYMODE* pModeTable = Device()->GetModeTable();
  1069. DWORD dwNumModes = Device()->GetNumModes();
  1070. DWORD i;
  1071. #if DBG
  1072. for (i = 0; i < dwNumModes; i++)
  1073. {
  1074. DPF(10,"Mode[%d] is %d x %d format=%08lx",
  1075. i,
  1076. pModeTable[i].Width,
  1077. pModeTable[i].Height,
  1078. pModeTable[i].Format);
  1079. }
  1080. #endif //DBG
  1081. FormatWithoutAlpha = CPixel::SuppressAlphaChannel(m_PresentationData.BackBufferFormat);
  1082. for (i = 0; i < dwNumModes; i++)
  1083. {
  1084. if ((pModeTable[i].Width == Width()) &&
  1085. (pModeTable[i].Height == Height()) &&
  1086. (pModeTable[i].Format == FormatWithoutAlpha))
  1087. {
  1088. // So far so good. Check refresh rate if they specified one
  1089. if ((m_PresentationData.FullScreen_RefreshRateInHz == 0) ||
  1090. (m_PresentationData.FullScreen_RefreshRateInHz ==
  1091. pModeTable[i].RefreshRate))
  1092. {
  1093. break;
  1094. }
  1095. }
  1096. }
  1097. if (i == dwNumModes)
  1098. {
  1099. // The specified mode is invalid
  1100. DPF_ERR("The specified mode is unsupported. CreateDevice/Reset Fails");
  1101. return D3DERR_INVALIDCALL;
  1102. }
  1103. // If the mode exists, does the device have caps in it?
  1104. if (FAILED(Device()->Enum()->CheckDeviceType(
  1105. Device()->AdapterIndex(),
  1106. Device()->GetDeviceType(),
  1107. FormatWithoutAlpha,
  1108. m_PresentationData.BackBufferFormat,
  1109. FALSE)))
  1110. {
  1111. DPF_ERR("Display Mode not supported by this device type. Use CheckDeviceType(X, X, <Desired fullscreen format>). CreateDevice/Reset Fails");
  1112. return D3DERR_INVALIDCALL;
  1113. }
  1114. // The mode is supported, so next we set the cooperative level to fullscreen
  1115. // Now do the mode change and update the driver caps
  1116. D3D8_SETMODEDATA SetModeData;
  1117. SetModeData.hDD = Device()->GetHandle();
  1118. SetModeData.dwWidth = Width();
  1119. SetModeData.dwHeight = Height();
  1120. SetModeData.Format = BackBufferFormat();
  1121. SetModeData.dwRefreshRate =
  1122. m_PresentationData.FullScreen_RefreshRateInHz;
  1123. SetModeData.bRestore = FALSE;
  1124. Device()->GetHalCallbacks()->SetMode(&SetModeData);
  1125. if (SetModeData.ddRVal != DD_OK)
  1126. {
  1127. DPF_ERR("Unable to set the new mode. CreateDevice/Reset Fails");
  1128. return SetModeData.ddRVal;
  1129. }
  1130. FetchDirectDrawData(Device()->GetDeviceData(), Device()->GetInitFunction(),
  1131. Device()->Enum()->GetUnknown16(Device()->AdapterIndex()),
  1132. Device()->Enum()->GetHalOpList(Device()->AdapterIndex()),
  1133. Device()->Enum()->GetNumHalOps(Device()->AdapterIndex()));
  1134. // We have to restore the device now, since out mode change above would
  1135. // have forced it to become lost.
  1136. bDeviceLost = TRUE; // need to restore right away
  1137. }
  1138. // For now, always destroy existing surfaces and recreate. Later, we
  1139. // may reuse the surfaces. We should also add an `initialized' flag,
  1140. // but for now will just arbitrarily use m_pPrimarySurface for this
  1141. // purpose.
  1142. Device()->UpdateRenderTarget(NULL, NULL);
  1143. if (m_pPrimarySurface != NULL)
  1144. {
  1145. Device()->ResourceManager()->DiscardBytes(0);
  1146. static_cast<CD3DBase*>(Device())->Destroy();
  1147. Destroy();
  1148. }
  1149. if (Device()->GetZStencil() != NULL)
  1150. {
  1151. Device()->GetZStencil()->DecrementUseCount();
  1152. Device()->ResetZStencil();
  1153. }
  1154. if (D3D8DoVidmemSurfacesExist(Device()->GetHandle()))
  1155. {
  1156. // user must free any video memory surfaces before doing
  1157. // fullscreen Reset, otherwise we fail.
  1158. DPF_ERR("All user created D3DPOOL_DEFAULT surfaces must be freed"
  1159. " before Reset can succeed. Reset Fails");
  1160. return D3DERR_DEVICELOST;
  1161. }
  1162. if (bDeviceLost)
  1163. {
  1164. D3D8RestoreDevice(Device()->GetHandle());
  1165. }
  1166. hr = CreateFullscreen(
  1167. m_PresentationData.BackBufferWidth,
  1168. m_PresentationData.BackBufferHeight,
  1169. m_PresentationData.BackBufferFormat,
  1170. m_PresentationData.BackBufferCount,
  1171. m_PresentationData.FullScreen_PresentationInterval,
  1172. m_PresentationData.MultiSampleType,
  1173. (D3DSWAPEFFECT_DISCARD == m_UserSwapEffect),
  1174. (pPresentationParameters->Flags & D3DPRESENTFLAG_LOCKABLE_BACKBUFFER)
  1175. );
  1176. #ifdef WINNT
  1177. if (SUCCEEDED(hr))
  1178. {
  1179. MakeFullscreen();
  1180. }
  1181. #endif //WINNT
  1182. // Restore the gamma ramp if it was previously set
  1183. if (m_GammaSet && SUCCEEDED(hr))
  1184. {
  1185. SetGammaRamp(0, &m_DesiredGammaRamp);
  1186. }
  1187. }
  1188. if (SUCCEEDED(hr))
  1189. {
  1190. m_pCursor = new CCursor(Device());
  1191. m_bClientChanged = TRUE;
  1192. m_pSrcRect = m_pDstRect = NULL;
  1193. }
  1194. return hr;
  1195. } // Reset
  1196. #undef DPF_MODNAME
  1197. #define DPF_MODNAME "CSwapChain::ClipIntervals"
  1198. //=============================================================================
  1199. // ClipIntervals
  1200. //
  1201. // calculate [low1 high1] and [low2 high2] after considering [low high]
  1202. //
  1203. // - [low1 high1] will be the interval corresponding to the width/height of
  1204. // target's size
  1205. //
  1206. // - [low2 high2] will be the interval corresponding to the width/height of
  1207. // the source's size
  1208. //
  1209. // - [low high] will be the interval corresponding of the width/height of
  1210. // the target clip
  1211. //
  1212. // The intention of this function is to clip the source for certain
  1213. // stretch scenarios where the target is clipped.
  1214. //
  1215. // Created 05/17/2000 kanqiu
  1216. //=============================================================================
  1217. void ClipIntervals(long & low1, long & high1,
  1218. long & low2, long & high2,
  1219. const long low, const long high)
  1220. {
  1221. DXGASSERT(low1 < high1);
  1222. DXGASSERT(low2 < high2);
  1223. DXGASSERT(low < high);
  1224. // shrink the target interval to lie within our Destination Clip [low high]
  1225. if (low > low1)
  1226. {
  1227. low1 = low;
  1228. }
  1229. if (high < high1)
  1230. {
  1231. high1 = high;
  1232. }
  1233. // if the destination interval is the same size as the destination
  1234. // clip, then we don't need to do anything
  1235. long length1 = high1 - low1;
  1236. long length = high - low;
  1237. // see if clamp is needed for low2 and high2 proportionally
  1238. if (length1 != length)
  1239. {
  1240. // find the length of our source interval
  1241. long length2 = high2 - low2;
  1242. // if the destination clip's low is outside our
  1243. // target's low
  1244. if (low < low1)
  1245. {
  1246. // Adjust the source low proportionally
  1247. low2 += (low1 - low) * length2 / length;
  1248. }
  1249. // if the destination clip's high is outside our
  1250. // target's high
  1251. if (high > high1)
  1252. {
  1253. // Adjust the source high proportionally
  1254. high2 -= (high - high1) * length2 / length;
  1255. }
  1256. /*
  1257. * Check for zero-sized dimensions and bump if necessary
  1258. */
  1259. DXGASSERT(high2 >= low2);
  1260. if (low2 == high2)
  1261. {
  1262. if (low1 - low >= high - high1)
  1263. {
  1264. low2--;
  1265. }
  1266. else
  1267. {
  1268. high2++;
  1269. }
  1270. }
  1271. }
  1272. } // ClipIntervals
  1273. #undef DPF_MODNAME
  1274. #define DPF_MODNAME "CSwapChain::ClipRects"
  1275. //=============================================================================
  1276. // ClipRects
  1277. //
  1278. // calculate pSrc and pDst after considering pSrcRect and pDstRect
  1279. //
  1280. // Created 05/17/2000 kanqiu
  1281. //=============================================================================
  1282. inline HRESULT ClipRects(RECT * pSrc, RECT * pDst,
  1283. RECT * pSrcRect, const RECT * pDstRect)
  1284. {
  1285. RECT SrcRect;
  1286. if (pDstRect)
  1287. {
  1288. if (pDstRect->top >= pDst->bottom ||
  1289. pDstRect->bottom <= pDst->top ||
  1290. pDstRect->left >= pDst->right ||
  1291. pDstRect->right <= pDst->left ||
  1292. pDstRect->top >= pDstRect->bottom ||
  1293. pDstRect->left >= pDstRect->right
  1294. )
  1295. {
  1296. // in case of insane RECT, fail it
  1297. DPF_ERR("Unable to present with invalid destionation RECT");
  1298. return D3DERR_INVALIDCALL;
  1299. }
  1300. if (pSrcRect)
  1301. {
  1302. SrcRect = *pSrcRect;
  1303. pSrcRect = &SrcRect; //make a local copy and then update
  1304. ClipIntervals(pDst->top,pDst->bottom,pSrcRect->top,pSrcRect->bottom,
  1305. pDstRect->top,pDstRect->bottom);
  1306. ClipIntervals(pDst->left,pDst->right,pSrcRect->left,pSrcRect->right,
  1307. pDstRect->left,pDstRect->right);
  1308. }
  1309. else
  1310. {
  1311. ClipIntervals(pDst->top,pDst->bottom,pSrc->top,pSrc->bottom,
  1312. pDstRect->top,pDstRect->bottom);
  1313. ClipIntervals(pDst->left,pDst->right,pSrc->left,pSrc->right,
  1314. pDstRect->left,pDstRect->right);
  1315. }
  1316. }
  1317. // this pSrcRect is either what the user passed in (if there is no pDstRect)
  1318. // or it now points to "SrcRect" temp which contains the clipped version
  1319. // of what the user passed it.
  1320. if (pSrcRect)
  1321. {
  1322. if (pSrcRect->top >= pSrc->bottom ||
  1323. pSrcRect->bottom <= pSrc->top ||
  1324. pSrcRect->left >= pSrc->right ||
  1325. pSrcRect->right <= pSrc->left ||
  1326. pSrcRect->top >= pSrcRect->bottom ||
  1327. pSrcRect->left >= pSrcRect->right
  1328. )
  1329. {
  1330. // in case of insane RECT, fail it
  1331. DPF_ERR("Unable to present with invalid source RECT");
  1332. return D3DERR_INVALIDCALL;
  1333. }
  1334. ClipIntervals(pSrc->top,pSrc->bottom,pDst->top,pDst->bottom,
  1335. pSrcRect->top,pSrcRect->bottom);
  1336. ClipIntervals(pSrc->left,pSrc->right,pDst->left,pDst->right,
  1337. pSrcRect->left,pSrcRect->right);
  1338. }
  1339. return S_OK;
  1340. }
  1341. #undef DPF_MODNAME
  1342. #define DPF_MODNAME "CSwapChain::UpdateFrameRate"
  1343. /*
  1344. * updateFrameRate
  1345. */
  1346. void
  1347. CSwapChain::UpdateFrameRate( void )
  1348. {
  1349. /*
  1350. * work out the frame rate if required...
  1351. */
  1352. if( 0xffffffff == m_dwFlipTime )
  1353. {
  1354. m_dwFlipTime = GetTickCount();
  1355. }
  1356. m_dwFlipCnt++;
  1357. if( m_dwFlipCnt >= 120 )
  1358. {
  1359. DWORD time2;
  1360. DWORD fps;
  1361. char buff[256];
  1362. time2 = GetTickCount() - m_dwFlipTime;
  1363. // Only do this at most every two seconds
  1364. if (time2 >= 2000)
  1365. {
  1366. fps = (m_dwFlipCnt*10000)/time2;
  1367. wsprintf(buff, "Adapter %d FPS = %ld.%01ld\r\n",
  1368. Device()->AdapterIndex(), fps/10, fps % 10 );
  1369. OutputDebugString(buff);
  1370. m_dwFlipTime = GetTickCount();
  1371. m_dwFlipCnt = 0;
  1372. }
  1373. }
  1374. } /* updateFrameRate */
  1375. #undef DPF_MODNAME
  1376. #define DPF_MODNAME "CSwapChain::DebugDiscardBackBuffer"
  1377. #ifdef DEBUG
  1378. void CSwapChain::DebugDiscardBackBuffer(HANDLE SurfaceToClear) const
  1379. {
  1380. // Disregard SW or Ref
  1381. if (Device()->GetDeviceType() == D3DDEVTYPE_REF ||
  1382. Device()->GetDeviceType() == D3DDEVTYPE_SW)
  1383. {
  1384. return;
  1385. }
  1386. if (m_UserSwapEffect != D3DSWAPEFFECT_DISCARD)
  1387. {
  1388. return;
  1389. }
  1390. D3D8_BLTDATA ColorFill;
  1391. ZeroMemory(&ColorFill, (sizeof ColorFill));
  1392. ColorFill.hDD = Device()->GetHandle();
  1393. ColorFill.hDestSurface = SurfaceToClear;
  1394. ColorFill.dwFlags = DDBLT_COLORFILL | DDBLT_WAIT;
  1395. ColorFill.rDest.right = Width();
  1396. ColorFill.rDest.bottom = Height();
  1397. // Switch between magenta and the inverse
  1398. static BOOL bMagenta = FALSE;
  1399. DWORD Color;
  1400. switch(Device()->DisplayFormat())
  1401. {
  1402. case D3DFMT_X8R8G8B8:
  1403. case D3DFMT_R8G8B8:
  1404. if (bMagenta)
  1405. Color = 0x00FF007F;
  1406. else
  1407. Color = 0x0000FF00;
  1408. break;
  1409. case D3DFMT_X1R5G5B5:
  1410. if (bMagenta)
  1411. Color = 0x7C0F;
  1412. else
  1413. Color = 0x03E0;
  1414. break;
  1415. case D3DFMT_R5G6B5:
  1416. if (bMagenta)
  1417. Color = 0xF80F;
  1418. else
  1419. Color = 0x07E0;
  1420. break;
  1421. }
  1422. if (bMagenta)
  1423. bMagenta = FALSE;
  1424. else
  1425. bMagenta = TRUE;
  1426. ColorFill.bltFX.dwFillColor = Color;
  1427. // In debug we want to clear the back-buffer
  1428. // if we're in discard mode
  1429. Device()->GetHalCallbacks()->Blt(&ColorFill);
  1430. return;
  1431. } // DebugDiscardBackBuffer
  1432. #endif // DEBUG
  1433. #undef DPF_MODNAME
  1434. #define DPF_MODNAME "CSwapChain::Present"
  1435. //=============================================================================
  1436. // IDirect3DSwapChain8::Present (public)
  1437. //
  1438. // Moves data from back-buffer to the primary
  1439. //
  1440. // Created 11/16/1999 johnstep
  1441. //=============================================================================
  1442. STDMETHODIMP
  1443. CSwapChain::Present(
  1444. CONST RECT *pSrcRect,
  1445. CONST RECT *pDestRect,
  1446. HWND hWndDestOverride,
  1447. CONST RGNDATA *pDirtyRegion
  1448. )
  1449. {
  1450. API_ENTER(Device());
  1451. HRESULT hr = E_FAIL;
  1452. // First, fail if the device is lost
  1453. if (D3D8IsDeviceLost(Device()->GetHandle()))
  1454. {
  1455. return D3DERR_DEVICELOST;
  1456. }
  1457. if (!m_ppBackBuffers)
  1458. {
  1459. return D3DERR_DEVICELOST;
  1460. }
  1461. if (D3DSWAPEFFECT_FLIP == m_PresentationData.SwapEffect)
  1462. {
  1463. if (NULL != pSrcRect || NULL != pDestRect || NULL != pDirtyRegion)
  1464. {
  1465. DPF_ERR("pSrcRect pDestRect pDirtyRegion must be NULL with "
  1466. "D3DSWAPEFFECT_FLIP. Present Fails.");
  1467. return D3DERR_INVALIDCALL;
  1468. }
  1469. }
  1470. if (NULL != pDirtyRegion)
  1471. {
  1472. DPF_ERR("Present with non-null pDirtyRegion is not supported");
  1473. return D3DERR_INVALIDCALL;
  1474. }
  1475. for (UINT i = 0; i < m_cBackBuffers; i++)
  1476. {
  1477. if (m_ppBackBuffers[i]->IsLocked())
  1478. {
  1479. DPF_ERR("A BackBuffer in this swap chain is Locked. Present failed.");
  1480. return D3DERR_INVALIDCALL;
  1481. }
  1482. }
  1483. // Check if we need to act against HW that queues too much
  1484. if (PresentUseBlt())
  1485. {
  1486. if (Device()->GetDeviceData()->DriverData.D3DCaps.MaxStreams == 0)
  1487. {
  1488. // Only pre-DX8 level drivers are suspected...
  1489. if (0 == (Device()->GetDeviceData()->DriverData.KnownDriverFlags & KNOWN_NOTAWINDOWEDBLTQUEUER))
  1490. {
  1491. // We don't want to treat a vis-region change as a failure to
  1492. // prevent the thunk layer from calling Reset. Reset
  1493. // confuses the clip-list caching that is done for Present.
  1494. //
  1495. // Also we want don't want to spew any errors here.
  1496. DPF_MUTE();
  1497. D3DLOCKED_RECT LockRect;
  1498. // all we need is a Lock sent down to driver so it would flush the queue
  1499. // therefore 1x1 rect is enough, larger area of lock would cause sprites to flick
  1500. // and therefore also slow down the system.
  1501. RECT DummyRect={0,0,1,1};
  1502. hr = m_pPrimarySurface->InternalLockRect(&LockRect, &DummyRect, DDLOCK_FAILONVISRGNCHANGED);
  1503. if (SUCCEEDED(hr))
  1504. {
  1505. m_pPrimarySurface->InternalUnlockRect();
  1506. }
  1507. else
  1508. {
  1509. hr = S_OK;
  1510. }
  1511. DPF_UNMUTE();
  1512. }
  1513. }
  1514. }
  1515. #ifdef WINNT
  1516. // If ~ 50 seconds have passed (assuming a 10Hz flip rate)
  1517. // and this is a primary surface, then make a magic call to
  1518. // disable screen savers.
  1519. // This isn't needed on 9x since we make a SPI call on that OS
  1520. // to disable screen savers.
  1521. if (0 == (Device()->BehaviorFlags() & 0x10000000)) //SCREENSAVER magic number
  1522. {
  1523. if (!m_PresentationData.Windowed)
  1524. {
  1525. static DWORD dwMagicTime = 0;
  1526. dwMagicTime++;
  1527. if (dwMagicTime > (50*10) )
  1528. {
  1529. DWORD dw=60*15;
  1530. dwMagicTime = 0;
  1531. SystemParametersInfo(SPI_GETSCREENSAVETIMEOUT,0,&dw,0);
  1532. SystemParametersInfo(SPI_SETSCREENSAVETIMEOUT,dw,0,0);
  1533. }
  1534. }
  1535. }
  1536. #endif
  1537. // Flush any pending commands before we send the Flip/Blt
  1538. static_cast<CD3DBase*>(Device())->FlushStatesNoThrow();
  1539. if ( FALSE == PresentUseBlt())
  1540. {
  1541. // We are fullscreen, so turn this into a flip
  1542. DXGASSERT(0==m_presentnext);
  1543. hr = FlipToSurface(BackBuffer(0)->KernelHandle());
  1544. }
  1545. else
  1546. {
  1547. if (m_PresentationData.Windowed)
  1548. {
  1549. RECT DestRect;
  1550. //
  1551. // Choose the presentation window. Override, or device window?
  1552. //
  1553. if (hWndDestOverride)
  1554. m_BltData.hWnd = hWndDestOverride;
  1555. else
  1556. m_BltData.hWnd = m_PresentationData.hDeviceWindow;
  1557. //The left and top members are zero. The right and bottom
  1558. //members contain the width and height of the window.
  1559. if (!GetClientRect(m_BltData.hWnd, &DestRect))
  1560. {
  1561. // in case of this unlikely event, fail it
  1562. DPF_ERR("Unable to get client during presentation");
  1563. return D3DERR_INVALIDCALL;
  1564. }
  1565. if (((UINT)DestRect.bottom != m_ClientHeight)
  1566. || ((UINT)DestRect.right != m_ClientWidth)
  1567. )
  1568. {
  1569. m_bClientChanged = TRUE;
  1570. m_ClientHeight = (UINT)DestRect.bottom;
  1571. m_ClientWidth = (UINT)DestRect.right;
  1572. }
  1573. }
  1574. if (D3DSWAPEFFECT_FLIP != m_PresentationData.SwapEffect)
  1575. {
  1576. if (pSrcRect)
  1577. {
  1578. if (m_pSrcRect)
  1579. {
  1580. if (memcmp(pSrcRect,m_pSrcRect,sizeof RECT))
  1581. {
  1582. m_bClientChanged = TRUE;
  1583. m_SrcRect = *pSrcRect;
  1584. }
  1585. }
  1586. else
  1587. {
  1588. m_bClientChanged = TRUE;
  1589. m_pSrcRect = &m_SrcRect;
  1590. m_SrcRect = *pSrcRect;
  1591. }
  1592. }
  1593. else if (m_pSrcRect)
  1594. {
  1595. m_bClientChanged = TRUE;
  1596. m_pSrcRect = NULL;
  1597. }
  1598. if (pDestRect)
  1599. {
  1600. if (m_pDstRect)
  1601. {
  1602. if (memcmp(pDestRect,m_pDstRect,sizeof RECT))
  1603. {
  1604. m_bClientChanged = TRUE;
  1605. m_DstRect = *pDestRect;
  1606. }
  1607. }
  1608. else
  1609. {
  1610. m_bClientChanged = TRUE;
  1611. m_pDstRect = &m_DstRect;
  1612. m_DstRect = *pDestRect;
  1613. }
  1614. }
  1615. else if (m_pDstRect)
  1616. {
  1617. m_bClientChanged = TRUE;
  1618. m_pDstRect = NULL;
  1619. }
  1620. }
  1621. if (m_bClientChanged)
  1622. {
  1623. m_bClientChanged = FALSE;
  1624. m_BltData.rSrc.left = m_BltData.rSrc.top = 0;
  1625. m_BltData.rSrc.right = Width();
  1626. m_BltData.rSrc.bottom = Height();
  1627. m_BltData.rDest.left = m_BltData.rDest.top = 0;
  1628. m_BltData.rDest.right = m_ClientWidth;
  1629. m_BltData.rDest.bottom = m_ClientHeight;
  1630. hr = ClipRects((RECT*)&m_BltData.rSrc, (RECT*)&m_BltData.rDest,
  1631. m_pSrcRect, m_pDstRect);
  1632. if (FAILED(hr))
  1633. {
  1634. return hr;
  1635. }
  1636. }
  1637. m_BltData.hSrcSurface =
  1638. m_ppBackBuffers[m_presentnext]->KernelHandle();
  1639. // Lock the software driver created buffer
  1640. // and unlock it immediately
  1641. if ((D3DDEVTYPE_HAL != Device()->GetDeviceType()) &&
  1642. (D3DMULTISAMPLE_NONE != m_PresentationData.MultiSampleType)
  1643. )
  1644. {
  1645. D3D8_LOCKDATA lockData;
  1646. ZeroMemory(&lockData, sizeof lockData);
  1647. lockData.hDD = Device()->GetHandle();
  1648. lockData.hSurface = m_BltData.hSrcSurface;
  1649. lockData.dwFlags = DDLOCK_READONLY;
  1650. hr = Device()->GetHalCallbacks()->Lock(&lockData);
  1651. if (SUCCEEDED(hr))
  1652. {
  1653. D3D8_UNLOCKDATA unlockData;
  1654. ZeroMemory(&unlockData, sizeof unlockData);
  1655. unlockData.hDD = Device()->GetHandle();
  1656. unlockData.hSurface = m_BltData.hSrcSurface;
  1657. hr = Device()->GetHalCallbacks()->Unlock(&unlockData);
  1658. if (FAILED(hr))
  1659. {
  1660. DPF_ERR("Driver failed to unlock MultiSample backbuffer. Present fails.");
  1661. return hr;
  1662. }
  1663. }
  1664. else
  1665. {
  1666. DPF_ERR("Driver failed to lock MultiSample backbuffer. Present Fails.");
  1667. return hr;
  1668. }
  1669. }
  1670. if (DDHAL_DRIVER_NOTHANDLED
  1671. == Device()->GetHalCallbacks()->Blt(&m_BltData))
  1672. {
  1673. hr = E_FAIL;
  1674. }
  1675. else
  1676. {
  1677. hr = m_BltData.ddRVal;
  1678. // Handle deferred DP2 errors specially
  1679. if (hr == D3DERR_DEFERRED_DP2ERROR)
  1680. {
  1681. // We only want to make this "error" visible
  1682. // if we have been created with the right flag
  1683. if (Device()->BehaviorFlags() & D3DCREATE_SHOW_DP2ERROR)
  1684. {
  1685. DPF_ERR("A prior call to DrawPrim2 has failed; returning error from Present.");
  1686. }
  1687. else
  1688. {
  1689. // Quietly just mask this error; this is ok; because
  1690. // we known that the Blt succeeded
  1691. hr = S_OK;
  1692. }
  1693. }
  1694. }
  1695. if (FAILED(hr))
  1696. {
  1697. DPF_ERR("BitBlt or StretchBlt failed in Present");
  1698. return hr;
  1699. }
  1700. // Clear the backbuffer if the user has specified
  1701. // discard semantics
  1702. DebugDiscardBackBuffer(m_BltData.hSrcSurface);
  1703. if (m_pMirrorSurface)
  1704. {
  1705. hr = FlipToSurface(m_pMirrorSurface->KernelHandle());
  1706. // need to reset it
  1707. m_BltData.hDestSurface = m_pMirrorSurface->KernelHandle();
  1708. if (FAILED(hr))
  1709. {
  1710. DPF_ERR("Driver failed Flip. Present Fails.");
  1711. return hr;
  1712. }
  1713. }
  1714. if (m_cBackBuffers > 1)
  1715. {
  1716. if (m_PresentationData.SwapEffect == D3DSWAPEFFECT_FLIP)
  1717. {
  1718. HANDLE hRenderTargetHandle =
  1719. Device()->RenderTarget()->KernelHandle();
  1720. BOOL bNeedSetRendertarget = FALSE;
  1721. HANDLE hSurfTarg = BackBuffer(0)->KernelHandle();
  1722. DXGASSERT(0 == m_presentnext);
  1723. for (int i = m_cBackBuffers - 1; i >= 0; i--)
  1724. {
  1725. if (hSurfTarg == hRenderTargetHandle)
  1726. bNeedSetRendertarget = TRUE;
  1727. // This swap handles function will
  1728. // return the value that were currently
  1729. // in the surface; which we use to
  1730. // pass to the next surface.
  1731. m_ppBackBuffers[i]->SwapKernelHandles(&hSurfTarg);
  1732. }
  1733. if (bNeedSetRendertarget)
  1734. (static_cast<CD3DBase*>(Device()))->SetRenderTargetI(
  1735. Device()->RenderTarget(),
  1736. Device()->ZBuffer());
  1737. }
  1738. else
  1739. if (++m_presentnext >= m_cBackBuffers)
  1740. {
  1741. m_presentnext = 0;
  1742. }
  1743. }
  1744. }
  1745. if ( D3D_REGFLAGS_SHOWFRAMERATE & m_dwFlags)
  1746. {
  1747. UpdateFrameRate();
  1748. }
  1749. return hr;
  1750. } // Present
  1751. HRESULT
  1752. CSwapChain::FlipToSurface(HANDLE hTargetSurface)
  1753. {
  1754. HRESULT hr;
  1755. D3D8_FLIPDATA FlipData;
  1756. HANDLE hSurfTarg;
  1757. FlipData.hDD = Device()->GetHandle();
  1758. FlipData.hSurfCurr = PrimarySurface()->KernelHandle();
  1759. FlipData.hSurfTarg = hTargetSurface;
  1760. FlipData.hSurfCurrLeft = NULL;
  1761. FlipData.hSurfTargLeft = NULL;
  1762. FlipData.dwFlags = m_dwFlipFlags;
  1763. m_pCursor->Flip();
  1764. hr = m_pCursor->Show(FlipData.hSurfTarg);
  1765. Device()->GetHalCallbacks()->Flip(&FlipData);
  1766. m_pCursor->Flip();
  1767. hr = m_pCursor->Hide(FlipData.hSurfCurr);
  1768. m_pCursor->Flip();
  1769. hr = FlipData.ddRVal;
  1770. // Handle deferred DP2 errors specially
  1771. if (hr == D3DERR_DEFERRED_DP2ERROR)
  1772. {
  1773. // We only want to make this "error" visible
  1774. // if we have been created with the right flag
  1775. if (Device()->BehaviorFlags() & D3DCREATE_SHOW_DP2ERROR)
  1776. {
  1777. DPF_ERR("A prior call to DrawPrim2 has failed; returning error from Present.");
  1778. }
  1779. else
  1780. {
  1781. // Quietly just mask this error; this is ok; because
  1782. // we known that the Flip succeeded
  1783. hr = S_OK;
  1784. }
  1785. }
  1786. // In debug, we may need to clear the data from
  1787. // our new back-buffer if the user specified
  1788. // SWAPEFFECT_DISCARD
  1789. DebugDiscardBackBuffer(FlipData.hSurfCurr);
  1790. if (m_pMirrorSurface)
  1791. {
  1792. hSurfTarg = PrimarySurface()->KernelHandle();
  1793. m_pMirrorSurface->SwapKernelHandles(&hSurfTarg);
  1794. PrimarySurface()->SwapKernelHandles(&hSurfTarg);
  1795. }
  1796. else
  1797. {
  1798. HANDLE hRenderTargetHandle;
  1799. CBaseSurface* pRenderTarget = Device()->RenderTarget();
  1800. if (pRenderTarget)
  1801. hRenderTargetHandle = pRenderTarget->KernelHandle();
  1802. else
  1803. hRenderTargetHandle = 0;
  1804. while (hTargetSurface != PrimarySurface()->KernelHandle())
  1805. {
  1806. hSurfTarg = PrimarySurface()->KernelHandle();
  1807. for (int i = m_cBackBuffers-1; i>=0; i--)
  1808. {
  1809. BackBuffer(i)->SwapKernelHandles(&hSurfTarg);
  1810. }
  1811. PrimarySurface()->SwapKernelHandles(&hSurfTarg);
  1812. }
  1813. if (hRenderTargetHandle)
  1814. {
  1815. BOOL bNeedSetRendertarget;
  1816. if (PrimarySurface()->KernelHandle() == hRenderTargetHandle)
  1817. {
  1818. bNeedSetRendertarget = TRUE;
  1819. }
  1820. else
  1821. {
  1822. bNeedSetRendertarget = FALSE;
  1823. for (int i = m_cBackBuffers-1; i>=0; i--)
  1824. {
  1825. if (BackBuffer(i)->KernelHandle() == hRenderTargetHandle)
  1826. {
  1827. bNeedSetRendertarget = TRUE;
  1828. break;
  1829. }
  1830. }
  1831. }
  1832. if (bNeedSetRendertarget)
  1833. {
  1834. (static_cast<CD3DBase*>(Device()))->SetRenderTargetI(
  1835. Device()->RenderTarget(),
  1836. Device()->ZBuffer());
  1837. }
  1838. }
  1839. }
  1840. return hr;
  1841. }
  1842. HRESULT
  1843. CSwapChain::FlipToGDISurface(void)
  1844. {
  1845. D3D8_FLIPTOGDISURFACEDATA FlipToGDISurfaceData;
  1846. FlipToGDISurfaceData.ddRVal = DD_OK;
  1847. FlipToGDISurfaceData.dwToGDI = TRUE;
  1848. FlipToGDISurfaceData.hDD = Device()->GetHandle();
  1849. Device()->GetHalCallbacks()->FlipToGDISurface(&FlipToGDISurfaceData);
  1850. if (NULL != m_hGDISurface && PrimarySurface() &&
  1851. PrimarySurface()->KernelHandle() != m_hGDISurface)
  1852. {
  1853. return FlipToSurface(m_hGDISurface);
  1854. }
  1855. return FlipToGDISurfaceData.ddRVal;
  1856. } // FlipToGDISurface
  1857. void
  1858. CSwapChain::SetGammaRamp(
  1859. DWORD dwFlags, // Calibrated or not.
  1860. CONST D3DGAMMARAMP *pRamp)
  1861. {
  1862. D3DGAMMARAMP TempRamp;
  1863. D3DGAMMARAMP * pRampToPassToHardware;
  1864. m_DesiredGammaRamp = *pRamp;
  1865. // Assume this for now. Calibration may use a temporary.
  1866. pRampToPassToHardware = &m_DesiredGammaRamp;
  1867. // If they want to calibrate the gamma, we will do that now. We will
  1868. // copy this to a different buffer so that we don't mess up the one
  1869. // passed in to us.
  1870. if (dwFlags & D3DSGR_CALIBRATE)
  1871. {
  1872. TempRamp = *pRamp;
  1873. Device()->Enum()->LoadAndCallGammaCalibrator(
  1874. &TempRamp,
  1875. (UCHAR*) Device()->GetDeviceData()->DriverName);
  1876. pRampToPassToHardware = &TempRamp;
  1877. }
  1878. DXGASSERT(pRampToPassToHardware);
  1879. DXGASSERT(Device()->GetDeviceData()->hDD);
  1880. DXGASSERT(Device()->GetDeviceData()->hDC);
  1881. D3D8SetGammaRamp(
  1882. Device()->GetDeviceData()->hDD,
  1883. Device()->GetDeviceData()->hDC,
  1884. pRampToPassToHardware);
  1885. if (pRamp != NULL)
  1886. {
  1887. m_GammaSet = TRUE;
  1888. }
  1889. else
  1890. {
  1891. m_GammaSet = FALSE;
  1892. }
  1893. }
  1894. void
  1895. CSwapChain::GetGammaRamp(
  1896. D3DGAMMARAMP *pRamp)
  1897. {
  1898. *pRamp = m_DesiredGammaRamp;
  1899. }
  1900. #undef DPF_MODNAME
  1901. #define DPF_MODNAME "CSwapChain::SetCooperativeLevel"
  1902. /*
  1903. * DD_SetCooperativeLevel
  1904. */
  1905. HRESULT
  1906. CSwapChain::SetCooperativeLevel()
  1907. {
  1908. #if _WIN32_WINNT >= 0x0501
  1909. {
  1910. //Turn off ghosting for any exclusive-mode app
  1911. //(Whistler onwards only)
  1912. typedef void (WINAPI *PFN_NOGHOST)( void );
  1913. HINSTANCE hInst = NULL;
  1914. hInst = LoadLibrary( "user32.dll" );
  1915. if( hInst )
  1916. {
  1917. PFN_NOGHOST pfnNoGhost = NULL;
  1918. pfnNoGhost = (PFN_NOGHOST)GetProcAddress( (HMODULE)hInst, "DisableProcessWindowsGhosting" );
  1919. if( pfnNoGhost )
  1920. {
  1921. pfnNoGhost();
  1922. }
  1923. FreeLibrary( hInst );
  1924. }
  1925. }
  1926. #endif // _WIN32_WINNT >= 0x0501
  1927. HRESULT ddrval;
  1928. #ifndef WINNT
  1929. ddrval = D3D8SetCooperativeLevel(Device()->GetHandle(),
  1930. m_PresentationData.hDeviceWindow,
  1931. m_PresentationData.Windowed ? DDSCL_NORMAL :
  1932. (DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_SETDEVICEWINDOW));
  1933. if (FAILED(ddrval))
  1934. return ddrval;
  1935. #else
  1936. BOOL bThisDeviceOwnsExclusive;
  1937. BOOL bExclusiveExists;
  1938. bExclusiveExists =
  1939. Device()->Enum()->CheckExclusiveMode(Device(),
  1940. &bThisDeviceOwnsExclusive,
  1941. !m_PresentationData.Windowed);
  1942. /*
  1943. * exclusive mode?
  1944. */
  1945. if (m_PresentationData.Windowed)
  1946. /*
  1947. * no, must be regular
  1948. */
  1949. {
  1950. DoneExclusiveMode(FALSE);
  1951. ddrval = SetAppHWnd();
  1952. }
  1953. if (bExclusiveExists && !bThisDeviceOwnsExclusive)
  1954. {
  1955. DPF_ERR("Exclusive Mode has been taken by other app or "
  1956. "other device on the same adapter. "
  1957. "SetCooperativeLevel returns D3DERR_DEVICELOST.");
  1958. return D3DERR_DEVICELOST;
  1959. }
  1960. if (!m_PresentationData.Windowed)
  1961. {
  1962. if (GetWindowLong(Device()->FocusWindow(), GWL_STYLE) & WS_CHILD)
  1963. {
  1964. DPF_ERR( "Focus Window must be a top level window. CreateDevice fails." );
  1965. return D3DERR_INVALIDCALL;
  1966. }
  1967. ddrval = SetAppHWnd();
  1968. if (S_OK == ddrval)
  1969. {
  1970. StartExclusiveMode(FALSE);
  1971. SetForegroundWindow(m_PresentationData.hDeviceWindow);
  1972. }
  1973. }
  1974. #endif
  1975. return ddrval;
  1976. } /* SetCooperativeLevel */
  1977. #ifdef WINNT
  1978. /*
  1979. * PickRefreshRate
  1980. *
  1981. * On NT, we want to pick a high reffresh rate, but we don't want to pick one
  1982. * too high. In theory, mode pruning would be 100% safe and we can always pick
  1983. * a high one, but we don't trust it 100%.
  1984. */
  1985. DWORD
  1986. CSwapChain::PickRefreshRate(
  1987. DWORD Width,
  1988. DWORD Height,
  1989. DWORD RefreshRate,
  1990. D3DFORMAT Format)
  1991. {
  1992. D3DFORMAT FormatWithoutAlpha;
  1993. D3DDISPLAYMODE* pModeTable = Device()->GetModeTable();
  1994. DWORD dwNumModes = Device()->GetNumModes();
  1995. DWORD i;
  1996. FormatWithoutAlpha = CPixel::SuppressAlphaChannel(Format);
  1997. // We will always use the refresh rate from the registry if it's specified.
  1998. if (m_dwForceRefreshRate > 0)
  1999. {
  2000. for (i = 0; i < dwNumModes; i++)
  2001. {
  2002. if ((pModeTable[i].Width == Width) &&
  2003. (pModeTable[i].Height == Height) &&
  2004. (pModeTable[i].Format == FormatWithoutAlpha) &&
  2005. (m_dwForceRefreshRate == pModeTable[i].RefreshRate))
  2006. {
  2007. return m_dwForceRefreshRate;
  2008. }
  2009. }
  2010. }
  2011. // If the app specified the refresh rate, then we'll use it; otherwise, we
  2012. // will pick one ourselves.
  2013. if (RefreshRate == 0)
  2014. {
  2015. // If the mode requires no more bandwidth than the desktop mode from which
  2016. // the app was launched, we will go ahead and try that mode.
  2017. DEVMODE dm;
  2018. ZeroMemory(&dm, sizeof dm);
  2019. dm.dmSize = sizeof dm;
  2020. EnumDisplaySettings(Device()->GetDeviceData()->DriverName,
  2021. ENUM_REGISTRY_SETTINGS, &dm);
  2022. if ((Width <= dm.dmPelsWidth) &&
  2023. (Height <= dm.dmPelsHeight))
  2024. {
  2025. // Now check to see if it's supported
  2026. for (i = 0; i < dwNumModes; i++)
  2027. {
  2028. if ((pModeTable[i].Width == Width) &&
  2029. (pModeTable[i].Height == Height) &&
  2030. (pModeTable[i].Format == FormatWithoutAlpha) &&
  2031. (dm.dmDisplayFrequency == pModeTable[i].RefreshRate))
  2032. {
  2033. RefreshRate = dm.dmDisplayFrequency;
  2034. break;
  2035. }
  2036. }
  2037. }
  2038. // If we still don't have a refresh rate, try 75hz
  2039. if (RefreshRate == 0)
  2040. {
  2041. for (i = 0; i < dwNumModes; i++)
  2042. {
  2043. if ((pModeTable[i].Width == Width) &&
  2044. (pModeTable[i].Height == Height) &&
  2045. (pModeTable[i].Format == FormatWithoutAlpha) &&
  2046. (75 == pModeTable[i].RefreshRate))
  2047. {
  2048. RefreshRate = 75;
  2049. break;
  2050. }
  2051. }
  2052. }
  2053. // If we still don't have a refresh rate, use 60hz
  2054. if (RefreshRate == 0)
  2055. {
  2056. for (i = 0; i < dwNumModes; i++)
  2057. {
  2058. if ((pModeTable[i].Width == Width) &&
  2059. (pModeTable[i].Height == Height) &&
  2060. (pModeTable[i].Format == FormatWithoutAlpha) &&
  2061. (pModeTable[i].RefreshRate == 60))
  2062. {
  2063. RefreshRate = pModeTable[i].RefreshRate;
  2064. break;
  2065. }
  2066. }
  2067. }
  2068. }
  2069. return RefreshRate;
  2070. }
  2071. #endif
  2072. // End of file : swapchain.cpp