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.

2369 lines
71 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 1995-1999 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: dxgcreat.cpp
  6. * Content Creates the dxg object
  7. *
  8. ***************************************************************************/
  9. #include "ddrawpr.h"
  10. // Includes for creation stuff
  11. #include "mipmap.hpp"
  12. #include "mipvol.hpp"
  13. #include "cubemap.hpp"
  14. #include "surface.hpp"
  15. #include "vbuffer.hpp"
  16. #include "ibuffer.hpp"
  17. #include "swapchan.hpp"
  18. #include "resource.hpp"
  19. #include "d3di.hpp"
  20. #include "resource.inl"
  21. #ifdef WINNT
  22. extern "C" BOOL IsWhistler();
  23. #endif
  24. //---------------------------------------------------------------------------
  25. // CBaseDevice methods
  26. //---------------------------------------------------------------------------
  27. #undef DPF_MODNAME
  28. #define DPF_MODNAME "CBaseDevice::AddRef"
  29. STDMETHODIMP_(ULONG) CBaseDevice::AddRef(void)
  30. {
  31. API_ENTER_NO_LOCK(this);
  32. // InterlockedIncrement requires the memory
  33. // to be aligned on DWORD boundary
  34. DXGASSERT(((ULONG_PTR)(&m_cRef) & 3) == 0);
  35. InterlockedIncrement((LONG *)&m_cRef);
  36. return m_cRef;
  37. } // AddRef
  38. #undef DPF_MODNAME
  39. #define DPF_MODNAME "CBaseDevice::Release"
  40. STDMETHODIMP_(ULONG) CBaseDevice::Release(void)
  41. {
  42. API_ENTER_NO_LOCK(this);
  43. // InterlockedDecrement requires the memory
  44. // to be aligned on DWORD boundary
  45. DXGASSERT(((ULONG_PTR)(&m_cRef) & 3) == 0);
  46. InterlockedDecrement((LONG *)&m_cRef);
  47. if (m_cRef != 0)
  48. return m_cRef;
  49. // If we are about to release; we
  50. // DPF a warning if the release is on a different
  51. // thread than the create
  52. if (!CheckThread())
  53. {
  54. DPF_ERR("Final Release for a device can only be called "
  55. "from the thread that the "
  56. "device was created from.");
  57. // No failure can be returned; but this is
  58. // dangerous situation for the app since
  59. // windows messages may still be processed
  60. }
  61. delete this;
  62. return 0;
  63. } // Release
  64. #undef DPF_MODNAME
  65. #define DPF_MODNAME "CBaseDevice::QueryInterface"
  66. STDMETHODIMP CBaseDevice::QueryInterface(REFIID riid, LPVOID FAR *ppv)
  67. {
  68. API_ENTER(this);
  69. if (!VALID_PTR_PTR(ppv))
  70. {
  71. DPF_ERR("Invalid pointer passed to QueryInterface for IDirect3DDevice8" );
  72. return D3DERR_INVALIDCALL;
  73. }
  74. if (!VALID_PTR(&riid, sizeof(GUID)))
  75. {
  76. DPF_ERR("Invalid guid memory address to QueryInterface for IDirect3DDevice8");
  77. return D3DERR_INVALIDCALL;
  78. }
  79. if (riid == IID_IUnknown || riid == IID_IDirect3DDevice8)
  80. {
  81. *ppv = static_cast<void*>(static_cast<IDirect3DDevice8*>(this));
  82. AddRef();
  83. }
  84. else
  85. {
  86. DPF_ERR("Unsupported Interface identifier passed to QueryInterface for IDirect3DDevice8");
  87. *ppv = NULL;
  88. return E_NOINTERFACE;
  89. }
  90. return S_OK;
  91. } // QueryInterface
  92. #undef DPF_MODNAME
  93. #define DPF_MODNAME "CBaseDevice::CreateAdditionalSwapChain"
  94. // Swap Chain stuff
  95. STDMETHODIMP
  96. CBaseDevice::CreateAdditionalSwapChain(
  97. D3DPRESENT_PARAMETERS *pPresentationParams,
  98. IDirect3DSwapChain8 **pSwapChain)
  99. {
  100. API_ENTER(this);
  101. if (!VALID_WRITEPTR(pPresentationParams, sizeof(D3DPRESENT_PARAMETERS)))
  102. {
  103. DPF_ERR("Invalid D3DPRESENT_PARAMETERS pointer to CreateAdditionalSwapChain");
  104. return D3DERR_INVALIDCALL;
  105. }
  106. if (!VALID_PTR_PTR(pSwapChain))
  107. {
  108. DPF_ERR("Invalid IDirect3DSwapChain8* pointer to CreateAdditionalSwapChain");
  109. return D3DERR_INVALIDCALL;
  110. }
  111. // Zero out return param
  112. *pSwapChain = NULL;
  113. if (NULL == m_pSwapChain)
  114. {
  115. DPF_ERR("No Swap Chain present; CreateAdditionalSwapChain fails");
  116. return D3DERR_INVALIDCALL;
  117. }
  118. if (pPresentationParams->BackBufferFormat == D3DFMT_UNKNOWN)
  119. {
  120. DPF_ERR("Invalid backbuffer format specified. CreateAdditionalSwapChain fails");
  121. return D3DERR_INVALIDCALL;
  122. }
  123. if (m_pSwapChain->m_PresentationData.Windowed
  124. && pPresentationParams->Windowed)
  125. {
  126. // both device and swapchain have to be windowed
  127. HRESULT hr;
  128. if ((NULL == pPresentationParams->hDeviceWindow)
  129. && (NULL == FocusWindow()))
  130. {
  131. DPF_ERR("Neither hDeviceWindow nor Focus window specified. CreateAdditionalSwapChain fails");
  132. return D3DERR_INVALIDCALL;
  133. }
  134. *pSwapChain = new CSwapChain(
  135. this,
  136. REF_EXTERNAL);
  137. if (*pSwapChain == NULL)
  138. {
  139. DPF_ERR("Out of memory creating swap chain. CreateAdditionalSwapChain fails");
  140. return E_OUTOFMEMORY;
  141. }
  142. static_cast<CSwapChain *> (*pSwapChain) ->Init(
  143. pPresentationParams,
  144. &hr);
  145. if (FAILED(hr))
  146. {
  147. DPF_ERR("Failure initializing swap chain. CreateAdditionalSwapChain fails");
  148. (*pSwapChain)->Release();
  149. *pSwapChain = NULL;
  150. return hr;
  151. }
  152. return hr;
  153. }
  154. else
  155. {
  156. DPF_ERR("Can't Create Additional SwapChain for FullScreen");
  157. return D3DERR_INVALIDCALL;
  158. }
  159. }
  160. #undef DPF_MODNAME
  161. #define DPF_MODNAME "CBaseDevice::SetCursorProperties"
  162. STDMETHODIMP
  163. CBaseDevice::SetCursorProperties(
  164. UINT xHotSpot,
  165. UINT yHotSpot,
  166. IDirect3DSurface8 *pCursorBitmap)
  167. {
  168. API_ENTER(this);
  169. if (pCursorBitmap == NULL)
  170. {
  171. DPF_ERR("Invalid parameter for pCursorBitmap");
  172. return D3DERR_INVALIDCALL;
  173. }
  174. CBaseSurface *pCursorSrc = static_cast<CBaseSurface*>(pCursorBitmap);
  175. if (pCursorSrc->InternalGetDevice() != this)
  176. {
  177. DPF_ERR("Cursor Surface wasn't allocated with this Device. SetCursorProperties fails");
  178. return D3DERR_INVALIDCALL;
  179. }
  180. if (SwapChain()->m_pCursor)
  181. {
  182. return SwapChain()->m_pCursor->SetProperties(
  183. xHotSpot,
  184. yHotSpot,
  185. pCursorSrc);
  186. }
  187. else
  188. {
  189. DPF_ERR("Device is lost. SetCursorProperties does nothing.");
  190. return S_OK;
  191. }
  192. } // SetCursorProperties
  193. #undef DPF_MODNAME
  194. #define DPF_MODNAME "CBaseDevice::SetCursorPosition"
  195. STDMETHODIMP_(void)
  196. CBaseDevice::SetCursorPosition(
  197. UINT xScreenSpace,
  198. UINT yScreenSpace,
  199. DWORD Flags)
  200. {
  201. API_ENTER_VOID(this);
  202. if (SwapChain()->m_pCursor)
  203. SwapChain()->m_pCursor->SetPosition(xScreenSpace,yScreenSpace,Flags);
  204. else
  205. DPF_ERR("Device is lost. SetCursorPosition does nothing.");
  206. return;
  207. } // SetCursorPosition
  208. #undef DPF_MODNAME
  209. #define DPF_MODNAME "CBaseDevice::ShowCursor"
  210. STDMETHODIMP_(BOOL)
  211. CBaseDevice::ShowCursor(
  212. BOOL bShow // cursor visibility flag
  213. )
  214. {
  215. API_ENTER_RET(this, BOOL);
  216. if (SwapChain()->m_pCursor)
  217. return m_pSwapChain->m_pCursor->SetVisibility(bShow);
  218. DPF_ERR("Device is lost. ShowCursor does nothing.");
  219. return FALSE;
  220. } // ShowCursor
  221. #undef DPF_MODNAME
  222. #define DPF_MODNAME "CBaseDevice::Reset"
  223. STDMETHODIMP
  224. CBaseDevice::Reset(
  225. D3DPRESENT_PARAMETERS *pPresentationParams
  226. )
  227. {
  228. API_ENTER(this);
  229. HRESULT hr;
  230. if (!CheckThread())
  231. {
  232. DPF_ERR("Reset can only be called from the thread that the "
  233. "device was created from.");
  234. return D3DERR_INVALIDCALL;
  235. }
  236. if (!VALID_WRITEPTR(pPresentationParams, sizeof(D3DPRESENT_PARAMETERS)))
  237. {
  238. DPF_ERR("Invalid D3DPRESENT_PARAMETERS pointer, Reset fails");
  239. hr = D3DERR_INVALIDCALL;
  240. goto LoseDevice;
  241. }
  242. if (NULL == FocusWindow())
  243. {
  244. if (!pPresentationParams->Windowed)
  245. {
  246. DPF_ERR("Can't Reset a Device w/o Focus window to Fullscreen");
  247. hr = D3DERR_INVALIDCALL;
  248. goto LoseDevice;
  249. }
  250. else
  251. if (NULL == pPresentationParams->hDeviceWindow)
  252. {
  253. DPF_ERR("Neither hDeviceWindow nor Focus window specified. Reset fails.");
  254. hr = D3DERR_INVALIDCALL;
  255. goto LoseDevice;
  256. }
  257. }
  258. if (pPresentationParams->BackBufferFormat == D3DFMT_UNKNOWN)
  259. {
  260. DPF_ERR("Invalid backbuffer format specified. Reset fails");
  261. hr = D3DERR_INVALIDCALL;
  262. goto LoseDevice;
  263. }
  264. if (NULL == m_pSwapChain)
  265. {
  266. DPF_ERR("No Swap Chain present, Reset fails");
  267. hr = D3DERR_INVALIDCALL;
  268. goto LoseDevice;
  269. }
  270. hr = TestCooperativeLevel();
  271. if (D3DERR_DEVICELOST == hr)
  272. {
  273. DPF_ERR("Reset fails. D3DERR_DEVICELOST returned.");
  274. goto LoseDevice;
  275. }
  276. else if (D3DERR_DEVICENOTRESET == hr)
  277. {
  278. // There might be a external mode switch or ALT-TAB from fullscreen
  279. FetchDirectDrawData(GetDeviceData(), GetInitFunction(),
  280. Enum()->GetUnknown16(AdapterIndex()),
  281. Enum()->GetHalOpList(AdapterIndex()),
  282. Enum()->GetNumHalOps(AdapterIndex()));
  283. // only update the DesktopMode
  284. // if lost device was windowed or Fullscreen(but ALT-TABed away)
  285. // in Multimon case, even Fullscreen with exclusive mode Device could
  286. // be lost due to a mode change in other adapters and DesktopMode
  287. // should NOT be updated as it's the current fullscreen mode
  288. if (!SwapChain()->m_bExclusiveMode)
  289. {
  290. m_DesktopMode.Height = DisplayHeight();
  291. m_DesktopMode.Width = DisplayWidth();
  292. m_DesktopMode.Format = DisplayFormat();
  293. m_DesktopMode.RefreshRate = DisplayRate();
  294. }
  295. }
  296. else if (m_fullscreen)
  297. {
  298. SwapChain()->FlipToGDISurface();
  299. }
  300. if ( S_OK == hr && RenderTarget())
  301. {
  302. RenderTarget()->Sync();
  303. }
  304. static_cast<CD3DBase*>(this)->CleanupTextures();
  305. hr = m_pSwapChain->Reset(
  306. pPresentationParams);
  307. if (FAILED(hr))
  308. {
  309. goto LoseDevice;
  310. }
  311. if (pPresentationParams->EnableAutoDepthStencil)
  312. {
  313. // Need to validate that this Z-buffer matches
  314. // the HW
  315. hr = CheckDepthStencilMatch(pPresentationParams->BackBufferFormat,
  316. pPresentationParams->AutoDepthStencilFormat);
  317. if (FAILED(hr))
  318. {
  319. DPF_ERR("AutoDepthStencilFormat does not match BackBufferFormat "
  320. "because the current Device requires the bitdepth of the "
  321. "zbuffer to match the render-target. Reset Failed");
  322. goto LoseDevice;
  323. }
  324. IDirect3DSurface8 *pSurf;
  325. hr = CSurface::CreateZStencil(this,
  326. m_pSwapChain->Width(),
  327. m_pSwapChain->Height(),
  328. pPresentationParams->AutoDepthStencilFormat,
  329. pPresentationParams->MultiSampleType,
  330. REF_INTRINSIC,
  331. &pSurf);
  332. if (FAILED(hr))
  333. {
  334. DPF_ERR("Failure trying to create automatic zstencil surface. Reset Fails");
  335. goto LoseDevice;
  336. }
  337. DXGASSERT(m_pAutoZStencil == NULL);
  338. m_pAutoZStencil = static_cast<CBaseSurface *>(pSurf);
  339. }
  340. // Disconnect Buffers from our device's state if there is any
  341. // I tried to not Destroy() upon window->window Reset
  342. // however, there are many other cares which require it,
  343. // such as device lost or m_pDDI=NULL due to earlier failure
  344. // also SetRenderTarget() is tough when m_pDDI is bad
  345. // some driver(like ATI Rage3) could not Reset view correctly
  346. // even after SetRenderTarget()
  347. // therefore always Destroy and do a Init, as a result, driver
  348. // will always get a DestroyContext and CreateContext clean
  349. // static_cast<CD3DBase*>(this)->Destroy();
  350. UpdateRenderTarget(m_pSwapChain->m_ppBackBuffers[0], m_pAutoZStencil);
  351. hr = static_cast<CD3DBase*>(this)->Init();
  352. LoseDevice:
  353. if (FAILED(hr))
  354. {
  355. DPF_ERR("Reset failed and Reset/TestCooperativeLevel/Release "
  356. "are the only legal APIs to be called subsequently");
  357. if ((SwapChain()) && (!SwapChain()->m_PresentationData.Windowed))
  358. {
  359. // release the exclusive upon failure
  360. SwapChain()->m_PresentationData.Windowed = TRUE;
  361. SwapChain()->SetCooperativeLevel();
  362. }
  363. D3D8LoseDevice(GetHandle());
  364. }
  365. else
  366. {
  367. hr = CResource::RestoreDriverManagementState(this);
  368. if (FAILED(hr))
  369. {
  370. goto LoseDevice;
  371. }
  372. hr = static_cast<CD3DBase*>(this)->ResetShaders();
  373. if (FAILED(hr))
  374. {
  375. goto LoseDevice;
  376. }
  377. }
  378. m_fullscreen = !SwapChain()->m_PresentationData.Windowed;
  379. return hr;
  380. } // Reset
  381. #undef DPF_MODNAME
  382. #define DPF_MODNAME "CBaseDevice::SetGammaRamp"
  383. STDMETHODIMP_(void)
  384. CBaseDevice::SetGammaRamp(DWORD dwFlags, CONST D3DGAMMARAMP *pRamp)
  385. {
  386. API_ENTER_VOID(this);
  387. if (NULL == pRamp)
  388. {
  389. DPF_ERR("Invalid D3DGAMMARAMP pointer. SetGammaRamp ignored.");
  390. return;
  391. }
  392. if (m_pSwapChain == NULL)
  393. {
  394. DPF_ERR("No Swap Chain present; SetGammaRamp fails");
  395. return;
  396. }
  397. m_pSwapChain->SetGammaRamp(dwFlags, pRamp);
  398. } // SetGammaRamp
  399. #undef DPF_MODNAME
  400. #define DPF_MODNAME "CBaseDevice::GetGammaRamp"
  401. STDMETHODIMP_(void)
  402. CBaseDevice::GetGammaRamp(D3DGAMMARAMP *pRamp)
  403. {
  404. API_ENTER_VOID(this);
  405. if (NULL == pRamp)
  406. {
  407. DPF_ERR("Invalid D3DGAMMARAMP pointer. GetGammaRamp ignored");
  408. return;
  409. }
  410. if (m_pSwapChain == NULL)
  411. {
  412. DPF_ERR("No Swap Chain present; GetGammaRamp fails");
  413. return;
  414. }
  415. m_pSwapChain->GetGammaRamp(pRamp);
  416. } // GetGammaRamp
  417. #undef DPF_MODNAME
  418. #define DPF_MODNAME "CBaseDevice::GetBackBuffer"
  419. HRESULT
  420. CBaseDevice::GetBackBuffer(UINT iBackBuffer,
  421. D3DBACKBUFFER_TYPE Type,
  422. IDirect3DSurface8 **ppBackBuffer)
  423. {
  424. API_ENTER(this);
  425. if (!VALID_PTR_PTR(ppBackBuffer))
  426. {
  427. DPF_ERR("Invalid IDirect3DSurface8* pointer to GetBackBuffer");
  428. return D3DERR_INVALIDCALL;
  429. }
  430. // Zero out return param
  431. *ppBackBuffer = NULL;
  432. if (m_pSwapChain == NULL)
  433. {
  434. DPF_ERR("No Swap Chain present; GetBackBuffer fails");
  435. return D3DERR_INVALIDCALL;
  436. }
  437. return m_pSwapChain->GetBackBuffer(iBackBuffer, Type, ppBackBuffer);
  438. } // GetBackBuffer
  439. #undef DPF_MODNAME
  440. #define DPF_MODNAME "CBaseDevice::Present"
  441. STDMETHODIMP
  442. CBaseDevice::Present(
  443. CONST RECT *pSrcRect,
  444. CONST RECT *pDestRect,
  445. HWND hWndDestOverride,
  446. CONST RGNDATA *pDstRegion
  447. )
  448. {
  449. API_ENTER(this);
  450. if (m_pSwapChain == NULL)
  451. {
  452. DPF_ERR("No Swap Chain present; Present fails");
  453. return D3DERR_INVALIDCALL;
  454. }
  455. return m_pSwapChain->Present(pSrcRect, pDestRect, hWndDestOverride, pDstRegion);
  456. } // Present
  457. #undef DPF_MODNAME
  458. #define DPF_MODNAME "CBaseDevice::TestCooperativeLevel"
  459. STDMETHODIMP CBaseDevice::TestCooperativeLevel(void)
  460. {
  461. API_ENTER(this);
  462. if (D3D8IsDeviceLost(GetHandle()))
  463. {
  464. #ifdef WINNT
  465. if (m_pSwapChain)
  466. {
  467. BOOL bDeactivated = m_pSwapChain->IsWinProcDeactivated();
  468. if (bDeactivated)
  469. return D3DERR_DEVICELOST;
  470. }
  471. HWND EnumFocusWindow = Enum()->ExclusiveOwnerWindow();
  472. if (EnumFocusWindow &&
  473. EnumFocusWindow != FocusWindow())
  474. {
  475. DPF(0, "Another device in the same process has gone full-screen."
  476. " If you wanted both to go full-screen at the same time,"
  477. " you need to pass the same HWND for the Focus Window.");
  478. return D3DERR_DEVICELOST;
  479. }
  480. BOOL bThisDeviceOwnsExclusive;
  481. BOOL bExclusiveExists = Enum()->CheckExclusiveMode(this,
  482. &bThisDeviceOwnsExclusive, FALSE);
  483. if (bExclusiveExists && !bThisDeviceOwnsExclusive)
  484. {
  485. return D3DERR_DEVICELOST;
  486. }
  487. #endif //WINNT
  488. if (D3D8CanRestoreNow(GetHandle()))
  489. {
  490. return D3DERR_DEVICENOTRESET;
  491. }
  492. return D3DERR_DEVICELOST;
  493. }
  494. return S_OK;
  495. } // TestCooperativeLevel
  496. #undef DPF_MODNAME
  497. #define DPF_MODNAME "CBaseDevice::GetRasterStatus"
  498. STDMETHODIMP CBaseDevice::GetRasterStatus(D3DRASTER_STATUS *pStatus)
  499. {
  500. API_ENTER(this);
  501. if (!VALID_WRITEPTR(pStatus, sizeof(*pStatus)))
  502. {
  503. DPF_ERR("Invalid Raster Status parameter to GetRasterStatus");
  504. return D3DERR_INVALIDCALL;
  505. }
  506. if (!(GetD3DCaps()->Caps & D3DCAPS_READ_SCANLINE))
  507. {
  508. pStatus->ScanLine = 0;
  509. pStatus->InVBlank = FALSE;
  510. DPF_ERR("Current device doesn't support D3DCAPS_READ_SCANLINE functionality. GetRasterStatus fails.");
  511. return D3DERR_INVALIDCALL;
  512. }
  513. D3D8_GETSCANLINEDATA getScanLineData;
  514. getScanLineData.hDD = GetHandle();
  515. DWORD dwRet = GetHalCallbacks()->GetScanLine(&getScanLineData);
  516. if (dwRet == DDHAL_DRIVER_HANDLED)
  517. {
  518. if (getScanLineData.ddRVal == S_OK)
  519. {
  520. pStatus->InVBlank = getScanLineData.bInVerticalBlank;
  521. if (getScanLineData.bInVerticalBlank)
  522. {
  523. pStatus->ScanLine = 0;
  524. }
  525. else
  526. {
  527. pStatus->ScanLine = getScanLineData.dwScanLine;
  528. }
  529. }
  530. else
  531. {
  532. DPF_ERR("Device failed GetScanline. GetRasterStatus fails");
  533. pStatus->ScanLine = 0;
  534. pStatus->InVBlank = FALSE;
  535. return D3DERR_NOTAVAILABLE;
  536. }
  537. }
  538. else
  539. {
  540. DPF_ERR("Device failed GetScanline. GetRasterStatus fails.");
  541. pStatus->ScanLine = 0;
  542. pStatus->InVBlank = FALSE;
  543. return D3DERR_NOTAVAILABLE;
  544. }
  545. return S_OK;
  546. } // GetRasterStatus
  547. #undef DPF_MODNAME
  548. #define DPF_MODNAME "CBaseDevice::GetDirect3D"
  549. STDMETHODIMP CBaseDevice::GetDirect3D(LPDIRECT3D8 *pD3D8)
  550. {
  551. API_ENTER(this);
  552. if (pD3D8 == NULL)
  553. {
  554. DPF_ERR("Invalid pointer specified. GetDirect3D fails.");
  555. return D3DERR_INVALIDCALL;
  556. }
  557. DXGASSERT(m_pD3DClass);
  558. m_pD3DClass->AddRef();
  559. *pD3D8 = m_pD3DClass;
  560. return D3D_OK;
  561. } // GetDirect3D
  562. #undef DPF_MODNAME
  563. #define DPF_MODNAME "CBaseDevice::GetCreationParameters"
  564. STDMETHODIMP CBaseDevice::GetCreationParameters(D3DDEVICE_CREATION_PARAMETERS *pParameters)
  565. {
  566. API_ENTER(this);
  567. if (!VALID_WRITEPTR(pParameters, sizeof(D3DDEVICE_CREATION_PARAMETERS)))
  568. {
  569. DPF_ERR("bad pointer for pParameters passed to GetCreationParameters");
  570. return D3DERR_INVALIDCALL;
  571. }
  572. pParameters->AdapterOrdinal = m_AdapterIndex;
  573. pParameters->DeviceType = m_DeviceType;
  574. pParameters->BehaviorFlags = m_dwOriginalBehaviorFlags;
  575. pParameters->hFocusWindow = m_hwndFocusWindow;
  576. return S_OK;
  577. } // GetCreationParameters
  578. #undef DPF_MODNAME
  579. #define DPF_MODNAME "CBaseDevice::GetDisplayMode"
  580. STDMETHODIMP CBaseDevice::GetDisplayMode(D3DDISPLAYMODE *pMode)
  581. {
  582. API_ENTER(this);
  583. if (!VALID_WRITEPTR(pMode, sizeof(*pMode)))
  584. {
  585. DPF_ERR("Invalid pointer specified to GetDisplayMode");
  586. return D3DERR_INVALIDCALL;
  587. }
  588. pMode->Width = DisplayWidth();
  589. pMode->Height = DisplayHeight();
  590. pMode->Format = DisplayFormat();
  591. pMode->RefreshRate = DisplayRate();
  592. return D3D_OK;
  593. } // GetDisplayMode
  594. #undef DPF_MODNAME
  595. #define DPF_MODNAME "CBaseDevice::GetAvailableTextureMem"
  596. STDMETHODIMP_(UINT) CBaseDevice::GetAvailableTextureMem(void)
  597. {
  598. API_ENTER_RET(this, UINT);
  599. D3D8_GETAVAILDRIVERMEMORYDATA GetAvailDriverMemory;
  600. GetAvailDriverMemory.hDD = GetHandle();
  601. GetAvailDriverMemory.Pool = D3DPOOL_DEFAULT;
  602. GetAvailDriverMemory.dwUsage = D3DUSAGE_TEXTURE;
  603. GetAvailDriverMemory.dwFree = 0;
  604. GetHalCallbacks()->GetAvailDriverMemory(&GetAvailDriverMemory);
  605. #define ONE_MEG_O_VRAM 0x100000
  606. //Round to nearest meg:
  607. return (GetAvailDriverMemory.dwFree + ONE_MEG_O_VRAM/2) & (~(ONE_MEG_O_VRAM-1));
  608. } // GetAvailableTextureMem
  609. #undef DPF_MODNAME
  610. #define DPF_MODNAME "CanHardwareBlt"
  611. BOOL CanHardwareBlt (const D3D8_DRIVERCAPS* pDriverCaps,
  612. D3DPOOL SrcPool,
  613. D3DFORMAT SrcFormat,
  614. D3DPOOL DstPool,
  615. D3DFORMAT DstFormat,
  616. D3DDEVTYPE DeviceType)
  617. {
  618. // Pools are supposed to be real pools as opposed to
  619. // what the app specified
  620. DXGASSERT(SrcPool != D3DPOOL_DEFAULT);
  621. DXGASSERT(DstPool != D3DPOOL_DEFAULT);
  622. DXGASSERT(VALID_INTERNAL_POOL(SrcPool));
  623. DXGASSERT(VALID_INTERNAL_POOL(DstPool));
  624. //Driver should never be allowed to see scratch:
  625. if (SrcPool == D3DPOOL_SCRATCH ||
  626. DstPool == D3DPOOL_SCRATCH)
  627. {
  628. return FALSE;
  629. }
  630. // For this case, we want to just lock and memcpy. Why?
  631. // It's a software driver, so it's going to be a memcpy anyway,
  632. // and we special case blt since we want to use a real hardware
  633. // blt for Present even when running a software driver. So either
  634. // we lock and memcpy, or we have to keep track of two different
  635. // Blt entry points (one for the real driver and one for the software
  636. // driver) just so the software driver can do the memcpy itself.
  637. if (DeviceType != D3DDEVTYPE_HAL)
  638. {
  639. return FALSE;
  640. }
  641. // Check that source and dest formats match
  642. DXGASSERT(SrcFormat == DstFormat);
  643. // FourCC may not be copy-able
  644. if (CPixel::IsFourCC(SrcFormat))
  645. {
  646. if (!(pDriverCaps->D3DCaps.Caps2 & DDCAPS2_COPYFOURCC))
  647. {
  648. return FALSE;
  649. }
  650. }
  651. // We can't do HW blts if either source or
  652. // dest is in system memory and the driver
  653. // needs PageLocks
  654. if (SrcPool == D3DPOOL_SYSTEMMEM ||
  655. DstPool == D3DPOOL_SYSTEMMEM)
  656. {
  657. if (!(pDriverCaps->D3DCaps.Caps2 & DDCAPS2_NOPAGELOCKREQUIRED))
  658. {
  659. return FALSE;
  660. }
  661. // Now this is tricky; but in DX7 we checked this cap when
  662. // deciding whether to do BLTs involving system-memory but not
  663. // when we decided whether to do real Blts. We need to check this.
  664. if (!(pDriverCaps->D3DCaps.Caps & DDCAPS_CANBLTSYSMEM))
  665. {
  666. return FALSE;
  667. }
  668. }
  669. // Check AGP caps first
  670. if (pDriverCaps->D3DCaps.Caps2 & DDCAPS2_NONLOCALVIDMEMCAPS)
  671. {
  672. if (SrcPool == D3DPOOL_SYSTEMMEM)
  673. {
  674. if ((DstPool == D3DPOOL_NONLOCALVIDMEM) &&
  675. (pDriverCaps->D3DCaps.Caps2 & DDCAPS2_SYSTONONLOCAL_AS_SYSTOLOCAL) &&
  676. (pDriverCaps->SVBCaps & DDCAPS_BLT))
  677. {
  678. return TRUE;
  679. }
  680. else if (((DstPool == D3DPOOL_LOCALVIDMEM) ||
  681. (DstPool == D3DPOOL_MANAGED)) &&
  682. (pDriverCaps->SVBCaps & DDCAPS_BLT))
  683. {
  684. return TRUE;
  685. }
  686. }
  687. else if (SrcPool == D3DPOOL_NONLOCALVIDMEM)
  688. {
  689. if (((DstPool == D3DPOOL_LOCALVIDMEM) ||
  690. (DstPool == D3DPOOL_MANAGED)) &&
  691. (pDriverCaps->NLVCaps & DDCAPS_BLT))
  692. {
  693. return TRUE;
  694. }
  695. }
  696. else if ((SrcPool == D3DPOOL_LOCALVIDMEM) ||
  697. (SrcPool == D3DPOOL_MANAGED))
  698. {
  699. if (((DstPool == D3DPOOL_LOCALVIDMEM) ||
  700. (DstPool == D3DPOOL_MANAGED)) &&
  701. (pDriverCaps->D3DCaps.Caps & DDCAPS_BLT))
  702. {
  703. return TRUE;
  704. }
  705. else if ((DstPool == D3DPOOL_SYSTEMMEM) &&
  706. (pDriverCaps->VSBCaps & DDCAPS_BLT))
  707. {
  708. return TRUE;
  709. }
  710. }
  711. }
  712. else
  713. {
  714. if (SrcPool == D3DPOOL_SYSTEMMEM)
  715. {
  716. if (((DstPool == D3DPOOL_LOCALVIDMEM) ||
  717. (DstPool == D3DPOOL_MANAGED)) &&
  718. (pDriverCaps->SVBCaps & DDCAPS_BLT))
  719. {
  720. return TRUE;
  721. }
  722. }
  723. else if ((SrcPool == D3DPOOL_LOCALVIDMEM) ||
  724. (SrcPool == D3DPOOL_MANAGED))
  725. {
  726. if (((DstPool == D3DPOOL_LOCALVIDMEM) ||
  727. (DstPool == D3DPOOL_MANAGED)) &&
  728. (pDriverCaps->D3DCaps.Caps & DDCAPS_BLT))
  729. {
  730. return TRUE;
  731. }
  732. else if ((DstPool == D3DPOOL_SYSTEMMEM) &&
  733. (pDriverCaps->VSBCaps & DDCAPS_BLT))
  734. {
  735. return TRUE;
  736. }
  737. }
  738. }
  739. return FALSE;
  740. } // CanHardwareBlt
  741. #undef DPF_MODNAME
  742. #define DPF_MODNAME "CBaseDevice::CopyRects"
  743. STDMETHODIMP CBaseDevice::CopyRects(IDirect3DSurface8 *pSrcSurface,
  744. CONST RECT *pSrcRectsArray,
  745. UINT cRects,
  746. IDirect3DSurface8 *pDstSurface,
  747. CONST POINT *pDstPointsArray)
  748. {
  749. API_ENTER(this);
  750. D3DSURFACE_DESC SrcDesc;
  751. D3DSURFACE_DESC DstDesc;
  752. HRESULT hr;
  753. UINT i;
  754. // Do some basic paramater checking
  755. if (!VALID_PTR(pSrcSurface, sizeof(void*)) ||
  756. !VALID_PTR(pDstSurface, sizeof(void*)))
  757. {
  758. DPF_ERR("NULL surface interface specified. CopyRect fails");
  759. return D3DERR_INVALIDCALL;
  760. }
  761. CBaseSurface *pSrc = static_cast<CBaseSurface*>(pSrcSurface);
  762. if (pSrc->InternalGetDevice() != this)
  763. {
  764. DPF_ERR("SrcSurface was not allocated with this Device. CopyRect fails.");
  765. return D3DERR_INVALIDCALL;
  766. }
  767. CBaseSurface *pDst = static_cast<CBaseSurface*>(pDstSurface);
  768. if (pDst->InternalGetDevice() != this)
  769. {
  770. DPF_ERR("DstSurface was not allocated with this Device. CopyRect fails.");
  771. return D3DERR_INVALIDCALL;
  772. }
  773. hr = pSrc->GetDesc(&SrcDesc);
  774. DXGASSERT(SUCCEEDED(hr));
  775. hr = pDst->GetDesc(&DstDesc);
  776. DXGASSERT(SUCCEEDED(hr));
  777. // Source can not be a load-once surface
  778. if (SrcDesc.Usage & D3DUSAGE_LOADONCE)
  779. {
  780. DPF_ERR("CopyRects can not be used from a Load_Once surface");
  781. return D3DERR_INVALIDCALL;
  782. }
  783. // Destination can not be a load-once surface
  784. // if it isn't currently lockable.
  785. if (DstDesc.Usage & D3DUSAGE_LOADONCE)
  786. {
  787. if (pDst->IsLoaded())
  788. {
  789. DPF_ERR("Destination for CopyRects a Load_Once surface that has"
  790. " already been loaded. CopyRects failed.");
  791. return D3DERR_INVALIDCALL;
  792. }
  793. }
  794. // Source can not be already locked
  795. if (pSrc->IsLocked())
  796. {
  797. DPF_ERR("Source for CopyRects is already Locked. CopyRect failed.");
  798. return D3DERR_INVALIDCALL;
  799. }
  800. if (pDst->IsLocked())
  801. {
  802. DPF_ERR("Destination for CopyRects is already Locked. CopyRect failed.");
  803. return D3DERR_INVALIDCALL;
  804. }
  805. if (SrcDesc.Format != DstDesc.Format)
  806. {
  807. DPF_ERR("Source and dest surfaces are different formats. CopyRects fails");
  808. return D3DERR_INVALIDCALL;
  809. }
  810. if (CPixel::IsEnumeratableZ(SrcDesc.Format) &&
  811. !CPixel::IsIHVFormat(SrcDesc.Format))
  812. {
  813. DPF_ERR("CopyRects is not supported for Z formats.");
  814. return D3DERR_INVALIDCALL;
  815. }
  816. // Make sure that the rects are entirely within the surface
  817. if ((cRects > 0) && (pSrcRectsArray == NULL))
  818. {
  819. DPF_ERR("Number of rects > 0, but rect array is NULL. CopyRects fails.");
  820. return D3DERR_INVALIDCALL;
  821. }
  822. D3DFORMAT InternalFormat = pSrc->InternalGetDesc().Format;
  823. BOOL bDXT = CPixel::IsDXT(InternalFormat);
  824. for (i = 0; i < cRects; i++)
  825. {
  826. if (!CPixel::IsValidRect(InternalFormat,
  827. SrcDesc.Width,
  828. SrcDesc.Height,
  829. &pSrcRectsArray[i]))
  830. {
  831. DPF_ERR("CopyRects failed");
  832. return D3DERR_INVALIDCALL;
  833. }
  834. // Validate the point parameter;
  835. // if it is NULL, then it means that we're
  836. // to use the left/top that was in the corresponding rect.
  837. CONST POINT *pPoint;
  838. if (pDstPointsArray != NULL)
  839. {
  840. pPoint = &pDstPointsArray[i];
  841. }
  842. else
  843. {
  844. pPoint = (CONST POINT *)&pSrcRectsArray[i];
  845. }
  846. if (bDXT)
  847. {
  848. if ((pPoint->x & 3) ||
  849. (pPoint->y & 3))
  850. {
  851. DPF_ERR("Destination points array coordinates must each be 4 pixel aligned for DXT surfaces. CopyRects fails");
  852. return D3DERR_INVALIDCALL;
  853. }
  854. }
  855. // Check that the dest rect (where left/top is the x/y of the point
  856. // and the right/bottom is x+width, y+height) fits inside
  857. // the DstDesc.
  858. if (((pPoint->x +
  859. (pSrcRectsArray[i].right - pSrcRectsArray[i].left)) > (int)DstDesc.Width) ||
  860. ((pPoint->y +
  861. (pSrcRectsArray[i].bottom - pSrcRectsArray[i].top)) > (int)DstDesc.Height) ||
  862. (pPoint->x < 0) ||
  863. (pPoint->y < 0))
  864. {
  865. DPF_ERR("Destination rect is outside of the surface. CopyRects fails.");
  866. return D3DERR_INVALIDCALL;
  867. }
  868. }
  869. return InternalCopyRects(pSrc,
  870. pSrcRectsArray,
  871. cRects,
  872. pDst,
  873. pDstPointsArray);
  874. } // CopyRects
  875. #undef DPF_MODNAME
  876. #define DPF_MODNAME "CBaseDevice::InternalCopyRects"
  877. HRESULT CBaseDevice::InternalCopyRects(CBaseSurface *pSrcSurface,
  878. CONST RECT *pSrcRectsArray,
  879. UINT cRects,
  880. CBaseSurface *pDstSurface,
  881. CONST POINT *pDstPointsArray)
  882. {
  883. D3DSURFACE_DESC SrcDesc = pSrcSurface->InternalGetDesc();
  884. D3DSURFACE_DESC DstDesc = pDstSurface->InternalGetDesc();
  885. HRESULT hr;
  886. RECT Rect;
  887. POINT Point;
  888. CONST RECT* pRect;
  889. CONST POINT* pPoint;
  890. int BPP;
  891. UINT i;
  892. // If either one of these surfaces is a deep mipmap level that the
  893. // driver can't handle, then we didn't really create it so we don't
  894. // want to try to copy it.
  895. if (D3D8IsDummySurface(pDstSurface->KernelHandle()) ||
  896. D3D8IsDummySurface(pSrcSurface->KernelHandle()))
  897. {
  898. return D3D_OK;
  899. }
  900. if (pSrcRectsArray == NULL)
  901. {
  902. cRects = 1;
  903. pSrcRectsArray = &Rect;
  904. Rect.left = Rect.top = 0;
  905. Rect.right = SrcDesc.Width;
  906. Rect.bottom = SrcDesc.Height;
  907. pDstPointsArray = &Point;
  908. Point.x = Point.y = 0;
  909. }
  910. // Now figure out what is the best way to copy the data.
  911. if (CanHardwareBlt(GetCoreCaps(),
  912. SrcDesc.Pool,
  913. SrcDesc.Format,
  914. DstDesc.Pool,
  915. DstDesc.Format,
  916. GetDeviceType()))
  917. {
  918. // If we are setting up a blt outside of the
  919. // the DP2 stream; then we must call Sync on the
  920. // source and destination surfaces to make sure
  921. // that any pending TexBlt to or from the surfaces
  922. // or any pending triangles using these textures
  923. // has been sent down to the driver
  924. pSrcSurface->Sync();
  925. pDstSurface->Sync();
  926. if (DstDesc.Pool == D3DPOOL_SYSTEMMEM)
  927. {
  928. // If the destination is system-memory,
  929. // then we need to mark it dirty. Easiest way
  930. // is lock/unlock
  931. D3DLOCKED_RECT LockTemp;
  932. hr = pDstSurface->InternalLockRect(&LockTemp, NULL, 0);
  933. if (FAILED(hr))
  934. {
  935. DPF_ERR("Could not lock sys-mem destination for CopyRects?");
  936. }
  937. else
  938. {
  939. hr = pDstSurface->InternalUnlockRect();
  940. DXGASSERT(SUCCEEDED(hr));
  941. }
  942. }
  943. D3D8_BLTDATA BltData;
  944. ZeroMemory(&BltData, sizeof BltData);
  945. BltData.hDD = GetHandle();
  946. BltData.hDestSurface = pDstSurface->KernelHandle();
  947. BltData.hSrcSurface = pSrcSurface->KernelHandle();
  948. BltData.dwFlags = DDBLT_ROP | DDBLT_WAIT;
  949. for (i = 0; i < cRects; i++)
  950. {
  951. if (pDstPointsArray == NULL)
  952. {
  953. BltData.rDest.left = pSrcRectsArray[i].left;
  954. BltData.rDest.top = pSrcRectsArray[i].top;
  955. }
  956. else
  957. {
  958. BltData.rDest.left = pDstPointsArray[i].x;
  959. BltData.rDest.top = pDstPointsArray[i].y;
  960. }
  961. BltData.rDest.right = BltData.rDest.left +
  962. pSrcRectsArray[i].right -
  963. pSrcRectsArray[i].left;
  964. BltData.rDest.bottom = BltData.rDest.top +
  965. pSrcRectsArray[i].bottom -
  966. pSrcRectsArray[i].top;
  967. BltData.rSrc.left = pSrcRectsArray[i].left;
  968. BltData.rSrc.right = pSrcRectsArray[i].right;
  969. BltData.rSrc.top = pSrcRectsArray[i].top;
  970. BltData.rSrc.bottom = pSrcRectsArray[i].bottom;
  971. GetHalCallbacks()->Blt(&BltData);
  972. if (FAILED(BltData.ddRVal))
  973. {
  974. // We should mask errors if we are lost
  975. // and the copy is to vidmem. Also, if
  976. // the copy is persistent-to-persistent,
  977. // then fail-over to our lock&copy code
  978. // later in this function.
  979. if (BltData.ddRVal == D3DERR_DEVICELOST)
  980. {
  981. if (DstDesc.Pool == D3DPOOL_MANAGED ||
  982. DstDesc.Pool == D3DPOOL_SYSTEMMEM)
  983. {
  984. if (SrcDesc.Pool == D3DPOOL_MANAGED ||
  985. SrcDesc.Pool == D3DPOOL_SYSTEMMEM)
  986. {
  987. // if we got here
  988. // then it must be persistent to persistent
  989. // so we break out of our loop
  990. break;
  991. }
  992. DPF_ERR("Failing copy from video-memory surface to "
  993. "system-memory or managed surface because "
  994. "device is lost. CopyRect returns D3DERR_DEVICELOST");
  995. return D3DERR_DEVICELOST;
  996. }
  997. else
  998. {
  999. // copying to vid-mem when we are lost
  1000. // can just be ignored; since the lock
  1001. // is faked anyhow
  1002. return S_OK;
  1003. }
  1004. }
  1005. }
  1006. }
  1007. // We can handle persistent-to-persistent even
  1008. // in case of loss. Other errors are fatal.
  1009. if (BltData.ddRVal != D3DERR_DEVICELOST)
  1010. {
  1011. if (FAILED(BltData.ddRVal))
  1012. {
  1013. DPF_ERR("Hardware Blt failed. CopyRects failed");
  1014. }
  1015. return BltData.ddRVal;
  1016. }
  1017. }
  1018. // We are here either because the device doesn't support Blt, or because
  1019. // the hardware blt failed due to device lost and we think that we can
  1020. // emulate it.
  1021. D3DLOCKED_RECT SrcLock;
  1022. D3DLOCKED_RECT DstLock;
  1023. BOOL bDXT = FALSE;
  1024. // We need to lock both surfaces and basically do a memcpy
  1025. BPP = CPixel::ComputePixelStride(SrcDesc.Format);
  1026. if (CPixel::IsDXT(BPP))
  1027. {
  1028. bDXT = TRUE;
  1029. BPP *= -1;
  1030. }
  1031. if (BPP == 0)
  1032. {
  1033. DPF_ERR("Format not understood - cannot perform the copy. CopyRects fails.");
  1034. return D3DERR_INVALIDCALL;
  1035. }
  1036. // CONSIDER: We should be passing D3DLOCK_NO_DIRTY_RECT
  1037. // and then call AddDirtyRect if this is part of a
  1038. // texture; probably need to add some method to CBaseSurface
  1039. // for this purpose
  1040. hr = pSrcSurface->InternalLockRect(&SrcLock, NULL, D3DLOCK_READONLY | D3DLOCK_NOSYSLOCK);
  1041. if (FAILED(hr))
  1042. {
  1043. return hr;
  1044. }
  1045. hr = pDstSurface->InternalLockRect(&DstLock, NULL, D3DLOCK_NOSYSLOCK);
  1046. if (FAILED(hr))
  1047. {
  1048. pSrcSurface->InternalUnlockRect();
  1049. return hr;
  1050. }
  1051. // We check for DeviceLost here when copying from vidmem to sysmem since
  1052. // device lost can happen asynchronously.
  1053. if (((DstDesc.Pool == D3DPOOL_MANAGED) ||
  1054. (DstDesc.Pool == D3DPOOL_SYSTEMMEM)) &&
  1055. ((SrcDesc.Pool != D3DPOOL_MANAGED) &&
  1056. (SrcDesc.Pool != D3DPOOL_SYSTEMMEM)))
  1057. {
  1058. if (D3D8IsDeviceLost(GetHandle()))
  1059. {
  1060. pSrcSurface->InternalUnlockRect();
  1061. pDstSurface->InternalUnlockRect();
  1062. return D3DERR_DEVICELOST;
  1063. }
  1064. }
  1065. pRect = pSrcRectsArray;
  1066. pPoint = pDstPointsArray;
  1067. for (i = 0; i < cRects; i++)
  1068. {
  1069. BYTE* pSrc;
  1070. BYTE* pDst;
  1071. DWORD BytesToCopy;
  1072. DWORD NumRows;
  1073. // If did not specify a dest point, then we
  1074. // will use the src (left, top) as the dest point.
  1075. if (pDstPointsArray == NULL)
  1076. {
  1077. pPoint = (POINT*) pRect;
  1078. }
  1079. // Handle DXT case inside the loop
  1080. // so that we don't have to touch the user's array
  1081. if (bDXT)
  1082. {
  1083. // Figure out our pointers by converting rect/point
  1084. // offsets to blocks
  1085. pSrc = (BYTE*)SrcLock.pBits;
  1086. pSrc += (pRect->top / 4) * SrcLock.Pitch;
  1087. pSrc += (pRect->left / 4) * BPP;
  1088. pDst = (BYTE*)DstLock.pBits;
  1089. pDst += (pPoint->y / 4) * DstLock.Pitch;
  1090. pDst += (pPoint->x / 4) * BPP;
  1091. // Convert top/bottom to blocks
  1092. DWORD top = (pRect->top) / 4;
  1093. // Handle nasty 1xN, 2xN, Nx1, Nx2 DXT cases
  1094. // by rounding.
  1095. DWORD bottom = (pRect->bottom + 3) / 4;
  1096. // For DXT formats, we know that pitch equals
  1097. // width; so we only need to check if we
  1098. // are copying an entire row to an entire
  1099. // row to go the fast path.
  1100. if ((pRect->left == 0) &&
  1101. (pRect->right == (INT)SrcDesc.Width) &&
  1102. (SrcLock.Pitch == DstLock.Pitch))
  1103. {
  1104. BytesToCopy = SrcLock.Pitch * (bottom - top);
  1105. NumRows = 1;
  1106. }
  1107. else
  1108. {
  1109. // Convert left/right to blocks
  1110. DWORD left = (pRect->left / 4);
  1111. // Round for the right -> block conversion
  1112. DWORD right = (pRect->right + 3) / 4;
  1113. BytesToCopy = (right - left) * BPP;
  1114. NumRows = bottom - top;
  1115. }
  1116. }
  1117. else
  1118. {
  1119. pSrc = (BYTE*)SrcLock.pBits +
  1120. (pRect->top * SrcLock.Pitch) +
  1121. (pRect->left * BPP);
  1122. pDst = (BYTE*)DstLock.pBits +
  1123. (pPoint->y * DstLock.Pitch) +
  1124. (pPoint->x * BPP);
  1125. // If the src and dest are linear, we can do it all in a single
  1126. // memcpy
  1127. if ((pRect->left == 0) &&
  1128. ((pRect->right * BPP) == SrcLock.Pitch) &&
  1129. (SrcDesc.Width == DstDesc.Width) &&
  1130. (SrcLock.Pitch == DstLock.Pitch))
  1131. {
  1132. BytesToCopy = SrcLock.Pitch * (pRect->bottom - pRect->top);
  1133. NumRows = 1;
  1134. }
  1135. else
  1136. {
  1137. BytesToCopy = (pRect->right - pRect->left) * BPP;
  1138. NumRows = pRect->bottom - pRect->top;
  1139. }
  1140. }
  1141. // Copy the rows
  1142. DXGASSERT(NumRows > 0);
  1143. DXGASSERT(BytesToCopy > 0);
  1144. DXGASSERT(SrcLock.Pitch > 0);
  1145. DXGASSERT(DstLock.Pitch > 0);
  1146. for (UINT j = 0; j < NumRows; j++)
  1147. {
  1148. memcpy(pDst,
  1149. pSrc,
  1150. BytesToCopy);
  1151. pSrc += SrcLock.Pitch;
  1152. pDst += DstLock.Pitch;
  1153. }
  1154. // Move onward to the next rect/point pair
  1155. pRect++;
  1156. pPoint++;
  1157. }
  1158. // We check for DeviceLost yet again since it coulkd have occurred while
  1159. // copying the data.
  1160. hr = D3D_OK;
  1161. if (((DstDesc.Pool == D3DPOOL_MANAGED) ||
  1162. (DstDesc.Pool == D3DPOOL_SYSTEMMEM)) &&
  1163. ((SrcDesc.Pool != D3DPOOL_MANAGED) &&
  1164. (SrcDesc.Pool != D3DPOOL_SYSTEMMEM)))
  1165. {
  1166. if (D3D8IsDeviceLost(GetHandle()))
  1167. {
  1168. hr = D3DERR_DEVICELOST;
  1169. }
  1170. }
  1171. pSrcSurface->InternalUnlockRect();
  1172. pDstSurface->InternalUnlockRect();
  1173. return hr;
  1174. } // InternalCopyRects
  1175. #undef DPF_MODNAME
  1176. #define DPF_MODNAME "CBaseDevice::UpdateTexture"
  1177. STDMETHODIMP CBaseDevice::UpdateTexture(IDirect3DBaseTexture8 *pSrcTexture,
  1178. IDirect3DBaseTexture8 *pDstTexture)
  1179. {
  1180. API_ENTER(this);
  1181. HRESULT hr;
  1182. #ifdef DEBUG
  1183. // Some parameter validation is in Debug only for performance reasons
  1184. if (pSrcTexture == NULL || pDstTexture == NULL)
  1185. {
  1186. DPF_ERR("Invalid parameter to UpdateTexture");
  1187. return D3DERR_INVALIDCALL;
  1188. }
  1189. #endif // DEBUG
  1190. CBaseTexture *pSrcTex = CBaseTexture::SafeCast(pSrcTexture);
  1191. if (pSrcTex->Device() != this)
  1192. {
  1193. DPF_ERR("SrcTexture was not created with this Device. UpdateTexture fails");
  1194. return D3DERR_INVALIDCALL;
  1195. }
  1196. CBaseTexture *pDstTex = CBaseTexture::SafeCast(pDstTexture);
  1197. if (pDstTex->Device() != this)
  1198. {
  1199. DPF_ERR("DstTexture was not created with this Device. UpdateTexture fails");
  1200. return D3DERR_INVALIDCALL;
  1201. }
  1202. #ifdef DEBUG
  1203. // Ensure matching formats
  1204. if (pSrcTex->GetUserFormat() != pDstTex->GetUserFormat())
  1205. {
  1206. DPF_ERR("Formats of source and dest don't match. UpdateTexture fails");
  1207. return D3DERR_INVALIDCALL;
  1208. }
  1209. // Ensure matching types
  1210. if (pSrcTex->GetBufferDesc()->Type !=
  1211. pDstTex->GetBufferDesc()->Type)
  1212. {
  1213. DPF_ERR("Types of source and dest don't match. UpdateTexture fails");
  1214. return D3DERR_INVALIDCALL;
  1215. }
  1216. // Check that Source has at least as many levels as dest
  1217. if (pSrcTex->GetLevelCount() < pDstTex->GetLevelCount())
  1218. {
  1219. DPF_ERR("Source for UpdateTexture must have at least as many levels"
  1220. " as the Destination.");
  1221. return D3DERR_INVALIDCALL;
  1222. }
  1223. // Check that the source texture is not already locked
  1224. if (pSrcTex->IsTextureLocked())
  1225. {
  1226. DPF_ERR("Source for UpdateTexture is currently locked. Unlock must be called "
  1227. "before calling UpdateTexture.");
  1228. return D3DERR_INVALIDCALL;
  1229. }
  1230. // Check that the dest texture is not already locked
  1231. if (pDstTex->IsTextureLocked())
  1232. {
  1233. DPF_ERR("Destination for UpdateTexture is currently locked. Unlock must be called "
  1234. "before calling UpdateTexture.");
  1235. return D3DERR_INVALIDCALL;
  1236. }
  1237. #endif // DEBUG
  1238. // Ensure that src was specified in Pool systemmem
  1239. if (pSrcTex->GetUserPool() != D3DPOOL_SYSTEMMEM)
  1240. {
  1241. DPF_ERR("Source Texture for UpdateTexture must be in POOL_SYSTEMMEM.");
  1242. return D3DERR_INVALIDCALL;
  1243. }
  1244. // Ensure that destination was specified in Pool default
  1245. if (pDstTex->GetUserPool() != D3DPOOL_DEFAULT)
  1246. {
  1247. DPF_ERR("Destination Texture for UpdateTexture must be in POOL_DEFAULT.");
  1248. return D3DERR_INVALIDCALL;
  1249. }
  1250. #ifdef DEBUG
  1251. // Call UpdateTexture on the source which will use the
  1252. // dirty rects to move just what is needed. This
  1253. // function will also do type-specific parameter checking.
  1254. hr = pSrcTex->UpdateTexture(pDstTex);
  1255. #else // !DEBUG
  1256. // In Retail we want to call UpdateDirtyPortion directly;
  1257. // which will bypass the parameter checking
  1258. hr = pSrcTex->UpdateDirtyPortion(pDstTex);
  1259. #endif // !DEBUG
  1260. if (FAILED(hr))
  1261. {
  1262. DPF_ERR("UpdateTexture failed to copy");
  1263. return hr;
  1264. }
  1265. return hr;
  1266. } // UpdateTexture
  1267. #undef DPF_MODNAME
  1268. #define DPF_MODNAME "CBaseDevice::CreateTexture"
  1269. STDMETHODIMP CBaseDevice::CreateTexture(UINT Width,
  1270. UINT Height,
  1271. UINT cLevels,
  1272. DWORD dwUsage,
  1273. D3DFORMAT Format,
  1274. D3DPOOL Pool,
  1275. IDirect3DTexture8 **ppTexture)
  1276. {
  1277. API_ENTER(this);
  1278. if (Format == D3DFMT_UNKNOWN)
  1279. {
  1280. DPF_ERR("D3DFMT_UNKNOWN is not a valid format. CreateTexture fails.");
  1281. return D3DERR_INVALIDCALL;
  1282. }
  1283. HRESULT hr = CMipMap::Create(this,
  1284. Width,
  1285. Height,
  1286. cLevels,
  1287. dwUsage,
  1288. Format,
  1289. Pool,
  1290. ppTexture);
  1291. if (FAILED(hr))
  1292. {
  1293. DPF_ERR("Failure trying to create a texture");
  1294. return hr;
  1295. }
  1296. return hr;
  1297. } // CreateTexture
  1298. #undef DPF_MODNAME
  1299. #define DPF_MODNAME "CBaseDevice::CreateVolumeTexture"
  1300. STDMETHODIMP CBaseDevice::CreateVolumeTexture(
  1301. UINT Width,
  1302. UINT Height,
  1303. UINT cpDepth,
  1304. UINT cLevels,
  1305. DWORD dwUsage,
  1306. D3DFORMAT Format,
  1307. D3DPOOL Pool,
  1308. IDirect3DVolumeTexture8 **ppVolumeTexture)
  1309. {
  1310. API_ENTER(this);
  1311. if (Format == D3DFMT_UNKNOWN)
  1312. {
  1313. DPF_ERR("D3DFMT_UNKNOWN is not a valid format. CreateVolumeTexture fails.");
  1314. return D3DERR_INVALIDCALL;
  1315. }
  1316. HRESULT hr = CMipVolume::Create(this,
  1317. Width,
  1318. Height,
  1319. cpDepth,
  1320. cLevels,
  1321. dwUsage,
  1322. Format,
  1323. Pool,
  1324. ppVolumeTexture);
  1325. if (FAILED(hr))
  1326. {
  1327. DPF_ERR("Failure trying to create a volume texture");
  1328. return hr;
  1329. }
  1330. return hr;
  1331. } // CreateVolumeTexture
  1332. #undef DPF_MODNAME
  1333. #define DPF_MODNAME "CBaseDevice::CreateCubeTexture"
  1334. STDMETHODIMP CBaseDevice::CreateCubeTexture(UINT cpEdge,
  1335. UINT cLevels,
  1336. DWORD dwUsage,
  1337. D3DFORMAT Format,
  1338. D3DPOOL Pool,
  1339. IDirect3DCubeTexture8 **ppCubeMap)
  1340. {
  1341. API_ENTER(this);
  1342. if (Format == D3DFMT_UNKNOWN)
  1343. {
  1344. DPF_ERR("D3DFMT_UNKNOWN is not a valid format. CreateCubeTexture fails.");
  1345. return D3DERR_INVALIDCALL;
  1346. }
  1347. HRESULT hr = CCubeMap::Create(this,
  1348. cpEdge,
  1349. cLevels,
  1350. dwUsage,
  1351. Format,
  1352. Pool,
  1353. ppCubeMap);
  1354. if (FAILED(hr))
  1355. {
  1356. DPF_ERR("Failure trying to create cubemap");
  1357. return hr;
  1358. }
  1359. return hr;
  1360. } // CreateCubeTexture
  1361. #undef DPF_MODNAME
  1362. #define DPF_MODNAME "CBaseDevice::CreateRenderTarget"
  1363. STDMETHODIMP CBaseDevice::CreateRenderTarget(UINT Width,
  1364. UINT Height,
  1365. D3DFORMAT Format,
  1366. D3DMULTISAMPLE_TYPE MultiSample,
  1367. BOOL bLockable,
  1368. IDirect3DSurface8 **ppSurface)
  1369. {
  1370. API_ENTER(this);
  1371. if (Format == D3DFMT_UNKNOWN)
  1372. {
  1373. DPF_ERR("D3DFMT_UNKNOWN is not a valid format. CreateRenderTarget fails.");
  1374. return D3DERR_INVALIDCALL;
  1375. }
  1376. HRESULT hr = CSurface::CreateRenderTarget(this,
  1377. Width,
  1378. Height,
  1379. Format,
  1380. MultiSample,
  1381. bLockable,
  1382. REF_EXTERNAL,
  1383. ppSurface);
  1384. if (FAILED(hr))
  1385. {
  1386. DPF_ERR("Failure trying to create render-target");
  1387. return hr;
  1388. }
  1389. return hr;
  1390. } // CreateRenderTarget
  1391. #undef DPF_MODNAME
  1392. #define DPF_MODNAME "CBaseDevice::CreateDepthStencilSurface"
  1393. STDMETHODIMP CBaseDevice::CreateDepthStencilSurface
  1394. (UINT Width,
  1395. UINT Height,
  1396. D3DFORMAT Format,
  1397. D3DMULTISAMPLE_TYPE MultiSample,
  1398. IDirect3DSurface8 **ppSurface)
  1399. {
  1400. API_ENTER(this);
  1401. if (Format == D3DFMT_UNKNOWN)
  1402. {
  1403. DPF_ERR("D3DFMT_UNKNOWN is not a valid format. CreateDepthStencilSurface fails.");
  1404. return D3DERR_INVALIDCALL;
  1405. }
  1406. HRESULT hr = CSurface::CreateZStencil(this,
  1407. Width,
  1408. Height,
  1409. Format,
  1410. MultiSample,
  1411. REF_EXTERNAL,
  1412. ppSurface);
  1413. if (FAILED(hr))
  1414. {
  1415. DPF_ERR("Failure trying to create zstencil surface");
  1416. return hr;
  1417. }
  1418. return hr;
  1419. } // CreateDepthStencilSurface
  1420. #undef DPF_MODNAME
  1421. #define DPF_MODNAME "CBaseDevice::CreateImageSurface"
  1422. STDMETHODIMP CBaseDevice::CreateImageSurface(UINT Width,
  1423. UINT Height,
  1424. D3DFORMAT Format,
  1425. IDirect3DSurface8 **ppSurface)
  1426. {
  1427. API_ENTER(this);
  1428. HRESULT hr = CSurface::CreateImageSurface(this,
  1429. Width,
  1430. Height,
  1431. Format,
  1432. REF_EXTERNAL,
  1433. ppSurface);
  1434. if (FAILED(hr))
  1435. {
  1436. DPF_ERR("Failure trying to create image surface");
  1437. return hr;
  1438. }
  1439. return hr;
  1440. } // CreateImageSurface
  1441. #undef DPF_MODNAME
  1442. #define DPF_MODNAME "CBaseDevice::CreateVertexBuffer"
  1443. STDMETHODIMP CBaseDevice::CreateVertexBuffer(UINT cbLength,
  1444. DWORD dwUsage,
  1445. DWORD dwFVF,
  1446. D3DPOOL Pool,
  1447. IDirect3DVertexBuffer8 **ppVertexBuffer)
  1448. {
  1449. API_ENTER(this);
  1450. if ((dwUsage & ~D3DUSAGE_VB_VALID) != 0)
  1451. {
  1452. DPF_ERR("Invalid usage flags. CreateVertexBuffer fails.");
  1453. return D3DERR_INVALIDCALL;
  1454. }
  1455. // Warn if POOL_DEFAULT and not WRITEONLY. We do this here, because fe creates
  1456. // a VB with WRITEONLY not set and we don't want to warn in that case.
  1457. if (Pool == D3DPOOL_DEFAULT && (dwUsage & D3DUSAGE_WRITEONLY) == 0)
  1458. {
  1459. DPF(1, "Vertexbuffer created with POOL_DEFAULT but WRITEONLY not set. Performance penalty could be severe.");
  1460. }
  1461. HRESULT hr = CVertexBuffer::Create(this,
  1462. cbLength,
  1463. dwUsage,
  1464. dwFVF,
  1465. Pool,
  1466. REF_EXTERNAL,
  1467. ppVertexBuffer);
  1468. if (FAILED(hr))
  1469. {
  1470. DPF_ERR("Failure trying to create Vertex Buffer");
  1471. return hr;
  1472. }
  1473. return hr;
  1474. } // CBaseDevice::CreateVertexBuffer
  1475. #undef DPF_MODNAME
  1476. #define DPF_MODNAME "CBaseDevice::CreateIndexBuffer"
  1477. STDMETHODIMP CBaseDevice::CreateIndexBuffer(UINT cbLength,
  1478. DWORD dwUsage,
  1479. D3DFORMAT Format,
  1480. D3DPOOL Pool,
  1481. IDirect3DIndexBuffer8 **ppIndexBuffer)
  1482. {
  1483. API_ENTER(this);
  1484. if ((dwUsage & ~D3DUSAGE_IB_VALID) != 0)
  1485. {
  1486. DPF_ERR("Invalid usage flags. CreateIndexBuffer fails");
  1487. return D3DERR_INVALIDCALL;
  1488. }
  1489. // Warn if POOL_DEFAULT and not WRITEONLY. We do this here, because fe creates
  1490. // a IB with WRITEONLY not set and we don't want to warn in that case.
  1491. if (Pool == D3DPOOL_DEFAULT && (dwUsage & D3DUSAGE_WRITEONLY) == 0)
  1492. {
  1493. DPF(1, "Indexbuffer created with POOL_DEFAULT but WRITEONLY not set. Performance penalty could be severe.");
  1494. }
  1495. HRESULT hr = CIndexBuffer::Create(this,
  1496. cbLength,
  1497. dwUsage,
  1498. Format,
  1499. Pool,
  1500. REF_EXTERNAL,
  1501. ppIndexBuffer);
  1502. if (FAILED(hr))
  1503. {
  1504. DPF_ERR("Failure trying to create indexbuffer");
  1505. return hr;
  1506. }
  1507. return hr;
  1508. } // CBaseDevice::CreateIndexBuffer
  1509. #undef DPF_MODNAME
  1510. #define DPF_MODNAME "CBaseDevice::UpdateRenderTarget"
  1511. void CBaseDevice::UpdateRenderTarget(CBaseSurface *pRenderTarget,
  1512. CBaseSurface *pZStencil)
  1513. {
  1514. // We only change things if the old and new are different;
  1515. // this is to allow the device to update itself to the
  1516. // same object without needing an extra-ref-count
  1517. // Has the RenderTarget changed?
  1518. if (pRenderTarget != m_pRenderTarget)
  1519. {
  1520. // Release old RT
  1521. if (m_pRenderTarget)
  1522. m_pRenderTarget->DecrementUseCount();
  1523. m_pRenderTarget = pRenderTarget;
  1524. if (m_pRenderTarget)
  1525. {
  1526. // IncrementUseCount the new RT
  1527. m_pRenderTarget->IncrementUseCount();
  1528. // Update the batch count for the new rendertarget
  1529. m_pRenderTarget->Batch();
  1530. }
  1531. }
  1532. // Has the Z changed?
  1533. if (m_pZBuffer != pZStencil)
  1534. {
  1535. // Release the old Z
  1536. if (m_pZBuffer)
  1537. m_pZBuffer->DecrementUseCount();
  1538. m_pZBuffer = pZStencil;
  1539. // IncrementUseCount the new Z
  1540. if (m_pZBuffer)
  1541. {
  1542. m_pZBuffer->IncrementUseCount();
  1543. // Update the batch count for the new zbuffer
  1544. m_pZBuffer->Batch();
  1545. }
  1546. }
  1547. return;
  1548. } // UpdateRenderTarget
  1549. #undef DPF_MODNAME
  1550. #define DPF_MODNAME "CBaseDevice::CBaseDevice"
  1551. CBaseDevice::CBaseDevice()
  1552. {
  1553. // Give our base class a pointer to ourselves
  1554. SetOwner(this);
  1555. m_hwndFocusWindow = 0;
  1556. m_cRef = 1;
  1557. m_pResourceList = 0;
  1558. m_pResourceManager = new CResourceManager();
  1559. m_dwBehaviorFlags = 0;
  1560. m_dwOriginalBehaviorFlags = 0;
  1561. m_fullscreen = FALSE;
  1562. m_bVBFailOversDisabled = FALSE;
  1563. m_pZBuffer = NULL;
  1564. m_pSwapChain = NULL;
  1565. m_pRenderTarget = NULL;
  1566. m_pAutoZStencil = NULL;
  1567. m_ddiType = D3DDDITYPE_NULL;
  1568. } // CBaseDevice
  1569. #undef DPF_MODNAME
  1570. #define DPF_MODNAME "CBaseDevice::~CBaseDevice"
  1571. CBaseDevice::~CBaseDevice()
  1572. {
  1573. DWORD cUseCount;
  1574. // Release our objects
  1575. if (m_pAutoZStencil)
  1576. {
  1577. cUseCount = m_pAutoZStencil->DecrementUseCount();
  1578. DXGASSERT(cUseCount == 0 || m_pAutoZStencil == m_pZBuffer);
  1579. }
  1580. // Mark Z buffer as no longer in use
  1581. if (m_pZBuffer)
  1582. {
  1583. cUseCount = m_pZBuffer->DecrementUseCount();
  1584. DXGASSERT(cUseCount == 0);
  1585. m_pZBuffer = NULL;
  1586. }
  1587. // Mark render target as no longer in use
  1588. if (m_pRenderTarget)
  1589. {
  1590. cUseCount = m_pRenderTarget->DecrementUseCount();
  1591. m_pRenderTarget = NULL; //so that FlipToGDISurface won't have to reset it
  1592. }
  1593. if (m_pSwapChain)
  1594. {
  1595. if (m_fullscreen)
  1596. m_pSwapChain->FlipToGDISurface();
  1597. cUseCount = m_pSwapChain->DecrementUseCount();
  1598. DXGASSERT(cUseCount == 0);
  1599. }
  1600. DD_DoneDC(m_DeviceData.hDC);
  1601. // Free allocations we made when the device was created
  1602. if (m_DeviceData.DriverData.pGDD8SupportedFormatOps != NULL)
  1603. {
  1604. MemFree(m_DeviceData.DriverData.pGDD8SupportedFormatOps);
  1605. }
  1606. // If a software driver is loaded, unload it now
  1607. if (m_DeviceData.hLibrary != NULL)
  1608. {
  1609. FreeLibrary(m_DeviceData.hLibrary);
  1610. }
  1611. // Shut down the thunk layer
  1612. D3D8DeleteDirectDrawObject(m_DeviceData.hDD);
  1613. delete m_pResourceManager;
  1614. // We release the Enum last because various destructors expect to
  1615. // be around i.e. the swapchain stuff. Also, because it is a
  1616. // stand-alone object; it should not have any dependencies on the
  1617. // the device.
  1618. if (NULL != Enum())
  1619. {
  1620. Enum()->Release();
  1621. }
  1622. } // ~CBaseDevice
  1623. #undef DPF_MODNAME
  1624. #define DPF_MODNAME "CBaseDevice::Init"
  1625. HRESULT CBaseDevice::Init(
  1626. PD3D8_DEVICEDATA pDevice,
  1627. D3DDEVTYPE DeviceType,
  1628. HWND hwndFocusWindow,
  1629. DWORD dwBehaviorFlags,
  1630. D3DPRESENT_PARAMETERS *pPresentationParams,
  1631. UINT AdapterIndex,
  1632. CEnum *ParentClass)
  1633. {
  1634. HRESULT hr;
  1635. DWORD value = 0;
  1636. m_DeviceData = *pDevice;
  1637. m_hwndFocusWindow = hwndFocusWindow;
  1638. m_DeviceType = DeviceType;
  1639. m_AdapterIndex = AdapterIndex;
  1640. m_pD3DClass = ParentClass;
  1641. GetD3DRegValue(REG_DWORD, "DisableDM", &value, sizeof(DWORD));
  1642. #ifdef WINNT
  1643. m_dwBehaviorFlags = dwBehaviorFlags | (!IsWhistler() || value != 0 ? D3DCREATE_DISABLE_DRIVER_MANAGEMENT : 0);
  1644. #else
  1645. m_dwBehaviorFlags = dwBehaviorFlags | (value != 0 ? D3DCREATE_DISABLE_DRIVER_MANAGEMENT : 0);
  1646. #endif
  1647. value = 0;
  1648. GetD3DRegValue(REG_DWORD, "DisableST", &value, sizeof(DWORD));
  1649. m_dwOriginalBehaviorFlags = m_dwBehaviorFlags;
  1650. if (value != 0)
  1651. {
  1652. m_dwBehaviorFlags |= D3DCREATE_MULTITHREADED;
  1653. }
  1654. MemFree(pDevice); // Now that we've stored the contents, we can free the old memory
  1655. ParentClass->AddRef();
  1656. #ifndef WINNT
  1657. if (FocusWindow())
  1658. {
  1659. hr = D3D8SetCooperativeLevel(GetHandle(), FocusWindow(), DDSCL_SETFOCUSWINDOW);
  1660. if (FAILED(hr))
  1661. {
  1662. return hr;
  1663. }
  1664. }
  1665. #endif //!WINNT
  1666. //Figure out if we're a screen-saver or not.
  1667. char name[_MAX_PATH];
  1668. HMODULE hfile = GetModuleHandle( NULL );
  1669. name[0]=0;
  1670. GetModuleFileName( hfile, name, sizeof( name ) -1 );
  1671. int len = strlen(name);
  1672. if( ( strlen(name) > 4 ) &&
  1673. name[len - 4 ] == '.' &&
  1674. (name[ len - 3 ] == 's' || name[ len - 3 ] == 'S' )&&
  1675. (name[ len - 2 ] == 'c' || name[ len - 2 ] == 'C' )&&
  1676. (name[ len - 1 ] == 'r' || name[ len - 1 ] == 'R' ))
  1677. {
  1678. m_dwBehaviorFlags |= 0x10000000;
  1679. }
  1680. // Initialize our critical section (if needed)
  1681. if (m_dwBehaviorFlags & D3DCREATE_MULTITHREADED)
  1682. {
  1683. EnableCriticalSection();
  1684. }
  1685. // Initialize the resource manager
  1686. hr = ResourceManager()->Init(this);
  1687. if (hr != S_OK)
  1688. {
  1689. return hr;
  1690. }
  1691. m_DesktopMode.Height = DisplayHeight();
  1692. m_DesktopMode.Width = DisplayWidth();
  1693. m_DesktopMode.Format = DisplayFormat();
  1694. m_DesktopMode.RefreshRate = DisplayRate();
  1695. // Now call Reset to do any mode changes required and to create
  1696. // the primary surface, etc.
  1697. m_pSwapChain = new CSwapChain(
  1698. this,
  1699. REF_INTRINSIC);
  1700. if (m_pSwapChain)
  1701. {
  1702. m_pSwapChain->Init(
  1703. pPresentationParams,
  1704. &hr);
  1705. if (FAILED(hr))
  1706. return hr;
  1707. }
  1708. else
  1709. {
  1710. hr = E_OUTOFMEMORY;
  1711. return hr;
  1712. }
  1713. // If we were created with a specification for a default
  1714. // z buffer; then we need to create one here.
  1715. if (pPresentationParams->EnableAutoDepthStencil)
  1716. {
  1717. // Need to validate that this Z-buffer matches
  1718. // the HW
  1719. hr = CheckDepthStencilMatch(pPresentationParams->BackBufferFormat,
  1720. pPresentationParams->AutoDepthStencilFormat);
  1721. if (FAILED(hr))
  1722. {
  1723. DPF_ERR("AutoDepthStencilFormat does not match BackBufferFormat because "
  1724. "the current Device requires the bitdepth of the zbuffer to "
  1725. "match the render-target. See CheckDepthStencilMatch documentation. CreateDevice fails.");
  1726. return hr;
  1727. }
  1728. IDirect3DSurface8 *pSurf;
  1729. hr = CSurface::CreateZStencil(
  1730. this,
  1731. m_pSwapChain->Width(),
  1732. m_pSwapChain->Height(),
  1733. pPresentationParams->AutoDepthStencilFormat,
  1734. pPresentationParams->MultiSampleType,
  1735. REF_INTRINSIC,
  1736. &pSurf);
  1737. if (FAILED(hr))
  1738. {
  1739. DPF_ERR("Failure trying to create automatic zstencil surface. CreateDevice Failed.");
  1740. return hr;
  1741. }
  1742. m_pAutoZStencil = static_cast<CBaseSurface *>(pSurf);
  1743. }
  1744. UpdateRenderTarget(m_pSwapChain->m_ppBackBuffers[0], m_pAutoZStencil);
  1745. m_fullscreen = !SwapChain()->m_PresentationData.Windowed;
  1746. HKEY hKey;
  1747. if(ERROR_SUCCESS == RegOpenKey(HKEY_LOCAL_MACHINE, RESPATH_D3D, &hKey))
  1748. {
  1749. DWORD dwType;
  1750. DWORD dwValue;
  1751. DWORD dwSize = 4;
  1752. if (ERROR_SUCCESS == RegQueryValueEx(hKey, "DisableVBFailovers", NULL, &dwType, (LPBYTE) &dwValue, &dwSize) &&
  1753. dwType == REG_DWORD &&
  1754. dwValue != 0)
  1755. {
  1756. m_bVBFailOversDisabled = TRUE;
  1757. }
  1758. RegCloseKey(hKey);
  1759. }
  1760. return hr;
  1761. } // Init
  1762. #undef DPF_MODNAME
  1763. #define DPF_MODNAME "CBaseDevice::GetDeviceCaps"
  1764. STDMETHODIMP CBaseDevice::GetDeviceCaps(D3DCAPS8 *pCaps)
  1765. {
  1766. API_ENTER(this);
  1767. if (pCaps == NULL)
  1768. {
  1769. DPF_ERR("Invalid pointer to D3DCAPS8 specified. GetDeviceCaps fails");
  1770. return D3DERR_INVALIDCALL;
  1771. }
  1772. Enum()->FillInCaps (
  1773. pCaps,
  1774. GetCoreCaps(),
  1775. m_DeviceType,
  1776. m_AdapterIndex);
  1777. // Emulation of NPatches is done in software when they are not supported
  1778. // for non-Pure devices.
  1779. if ((pCaps->DevCaps & D3DDEVCAPS_RTPATCHES) && (BehaviorFlags() & D3DCREATE_PUREDEVICE) == 0)
  1780. pCaps->DevCaps |= D3DDEVCAPS_NPATCHES;
  1781. // Now the Caps struct has all the hardware caps.
  1782. // In case the device is running in a software vertex-processing mode
  1783. // fix up the caps to reflect that.
  1784. if( ((BehaviorFlags() & D3DCREATE_PUREDEVICE) == 0)
  1785. &&
  1786. (static_cast<CD3DHal *>(this))->m_dwRuntimeFlags &
  1787. D3DRT_RSSOFTWAREPROCESSING )
  1788. {
  1789. // We always do TL Vertex clipping for software vertex processing.
  1790. pCaps->PrimitiveMiscCaps |= D3DPMISCCAPS_CLIPTLVERTS;
  1791. pCaps->RasterCaps |= (D3DPRASTERCAPS_FOGVERTEX |
  1792. D3DPRASTERCAPS_FOGRANGE);
  1793. // We do emulation when FVF has point size but the device does not
  1794. // support it
  1795. pCaps->FVFCaps |= D3DFVFCAPS_PSIZE;
  1796. // All DX8 drivers have to support this cap.
  1797. // Emulation is provided by the software vertex pipeline for all
  1798. // pre-DX8 drivers.
  1799. if( pCaps->MaxPointSize == 0 )
  1800. {
  1801. pCaps->MaxPointSize = 64; // __MAX_POINT_SIZE in d3ditype.h
  1802. }
  1803. pCaps->MaxActiveLights = 0xffffffff;
  1804. pCaps->MaxVertexBlendMatrices = 4;
  1805. pCaps->MaxUserClipPlanes = 6; // __MAXUSERCLIPPLANES in d3dfe.hpp
  1806. pCaps->VertexProcessingCaps = (D3DVTXPCAPS_TEXGEN |
  1807. D3DVTXPCAPS_MATERIALSOURCE7 |
  1808. D3DVTXPCAPS_DIRECTIONALLIGHTS |
  1809. D3DVTXPCAPS_POSITIONALLIGHTS |
  1810. D3DVTXPCAPS_LOCALVIEWER |
  1811. D3DVTXPCAPS_TWEENING);
  1812. pCaps->MaxVertexBlendMatrixIndex = 255; // __MAXWORLDMATRICES - 1 in
  1813. // d3dfe.hpp
  1814. pCaps->MaxStreams = 16; // __NUMSTREAMS in d3dfe.hpp
  1815. pCaps->VertexShaderVersion = D3DVS_VERSION(1, 1); // Version 1.1
  1816. pCaps->MaxVertexShaderConst = D3DVS_CONSTREG_MAX_V1_1;
  1817. // Nuke NPATCHES and RT Patches caps, because software emulation
  1818. // cannot do that.
  1819. pCaps->DevCaps &= ~(D3DDEVCAPS_NPATCHES | D3DDEVCAPS_RTPATCHES);
  1820. }
  1821. // MaxPointSize should never be reported as Zero. Internally though
  1822. // we depend on Zero to be what decides to take the point-sprite emulation
  1823. // path or not.
  1824. // If it is still zero at this point, fudge it up here.
  1825. if( pCaps->MaxPointSize == 0 )
  1826. {
  1827. pCaps->MaxPointSize = 1.0f;
  1828. }
  1829. return D3D_OK;
  1830. } // GetDeviceCaps
  1831. #undef DPF_MODNAME
  1832. #define DPF_MODNAME "CBaseDevice::GetDeviceCaps"
  1833. STDMETHODIMP CBaseDevice::GetFrontBuffer(IDirect3DSurface8 *pDSurface)
  1834. {
  1835. API_ENTER(this);
  1836. RECT Rect;
  1837. D3DSURFACE_DESC SurfDesc;
  1838. CDriverSurface* pPrimary;
  1839. D3DLOCKED_RECT PrimaryRect;
  1840. D3DLOCKED_RECT DestRect;
  1841. HRESULT hr;
  1842. D3DFORMAT Format;
  1843. UINT Width;
  1844. UINT Height;
  1845. BYTE* pSrc;
  1846. BYTE* pDest;
  1847. DWORD* pDstTemp;
  1848. BYTE* pSrc8;
  1849. WORD* pSrc16;
  1850. DWORD* pSrc32;
  1851. UINT i;
  1852. UINT j;
  1853. PALETTEENTRY Palette[256];
  1854. if (pDSurface == NULL)
  1855. {
  1856. DPF_ERR("Invalid pointer to destination surface specified. GetFrontBuffer fails.");
  1857. return D3DERR_INVALIDCALL;
  1858. }
  1859. CBaseSurface *pDestSurface = static_cast<CBaseSurface*>(pDSurface);
  1860. if (pDestSurface->InternalGetDevice() != this)
  1861. {
  1862. DPF_ERR("Destination Surface was not allocated with this Device. GetFrontBuffer fails. ");
  1863. return D3DERR_INVALIDCALL;
  1864. }
  1865. hr = pDestSurface->GetDesc(&SurfDesc);
  1866. DXGASSERT(SUCCEEDED(hr));
  1867. if (SurfDesc.Format != D3DFMT_A8R8G8B8)
  1868. {
  1869. DPF_ERR("Destination surface must have format D3DFMT_A8R8G8B8. GetFrontBuffer fails.");
  1870. return D3DERR_INVALIDCALL;
  1871. }
  1872. if (SurfDesc.Type != D3DRTYPE_SURFACE)
  1873. {
  1874. DPF_ERR("Destination surface is an invalid type. GetFrontBuffer fails.");
  1875. return D3DERR_INVALIDCALL;
  1876. }
  1877. if ( (SurfDesc.Pool != D3DPOOL_SYSTEMMEM) && (SurfDesc.Pool != D3DPOOL_SCRATCH))
  1878. {
  1879. DPF_ERR("Destination surface must be in system or scratch memory. GetFrontBuffer fails.");
  1880. return D3DERR_INVALIDCALL;
  1881. }
  1882. Rect.left = Rect.top = 0;
  1883. Rect.right = DisplayWidth();
  1884. Rect.bottom = DisplayHeight();
  1885. if ((SurfDesc.Width < (UINT)(Rect.right - Rect.left)) ||
  1886. (SurfDesc.Height < (UINT)(Rect.bottom - Rect.top)))
  1887. {
  1888. DPF_ERR("Destination surface not big enough to hold the size of the screen. GetFrontBuffer fails.");
  1889. return D3DERR_INVALIDCALL;
  1890. }
  1891. if (NULL == m_pSwapChain)
  1892. {
  1893. DPF_ERR("No Swap Chain present, GetFrontBuffer fails.");
  1894. return D3DERR_INVALIDCALL;
  1895. }
  1896. // Lock the primary surface
  1897. pPrimary = m_pSwapChain->PrimarySurface();
  1898. if (NULL == pPrimary)
  1899. {
  1900. DPF_ERR("No Primary present, GetFrontBuffer fails");
  1901. return D3DERR_DEVICELOST;
  1902. }
  1903. hr = pPrimary->LockRect(&PrimaryRect,
  1904. NULL,
  1905. 0);
  1906. if (SUCCEEDED(hr))
  1907. {
  1908. hr = pDestSurface->LockRect(&DestRect,
  1909. NULL,
  1910. 0);
  1911. if (FAILED(hr))
  1912. {
  1913. DPF_ERR("Unable to lock destination surface. GetFrontBuffer fails.");
  1914. pPrimary->UnlockRect();
  1915. return hr;
  1916. }
  1917. Format = DisplayFormat();
  1918. Width = Rect.right;
  1919. Height = Rect.bottom;
  1920. pSrc = (BYTE*) PrimaryRect.pBits;
  1921. pDest = (BYTE*) DestRect.pBits;
  1922. if (Format == D3DFMT_P8)
  1923. {
  1924. HDC hdc;
  1925. hdc = GetDC (NULL);
  1926. GetSystemPaletteEntries(hdc, 0, 256, Palette);
  1927. ReleaseDC (NULL, hdc);
  1928. }
  1929. for (i = 0; i < Height; i++)
  1930. {
  1931. pDstTemp = (DWORD*) pDest;
  1932. switch (Format)
  1933. {
  1934. case D3DFMT_P8:
  1935. pSrc8 = pSrc;
  1936. for (j = 0; j < Width; j++)
  1937. {
  1938. *pDstTemp = (Palette[*pSrc8].peRed << 16) |
  1939. (Palette[*pSrc8].peGreen << 8) |
  1940. (Palette[*pSrc8].peBlue);
  1941. pSrc8++;
  1942. pDstTemp++;
  1943. }
  1944. break;
  1945. case D3DFMT_R5G6B5:
  1946. pSrc16 = (WORD*) pSrc;
  1947. for (j = 0; j < Width; j++)
  1948. {
  1949. DWORD dwTemp = ((*pSrc16 & 0xf800) << 8) |
  1950. ((*pSrc16 & 0x07e0) << 5) |
  1951. ((*pSrc16 & 0x001f) << 3);
  1952. // Need to tweak ranges so that
  1953. // we map entirely to the 0x00 to 0xff
  1954. // for each channel. Basically, we
  1955. // map the high two/three bits of each
  1956. // channel to fill the gap at the bottom.
  1957. dwTemp |= (dwTemp & 0x00e000e0) >> 5;
  1958. dwTemp |= (dwTemp & 0x0000c000) >> 6;
  1959. // Write out our value
  1960. *pDstTemp = dwTemp;
  1961. pDstTemp++;
  1962. pSrc16++;
  1963. }
  1964. break;
  1965. case D3DFMT_X1R5G5B5:
  1966. pSrc16 = (WORD*) pSrc;
  1967. for (j = 0; j < Width; j++)
  1968. {
  1969. DWORD dwTemp= ((*pSrc16 & 0x7c00) << 9) |
  1970. ((*pSrc16 & 0x03e0) << 6) |
  1971. ((*pSrc16 & 0x001f) << 3);
  1972. // Need to tweak ranges so that
  1973. // we map entirely to the 0x00 to 0xff
  1974. // for each channel. Basically, we
  1975. // map the high three bits of each
  1976. // channel to fill the gap at the bottom.
  1977. dwTemp |= (dwTemp & 0x00e0e0e0) >> 5;
  1978. // Write out our value
  1979. *pDstTemp = dwTemp;
  1980. pDstTemp++;
  1981. pSrc16++;
  1982. }
  1983. break;
  1984. case D3DFMT_R8G8B8:
  1985. pSrc8 = pSrc;
  1986. for (j = 0; j < Width; j++)
  1987. {
  1988. *pDstTemp = (pSrc8[0] << 16) |
  1989. (pSrc8[1] << 8) |
  1990. (pSrc8[2]);
  1991. pDstTemp++;
  1992. pSrc8 += 3;
  1993. }
  1994. break;
  1995. case D3DFMT_X8R8G8B8:
  1996. pSrc32 = (DWORD*) pSrc;
  1997. for (j = 0; j < Width; j++)
  1998. {
  1999. *pDstTemp = *pSrc32 & 0xffffff;
  2000. pDstTemp++;
  2001. pSrc32++;
  2002. }
  2003. break;
  2004. default:
  2005. DXGASSERT(0);
  2006. pDestSurface->UnlockRect();
  2007. pPrimary->UnlockRect();
  2008. return D3DERR_INVALIDCALL;
  2009. }
  2010. pSrc += PrimaryRect.Pitch;
  2011. pDest += DestRect.Pitch;
  2012. }
  2013. pDestSurface->UnlockRect();
  2014. pPrimary->UnlockRect();
  2015. }
  2016. return hr;
  2017. }
  2018. // End of file : dxgcreate.cpp