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.

721 lines
19 KiB

  1. #ifndef __RESOURCE_HPP__
  2. #define __RESOURCE_HPP__
  3. /*==========================================================================;
  4. *
  5. * Copyright (C) 1999-2000 Microsoft Corporation. All Rights Reserved.
  6. *
  7. * File: resource.hpp
  8. * Content: Base class header for resources. A resource is an non-trivial
  9. * object that is directly used by the graphics pipeline. It
  10. * be composed of a set of buffers; for example a mip-map is
  11. * a resource that is composed of Surfaces (which are buffers).
  12. *
  13. * Since resources are non-trivial (i.e. more than few bytes),
  14. * they may need management. The resource cooperates with the
  15. * Resource Manager component to get management functionality.
  16. *
  17. ***************************************************************************/
  18. #include "d3dobj.hpp"
  19. // Forward Decl
  20. struct CMgmtInfo;
  21. class CResourceManager;
  22. // Handle for Resource Manager; internally implemented as a pointer
  23. typedef CMgmtInfo *RMHANDLE;
  24. // A Resource is a Base Object that additionally
  25. // has a Priority field
  26. class CResource : public CBaseObject
  27. {
  28. public:
  29. static HRESULT RestoreDriverManagementState(CBaseDevice *pDevice);
  30. // These methods are for the
  31. // use of the Resource Manager
  32. RMHANDLE RMHandle() const
  33. {
  34. return m_RMHandle;
  35. }; // RMHandle
  36. // Determine if a resource is managed or driver-managed
  37. BOOL IsD3DManaged() const
  38. {
  39. // Zero is not a valid RM handle
  40. return (m_RMHandle != 0);
  41. }; // IsD3DManaged
  42. // Set the device batch number that
  43. // this resource was last used in. In this
  44. // context; the batch refers to whether
  45. // this resource was used in the current
  46. // command buffer (i.e. containing unflushed commands).
  47. void Batch();
  48. // Same as Batch() except it batches the
  49. // backing (or sysmem) texture rather than the
  50. // promoted (or vidmem) one.
  51. void BatchBase();
  52. // Notifies the device that this resource
  53. // is about to be modified in a way that
  54. // may require a flush. (i.e. Whenever the bits
  55. // could change or a surface is going away.)
  56. void Sync();
  57. // Sets batch number
  58. void SetBatchNumber(ULONGLONG batch)
  59. {
  60. // Batch numbers should only be increasing since we
  61. // start at zero.
  62. DXGASSERT(batch >= m_qwBatchCount);
  63. m_qwBatchCount = batch;
  64. } // SetBatchNumber
  65. // returns the batch number that this resource
  66. // was last referred in
  67. ULONGLONG GetBatchNumber() const
  68. {
  69. return m_qwBatchCount;
  70. }
  71. // returns the DrawPrim handle associated with
  72. // the Driver-Accessible clone if it is Managed;
  73. // otherwise returns the handle of itself.
  74. DWORD DriverAccessibleDrawPrimHandle() const;
  75. // returns the Kernel handle associated with
  76. // the Driver-Accessible clone if it is Managed;
  77. // otherwise returns the handle of itself.
  78. HANDLE DriverAccessibleKernelHandle() const;
  79. // Specifies a creation of a resource that
  80. // looks just like the current one. The LOD parameter
  81. // may not be relevant for all Resource types.
  82. virtual HRESULT Clone(D3DPOOL Pool,
  83. CResource **ppResource) const PURE;
  84. // Provides a method to access basic structure of the
  85. // pieces of the resource.
  86. virtual const D3DBUFFER_DESC* GetBufferDesc() const PURE;
  87. // Tells the resource that it should copy itself
  88. // to the target. It is the caller's responsibility
  89. // to make sure that Target is compatible with the
  90. // Source. (The Target may have different number of mip-levels
  91. // and be in a different pool; however, it must have the same size,
  92. // faces, format, etc.)
  93. //
  94. // This function will clear the dirty state.
  95. virtual HRESULT UpdateDirtyPortion(CResource *pResourceTarget) PURE;
  96. // Allows the Resource Manager to mark the texture
  97. // as needing to be completely updated on next
  98. // call to UpdateDirtyPortion
  99. virtual void MarkAllDirty() PURE;
  100. // Indicates whether the Resource has been modified since
  101. // the last time that UpdateDirtyPortion has been called.
  102. // All managed resources start out in the Dirty state.
  103. BOOL IsDirty() const
  104. {
  105. return m_bIsDirty;
  106. } // IsDirty
  107. void PreLoadImpl();
  108. // Returns the pool which the user passed in
  109. D3DPOOL GetUserPool() const
  110. {
  111. return m_poolUser;
  112. } // GetUserPool
  113. protected:
  114. // The following are methods that only make sense
  115. // to be called by derived classes
  116. // Helper to check if a type is managed
  117. static BOOL IsTypeD3DManaged(CBaseDevice *pDevice,
  118. D3DRESOURCETYPE Type,
  119. D3DPOOL Pool);
  120. static BOOL IsTypeDriverManaged(CBaseDevice *pDevice,
  121. D3DRESOURCETYPE Type,
  122. D3DPOOL Pool);
  123. // Helper to determine what the 'real' pool is
  124. // for a managed resource.
  125. static D3DPOOL DetermineCreationPool(CBaseDevice *pDevice,
  126. D3DRESOURCETYPE Type,
  127. DWORD dwUsage,
  128. D3DPOOL Pool);
  129. // Constructor for Resources; all resources start out dirty
  130. CResource(CBaseDevice *pDevice, D3DPOOL Pool, REF_TYPE refType = REF_EXTERNAL) :
  131. CBaseObject(pDevice, refType),
  132. m_RMHandle(0),
  133. m_qwBatchCount(0),
  134. m_Priority(0),
  135. m_bIsDirty(TRUE),
  136. m_poolUser(Pool),
  137. m_pPrev(0)
  138. {
  139. m_pNext = pDevice->GetResourceList();
  140. pDevice->SetResourceList(this);
  141. if (m_pNext != 0)
  142. {
  143. m_pNext->m_pPrev = this;
  144. }
  145. }; // CResource
  146. virtual ~CResource();
  147. // Priority Inlines
  148. DWORD SetPriorityImpl(DWORD newPri);
  149. DWORD GetPriorityImpl();
  150. // Allows initialization of the RMHandle after
  151. // construction is basically complete
  152. HRESULT InitializeRMHandle();
  153. // Allows RMHandle to be set to zero
  154. void DeleteRMHandle();
  155. // Helper to notify the RM that
  156. // we are now dirty.
  157. void OnResourceDirty();
  158. // Helper to notify resource when it
  159. // is all clean
  160. void OnResourceClean();
  161. // Resources need to implement OnDestroy by
  162. // calling Sync; (Textures overload this
  163. // to call OnTextureDestroy on the device before
  164. // calling their base class.)
  165. virtual void OnDestroy(void)
  166. {
  167. Sync();
  168. return;
  169. } // OnDestroy
  170. // Returns the current priority
  171. DWORD GetPriorityI() const
  172. {
  173. return m_Priority;
  174. }
  175. // Sets the current priority (but does not do any work)
  176. DWORD SetPriorityI(DWORD Priority)
  177. {
  178. DWORD oldPriority = m_Priority;
  179. m_Priority = Priority;
  180. return oldPriority;
  181. }
  182. private:
  183. RMHANDLE m_RMHandle;
  184. ULONGLONG m_qwBatchCount;
  185. DWORD m_Priority;
  186. BOOL m_bIsDirty;
  187. // Remember the pool that the user passed in
  188. D3DPOOL m_poolUser;
  189. // Linked list of resources
  190. CResource *m_pPrev;
  191. CResource *m_pNext;
  192. friend CResourceManager;
  193. }; // CResource
  194. struct CMgmtInfo
  195. {
  196. // This is static because we assume all resources
  197. // to be in heap zero. WHEN the resource manager
  198. // supports multiple heaps, m_rmHeap should be
  199. // made per object again.
  200. static DWORD m_rmHeap;
  201. DWORD m_priority;
  202. DWORD m_LOD;
  203. BOOL m_bInUse;
  204. DWORD m_rmHeapIndex;
  205. DWORD m_scene;
  206. DWORD m_ticks;
  207. CResource *m_pRes;
  208. CResource *m_pBackup;
  209. CMgmtInfo(CResource*);
  210. ~CMgmtInfo();
  211. ULONGLONG Cost() const
  212. {
  213. #ifdef _X86_
  214. ULONGLONG retval;
  215. _asm
  216. {
  217. mov ebx, this;
  218. mov edx, [ebx]CMgmtInfo.m_bInUse;
  219. shl edx, 31;
  220. mov eax, [ebx]CMgmtInfo.m_priority;
  221. mov ecx, eax;
  222. shr eax, 1;
  223. or edx, eax;
  224. mov DWORD PTR retval + 4, edx;
  225. shl ecx, 31;
  226. mov eax, [ebx]CMgmtInfo.m_ticks;
  227. shr eax, 1;
  228. or eax, ecx;
  229. mov DWORD PTR retval, eax;
  230. }
  231. return retval;
  232. #else
  233. return ((ULONGLONG)m_bInUse << 63) + ((ULONGLONG)m_priority << 31) + ((ULONGLONG)(m_ticks >> 1));
  234. #endif
  235. }
  236. }; // CMgmtInfo
  237. inline CMgmtInfo::CMgmtInfo(CResource *pBackup)
  238. {
  239. m_priority = 0;
  240. m_LOD = 0;
  241. m_bInUse = FALSE;
  242. m_rmHeap = 0;
  243. m_rmHeapIndex = 0;
  244. m_scene = 0;
  245. m_ticks = 0;
  246. m_pRes = 0;
  247. m_pBackup = pBackup;
  248. } // CMgmtInfo::CMgmtInfo
  249. inline CMgmtInfo::~CMgmtInfo()
  250. {
  251. if (m_pRes != 0)
  252. {
  253. m_pRes->DecrementUseCount();
  254. }
  255. } // CMgmtInfo::~CMgmtInfo
  256. class CRMHeap
  257. {
  258. private:
  259. enum { InitialSize = 1023 };
  260. DWORD m_next, m_size;
  261. CMgmtInfo **m_data_p;
  262. DWORD parent(DWORD k) const { return k / 2; }
  263. DWORD lchild(DWORD k) const { return k * 2; }
  264. DWORD rchild(DWORD k) const { return k * 2 + 1; }
  265. void heapify(DWORD k);
  266. public:
  267. CRMHeap(DWORD size = InitialSize);
  268. ~CRMHeap();
  269. BOOL Initialize();
  270. DWORD length() const { return m_next - 1; }
  271. CMgmtInfo* minCost() const { return m_data_p[1]; }
  272. BOOL add(CMgmtInfo*);
  273. CMgmtInfo* extractMin();
  274. CMgmtInfo* extractMax();
  275. CMgmtInfo* extractNotInScene(DWORD dwScene);
  276. void del(CMgmtInfo*);
  277. void update(CMgmtInfo*, BOOL inuse, DWORD priority, DWORD ticks);
  278. void resetAllTimeStamps(DWORD ticks);
  279. }; // class CRMHeap
  280. inline CRMHeap::CRMHeap(DWORD size)
  281. {
  282. m_next = 1;
  283. m_size = size + 1;
  284. } // CRMHeap::CRMHeap
  285. inline CRMHeap::~CRMHeap()
  286. {
  287. delete[] m_data_p;
  288. } // CRMHeap::~CRMHeap
  289. class CResourceManager
  290. {
  291. public:
  292. CResourceManager();
  293. ~CResourceManager();
  294. // Need to call before using the manager
  295. HRESULT Init(CBaseDevice *pD3D8);
  296. // Check to see if a type is going to driver managed
  297. // or going to be D3D managed
  298. BOOL IsDriverManaged(D3DRESOURCETYPE Type) const;
  299. // Specify that a resource needs to be managed
  300. //
  301. // Error indicates that we don't support management for this
  302. // resource type.
  303. HRESULT Manage(CResource *pResource, RMHANDLE *pHandle);
  304. // Stop managing a resouce; called when a managed resource
  305. // is going away
  306. void UnManage(RMHANDLE hRMHandle);
  307. // The RM manages Priority and LOD for the resource
  308. DWORD SetPriority(RMHANDLE hRMHandle, DWORD newPriority);
  309. DWORD SetLOD(RMHANDLE hRMHandle, DWORD dwLodNew);
  310. // Preloads resource into video memory
  311. void PreLoad(RMHANDLE hRMHandle);
  312. // Checks if the resource is in video memory
  313. BOOL InVidmem(RMHANDLE hRMHandle) const;
  314. // This is called when DrawPrimitive needs to
  315. // make sure that all resources used in the
  316. // current call are in video memory and are
  317. // uptodate.
  318. HRESULT UpdateVideo(RMHANDLE hRMHandle, BOOL *bDirty);
  319. HRESULT UpdateVideoInternal(CMgmtInfo *pMgmtInfo);
  320. // This returns the appropriate handle for a
  321. // managed resource
  322. DWORD DrawPrimHandle(RMHANDLE hRMHandle) const;
  323. // This returns the appropriate kernel handle for a
  324. // managed resource
  325. HANDLE KernelHandle(RMHANDLE hRMHandle) const;
  326. // This call will batch the appropriate resource
  327. // for the purpose of syncing
  328. void Batch(RMHANDLE hRMHandle, ULONGLONG batch) const;
  329. // Called from outside when a managed resource becomes dirty
  330. void OnResourceDirty(RMHANDLE hRMHandle) const;
  331. void DiscardBytes(DWORD cbBytes);
  332. void SceneStamp() { ++m_dwScene; }
  333. private:
  334. CBaseDevice *m_pD3D8;
  335. unsigned tcm_ticks, m_dwScene, m_dwNumHeaps;
  336. BOOL m_PreLoading;
  337. CRMHeap *m_heap_p;
  338. BOOL FreeResources(DWORD dwHeap, DWORD dwBytes);
  339. void Lock(RMHANDLE hRMHandle);
  340. void Unlock(RMHANDLE hRMHandle);
  341. void TimeStamp(CMgmtInfo *pMgmtInfo);
  342. }; // class CResourceManager
  343. #undef DPF_MODNAME
  344. #define DPF_MODNAME "CResource::IsTypeD3DManaged"
  345. inline BOOL CResource::IsTypeD3DManaged(CBaseDevice *pDevice,
  346. D3DRESOURCETYPE Type,
  347. D3DPOOL Pool)
  348. {
  349. if (Pool == D3DPOOL_MANAGED)
  350. {
  351. return !IsTypeDriverManaged(pDevice, Type, Pool);
  352. }
  353. else
  354. {
  355. return FALSE;
  356. }
  357. }; // IsTypeD3DManaged
  358. #undef DPF_MODNAME
  359. #define DPF_MODNAME "CResource::IsTypeDriverManaged"
  360. inline BOOL CResource::IsTypeDriverManaged(CBaseDevice *pDevice,
  361. D3DRESOURCETYPE Type,
  362. D3DPOOL Pool)
  363. {
  364. if (Pool == D3DPOOL_MANAGED)
  365. {
  366. if (pDevice->ResourceManager()->IsDriverManaged(Type))
  367. {
  368. return TRUE;
  369. }
  370. }
  371. return FALSE;
  372. }; // IsTypeDriverManaged
  373. #undef DPF_MODNAME
  374. #define DPF_MODNAME "CResource::DetermineCreationPool"
  375. inline D3DPOOL CResource::DetermineCreationPool(CBaseDevice *pDevice,
  376. D3DRESOURCETYPE Type,
  377. DWORD dwUsage,
  378. D3DPOOL Pool)
  379. {
  380. if (Pool == D3DPOOL_MANAGED)
  381. {
  382. if (IsTypeDriverManaged(pDevice, Type, Pool))
  383. {
  384. // This pool is used by the thunk layer
  385. // to use the driver management flag during
  386. // create
  387. return D3DPOOL_MANAGED;
  388. }
  389. else
  390. {
  391. // If it is not driver managed; then it
  392. // becomes D3DMANAGED
  393. return D3DPOOL_SYSTEMMEM;
  394. }
  395. }
  396. else
  397. {
  398. // Not managed at all; so we just
  399. // use the same pool we started with
  400. return Pool;
  401. }
  402. } // DetermineCreationPool
  403. #undef DPF_MODNAME
  404. #define DPF_MODNAME "CResource::~CResource"
  405. inline CResource::~CResource()
  406. {
  407. // If managed, we need to notify
  408. // the ResourceManager that we are going away
  409. if (IsD3DManaged())
  410. {
  411. Device()->ResourceManager()->UnManage(m_RMHandle);
  412. }
  413. // Unlink from the resource list
  414. if (m_pNext != 0)
  415. {
  416. m_pNext->m_pPrev = m_pPrev;
  417. }
  418. if (m_pPrev != 0)
  419. {
  420. m_pPrev->m_pNext = m_pNext;
  421. DXGASSERT(Device()->GetResourceList() != this);
  422. }
  423. else
  424. {
  425. DXGASSERT(Device()->GetResourceList() == this);
  426. Device()->SetResourceList(m_pNext);
  427. }
  428. }; // ~CResource
  429. #undef DPF_MODNAME
  430. #define DPF_MODNAME "CResource::InitializeRMHandle"
  431. // Allows initialization of the RMHandle after
  432. // construction is basically complete
  433. inline HRESULT CResource::InitializeRMHandle()
  434. {
  435. // We should not already have a handle
  436. DXGASSERT(m_RMHandle == 0);
  437. // Get a handle from the resource manager
  438. return Device()->ResourceManager()->Manage(this, &m_RMHandle);
  439. }; // InitializeRMHandle
  440. #undef DPF_MODNAME
  441. #define DPF_MODNAME "CResource::DeleteRMHandle"
  442. inline void CResource::DeleteRMHandle()
  443. {
  444. // We should already have a handle
  445. DXGASSERT(m_RMHandle != 0);
  446. Device()->ResourceManager()->UnManage(m_RMHandle);
  447. m_RMHandle = 0;
  448. }
  449. #undef DPF_MODNAME
  450. #define DPF_MODNAME "CResource::OnResourceDirty"
  451. // Add a helper to notify the RM that
  452. // we are now dirty.
  453. inline void CResource::OnResourceDirty()
  454. {
  455. // Update our state
  456. m_bIsDirty = TRUE;
  457. // Only need to notify RM for managed textures
  458. // that have been been set through SetTexture
  459. if (IsD3DManaged() && IsInUse())
  460. {
  461. Device()->ResourceManager()->OnResourceDirty(m_RMHandle);
  462. }
  463. return;
  464. }; // OnResourceDirty
  465. #undef DPF_MODNAME
  466. #define DPF_MODNAME "CResource::OnResourceClean"
  467. // Add a helper to help maintain m_bIsDirty bit
  468. inline void CResource::OnResourceClean()
  469. {
  470. DXGASSERT(m_bIsDirty == TRUE);
  471. m_bIsDirty = FALSE;
  472. return;
  473. }; // OnResourceDirty
  474. #undef DPF_MODNAME
  475. #define DPF_MODNAME "CResource::DriverAccessibleDrawPrimHandle"
  476. inline DWORD CResource::DriverAccessibleDrawPrimHandle() const
  477. {
  478. if (IsD3DManaged())
  479. {
  480. // Return the DrawPrim handle of my clone
  481. return Device()->ResourceManager()->DrawPrimHandle(RMHandle());
  482. }
  483. else
  484. {
  485. return BaseDrawPrimHandle();
  486. }
  487. } // CResource::DriverAccessibleDrawPrimHandle
  488. #undef DPF_MODNAME
  489. #define DPF_MODNAME "CResource::DriverAccessibleKernelHandle"
  490. inline HANDLE CResource::DriverAccessibleKernelHandle() const
  491. {
  492. if (IsD3DManaged())
  493. {
  494. // Return the DrawPrim handle of my clone
  495. HANDLE h = Device()->ResourceManager()->KernelHandle(RMHandle());
  496. // If this handle is NULL, then it means it was called
  497. // without calling UpdateVideo which isn't allowed/sane
  498. DXGASSERT(h != NULL);
  499. return h;
  500. }
  501. else
  502. {
  503. return BaseKernelHandle();
  504. }
  505. } // CResource::DriverAccessibleKernelHandle
  506. #undef DPF_MODNAME
  507. #define DPF_MODNAME "CResourceManager::CResourceManager"
  508. inline CResourceManager::CResourceManager()
  509. {
  510. m_pD3D8 = 0;
  511. tcm_ticks = m_dwScene = m_dwNumHeaps = 0;
  512. m_heap_p = 0;
  513. m_PreLoading = FALSE;
  514. } // CResourceManager::CResourceManager
  515. #undef DPF_MODNAME
  516. #define DPF_MODNAME "CResourceManager::~CResourceManager"
  517. inline CResourceManager::~CResourceManager()
  518. {
  519. // We should not call DiscardBytes here
  520. // because this destructor can be called via
  521. // the device destructor chain. In this situation
  522. // DiscardBytes will access bad or already freed
  523. // data.
  524. delete[] m_heap_p;
  525. } // CResourceManager::~CResourceManager
  526. #undef DPF_MODNAME
  527. #define DPF_MODNAME "CResourceManager::DrawPrimHandle"
  528. inline DWORD CResourceManager::DrawPrimHandle(RMHANDLE hRMHandle) const
  529. {
  530. if (InVidmem(hRMHandle))
  531. {
  532. CMgmtInfo* &pMgmtInfo = hRMHandle;
  533. return pMgmtInfo->m_pRes->BaseDrawPrimHandle();
  534. }
  535. else
  536. {
  537. return 0;
  538. }
  539. } // CResourceManager::DrawPrimHandle
  540. #undef DPF_MODNAME
  541. #define DPF_MODNAME "CResourceManager::KernelHandle"
  542. inline HANDLE CResourceManager::KernelHandle(RMHANDLE hRMHandle) const
  543. {
  544. if (InVidmem(hRMHandle))
  545. {
  546. CMgmtInfo* &pMgmtInfo = hRMHandle;
  547. return pMgmtInfo->m_pRes->BaseKernelHandle();
  548. }
  549. else
  550. {
  551. return 0;
  552. }
  553. } // CResourceManager::Kernelhandle
  554. #undef DPF_MODNAME
  555. #define DPF_MODNAME "CResourceManager::InVidmem"
  556. inline BOOL CResourceManager::InVidmem(RMHANDLE hRMHandle) const
  557. {
  558. CMgmtInfo* &pMgmtInfo = hRMHandle;
  559. DXGASSERT(pMgmtInfo != 0);
  560. return pMgmtInfo->m_pRes != 0;
  561. } // CResourceManager::InVidmem
  562. #undef DPF_MODNAME
  563. #define DPF_MODNAME "CResourceManager::Batch"
  564. inline void CResourceManager::Batch(RMHANDLE hRMHandle, ULONGLONG batch) const
  565. {
  566. if (InVidmem(hRMHandle))
  567. {
  568. CMgmtInfo* &pMgmtInfo = hRMHandle;
  569. pMgmtInfo->m_pRes->SetBatchNumber(batch);
  570. }
  571. } // CResourceManager::Batch
  572. #undef DPF_MODNAME
  573. #define DPF_MODNAME "CResourceManager::UpdateVideo"
  574. inline HRESULT CResourceManager::UpdateVideo(RMHANDLE hRMHandle, BOOL *bDirty)
  575. {
  576. HRESULT ddrval = S_OK;
  577. CMgmtInfo* &pMgmtInfo = hRMHandle;
  578. if (!InVidmem(hRMHandle))
  579. {
  580. ddrval = UpdateVideoInternal(pMgmtInfo);
  581. *bDirty = TRUE;
  582. }
  583. else
  584. {
  585. if (pMgmtInfo->m_pBackup->IsDirty())
  586. {
  587. ddrval = pMgmtInfo->m_pBackup->UpdateDirtyPortion(pMgmtInfo->m_pRes);
  588. }
  589. TimeStamp(pMgmtInfo);
  590. }
  591. return ddrval;
  592. }
  593. #endif // __RESOURCE_HPP__