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.

386 lines
11 KiB

  1. /*==========================================================================;
  2. *
  3. * Copyright (C) 1999-2000 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: texture.cpp
  6. * Content: Implementation of the CBaseTexture class.
  7. *
  8. *
  9. ***************************************************************************/
  10. #include "ddrawpr.h"
  11. #include "texture.hpp"
  12. #include "d3di.hpp"
  13. #include "ddi.h"
  14. #undef DPF_MODNAME
  15. #define DPF_MODNAME "CBaseTexture::CanTexBlt"
  16. BOOL CBaseTexture::CanTexBlt(CBaseTexture *pDstTexture) const
  17. {
  18. const D3D8_DRIVERCAPS* pDriverCaps = Device()->GetCoreCaps();
  19. D3DPOOL SrcPool = GetBufferDesc()->Pool;
  20. D3DPOOL DstPool = pDstTexture->GetBufferDesc()->Pool;
  21. // Real pools should not be default
  22. DXGASSERT(SrcPool != D3DPOOL_DEFAULT);
  23. DXGASSERT(DstPool != D3DPOOL_DEFAULT);
  24. DXGASSERT(VALID_INTERNAL_POOL(SrcPool));
  25. DXGASSERT(VALID_INTERNAL_POOL(DstPool));
  26. // Check if the device can do TexBlt
  27. if (Device()->CanTexBlt() == FALSE)
  28. return FALSE;
  29. // Check that source and dest formats match
  30. DXGASSERT(GetBufferDesc()->Format == pDstTexture->GetBufferDesc()->Format);
  31. // FourCC may not be copy-able
  32. if (CPixel::IsFourCC(GetBufferDesc()->Format))
  33. {
  34. if (!(pDriverCaps->D3DCaps.Caps2 & DDCAPS2_COPYFOURCC))
  35. {
  36. return FALSE;
  37. }
  38. }
  39. // Note that we do not support TexBlt to anything
  40. // that is persistent across Reset; because TexBlt is
  41. // asynchronous and may not succeed if we get lost.
  42. //
  43. // This can break apps that expect the blt to have
  44. // succeeded.
  45. if (pDriverCaps->D3DCaps.Caps2 & DDCAPS2_NONLOCALVIDMEMCAPS)
  46. {
  47. if (SrcPool == D3DPOOL_SYSTEMMEM)
  48. {
  49. if ((DstPool == D3DPOOL_NONLOCALVIDMEM) &&
  50. (pDriverCaps->D3DCaps.DevCaps & D3DDEVCAPS_CANBLTSYSTONONLOCAL))
  51. {
  52. return TRUE;
  53. }
  54. else if ((DstPool == D3DPOOL_LOCALVIDMEM) &&
  55. (pDriverCaps->SVBCaps & DDCAPS_BLT))
  56. {
  57. return TRUE;
  58. }
  59. }
  60. else if (SrcPool == D3DPOOL_NONLOCALVIDMEM)
  61. {
  62. if ((DstPool == D3DPOOL_LOCALVIDMEM) &&
  63. (pDriverCaps->NLVCaps & DDCAPS_BLT))
  64. {
  65. return TRUE;
  66. }
  67. }
  68. else if ((SrcPool == D3DPOOL_LOCALVIDMEM) ||
  69. (SrcPool == D3DPOOL_MANAGED))
  70. {
  71. if ((DstPool == D3DPOOL_LOCALVIDMEM) &&
  72. (pDriverCaps->D3DCaps.Caps & DDCAPS_BLT))
  73. {
  74. return TRUE;
  75. }
  76. }
  77. }
  78. else
  79. {
  80. if (SrcPool == D3DPOOL_SYSTEMMEM)
  81. {
  82. if ((DstPool == D3DPOOL_LOCALVIDMEM) &&
  83. (pDriverCaps->SVBCaps & DDCAPS_BLT))
  84. {
  85. return TRUE;
  86. }
  87. }
  88. else if ((SrcPool == D3DPOOL_LOCALVIDMEM) ||
  89. (SrcPool == D3DPOOL_MANAGED))
  90. {
  91. if ((DstPool == D3DPOOL_LOCALVIDMEM) &&
  92. (pDriverCaps->D3DCaps.Caps & DDCAPS_BLT))
  93. {
  94. return TRUE;
  95. }
  96. }
  97. }
  98. return FALSE;
  99. } // CBaseTexture::CanTexBlt
  100. #undef DPF_MODNAME
  101. #define DPF_MODNAME "CBaseTexture::VerifyFormat"
  102. HRESULT CBaseTexture::Validate(CBaseDevice *pDevice,
  103. D3DRESOURCETYPE Type,
  104. D3DPOOL Pool,
  105. DWORD Usage,
  106. D3DFORMAT Format)
  107. {
  108. DXGASSERT(pDevice);
  109. DXGASSERT(Type == D3DRTYPE_TEXTURE ||
  110. Type == D3DRTYPE_CUBETEXTURE ||
  111. Type == D3DRTYPE_VOLUMETEXTURE);
  112. // Check pool
  113. if (!VALID_POOL(Pool))
  114. {
  115. DPF_ERR("Invalid Pool specified for texture");
  116. return D3DERR_INVALIDCALL;
  117. }
  118. //pool scratch doesn't allow any usages
  119. if (Pool == D3DPOOL_SCRATCH)
  120. {
  121. if (Usage)
  122. {
  123. DPF_ERR("D3DPOOL_SCRATCH resources aren't allowed to have any usage flags");
  124. return D3DERR_INVALIDCALL;
  125. }
  126. }
  127. // Check usage flags
  128. if (Usage & ~D3DUSAGE_TEXTURE_VALID)
  129. {
  130. DPF_ERR("Invalid usage flag specified for texture.");
  131. return D3DERR_INVALIDCALL;
  132. }
  133. // Check if USAGE_DYNAMIC is allowed
  134. if (Usage & D3DUSAGE_DYNAMIC)
  135. {
  136. if (Pool == D3DPOOL_MANAGED)
  137. {
  138. DPF_ERR("Managed textures cannot be dynamic.");
  139. return D3DERR_INVALIDCALL;
  140. }
  141. }
  142. // Check is load-once is supported
  143. if (Usage & D3DUSAGE_LOADONCE)
  144. {
  145. // Only SysMem and Managed are load-once-able
  146. if (Pool != D3DPOOL_SYSTEMMEM &&
  147. Pool != D3DPOOL_MANAGED)
  148. {
  149. DPF_ERR("Only SysMem and Managed textures support D3DUSAGE_LOADONCE");
  150. return D3DERR_INVALIDCALL;
  151. }
  152. // Only D16_LOCKABLE is a lockable depth; doesn't
  153. // make sense to have a non-lockable LOAD_ONCE texture
  154. if (CPixel::IsNonLockableZ(Format))
  155. {
  156. DPF_ERR("Depth formats other than D3DFMT_D16_LOCKABLE are not lockable.");
  157. return D3DERR_INVALIDCALL;
  158. }
  159. }
  160. // Check that only POOL_DEFAULT is supported for
  161. // RT or DS textures
  162. if (Usage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL))
  163. {
  164. if (Pool != D3DPOOL_DEFAULT)
  165. {
  166. DPF_ERR("Pool must be D3DPOOL_DEFAULT for RenderTarget and"
  167. " DepthStencil Usages");
  168. return D3DERR_INVALIDCALL;
  169. }
  170. }
  171. // Sys scratch or Managed must have a format that we can use directly
  172. if (Pool == D3DPOOL_SYSTEMMEM ||
  173. Pool == D3DPOOL_MANAGED ||
  174. Pool == D3DPOOL_SCRATCH)
  175. {
  176. // Can't create format unless it is supported
  177. if (!CPixel::IsSupported(Type, Format))
  178. {
  179. DPF_ERR("SystemMem, Scratch and Managed textures do not support this"
  180. " format.");
  181. return D3DERR_INVALIDCALL;
  182. }
  183. if (CPixel::IsNonLockableZ(Format))
  184. {
  185. DPF_ERR("This format is not supported for SystemMem, Scratch or Managed textures");
  186. return D3DERR_INVALIDCALL;
  187. }
  188. }
  189. if (Pool != D3DPOOL_SCRATCH)
  190. {
  191. HRESULT hr = pDevice->CheckDeviceFormat(Usage & (D3DUSAGE_RENDERTARGET | D3DUSAGE_DEPTHSTENCIL | D3DUSAGE_DYNAMIC),
  192. Type,
  193. Format);
  194. if (FAILED(hr))
  195. {
  196. DPF_ERR("Invalid format specified for texture");
  197. return D3DERR_INVALIDCALL;
  198. }
  199. }
  200. return S_OK;
  201. }; // CBaseTexture::Validate
  202. #undef DPF_MODNAME
  203. #define DPF_MODNAME "CBaseTexture::InferUsageFlags"
  204. // Infer usage flags based on external parameters
  205. DWORD CBaseTexture::InferUsageFlags(D3DPOOL Pool,
  206. DWORD Usage,
  207. D3DFORMAT Format)
  208. {
  209. //scratch textures have only usage lock
  210. if (Pool == D3DPOOL_SCRATCH)
  211. return D3DUSAGE_LOCK;
  212. // All textures have this usage set
  213. DWORD UsageInferred = D3DUSAGE_TEXTURE;
  214. DXGASSERT(!(Usage & D3DUSAGE_LOCK));
  215. DXGASSERT(!(Usage & D3DUSAGE_TEXTURE));
  216. // Infer Lock
  217. if ((Pool != D3DPOOL_DEFAULT) &&
  218. !(CPixel::IsNonLockableZ(Format)) &&
  219. !(Usage & D3DUSAGE_LOADONCE))
  220. {
  221. // Pool Default is not lockable
  222. // Usage Load Once implies absence of USAGE_LOCK
  223. // Z formats (other than D16_LOCKABLE) are not lockable
  224. // Otherwise, locking is support by default
  225. UsageInferred |= D3DUSAGE_LOCK;
  226. }
  227. else if (CPixel::IsIHVFormat(Format))
  228. {
  229. // IHV formats are lockable
  230. UsageInferred |= D3DUSAGE_LOCK;
  231. }
  232. else if (Usage & D3DUSAGE_DYNAMIC)
  233. {
  234. DXGASSERT(Pool != D3DPOOL_MANAGED);
  235. // Dynamic textures are lockable
  236. UsageInferred |= D3DUSAGE_LOCK;
  237. }
  238. return (UsageInferred | Usage);
  239. } // CBaseTexture::InferUsageFlags
  240. #ifdef DEBUG
  241. #undef DPF_MODNAME
  242. #define DPF_MODNAME "CBaseTexture::ReportWhyLockFailed"
  243. // DPF why Lock failed as clearly as possible
  244. void CBaseTexture::ReportWhyLockFailed(void) const
  245. {
  246. // If there are multiple reasons that lock failed; we report
  247. // them all to minimize user confusion
  248. if (GetUserPool() == D3DPOOL_DEFAULT)
  249. {
  250. DPF_ERR("Lock is not supported for textures allocated with"
  251. " POOL_DEFAULT unless they are marked D3DUSAGE_DYNAMIC.");
  252. }
  253. if (CPixel::IsNonLockableZ(GetUserFormat()))
  254. {
  255. DPF_ERR("Lock is not supported for depth formats other than D3DFMT_D16_LOCKABLE");
  256. }
  257. if (GetBufferDesc()->Usage & D3DUSAGE_LOADONCE)
  258. {
  259. DPF_ERR("For textures created with D3DUSAGE_LOADONCE,"
  260. " each level can only be locked once.");
  261. }
  262. // If we got here; then USAGE_LOCK should not have been set
  263. DXGASSERT(!(GetBufferDesc()->Usage & D3DUSAGE_LOCK));
  264. return;
  265. } // CBaseTexture::ReportWhyLockFailed
  266. #endif // DEBUG
  267. #undef DPF_MODNAME
  268. #define DPF_MODNAME "CBaseTexture::OnDestroy"
  269. // Textures overload this to call OnTextureDestroy on the
  270. // Device before calling Sync.
  271. void CBaseTexture::OnDestroy(void)
  272. {
  273. if (GetUserPool() != D3DPOOL_SCRATCH)
  274. {
  275. // we need to call this before freeing the texture so
  276. // that currently set textures get unset.
  277. if (BaseKernelHandle())
  278. {
  279. // m_hKernelHandle might not be available if Create fails early
  280. CD3DBase *pDev = static_cast<CD3DBase *>(Device());
  281. pDev->OnTextureDestroy(this);
  282. }
  283. // After FE has been notified, then we need
  284. // to sync; so call our base class
  285. CResource::OnDestroy();
  286. }
  287. return;
  288. } // CBaseTexture::OnDestroy
  289. #undef DPF_MODNAME
  290. #define DPF_MODNAME "CBaseTexture::SetLODImpl"
  291. DWORD CBaseTexture::SetLODImpl(DWORD LOD)
  292. {
  293. // Clamp to max lod since we can't return errors
  294. if (LOD >= GetLevelCountImpl())
  295. {
  296. DPF_ERR("Invalid dwLOD passed to SetLOD; clamping to number-of-levels-minus-one.");
  297. LOD = GetLevelCountImpl() - 1;
  298. }
  299. DWORD oldLOD = 0;
  300. if (IsD3DManaged())
  301. {
  302. oldLOD = Device()->ResourceManager()->SetLOD(RMHandle(), LOD);
  303. }
  304. // If IsD3DManaged() is FALSE and if the actual pool
  305. // is found to be D3DPOOL_MANAGED then the resource
  306. // MUST be driver managed.
  307. else if (GetBufferDesc()->Pool == D3DPOOL_MANAGED)
  308. {
  309. CD3DBase *pDev = static_cast<CD3DBase*>(Device());
  310. DXGASSERT(IS_DX8HAL_DEVICE(pDev));
  311. oldLOD = SetLODI(LOD);
  312. pDev->SetTexLOD(this, LOD);
  313. }
  314. // If above two conditions are false, then we must
  315. // check if we have fallen back to sysmem for some
  316. // reason even if the app requested managed. THIS
  317. // IS IMPOSSIBLE, so ASSERT.
  318. else if (GetUserPool() == D3DPOOL_MANAGED)
  319. {
  320. // We assert because sysmem fallback is not possible
  321. // for textures (and hence SetLOD)
  322. DXGASSERT(FALSE);
  323. }
  324. else
  325. {
  326. DPF_ERR("LOD set on non-managed object");
  327. }
  328. return oldLOD;
  329. }; // SetLODImpl
  330. #undef DPF_MODNAME
  331. #define DPF_MODNAME "CBaseTexture::GetLODImpl"
  332. DWORD CBaseTexture::GetLODImpl()
  333. {
  334. if (!IsD3DManaged() && GetBufferDesc()->Pool != D3DPOOL_MANAGED)
  335. {
  336. DPF_ERR("LOD accessed on non-managed object");
  337. return 0;
  338. }
  339. return GetLODI();
  340. }; // GetLODImpl
  341. // End of file : texture.cpp