Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

658 lines
18 KiB

  1. /*==========================================================================;
  2. *
  3. * Copyright (C) 1999-2000 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: d3dobj.cpp
  6. * Content: Base class implementation for resources and buffers
  7. *
  8. *
  9. ***************************************************************************/
  10. #include "ddrawpr.h"
  11. #include "pixel.hpp"
  12. IHVFormatInfo *CPixel::m_pFormatList = 0;
  13. extern "C" void CPixel__Cleanup()
  14. {
  15. CPixel::Cleanup();
  16. }
  17. #undef DPF_MODNAME
  18. #define DPF_MODNAME "CPixel::Cleanup"
  19. void CPixel::Cleanup()
  20. {
  21. while(m_pFormatList != 0)
  22. {
  23. IHVFormatInfo *t = m_pFormatList->m_pNext;
  24. delete m_pFormatList;
  25. m_pFormatList = t;
  26. }
  27. }
  28. #undef DPF_MODNAME
  29. #define DPF_MODNAME "CPixel::BytesPerPixel"
  30. UINT CPixel::BytesPerPixel(D3DFORMAT Format)
  31. {
  32. switch (Format)
  33. {
  34. case D3DFMT_DXT1:
  35. // Size is negative to indicate DXT; and indicates
  36. // the size of the block
  37. return (UINT)(-8);
  38. case D3DFMT_DXT2:
  39. case D3DFMT_DXT3:
  40. case D3DFMT_DXT4:
  41. case D3DFMT_DXT5:
  42. // Size is negative to indicate DXT; and indicates
  43. // the size of the block
  44. return (UINT)(-16);
  45. #ifdef VOLUME_DXT
  46. case D3DFMT_DXV1:
  47. // Size is negative to indicate DXT; and indicates
  48. // the size of the block
  49. return (UINT)(-32);
  50. case D3DFMT_DXV2:
  51. case D3DFMT_DXV3:
  52. case D3DFMT_DXV4:
  53. case D3DFMT_DXV5:
  54. return (UINT)(-64);
  55. #endif //VOLUME_DXT
  56. case D3DFMT_A8R8G8B8:
  57. case D3DFMT_X8R8G8B8:
  58. case D3DFMT_D32:
  59. case D3DFMT_D24S8:
  60. case D3DFMT_S8D24:
  61. case D3DFMT_X8L8V8U8:
  62. case D3DFMT_X4S4D24:
  63. case D3DFMT_D24X4S4:
  64. case D3DFMT_Q8W8V8U8:
  65. case D3DFMT_V16U16:
  66. case D3DFMT_W11V11U10:
  67. case D3DFMT_W10V11U11:
  68. case D3DFMT_A2W10V10U10:
  69. case D3DFMT_A8X8V8U8:
  70. case D3DFMT_L8X8V8U8:
  71. case D3DFMT_A2B10G10R10:
  72. case D3DFMT_A8B8G8R8:
  73. case D3DFMT_X8B8G8R8:
  74. case D3DFMT_G16R16:
  75. case D3DFMT_D24X8:
  76. return 4;
  77. case D3DFMT_R8G8B8:
  78. return 3;
  79. case D3DFMT_R5G6B5:
  80. case D3DFMT_X1R5G5B5:
  81. case D3DFMT_A1R5G5B5:
  82. case D3DFMT_A4R4G4B4:
  83. case D3DFMT_A8L8:
  84. case D3DFMT_V8U8:
  85. case D3DFMT_L6V5U5:
  86. case D3DFMT_D16:
  87. case D3DFMT_D16_LOCKABLE:
  88. case D3DFMT_D15S1:
  89. case D3DFMT_S1D15:
  90. case D3DFMT_A8P8:
  91. case D3DFMT_A8R3G3B2:
  92. case D3DFMT_UYVY:
  93. case D3DFMT_YUY2:
  94. case D3DFMT_X4R4G4B4:
  95. return 2;
  96. case D3DFMT_P8:
  97. case D3DFMT_L8:
  98. case D3DFMT_R3G3B2:
  99. case D3DFMT_A4L4:
  100. case D3DFMT_A8:
  101. return 1;
  102. default:
  103. return 0;
  104. };
  105. }; // BytesPerPixel
  106. #undef DPF_MODNAME
  107. #define DPF_MODNAME "CPixel::ComputePixelStride"
  108. UINT CPixel::ComputePixelStride(D3DFORMAT Format)
  109. {
  110. UINT BPP = BytesPerPixel(Format);
  111. if (BPP == 0)
  112. {
  113. for(IHVFormatInfo *p = m_pFormatList; p != 0; p = p->m_pNext)
  114. {
  115. if (p->m_Format == Format)
  116. {
  117. return p->m_BPP >> 3;
  118. }
  119. }
  120. }
  121. return BPP;
  122. }; // ComputePixelStride
  123. #undef DPF_MODNAME
  124. #define DPF_MODNAME "CPixel::ComputeSurfaceStride"
  125. // Figure out a stride for a particular surface based on format and width
  126. inline UINT CPixel::ComputeSurfaceStride(UINT cpWidth, UINT cbPixel)
  127. {
  128. // Figure out basic (linear) stride;
  129. UINT dwStride = cpWidth * cbPixel;
  130. // Round up to multiple of 4 (for NT; but makes sense to maximize
  131. // cache hits and reduce unaligned accesses)
  132. dwStride = (dwStride + 3) & ~3;
  133. return dwStride;
  134. }; // ComputeSurfaceStride
  135. #undef DPF_MODNAME
  136. #define DPF_MODNAME "CPixel::ComputeSurfaceSize"
  137. UINT CPixel::ComputeSurfaceSize(UINT cpWidth,
  138. UINT cpHeight,
  139. UINT cbPixel)
  140. {
  141. return cpHeight * ComputeSurfaceStride(cpWidth, cbPixel);
  142. } // ComputeSurfaceSize
  143. #undef DPF_MODNAME
  144. #define DPF_MODNAME "CPixel::ComputeMipMapSize"
  145. UINT CPixel::ComputeMipMapSize(UINT cpWidth,
  146. UINT cpHeight,
  147. UINT cLevels,
  148. D3DFORMAT Format)
  149. {
  150. UINT cbPixel = ComputePixelStride(Format);
  151. // Adjust pixel->block if necessary
  152. BOOL isDXT = IsDXT(cbPixel);
  153. DDASSERT((UINT)isDXT <= 1);
  154. if (isDXT)
  155. {
  156. AdjustForDXT(&cpWidth, &cpHeight, &cbPixel);
  157. }
  158. UINT cbSize = 0;
  159. for (UINT i = 0; i < cLevels; i++)
  160. {
  161. // Figure out the size for
  162. // each level of the mip-map
  163. cbSize += ComputeSurfaceSize(cpWidth, cpHeight, cbPixel);
  164. // Shrink width and height by half; clamp to 1 pixel
  165. if (cpWidth > 1)
  166. {
  167. cpWidth += (UINT)isDXT;
  168. cpWidth >>= 1;
  169. }
  170. if (cpHeight > 1)
  171. {
  172. cpHeight += (UINT)isDXT;
  173. cpHeight >>= 1;
  174. }
  175. }
  176. return cbSize;
  177. } // ComputeMipMapSize
  178. #undef DPF_MODNAME
  179. #define DPF_MODNAME "CPixel::ComputeMipVolumeSize"
  180. UINT CPixel::ComputeMipVolumeSize(UINT cpWidth,
  181. UINT cpHeight,
  182. UINT cpDepth,
  183. UINT cLevels,
  184. D3DFORMAT Format)
  185. {
  186. UINT cbPixel = ComputePixelStride(Format);
  187. // Adjust pixel->block if necessary
  188. BOOL isDXT = IsDXT(cbPixel);
  189. BOOL isVolumeDXT = IsVolumeDXT(Format);
  190. DDASSERT((UINT)isDXT <= 1);
  191. if (isVolumeDXT)
  192. {
  193. DXGASSERT(isDXT);
  194. AdjustForVolumeDXT(&cpWidth, &cpHeight, &cpDepth, &cbPixel);
  195. }
  196. else if (isDXT)
  197. {
  198. AdjustForDXT(&cpWidth, &cpHeight, &cbPixel);
  199. }
  200. UINT cbSize = 0;
  201. for (UINT i = 0; i < cLevels; i++)
  202. {
  203. // Figure out the size for
  204. // each level of the mip-volume
  205. cbSize += cpDepth * ComputeSurfaceSize(cpWidth, cpHeight, cbPixel);
  206. // Shrink width and height by half; clamp to 1 pixel
  207. if (cpWidth > 1)
  208. {
  209. cpWidth += (UINT)isDXT;
  210. cpWidth >>= 1;
  211. }
  212. if (cpHeight > 1)
  213. {
  214. cpHeight += (UINT)isDXT;
  215. cpHeight >>= 1;
  216. }
  217. if (cpDepth > 1)
  218. {
  219. cpDepth >>= 1;
  220. }
  221. }
  222. return cbSize;
  223. } // ComputeMipVolumeSize
  224. // Given a surface desc, a level, and pointer to
  225. // bits (pBits in the LockedRectData) and a sub-rect,
  226. // this will fill in the pLockedRectData structure
  227. void CPixel::ComputeMipMapOffset(const D3DSURFACE_DESC *pDescTopLevel,
  228. UINT iLevel,
  229. BYTE *pBits,
  230. CONST RECT *pRect,
  231. D3DLOCKED_RECT *pLockedRectData)
  232. {
  233. DXGASSERT(pBits != NULL);
  234. DXGASSERT(pLockedRectData != NULL);
  235. DXGASSERT(iLevel < 32);
  236. DXGASSERT(pDescTopLevel != NULL);
  237. DXGASSERT(0 != ComputePixelStride(pDescTopLevel->Format));
  238. DXGASSERT(pDescTopLevel->Width > 0);
  239. DXGASSERT(pDescTopLevel->Height > 0);
  240. // CONSIDER: This is slow; and we can do a much better
  241. // job for the non-compressed/wacky cases.
  242. UINT cbOffset = 0;
  243. UINT cbPixel = ComputePixelStride(pDescTopLevel->Format);
  244. UINT cpWidth = pDescTopLevel->Width;
  245. UINT cpHeight = pDescTopLevel->Height;
  246. // Adjust pixel->block if necessary
  247. BOOL isDXT = IsDXT(cbPixel);
  248. DDASSERT((UINT)isDXT <= 1);
  249. if (isDXT)
  250. {
  251. AdjustForDXT(&cpWidth, &cpHeight, &cbPixel);
  252. }
  253. for (UINT i = 0; i < iLevel; i++)
  254. {
  255. cbOffset += ComputeSurfaceSize(cpWidth,
  256. cpHeight,
  257. cbPixel);
  258. // Shrink width and height by half; clamp to 1 pixel
  259. if (cpWidth > 1)
  260. {
  261. cpWidth += (UINT)isDXT;
  262. cpWidth >>= 1;
  263. }
  264. if (cpHeight > 1)
  265. {
  266. cpHeight += (UINT)isDXT;
  267. cpHeight >>= 1;
  268. }
  269. }
  270. // For DXTs, the pitch is the number of bytes
  271. // for a single row of blocks; which is the same
  272. // thing as the normal routine
  273. pLockedRectData->Pitch = ComputeSurfaceStride(cpWidth,
  274. cbPixel);
  275. DXGASSERT(pLockedRectData->Pitch != 0);
  276. // Don't adjust for Rect for DXT formats
  277. if (pRect)
  278. {
  279. if (isDXT)
  280. {
  281. DXGASSERT((pRect->top & 3) == 0);
  282. DXGASSERT((pRect->left & 3) == 0);
  283. cbOffset += (pRect->top / 4) * pLockedRectData->Pitch +
  284. (pRect->left / 4) * cbPixel;
  285. }
  286. else
  287. {
  288. cbOffset += pRect->top * pLockedRectData->Pitch +
  289. pRect->left * cbPixel;
  290. }
  291. }
  292. pLockedRectData->pBits = pBits + cbOffset;
  293. } // ComputeMipMapOffset
  294. #undef DPF_MODNAME
  295. #define DPF_MODNAME "CPixel::ComputeMipVolumeOffset"
  296. // MipVolume version of ComputeMipMapOffset
  297. void CPixel::ComputeMipVolumeOffset(const D3DVOLUME_DESC *pDescTopLevel,
  298. UINT iLevel,
  299. BYTE *pBits,
  300. CONST D3DBOX *pBox,
  301. D3DLOCKED_BOX *pLockedBoxData)
  302. {
  303. DXGASSERT(pBits != NULL);
  304. DXGASSERT(pLockedBoxData != NULL);
  305. DXGASSERT(iLevel < 32);
  306. DXGASSERT(pDescTopLevel != NULL);
  307. DXGASSERT(0 != ComputePixelStride(pDescTopLevel->Format));
  308. DXGASSERT(pDescTopLevel->Width > 0);
  309. DXGASSERT(pDescTopLevel->Height > 0);
  310. DXGASSERT(pDescTopLevel->Depth > 0);
  311. UINT cbOffset = 0;
  312. UINT cbPixel = ComputePixelStride(pDescTopLevel->Format);
  313. UINT cpWidth = pDescTopLevel->Width;
  314. UINT cpHeight = pDescTopLevel->Height;
  315. UINT cpDepth = pDescTopLevel->Depth;
  316. // Adjust pixel->block if necessary
  317. BOOL isDXT = IsDXT(cbPixel);
  318. BOOL isVolumeDXT = IsVolumeDXT(pDescTopLevel->Format);
  319. DDASSERT((UINT)isDXT <= 1);
  320. if (isVolumeDXT)
  321. {
  322. DXGASSERT(isDXT);
  323. AdjustForVolumeDXT(&cpWidth, &cpHeight, &cpDepth, &cbPixel);
  324. }
  325. else if (isDXT)
  326. {
  327. AdjustForDXT(&cpWidth, &cpHeight, &cbPixel);
  328. }
  329. for (UINT i = 0; i < iLevel; i++)
  330. {
  331. cbOffset += cpDepth * ComputeSurfaceSize(cpWidth,
  332. cpHeight,
  333. cbPixel);
  334. // Shrink width and height by half; clamp to 1 pixel
  335. if (cpWidth > 1)
  336. {
  337. cpWidth += (UINT)isDXT;
  338. cpWidth >>= 1;
  339. }
  340. if (cpHeight > 1)
  341. {
  342. cpHeight += (UINT)isDXT;
  343. cpHeight >>= 1;
  344. }
  345. if (cpDepth > 1)
  346. {
  347. cpDepth >>= 1;
  348. }
  349. }
  350. // For DXTs, the row pitch is the number of bytes
  351. // for a single row of blocks; which is the same
  352. // thing as the normal routine
  353. pLockedBoxData->RowPitch = ComputeSurfaceStride(cpWidth,
  354. cbPixel);
  355. DXGASSERT(pLockedBoxData->RowPitch != 0);
  356. // For DXVs the slice pitch is the number of bytes
  357. // for a single plane of blocks; which is the same thing
  358. // as the normal routine
  359. pLockedBoxData->SlicePitch = ComputeSurfaceSize(cpWidth,
  360. cpHeight,
  361. cbPixel);
  362. DXGASSERT(pLockedBoxData->SlicePitch != 0);
  363. // Adjust for Box
  364. if (pBox)
  365. {
  366. UINT iStride = pLockedBoxData->RowPitch;
  367. UINT iSlice = pLockedBoxData->SlicePitch;
  368. if (isDXT)
  369. {
  370. if (isVolumeDXT)
  371. {
  372. DXGASSERT((pBox->Front & 3) == 0);
  373. cbOffset += (pBox->Front / 4) * iSlice;
  374. }
  375. else
  376. {
  377. cbOffset += (pBox->Front) * iSlice;
  378. }
  379. DXGASSERT((pBox->Top & 3) == 0);
  380. DXGASSERT((pBox->Left & 3) == 0);
  381. cbOffset += (pBox->Top / 4) * iStride +
  382. (pBox->Left / 4) * cbPixel;
  383. }
  384. else
  385. {
  386. cbOffset += pBox->Front * iSlice +
  387. pBox->Top * iStride +
  388. pBox->Left * cbPixel;
  389. }
  390. }
  391. pLockedBoxData->pBits = pBits + cbOffset;
  392. } // ComputeMipVolumeOffset
  393. #undef DPF_MODNAME
  394. #define DPF_MODNAME "CPixel::IsValidRect"
  395. BOOL CPixel::IsValidRect(D3DFORMAT Format,
  396. UINT Width,
  397. UINT Height,
  398. const RECT *pRect)
  399. {
  400. if (!VALID_PTR(pRect, sizeof(RECT)))
  401. {
  402. DPF_ERR("bad pointer for pRect");
  403. return FALSE;
  404. }
  405. // Treat width/height of zero as 1
  406. if (Width == 0)
  407. Width = 1;
  408. if (Height == 0)
  409. Height = 1;
  410. // Check that Rect is reasonable
  411. if ((pRect->left >= pRect->right) ||
  412. (pRect->top >= pRect->bottom))
  413. {
  414. DPF_ERR("Invalid Rect: zero-area.");
  415. return FALSE;
  416. }
  417. // Check that Rect fits the surface
  418. if (pRect->left < 0 ||
  419. pRect->top < 0 ||
  420. pRect->right > (INT)Width ||
  421. pRect->bottom > (INT)Height)
  422. {
  423. DPF_ERR("pRect doesn't fit inside the surface");
  424. return FALSE;
  425. }
  426. // Check if 4X4 rules are needed
  427. if (CPixel::Requires4X4(Format))
  428. {
  429. if ((pRect->left & 3) ||
  430. (pRect->top & 3))
  431. {
  432. DPF_ERR("Rects for DXT surfaces must be on 4x4 boundaries");
  433. return FALSE;
  434. }
  435. if ((pRect->right & 3) && ((INT)Width != pRect->right))
  436. {
  437. DPF_ERR("Rects for DXT surfaces must be on 4x4 boundaries");
  438. return FALSE;
  439. }
  440. if ((pRect->bottom & 3) && ((INT)Height != pRect->bottom))
  441. {
  442. DPF_ERR("Rects for DXT surfaces must be on 4x4 boundaries");
  443. return FALSE;
  444. }
  445. }
  446. // Everything checks out
  447. return TRUE;
  448. } // IsValidRect
  449. #undef DPF_MODNAME
  450. #define DPF_MODNAME "CPixel::IsValidBox"
  451. BOOL CPixel::IsValidBox(D3DFORMAT Format,
  452. UINT Width,
  453. UINT Height,
  454. UINT Depth,
  455. const D3DBOX *pBox)
  456. {
  457. if (!VALID_PTR(pBox, sizeof(D3DBOX)))
  458. {
  459. DPF_ERR("bad pointer for pBox");
  460. return FALSE;
  461. }
  462. // Treat width/height/depth of zero as 1
  463. if (Width == 0)
  464. Width = 1;
  465. if (Height == 0)
  466. Height = 1;
  467. if (Depth == 0)
  468. Depth = 1;
  469. // Check that Box is reasonable
  470. if ((pBox->Left >= pBox->Right) ||
  471. (pBox->Top >= pBox->Bottom) ||
  472. (pBox->Front >= pBox->Back))
  473. {
  474. DPF_ERR("Invalid Box passed: non-positive volume.");
  475. return FALSE;
  476. }
  477. // Check that box fits the surface
  478. if (pBox->Right > Width ||
  479. pBox->Bottom > Height ||
  480. pBox->Back > Depth)
  481. {
  482. DPF_ERR("Box doesn't fit inside the volume");
  483. return FALSE;
  484. }
  485. // Check if 4X4 rules are needed
  486. if (CPixel::Requires4X4(Format))
  487. {
  488. if ((pBox->Left & 3) ||
  489. (pBox->Top & 3))
  490. {
  491. if (CPixel::IsVolumeDXT(Format))
  492. DPF_ERR("Boxes for DXV volumes must be on 4x4x4 boundaries");
  493. else
  494. DPF_ERR("Boxes for DXT volumes must be on 4x4 boundaries");
  495. return FALSE;
  496. }
  497. if ((pBox->Right & 3) && (Width != pBox->Right))
  498. {
  499. if (CPixel::IsVolumeDXT(Format))
  500. DPF_ERR("Boxes for DXV volumes must be on 4x4x4 boundaries");
  501. else
  502. DPF_ERR("Boxes for DXT volumes must be on 4x4 boundaries");
  503. return FALSE;
  504. }
  505. if ((pBox->Bottom & 3) && (Height != pBox->Bottom))
  506. {
  507. if (CPixel::IsVolumeDXT(Format))
  508. DPF_ERR("Boxes for DXV volumes must be on 4x4x4 boundaries");
  509. else
  510. DPF_ERR("Boxes for DXT volumes must be on 4x4 boundaries");
  511. return FALSE;
  512. }
  513. if (CPixel::IsVolumeDXT(Format))
  514. {
  515. // For Volume DXT; we need to check front/back too
  516. if (pBox->Front & 3)
  517. {
  518. DPF_ERR("Boxes for DXV volumes must be on 4x4x4 boundaries");
  519. return FALSE;
  520. }
  521. if ((pBox->Back & 3) && (Depth != pBox->Back))
  522. {
  523. DPF_ERR("Boxes for DXV volumes must be on 4x4x4 boundaries");
  524. return FALSE;
  525. }
  526. }
  527. }
  528. // Everything checks out
  529. return TRUE;
  530. } // IsValidBox
  531. D3DFORMAT CPixel::SuppressAlphaChannel(D3DFORMAT Format)
  532. {
  533. switch(Format)
  534. {
  535. case D3DFMT_A8R8G8B8:
  536. return D3DFMT_X8R8G8B8;
  537. case D3DFMT_A1R5G5B5:
  538. return D3DFMT_X1R5G5B5;
  539. case D3DFMT_A4R4G4B4:
  540. return D3DFMT_X4R4G4B4;
  541. }
  542. return Format;
  543. }
  544. #undef DPF_MODNAME
  545. #define DPF_MODNAME "CPixel::Register"
  546. HRESULT CPixel::Register(D3DFORMAT Format, DWORD BPP)
  547. {
  548. DXGASSERT(BPP != 0);
  549. // Do not register duplicates
  550. for(IHVFormatInfo *p = m_pFormatList; p != 0; p = p->m_pNext)
  551. {
  552. if (p->m_Format == Format)
  553. {
  554. return S_OK;
  555. }
  556. }
  557. // Not found, add to registry.
  558. // This allocation will be leaked, but since
  559. // we don't expect to have a large number of
  560. // IHV formats, the leak is not a big deal.
  561. // Also, the leak will be immediately recovered
  562. // upon process exit.
  563. p = new IHVFormatInfo;
  564. if (p == 0)
  565. {
  566. return E_OUTOFMEMORY;
  567. }
  568. p->m_Format = Format;
  569. p->m_BPP = BPP;
  570. p->m_pNext = m_pFormatList;
  571. m_pFormatList = p;
  572. return S_OK;
  573. }
  574. // End of file : pixel.cpp