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.

619 lines
17 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 1999-2000 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: cubesurf.cpp
  6. * Content: Implementation of the CCubeSurface class
  7. *
  8. *
  9. ***************************************************************************/
  10. #include "ddrawpr.h"
  11. #include "cubesurf.hpp"
  12. // IUnknown methods
  13. #undef DPF_MODNAME
  14. #define DPF_MODNAME "CCubeSurface::QueryInterface"
  15. STDMETHODIMP CCubeSurface::QueryInterface(REFIID riid,
  16. void **ppvObj)
  17. {
  18. API_ENTER(Device());
  19. if (!VALID_PTR_PTR(ppvObj))
  20. {
  21. DPF_ERR("Invalid ppvObj parameter for Surface of a Cube Texture");
  22. return D3DERR_INVALIDCALL;
  23. }
  24. if (!VALID_PTR(&riid, sizeof(GUID)))
  25. {
  26. DPF_ERR("Invalid guid memory address to QueryInterface for Surface of a Cube Texture");
  27. return D3DERR_INVALIDCALL;
  28. }
  29. if (riid == IID_IDirect3DSurface8 ||
  30. riid == IID_IUnknown)
  31. {
  32. *ppvObj = static_cast<void*>(static_cast<IDirect3DSurface8 *>(this));
  33. AddRef();
  34. return S_OK;
  35. }
  36. DPF_ERR("Unsupported Interface identifier passed to QueryInterface for Surface of a Cubemap");
  37. // Null out param
  38. *ppvObj = NULL;
  39. return E_NOINTERFACE;
  40. } // QueryInterface
  41. #undef DPF_MODNAME
  42. #define DPF_MODNAME "CCubeSurface::AddRef"
  43. STDMETHODIMP_(ULONG) CCubeSurface::AddRef()
  44. {
  45. API_ENTER_NO_LOCK(Device());
  46. #ifdef DEBUG
  47. m_cRefDebug++;
  48. #endif // DEBUG
  49. return m_pParent->AddRefImpl();
  50. } // AddRef
  51. #undef DPF_MODNAME
  52. #define DPF_MODNAME "CCubeSurface::Release"
  53. STDMETHODIMP_(ULONG) CCubeSurface::Release()
  54. {
  55. API_ENTER_SUBOBJECT_RELEASE(Device());
  56. #ifdef DEBUG
  57. m_cRefDebug--;
  58. if (m_cRefDebug & 0x80000000)
  59. {
  60. DPF_ERR("A level of a cube-map has been released more often than it has been add-ref'ed! Danger!!");
  61. }
  62. #endif // DEBUG
  63. return m_pParent->ReleaseImpl();
  64. } // Release
  65. // IBuffer methods
  66. #undef DPF_MODNAME
  67. #define DPF_MODNAME "CCubeSurface::SetPrivateData"
  68. STDMETHODIMP CCubeSurface::SetPrivateData(REFGUID riid,
  69. CONST void *pvData,
  70. DWORD cbData,
  71. DWORD dwFlags)
  72. {
  73. API_ENTER(Device());
  74. return m_pParent->SetPrivateDataImpl(riid,
  75. pvData,
  76. cbData,
  77. dwFlags,
  78. CombinedFaceLevel());
  79. } // SetPrivateData
  80. #undef DPF_MODNAME
  81. #define DPF_MODNAME "CCubeSurface::GetPrivateData"
  82. STDMETHODIMP CCubeSurface::GetPrivateData(REFGUID riid,
  83. void *pvData,
  84. DWORD *pcbData)
  85. {
  86. API_ENTER(Device());
  87. return m_pParent->GetPrivateDataImpl(riid,
  88. pvData,
  89. pcbData,
  90. CombinedFaceLevel());
  91. } // GetPrivateData
  92. #undef DPF_MODNAME
  93. #define DPF_MODNAME "CCubeSurface::FreePrivateData"
  94. STDMETHODIMP CCubeSurface::FreePrivateData(REFGUID riid)
  95. {
  96. API_ENTER(Device());
  97. return m_pParent->FreePrivateDataImpl(riid,
  98. CombinedFaceLevel());
  99. } // FreePrivateData
  100. #undef DPF_MODNAME
  101. #define DPF_MODNAME "CCubeSurface::GetContainer"
  102. STDMETHODIMP CCubeSurface::GetContainer(REFIID riid,
  103. void **ppContainer)
  104. {
  105. API_ENTER(Device());
  106. return m_pParent->QueryInterface(riid, ppContainer);
  107. } // OpenContainer
  108. #undef DPF_MODNAME
  109. #define DPF_MODNAME "CCubeSurface::GetDevice"
  110. STDMETHODIMP CCubeSurface::GetDevice(IDirect3DDevice8 ** ppDevice)
  111. {
  112. API_ENTER(Device());
  113. return m_pParent->GetDevice(ppDevice);
  114. } // OpenDevice
  115. // IDirect3DSurface methods
  116. #undef DPF_MODNAME
  117. #define DPF_MODNAME "CCubeSurface::GetDesc"
  118. STDMETHODIMP CCubeSurface::GetDesc(D3DSURFACE_DESC *pDesc)
  119. {
  120. API_ENTER(Device());
  121. // If parameters are bad, then we should fail some stuff
  122. if (!VALID_WRITEPTR(pDesc, sizeof(D3DSURFACE_DESC)))
  123. {
  124. DPF_ERR("bad pointer for pDesc passed to GetDesc for Surface of a Cubemap");
  125. return D3DERR_INVALIDCALL;
  126. }
  127. // The internal desc indicates the real
  128. // format and pool. We need to report
  129. // back the original data
  130. *pDesc = InternalGetDesc();
  131. pDesc->Pool = m_pParent->GetUserPool();
  132. pDesc->Format = m_pParent->GetUserFormat();
  133. pDesc->Usage &= D3DUSAGE_EXTERNAL;
  134. // We're done
  135. return S_OK;
  136. } // GetDesc
  137. #undef DPF_MODNAME
  138. #define DPF_MODNAME "CCubeSurface::InternalGetDesc"
  139. D3DSURFACE_DESC CCubeSurface::InternalGetDesc() const
  140. {
  141. D3DSURFACE_DESC desc;
  142. // Start from the parent's desc
  143. desc = *m_pParent->Desc();
  144. // Width and height are the shifted from the parent
  145. desc.Width >>= m_iLevel;
  146. desc.Height >>= m_iLevel;
  147. if (desc.Width == 0)
  148. {
  149. desc.Width = 1;
  150. }
  151. if (desc.Height == 0)
  152. {
  153. desc.Height = 1;
  154. }
  155. // Modify the type
  156. desc.Type = D3DRTYPE_SURFACE;
  157. // Modify the size field
  158. desc.Size = CPixel::ComputeSurfaceSize(desc.Width,
  159. desc.Height,
  160. desc.Format);
  161. // We're done
  162. return desc;
  163. } // InternalGetDesc
  164. #undef DPF_MODNAME
  165. #define DPF_MODNAME "CCubeSurface::LockRect"
  166. STDMETHODIMP CCubeSurface::LockRect(D3DLOCKED_RECT *pLockedRectData,
  167. CONST RECT *pRect,
  168. DWORD dwFlags)
  169. {
  170. API_ENTER(Device());
  171. // If parameters are bad, then we should fail some stuff
  172. if (!VALID_WRITEPTR(pLockedRectData, sizeof(D3DLOCKED_RECT)))
  173. {
  174. DPF_ERR("bad pointer for pLockedRectData passed to LockRect for Surface of a Cubemap");
  175. return D3DERR_INVALIDCALL;
  176. }
  177. // Zero out returned data
  178. ZeroMemory(pLockedRectData, sizeof(D3DLOCKED_RECT));
  179. // Validate Rect
  180. if (pRect != NULL)
  181. {
  182. DWORD Width = m_pParent->Desc()->Width >> m_iLevel;
  183. DWORD Height = m_pParent->Desc()->Height >> m_iLevel;
  184. if (!CPixel::IsValidRect(m_pParent->Desc()->Format,
  185. Width,
  186. Height,
  187. pRect))
  188. {
  189. DPF_ERR("LockRect for a level of a Cube Texture failed");
  190. return D3DERR_INVALIDCALL;
  191. }
  192. }
  193. if (dwFlags & ~D3DLOCK_SURF_VALID)
  194. {
  195. if (dwFlags & D3DLOCK_DISCARD)
  196. {
  197. if (dwFlags & D3DLOCK_READONLY)
  198. {
  199. DPF_ERR("D3DLOCK_READONLY is not allowed with D3DLOCK_DISCARD");
  200. return D3DERR_INVALIDCALL;
  201. }
  202. if (!(m_pParent->Desc()->Usage & D3DUSAGE_DYNAMIC))
  203. {
  204. DPF_ERR("D3DLOCK_DISCARD is allowed only with dynamic textures");
  205. return D3DERR_INVALIDCALL;
  206. }
  207. if (CombinedFaceLevel() > 0)
  208. {
  209. DPF_ERR("D3DLOCK_DISCARD is allowed only on D3DCUBEMAP_FACE_POSITIVE_X"
  210. " and the top mip level. DISCARD in this case will discard"
  211. " the entire cubemap.");
  212. return D3DERR_INVALIDCALL;
  213. }
  214. if (pRect != NULL)
  215. {
  216. DPF_ERR("Subrects not allowed with D3DLOCK_DISCARD");
  217. return D3DERR_INVALIDCALL;
  218. }
  219. }
  220. else
  221. {
  222. DPF_ERR("Invalid dwFlags parameter passed to LockRect for Surface of a Cubemap");
  223. DPF_EXPLAIN_BAD_LOCK_FLAGS(0, dwFlags & ~D3DLOCK_SURF_VALID);
  224. return D3DERR_INVALIDCALL;
  225. }
  226. }
  227. if (!m_isLockable)
  228. {
  229. m_pParent->ReportWhyLockFailed();
  230. return D3DERR_INVALIDCALL;
  231. }
  232. return InternalLockRect(pLockedRectData, pRect, dwFlags);
  233. } // LockRect
  234. #undef DPF_MODNAME
  235. #define DPF_MODNAME "CCubeSurface::InternalLockRect"
  236. HRESULT CCubeSurface::InternalLockRect(D3DLOCKED_RECT *pLockedRectData,
  237. CONST RECT *pRect,
  238. DWORD dwFlags)
  239. {
  240. // Only one lock outstanding at a time is supported
  241. if (m_isLocked)
  242. {
  243. DPF_ERR("LockRect failed on a cube map level; surface was already locked.");
  244. return D3DERR_INVALIDCALL;
  245. }
  246. // Notify the parent/device if we are about to be modified
  247. if ( (m_pParent->GetUserPool() != D3DPOOL_SCRATCH) && (!(dwFlags & D3DLOCK_READONLY)) )
  248. {
  249. m_pParent->OnSurfaceLock(m_iFace, m_iLevel, pRect, dwFlags);
  250. }
  251. // Fill out the locked rect structure
  252. m_pParent->ComputeCubeMapOffset(m_iFace,
  253. m_iLevel,
  254. pRect,
  255. pLockedRectData);
  256. DXGASSERT(pLockedRectData->pBits != NULL);
  257. // Mark ourselves as locked
  258. m_isLocked = 1;
  259. // Done
  260. return S_OK;
  261. } // InternalLockRect
  262. #undef DPF_MODNAME
  263. #define DPF_MODNAME "CCubeSurface::UnlockRect"
  264. STDMETHODIMP CCubeSurface::UnlockRect()
  265. {
  266. API_ENTER(Device());
  267. // If we aren't locked; then something is wrong
  268. if (m_isLocked == 0)
  269. {
  270. DPF_ERR("UnlockRect failed on a cube map level; surface wasn't locked.");
  271. return D3DERR_INVALIDCALL;
  272. }
  273. DXGASSERT(m_isLockable);
  274. return InternalUnlockRect();
  275. } // UnlockRect
  276. #undef DPF_MODNAME
  277. #define DPF_MODNAME "CCubeSurface::InternalUnlockRect"
  278. HRESULT CCubeSurface::InternalUnlockRect()
  279. {
  280. // Clear our locked state
  281. m_isLocked = 0;
  282. // If we are lock-once; then we mark ourselves as not lockable
  283. if (m_pParent->Desc()->Usage & D3DUSAGE_LOADONCE)
  284. {
  285. m_isLockable = FALSE;
  286. }
  287. // Done
  288. return S_OK;
  289. } // InternalUnlockRect
  290. //
  291. // CDriverCubeSurface class modifies the implementation
  292. // of the LockRect and UnlockRect methods of the CCubeSurface class
  293. //
  294. #undef DPF_MODNAME
  295. #define DPF_MODNAME "CDriverCubeSurface::LockRect"
  296. STDMETHODIMP CDriverCubeSurface::LockRect(D3DLOCKED_RECT *pLockedRectData,
  297. CONST RECT *pRect,
  298. DWORD dwFlags)
  299. {
  300. API_ENTER(Device());
  301. // If parameters are bad, then we should fail some stuff
  302. if (!VALID_WRITEPTR(pLockedRectData, sizeof(D3DLOCKED_RECT)))
  303. {
  304. DPF_ERR("bad pointer for m_pLockedRectData passed to LockRect for Surface of a driver-allocated Cubemap");
  305. return D3DERR_INVALIDCALL;
  306. }
  307. // Zero out returned data
  308. ZeroMemory(pLockedRectData, sizeof(D3DLOCKED_RECT));
  309. // Validate Rect
  310. if (pRect != NULL)
  311. {
  312. DWORD Width = m_pParent->Desc()->Width >> m_iLevel;
  313. DWORD Height = m_pParent->Desc()->Height >> m_iLevel;
  314. if (!CPixel::IsValidRect(m_pParent->Desc()->Format,
  315. Width,
  316. Height,
  317. pRect))
  318. {
  319. DPF_ERR("LockRect for a level of a Cube Texture failed");
  320. return D3DERR_INVALIDCALL;
  321. }
  322. }
  323. if (dwFlags & ~D3DLOCK_SURF_VALID)
  324. {
  325. if (dwFlags & D3DLOCK_DISCARD)
  326. {
  327. if (dwFlags & D3DLOCK_READONLY)
  328. {
  329. DPF_ERR("D3DLOCK_READONLY is not allowed with D3DLOCK_DISCARD");
  330. return D3DERR_INVALIDCALL;
  331. }
  332. if (!(m_pParent->Desc()->Usage & D3DUSAGE_DYNAMIC))
  333. {
  334. DPF_ERR("D3DLOCK_DISCARD is allowed only with dynamic textures");
  335. return D3DERR_INVALIDCALL;
  336. }
  337. if (CombinedFaceLevel() > 0)
  338. {
  339. DPF_ERR("D3DLOCK_DISCARD is allowed only on D3DCUBEMAP_FACE_POSITIVE_X"
  340. " and the top mip level. DISCARD in this case will discard"
  341. " the entire cubemap.");
  342. return D3DERR_INVALIDCALL;
  343. }
  344. if (pRect != NULL)
  345. {
  346. DPF_ERR("Subrects not allowed with D3DLOCK_DISCARD");
  347. return D3DERR_INVALIDCALL;
  348. }
  349. }
  350. else
  351. {
  352. DPF_ERR("Invalid dwFlags parameter passed to LockRect for a Surface of a driver allocated Cubemap");
  353. DPF_EXPLAIN_BAD_LOCK_FLAGS(0, dwFlags & ~D3DLOCK_SURF_VALID);
  354. return D3DERR_INVALIDCALL;
  355. }
  356. }
  357. if (!m_isLockable)
  358. {
  359. m_pParent->ReportWhyLockFailed();
  360. return D3DERR_INVALIDCALL;
  361. }
  362. return InternalLockRect(pLockedRectData, pRect, dwFlags);
  363. } // CDriverCubeSurface::LockRect
  364. #undef DPF_MODNAME
  365. #define DPF_MODNAME "CDriverCubeSurface::InternalLockRect"
  366. HRESULT CDriverCubeSurface::InternalLockRect(D3DLOCKED_RECT *pLockedRectData,
  367. CONST RECT *pRect,
  368. DWORD dwFlags)
  369. {
  370. // Only one lock outstanding at a time is supported
  371. if (m_isLocked)
  372. {
  373. DPF_ERR("LockRect failed on a Cube level; surface was already locked.");
  374. return D3DERR_INVALIDCALL;
  375. }
  376. // Notify the parent/device if we are about to be accessed.
  377. // Driver textures may be written to by HW through
  378. // SRT/DrawPrim as well as UpdateTexture. So we may need to sync
  379. // with the current command batch.
  380. m_pParent->OnSurfaceLock(m_iFace, m_iLevel, pRect, dwFlags);
  381. // Prepare a LockData structure for the HAL call
  382. D3D8_LOCKDATA lockData;
  383. ZeroMemory(&lockData, sizeof lockData);
  384. lockData.hDD = m_pParent->Device()->GetHandle();
  385. lockData.hSurface = m_hKernelHandle;
  386. lockData.dwFlags = dwFlags;
  387. if (pRect != NULL)
  388. {
  389. lockData.bHasRect = TRUE;
  390. lockData.rArea = *((RECTL *) pRect);
  391. }
  392. HRESULT hr = m_pParent->Device()->GetHalCallbacks()->Lock(&lockData);
  393. if (FAILED(hr))
  394. {
  395. DPF_ERR("Failed to lock driver cube-map surface");
  396. return hr;
  397. }
  398. // Fill in the Locked_Rect fields
  399. D3DFORMAT Format = m_pParent->Desc()->Format;
  400. if (CPixel::IsDXT(Format))
  401. {
  402. // Pitch is the number of bytes for
  403. // one row's worth of blocks for linear formats
  404. // Start with our width
  405. UINT Width = m_pParent->Desc()->Width >> m_iLevel;
  406. // Convert to blocks
  407. Width = Width / 4;
  408. // At least one block
  409. if (Width == 0)
  410. Width = 1;
  411. if (Format == D3DFMT_DXT1)
  412. {
  413. // 8 bytes per block for DXT1
  414. pLockedRectData->Pitch = Width * 8;
  415. }
  416. else
  417. {
  418. // 16 bytes per block for DXT2-5
  419. pLockedRectData->Pitch = Width * 16;
  420. }
  421. }
  422. else
  423. {
  424. pLockedRectData->Pitch = lockData.lPitch;
  425. }
  426. pLockedRectData->pBits = lockData.lpSurfData;
  427. #ifdef DEBUG
  428. if ((dwFlags & D3DLOCK_DISCARD))
  429. {
  430. DXGASSERT(m_iLevel == 0 && m_iFace == 0);
  431. if (!CPixel::IsFourCC(Format) &&
  432. !CPixel::IsIHVFormat(Format))
  433. {
  434. DXGASSERT(pRect == NULL);
  435. memset(pLockedRectData->pBits, 0xDD, pLockedRectData->Pitch * m_pParent->Desc()->Height);
  436. for (UINT j = 0; j < 6; ++j)
  437. {
  438. for (UINT i = 0; i < m_pParent->GetLevelCount(); ++i)
  439. {
  440. if (i != 0 || j != 0)
  441. {
  442. DXGASSERT(i != 0 || j != 0);
  443. D3DLOCKED_RECT Rect;
  444. HRESULT hr = m_pParent->LockRect((D3DCUBEMAP_FACES)j, i, &Rect, NULL, 0);
  445. if (FAILED(hr))
  446. {
  447. DPF(1, "Lock to cube mipsublevel failed. Not good.");
  448. break;
  449. }
  450. D3DSURFACE_DESC LevelDesc;
  451. m_pParent->GetLevelDesc(i, &LevelDesc);
  452. memset(Rect.pBits, 0xDD, Rect.Pitch * LevelDesc.Height);
  453. m_pParent->UnlockRect((D3DCUBEMAP_FACES)j, i);
  454. }
  455. }
  456. }
  457. }
  458. }
  459. #endif // DEBUG
  460. // Mark ourselves as locked
  461. m_isLocked = 1;
  462. // Done
  463. return S_OK;
  464. } // CDriverCubeSurface::InternalLockRect
  465. #undef DPF_MODNAME
  466. #define DPF_MODNAME "CDriverCubeSurface::UnlockRect"
  467. STDMETHODIMP CDriverCubeSurface::UnlockRect()
  468. {
  469. API_ENTER(Device());
  470. // If we aren't locked; then something is wrong
  471. if (m_isLocked == 0)
  472. {
  473. DPF_ERR("UnlockRect failed on a driver-allocated Cube level; surface wasn't locked.");
  474. return D3DERR_INVALIDCALL;
  475. }
  476. DXGASSERT(m_isLockable);
  477. return InternalUnlockRect();
  478. } // CDriverCubeSurface::UnlockRect
  479. #undef DPF_MODNAME
  480. #define DPF_MODNAME "CDriverCubeSurface::UnlockRect"
  481. HRESULT CDriverCubeSurface::InternalUnlockRect()
  482. {
  483. // Call the driver to perform the unlock
  484. D3D8_UNLOCKDATA unlockData = {
  485. m_pParent->Device()->GetHandle(),
  486. m_hKernelHandle
  487. };
  488. HRESULT hr = Device()->GetHalCallbacks()->Unlock(&unlockData);
  489. if (FAILED(hr))
  490. {
  491. DPF_ERR("Driver cube-map surface failed to unlock");
  492. return hr;
  493. }
  494. // Clear our locked state
  495. m_isLocked = 0;
  496. // If we are lock-once; then we mark ourselves as not lockable
  497. if (m_pParent->Desc()->Usage & D3DUSAGE_LOADONCE)
  498. {
  499. m_isLockable = FALSE;
  500. }
  501. // Done
  502. return S_OK;
  503. } // CDriverCubeSurface::InternalUnlockRect
  504. // End of file : cubesurf.cpp