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.

905 lines
27 KiB

  1. /*==========================================================================;
  2. *
  3. * Copyright (C) 1999-2000 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: rman.cpp
  6. * Content: Resource management
  7. *
  8. ***************************************************************************/
  9. #include "ddrawpr.h"
  10. #include "dxgint.h"
  11. #include "resource.hpp"
  12. #include "texture.hpp"
  13. #include "d3di.hpp"
  14. #include "ddi.h"
  15. // Always use heap 0
  16. DWORD CMgmtInfo::m_rmHeap = 0;
  17. #undef DPF_MODNAME
  18. #define DPF_MODNAME "CResource::UpdateDirtyPortion"
  19. // These stub functions are only supported for managed resources;
  20. // they should never get called; the asserts are there to help
  21. // determine where the bug is if they do get called.
  22. HRESULT CResource::UpdateDirtyPortion(CResource *pResourceTarget)
  23. {
  24. // This should not be called except for D3D_MANAGED
  25. // objects because we don't keep dirty portion records
  26. // for other kinds of objects.
  27. // If we were D3D_MANAGED: the real class should have
  28. // overriden this method
  29. DXGASSERT(!IsTypeD3DManaged(Device(),
  30. GetBufferDesc()->Type,
  31. GetBufferDesc()->Pool));
  32. // If this isn't D3DManaged, we shouldn't have
  33. // been called.
  34. DXGASSERT(FALSE);
  35. // return something benign for retail build
  36. return S_OK;
  37. }
  38. #undef DPF_MODNAME
  39. #define DPF_MODNAME "CResource::MarkAllDirty"
  40. void CResource::MarkAllDirty()
  41. {
  42. // This should not be called except for D3D_MANAGED
  43. // objects because we don't keep dirty portion records
  44. // for other kinds of objects.
  45. // If we were D3D_MANAGED: the real class should have
  46. // overriden this method
  47. DXGASSERT(!IsTypeD3DManaged(Device(),
  48. GetBufferDesc()->Type,
  49. GetBufferDesc()->Pool));
  50. // If this isn't D3DManaged, we shouldn't have
  51. // been called.
  52. DXGASSERT(FALSE);
  53. } // CResource::MarkAllDirty
  54. #undef DPF_MODNAME
  55. #define DPF_MODNAME "CResource::SetPriorityImpl"
  56. DWORD CResource::SetPriorityImpl(DWORD newPri)
  57. {
  58. DWORD oldPriority = 0;
  59. if (IsD3DManaged())
  60. {
  61. oldPriority = Device()->ResourceManager()->SetPriority(m_RMHandle, newPri);
  62. }
  63. // If IsD3DManaged() is FALSE and if the actual pool
  64. // is found to be D3DPOOL_MANAGED then the resource
  65. // MUST be driver managed.
  66. else if (GetBufferDesc()->Pool == D3DPOOL_MANAGED)
  67. {
  68. CD3DBase *pDev = static_cast<CD3DBase*>(Device());
  69. DXGASSERT(IS_DX8HAL_DEVICE(pDev));
  70. oldPriority = SetPriorityI(newPri);
  71. pDev->SetPriority(this, newPri);
  72. }
  73. // If above two conditions are false, then we must
  74. // check if we have fallen back to sysmem for some
  75. // reason even if the app requested managed. We
  76. // can know whether the app requested D3DPOOL_MANAGED
  77. // by calling GetUserPool().
  78. else if (GetUserPool() == D3DPOOL_MANAGED)
  79. {
  80. // We assert because sysmem fallback is currently
  81. // possible for only vertex or index buffers.
  82. DXGASSERT(GetBufferDesc()->Type == D3DRTYPE_VERTEXBUFFER ||
  83. GetBufferDesc()->Type == D3DRTYPE_INDEXBUFFER);
  84. // No need to do any real work since the
  85. // resource is in sysmem in any case.
  86. oldPriority = SetPriorityI(newPri);
  87. }
  88. else
  89. {
  90. DPF_ERR("Priority set on non-managed object. SetPriority returns zero.");
  91. }
  92. return oldPriority;
  93. } // SetPriorityImpl
  94. #undef DPF_MODNAME
  95. #define DPF_MODNAME "CResource::GetPriorityImpl"
  96. DWORD CResource::GetPriorityImpl()
  97. {
  98. if (!IsD3DManaged() && GetBufferDesc()->Pool != D3DPOOL_MANAGED && GetUserPool() != D3DPOOL_MANAGED)
  99. {
  100. DPF_ERR("Priority accessed on non-managed object. GetPriority returns zero.");
  101. return 0;
  102. }
  103. return GetPriorityI();
  104. } // GetPriorityImpl
  105. #undef DPF_MODNAME
  106. #define DPF_MODNAME "CResource::PreLoadImpl"
  107. void CResource::PreLoadImpl()
  108. {
  109. if (IsD3DManaged())
  110. {
  111. Device()->ResourceManager()->PreLoad(m_RMHandle);
  112. }
  113. // If IsD3DManaged() is FALSE and if the actual pool
  114. // is found to be D3DPOOL_MANAGED then the resource
  115. // MUST be driver managed.
  116. else if (GetBufferDesc()->Pool == D3DPOOL_MANAGED)
  117. {
  118. CD3DBase *pDev = static_cast<CD3DBase*>(Device());
  119. DXGASSERT(IS_DX8HAL_DEVICE(pDev));
  120. if(GetBufferDesc()->Type == D3DRTYPE_TEXTURE ||
  121. GetBufferDesc()->Type == D3DRTYPE_VOLUMETEXTURE ||
  122. GetBufferDesc()->Type == D3DRTYPE_CUBETEXTURE)
  123. {
  124. POINT p = {0, 0};
  125. RECTL r = {0, 0, 0, 0};
  126. pDev->TexBlt(0,
  127. static_cast<CBaseTexture*>(this),
  128. &p,
  129. &r);
  130. }
  131. else
  132. {
  133. DXGASSERT(GetBufferDesc()->Type == D3DRTYPE_VERTEXBUFFER ||
  134. GetBufferDesc()->Type == D3DRTYPE_INDEXBUFFER);
  135. D3DRANGE range = {0, 0};
  136. pDev->BufBlt(0,
  137. static_cast<CBuffer*>(this),
  138. 0,
  139. &range);
  140. }
  141. }
  142. // If above two conditions are false, then we must
  143. // check if we have fallen back to sysmem for some
  144. // reason even if the app requested managed. We
  145. // can know whether the app requested D3DPOOL_MANAGED
  146. // by calling GetUserPool().
  147. else if (GetUserPool() == D3DPOOL_MANAGED)
  148. {
  149. // We assert because sysmem fallback is currently
  150. // possible for only vertex or index buffers.
  151. DXGASSERT(GetBufferDesc()->Type == D3DRTYPE_VERTEXBUFFER ||
  152. GetBufferDesc()->Type == D3DRTYPE_INDEXBUFFER);
  153. // Do nothing since vertex/index buffer are in sysmem
  154. // and preload has no meaning
  155. }
  156. else
  157. {
  158. DPF_ERR("PreLoad called on non-managed object");
  159. }
  160. } // PreLoadImpl
  161. #undef DPF_MODNAME
  162. #define DPF_MODNAME "CResource::RestoreDriverManagementState"
  163. HRESULT CResource::RestoreDriverManagementState(CBaseDevice *pDevice)
  164. {
  165. for(CResource *pRes = pDevice->GetResourceList(); pRes != 0; pRes = pRes->m_pNext)
  166. {
  167. if (pRes->GetBufferDesc()->Pool == D3DPOOL_MANAGED && !pRes->IsD3DManaged()) // Must be driver managed
  168. {
  169. static_cast<CD3DBase*>(pDevice)->SetPriority(pRes, pRes->GetPriorityI());
  170. if (pRes->GetBufferDesc()->Type == D3DRTYPE_TEXTURE ||
  171. pRes->GetBufferDesc()->Type == D3DRTYPE_VOLUMETEXTURE ||
  172. pRes->GetBufferDesc()->Type == D3DRTYPE_CUBETEXTURE)
  173. {
  174. static_cast<CD3DBase*>(pDevice)->SetTexLOD(static_cast<CBaseTexture*>(pRes),
  175. static_cast<CBaseTexture*>(pRes)->GetLODI());
  176. }
  177. // We need to update cached pointers for read/write vertex and index buffers
  178. else if (pRes->GetBufferDesc()->Type == D3DRTYPE_VERTEXBUFFER &&
  179. (pRes->GetBufferDesc()->Usage & D3DUSAGE_WRITEONLY) == 0)
  180. {
  181. HRESULT hr = static_cast<CDriverManagedVertexBuffer*>(pRes)->UpdateCachedPointer(pDevice);
  182. if (FAILED(hr))
  183. {
  184. return hr;
  185. }
  186. }
  187. else if (pRes->GetBufferDesc()->Type == D3DRTYPE_INDEXBUFFER &&
  188. (pRes->GetBufferDesc()->Usage & D3DUSAGE_WRITEONLY) == 0)
  189. {
  190. HRESULT hr = static_cast<CDriverManagedIndexBuffer*>(pRes)->UpdateCachedPointer(pDevice);
  191. if (FAILED(hr))
  192. {
  193. return hr;
  194. }
  195. }
  196. }
  197. }
  198. return S_OK;
  199. } // RestoreDriverManagementState
  200. #undef DPF_MODNAME
  201. #define DPF_MODNAME "CRMHeap::Initialize"
  202. BOOL CRMHeap::Initialize()
  203. {
  204. m_data_p = new CMgmtInfo*[m_size];
  205. if (m_data_p == 0)
  206. {
  207. DPF_ERR("Failed to allocate texture heap.");
  208. return FALSE;
  209. }
  210. memset(m_data_p, 0, sizeof(CMgmtInfo*) * m_size);
  211. return TRUE;
  212. } // CRMHeap::Initialize
  213. #undef DPF_MODNAME
  214. #define DPF_MODNAME "CRMHeap::heapify"
  215. void CRMHeap::heapify(DWORD k)
  216. {
  217. while(TRUE)
  218. {
  219. DWORD smallest;
  220. DWORD l = lchild(k);
  221. DWORD r = rchild(k);
  222. if (l < m_next)
  223. if (m_data_p[l]->Cost() < m_data_p[k]->Cost())
  224. smallest = l;
  225. else
  226. smallest = k;
  227. else
  228. smallest = k;
  229. if (r < m_next)
  230. if (m_data_p[r]->Cost() < m_data_p[smallest]->Cost())
  231. smallest = r;
  232. if (smallest != k)
  233. {
  234. CMgmtInfo *t = m_data_p[k];
  235. m_data_p[k] = m_data_p[smallest];
  236. m_data_p[k]->m_rmHeapIndex = k;
  237. m_data_p[smallest] = t;
  238. m_data_p[smallest]->m_rmHeapIndex = smallest;
  239. k = smallest;
  240. }
  241. else
  242. break;
  243. }
  244. } // CRMHeap::heapify
  245. #undef DPF_MODNAME
  246. #define DPF_MODNAME "CRMHeap::add"
  247. BOOL CRMHeap::add(CMgmtInfo *pMgmtInfo)
  248. {
  249. DXGASSERT(pMgmtInfo->m_rmHeapIndex == 0);
  250. if (m_next == m_size)
  251. {
  252. m_size = m_size * 2 - 1;
  253. CMgmtInfo **p = new CMgmtInfo*[m_size];
  254. if (p == 0)
  255. {
  256. DPF_ERR("Failed to allocate memory to grow heap.");
  257. m_size = (m_size + 1) / 2; // restore size
  258. return FALSE;
  259. }
  260. memcpy(p + 1, m_data_p + 1, sizeof(CMgmtInfo*) * (m_next - 1));
  261. delete[] m_data_p;
  262. m_data_p = p;
  263. }
  264. ULONGLONG Cost = pMgmtInfo->Cost();
  265. for (DWORD k = m_next; k > 1; k = parent(k))
  266. if (Cost < m_data_p[parent(k)]->Cost())
  267. {
  268. m_data_p[k] = m_data_p[parent(k)];
  269. m_data_p[k]->m_rmHeapIndex = k;
  270. }
  271. else
  272. break;
  273. m_data_p[k] = pMgmtInfo;
  274. m_data_p[k]->m_rmHeapIndex = k;
  275. ++m_next;
  276. return TRUE;
  277. } // CRMHeap::add
  278. #undef DPF_MODNAME
  279. #define DPF_MODNAME "CRMHeap::extractMin"
  280. CMgmtInfo* CRMHeap::extractMin()
  281. {
  282. CMgmtInfo *pMgmtInfo = m_data_p[1];
  283. --m_next;
  284. m_data_p[1] = m_data_p[m_next];
  285. m_data_p[1]->m_rmHeapIndex = 1;
  286. heapify(1);
  287. pMgmtInfo->m_rmHeapIndex = 0;
  288. return pMgmtInfo;
  289. } // CRMHeap::extractMin
  290. #undef DPF_MODNAME
  291. #define DPF_MODNAME "CRMHeap::extractMax"
  292. CMgmtInfo* CRMHeap::extractMax()
  293. {
  294. // When extracting the max element from the heap, we don't need to
  295. // search the entire heap, but just the leafnodes. This is because
  296. // it is guaranteed that parent nodes are cheaper than the leaf nodes
  297. // so once you have looked through the leaves, you won't find anything
  298. // cheaper.
  299. // NOTE: (lchild(i) >= m_next) is TRUE only for leaf nodes.
  300. // ALSO NOTE: You cannot have a rchild without a lchild, so simply
  301. // checking for lchild is sufficient.
  302. //
  303. // CONSIDER(40358): Should have asserts to verify above assumptions; but
  304. // it would require writing a heap-consistency
  305. // checker. Maybe someday.
  306. //
  307. unsigned max = m_next - 1;
  308. ULONGLONG maxcost = 0;
  309. for (unsigned i = max; lchild(i) >= m_next; --i)
  310. {
  311. ULONGLONG Cost = m_data_p[i]->Cost();
  312. if (maxcost < Cost)
  313. {
  314. maxcost = Cost;
  315. max = i;
  316. }
  317. }
  318. CMgmtInfo* pMgmtInfo = m_data_p[max];
  319. if (pMgmtInfo->m_bInUse)
  320. {
  321. max = 0;
  322. maxcost = 0;
  323. for (i = m_next - 1; i > 0; --i)
  324. {
  325. ULONGLONG Cost = m_data_p[i]->Cost();
  326. if (maxcost < Cost && !m_data_p[i]->m_bInUse)
  327. {
  328. maxcost = Cost;
  329. max = i;
  330. }
  331. }
  332. if (max == 0) // All textures in use
  333. return 0;
  334. pMgmtInfo = m_data_p[max];
  335. }
  336. del(m_data_p[max]);
  337. return pMgmtInfo;
  338. } // CRMHeap::extractMax
  339. #undef DPF_MODNAME
  340. #define DPF_MODNAME "CRMHeap::extractNotInScene"
  341. CMgmtInfo* CRMHeap::extractNotInScene(DWORD dwScene)
  342. {
  343. for (unsigned i = 1; i < m_next; ++i)
  344. {
  345. if (m_data_p[i]->m_scene != dwScene)
  346. {
  347. CMgmtInfo* pMgmtInfo = m_data_p[i];
  348. del(m_data_p[i]);
  349. return pMgmtInfo;
  350. }
  351. }
  352. return 0;
  353. } // CRMHeap::extractNotInScene
  354. #undef DPF_MODNAME
  355. #define DPF_MODNAME "CRMHeap::del"
  356. void CRMHeap::del(CMgmtInfo* pMgmtInfo)
  357. {
  358. DWORD k = pMgmtInfo->m_rmHeapIndex;
  359. --m_next;
  360. ULONGLONG Cost = m_data_p[m_next]->Cost();
  361. if (Cost < pMgmtInfo->Cost())
  362. {
  363. while(k > 1)
  364. {
  365. if (Cost < m_data_p[parent(k)]->Cost())
  366. {
  367. m_data_p[k] = m_data_p[parent(k)];
  368. m_data_p[k]->m_rmHeapIndex = k;
  369. }
  370. else
  371. break;
  372. k = parent(k);
  373. }
  374. m_data_p[k] = m_data_p[m_next];
  375. m_data_p[k]->m_rmHeapIndex = k;
  376. }
  377. else
  378. {
  379. m_data_p[k] = m_data_p[m_next];
  380. m_data_p[k]->m_rmHeapIndex = k;
  381. heapify(k);
  382. }
  383. pMgmtInfo->m_rmHeapIndex = 0;
  384. } // CRMHeap::del
  385. #undef DPF_MODNAME
  386. #define DPF_MODNAME "CRMHeap::update"
  387. void CRMHeap::update(CMgmtInfo* pMgmtInfo, BOOL inuse, DWORD priority, DWORD ticks)
  388. {
  389. DWORD k = pMgmtInfo->m_rmHeapIndex;
  390. ULONGLONG Cost;
  391. #ifdef _X86_
  392. _asm
  393. {
  394. mov edx, inuse;
  395. shl edx, 31;
  396. mov eax, priority;
  397. mov ecx, eax;
  398. shr eax, 1;
  399. or edx, eax;
  400. mov DWORD PTR Cost + 4, edx;
  401. shl ecx, 31;
  402. mov eax, ticks;
  403. shr eax, 1;
  404. or eax, ecx;
  405. mov DWORD PTR Cost, eax;
  406. }
  407. #else
  408. Cost = ((ULONGLONG)inuse << 63) + ((ULONGLONG)priority << 31) + ((ULONGLONG)(ticks >> 1));
  409. #endif
  410. if (Cost < pMgmtInfo->Cost())
  411. {
  412. while(k > 1)
  413. {
  414. if (Cost < m_data_p[parent(k)]->Cost())
  415. {
  416. m_data_p[k] = m_data_p[parent(k)];
  417. m_data_p[k]->m_rmHeapIndex = k;
  418. }
  419. else
  420. break;
  421. k = parent(k);
  422. }
  423. pMgmtInfo->m_bInUse = inuse;
  424. pMgmtInfo->m_priority = priority;
  425. pMgmtInfo->m_ticks = ticks;
  426. pMgmtInfo->m_rmHeapIndex = k;
  427. m_data_p[k] = pMgmtInfo;
  428. }
  429. else
  430. {
  431. pMgmtInfo->m_bInUse = inuse;
  432. pMgmtInfo->m_priority = priority;
  433. pMgmtInfo->m_ticks = ticks;
  434. heapify(k);
  435. }
  436. } // CRMHeap::update
  437. #undef DPF_MODNAME
  438. #define DPF_MODNAME "CRMHeap::resetAllTimeStamps"
  439. void CRMHeap::resetAllTimeStamps(DWORD ticks)
  440. {
  441. for (unsigned i = 1; i < m_next; ++i)
  442. {
  443. update(m_data_p[i], m_data_p[i]->m_bInUse, m_data_p[i]->m_priority, ticks);
  444. }
  445. } // CRMHeap::resetAllTimeStamps
  446. #undef DPF_MODNAME
  447. #define DPF_MODNAME "CResourceManager::Init"
  448. HRESULT CResourceManager::Init(CBaseDevice *pD3D8)
  449. {
  450. const D3DCAPS8* pCaps = pD3D8->GetD3DCaps();
  451. if (pCaps != 0)
  452. if (pCaps->DevCaps & D3DDEVCAPS_SEPARATETEXTUREMEMORIES)
  453. {
  454. m_dwNumHeaps = pD3D8->GetD3DCaps()->MaxSimultaneousTextures;
  455. if (m_dwNumHeaps < 1)
  456. {
  457. DPF_ERR("Max simultaneous textures not set. Forced to 1.");
  458. m_dwNumHeaps = 1;
  459. }
  460. DPF(2, "Number of heaps set to %u.", m_dwNumHeaps);
  461. }
  462. else
  463. m_dwNumHeaps = 1;
  464. else
  465. m_dwNumHeaps = 1;
  466. m_heap_p = new CRMHeap[m_dwNumHeaps];
  467. if (m_heap_p == 0)
  468. {
  469. DPF_ERR("Out of memory allocating texture heap.");
  470. return E_OUTOFMEMORY;
  471. }
  472. for (DWORD i = 0; i < m_dwNumHeaps; ++i)
  473. {
  474. if (m_heap_p[i].Initialize() == FALSE)
  475. {
  476. delete[] m_heap_p;
  477. m_heap_p = 0;
  478. return E_OUTOFMEMORY;
  479. }
  480. }
  481. m_pD3D8 = pD3D8;
  482. return S_OK;
  483. } // CResourceManager::Init
  484. #undef DPF_MODNAME
  485. #define DPF_MODNAME "CResourceManager::IsDriverManaged"
  486. BOOL CResourceManager::IsDriverManaged(D3DRESOURCETYPE Type) const
  487. {
  488. #if DBG
  489. switch (Type)
  490. {
  491. case D3DRTYPE_TEXTURE:
  492. case D3DRTYPE_VOLUMETEXTURE:
  493. case D3DRTYPE_CUBETEXTURE:
  494. case D3DRTYPE_VERTEXBUFFER:
  495. case D3DRTYPE_INDEXBUFFER:
  496. break;
  497. default:
  498. DXGASSERT(FALSE && "Management not supported for this type");
  499. return FALSE;
  500. };
  501. #endif // DBG
  502. return m_pD3D8->CanDriverManageResource();
  503. }; // IsDriverManaged(D3DRESOURCETYPE)
  504. #undef DPF_MODNAME
  505. #define DPF_MODNAME "CResourceManager::Manage"
  506. HRESULT CResourceManager::Manage(CResource *pResource, RMHANDLE *pHandle)
  507. {
  508. *pHandle = 0;
  509. DXGASSERT(!pResource->IsD3DManaged());
  510. CMgmtInfo *pRMInfo = new CMgmtInfo(pResource);
  511. if (pRMInfo == 0)
  512. {
  513. return E_OUTOFMEMORY;
  514. }
  515. *pHandle = pRMInfo;
  516. return S_OK;
  517. } // CResourceManager::Manage
  518. #undef DPF_MODNAME
  519. #define DPF_MODNAME "CResourceManager::UnManage"
  520. void CResourceManager::UnManage(RMHANDLE hRMHandle)
  521. {
  522. CMgmtInfo* &pMgmtInfo = hRMHandle;
  523. if (pMgmtInfo == 0)
  524. return;
  525. if (InVidmem(hRMHandle))
  526. {
  527. m_heap_p[pMgmtInfo->m_rmHeap].del(pMgmtInfo);
  528. }
  529. delete pMgmtInfo;
  530. } // CResourceManager::UnManage
  531. #undef DPF_MODNAME
  532. #define DPF_MODNAME "CResourceManager::SetPriority"
  533. DWORD CResourceManager::SetPriority(RMHANDLE hRMHandle, DWORD newPriority)
  534. {
  535. CMgmtInfo* &pMgmtInfo = hRMHandle;
  536. DXGASSERT(pMgmtInfo != 0);
  537. DWORD oldPriority = pMgmtInfo->m_pBackup->SetPriorityI(newPriority);
  538. if (InVidmem(hRMHandle))
  539. {
  540. m_heap_p[pMgmtInfo->m_rmHeap].update(pMgmtInfo, pMgmtInfo->m_bInUse, newPriority, pMgmtInfo->m_ticks);
  541. }
  542. return oldPriority;
  543. } // CResourceManager::SetPriority
  544. #undef DPF_MODNAME
  545. #define DPF_MODNAME "CResourceManager::SetLOD"
  546. DWORD CResourceManager::SetLOD(RMHANDLE hRMHandle, DWORD dwLodNew)
  547. {
  548. DWORD oldLOD;
  549. CMgmtInfo* &pMgmtInfo = hRMHandle;
  550. DXGASSERT(pMgmtInfo != 0);
  551. DXGASSERT(pMgmtInfo->m_pBackup->GetBufferDesc()->Type == D3DRTYPE_TEXTURE ||
  552. pMgmtInfo->m_pBackup->GetBufferDesc()->Type == D3DRTYPE_VOLUMETEXTURE ||
  553. pMgmtInfo->m_pBackup->GetBufferDesc()->Type == D3DRTYPE_CUBETEXTURE);
  554. CBaseTexture *pTex = static_cast<CBaseTexture*>(pMgmtInfo->m_pBackup);
  555. if (dwLodNew < pTex->GetLevelCount())
  556. {
  557. oldLOD = pTex->SetLODI(dwLodNew);
  558. }
  559. else
  560. {
  561. DPF_ERR("Texture does not have sufficient miplevels for current LOD. LOD set to GetLevelCount()-1.");
  562. oldLOD = pTex->SetLODI(pTex->GetLevelCount() - 1);
  563. }
  564. if (InVidmem(hRMHandle))
  565. {
  566. m_heap_p[pMgmtInfo->m_rmHeap].del(pMgmtInfo);
  567. pMgmtInfo->m_pRes->DecrementUseCount();
  568. pMgmtInfo->m_pRes = 0;
  569. static_cast<LPD3DBASE>(this->m_pD3D8)->NeedResourceStateUpdate(); // Need to call this so that DrawPrimitive will do the necessary work
  570. }
  571. return oldLOD;
  572. } // CResourceManager::SetLOD
  573. #undef DPF_MODNAME
  574. #define DPF_MODNAME "CResourceManager::PreLoad"
  575. void CResourceManager::PreLoad(RMHANDLE hRMHandle)
  576. {
  577. CMgmtInfo* &pMgmtInfo = hRMHandle;
  578. DXGASSERT(pMgmtInfo != 0);
  579. BOOL bDirty = FALSE;
  580. m_PreLoading = TRUE;
  581. UpdateVideo(hRMHandle, &bDirty);
  582. m_PreLoading = FALSE;
  583. } // CResourceManaged::PreLoad
  584. #undef DPF_MODNAME
  585. #define DPF_MODNAME "CResourceManager::Lock"
  586. void CResourceManager::Lock(RMHANDLE hRMHandle)
  587. {
  588. if (hRMHandle != 0)
  589. {
  590. CMgmtInfo* &pMgmtInfo = hRMHandle;
  591. if (InVidmem(hRMHandle))
  592. {
  593. m_heap_p[pMgmtInfo->m_rmHeap].update(pMgmtInfo, TRUE, pMgmtInfo->m_pBackup->GetPriorityI(), pMgmtInfo->m_ticks);
  594. }
  595. }
  596. } // CResourceManager::Lock
  597. #undef DPF_MODNAME
  598. #define DPF_MODNAME "CResourceManager::Unlock"
  599. void CResourceManager::Unlock(RMHANDLE hRMHandle)
  600. {
  601. if (hRMHandle != 0)
  602. {
  603. CMgmtInfo* &pMgmtInfo = hRMHandle;
  604. if (InVidmem(hRMHandle))
  605. {
  606. m_heap_p[pMgmtInfo->m_rmHeap].update(pMgmtInfo, FALSE, pMgmtInfo->m_pBackup->GetPriorityI(), pMgmtInfo->m_ticks);
  607. }
  608. }
  609. } // CResourceManager::Unlock
  610. #undef DPF_MODNAME
  611. #define DPF_MODNAME "CResourceManager::FreeResources"
  612. BOOL CResourceManager::FreeResources(DWORD dwHeap, DWORD dwBytes)
  613. {
  614. if (m_heap_p[dwHeap].length() == 0)
  615. return FALSE;
  616. unsigned sz;
  617. CMgmtInfo *rc;
  618. for (unsigned i = 0; m_heap_p[dwHeap].length() != 0 && i < dwBytes; i += sz)
  619. {
  620. // Find the LRU texture and remove it.
  621. rc = m_heap_p[dwHeap].minCost();
  622. if (rc->m_bInUse)
  623. return FALSE;
  624. sz = rc->m_pRes->GetBufferDesc()->Size; // save size
  625. if (rc->m_scene == m_dwScene)
  626. {
  627. if(m_PreLoading)
  628. {
  629. return TRUE;
  630. }
  631. if (m_pD3D8->GetD3DCaps()->RasterCaps & D3DPRASTERCAPS_ZBUFFERLESSHSR)
  632. {
  633. DPF(0, "Trying to locate texture not used in current scene...");
  634. rc = m_heap_p[dwHeap].extractNotInScene(m_dwScene);
  635. if (rc == 0)
  636. {
  637. DPF_ERR("No such texture found. Cannot evict textures used in current scene.");
  638. return FALSE;
  639. }
  640. DPF(0, "Texture found!");
  641. rc->m_pRes->DecrementUseCount();
  642. rc->m_pRes = 0;
  643. }
  644. else
  645. {
  646. DPF(1, "Texture cache thrashing. Removing MRU texture.");
  647. rc = m_heap_p[dwHeap].extractMax();
  648. if (rc == 0)
  649. {
  650. DPF_ERR("All textures in use, cannot evict texture.");
  651. return FALSE;
  652. }
  653. rc->m_pRes->DecrementUseCount();
  654. rc->m_pRes = 0;
  655. }
  656. }
  657. else
  658. {
  659. rc = m_heap_p[dwHeap].extractMin();
  660. rc->m_pRes->DecrementUseCount();
  661. rc->m_pRes = 0;
  662. }
  663. DPF(2, "Removed texture with timestamp %u,%u (current = %u).", rc->m_priority, rc->m_ticks, tcm_ticks);
  664. }
  665. return TRUE;
  666. } // CResourceManager::FreeResources
  667. #undef DPF_MODNAME
  668. #define DPF_MODNAME "CResourceManager::DiscardBytes"
  669. void CResourceManager::DiscardBytes(DWORD cbBytes)
  670. {
  671. for (DWORD i = 0; i < m_dwNumHeaps; ++i)
  672. {
  673. if (cbBytes == 0)
  674. {
  675. while(m_heap_p[i].length())
  676. {
  677. CMgmtInfo *pMgmtInfo = m_heap_p[i].extractMin();
  678. pMgmtInfo->m_pRes->DecrementUseCount();
  679. pMgmtInfo->m_pRes = 0;
  680. }
  681. }
  682. else
  683. {
  684. FreeResources(i, cbBytes / m_dwNumHeaps);
  685. }
  686. }
  687. static_cast<LPD3DBASE>(m_pD3D8)->NeedResourceStateUpdate();
  688. tcm_ticks = 0;
  689. m_dwScene = 0;
  690. } // CResourceManager::DiscardBytes
  691. #undef DPF_MODNAME
  692. #define DPF_MODNAME "CResourceManager::TimeStamp"
  693. void CResourceManager::TimeStamp(CMgmtInfo *pMgmtInfo)
  694. {
  695. pMgmtInfo->m_scene = m_dwScene;
  696. m_heap_p[pMgmtInfo->m_rmHeap].update(pMgmtInfo, pMgmtInfo->m_bInUse, pMgmtInfo->m_pBackup->GetPriorityI(), tcm_ticks);
  697. unsigned tickp2 = tcm_ticks + 2;
  698. if (tickp2 > tcm_ticks)
  699. {
  700. tcm_ticks = tickp2;
  701. }
  702. else // counter has overflowed. Let's reset all timestamps to zero
  703. {
  704. DPF(2, "Timestamp counter overflowed. Reseting timestamps for all textures.");
  705. tcm_ticks = 0;
  706. for (DWORD i = 0; i < m_dwNumHeaps; ++i)
  707. m_heap_p[i].resetAllTimeStamps(0);
  708. }
  709. } // CResourceManager::TimeStamp
  710. #undef DPF_MODNAME
  711. #define DPF_MODNAME "CResourceManager::UpdateVideoInternal"
  712. HRESULT CResourceManager::UpdateVideoInternal(CMgmtInfo *pMgmtInfo)
  713. {
  714. HRESULT ddrval;
  715. DWORD trycount = 0, bytecount = pMgmtInfo->m_pBackup->GetBufferDesc()->Size;
  716. LPD3DBASE lpDevI = static_cast<LPD3DBASE>(m_pD3D8);
  717. // We need to make sure that we don't evict any mapped textures
  718. for (DWORD dwStage = 0; dwStage < lpDevI->m_dwMaxTextureBlendStages; ++dwStage)
  719. {
  720. if (lpDevI->m_lpD3DMappedTexI[dwStage] != 0)
  721. {
  722. Lock(lpDevI->m_lpD3DMappedTexI[dwStage]->RMHandle());
  723. }
  724. }
  725. for (DWORD dwStream = 0; dwStream < lpDevI->m_dwNumStreams; ++dwStream)
  726. {
  727. if (lpDevI->m_pStream[dwStream].m_pVB != 0)
  728. {
  729. Lock(lpDevI->m_pStream[dwStream].m_pVB->RMHandle());
  730. }
  731. }
  732. if (lpDevI->m_pIndexStream->m_pVBI != 0)
  733. {
  734. Lock(lpDevI->m_pIndexStream->m_pVBI->RMHandle());
  735. }
  736. // Attempt to allocate a texture.
  737. do
  738. {
  739. ++trycount;
  740. ddrval = pMgmtInfo->m_pBackup->Clone(D3DPOOL_DEFAULT, &pMgmtInfo->m_pRes);
  741. if (SUCCEEDED(ddrval)) // No problem, there is enough memory.
  742. {
  743. pMgmtInfo->m_scene = m_dwScene;
  744. pMgmtInfo->m_ticks = tcm_ticks;
  745. DXGASSERT(pMgmtInfo->m_rmHeapIndex == 0);
  746. if (!m_heap_p[pMgmtInfo->m_rmHeap].add(pMgmtInfo))
  747. {
  748. ddrval = E_OUTOFMEMORY;
  749. goto exit2;
  750. }
  751. }
  752. else if (ddrval == D3DERR_OUTOFVIDEOMEMORY) // If out of video memory
  753. {
  754. if (!FreeResources(pMgmtInfo->m_rmHeap, bytecount))
  755. {
  756. DPF_ERR("all Freed no further video memory available");
  757. ddrval = D3DERR_OUTOFVIDEOMEMORY; //nothing left
  758. goto exit1;
  759. }
  760. bytecount <<= 1;
  761. }
  762. else
  763. {
  764. D3DRESOURCETYPE Type = pMgmtInfo->m_pBackup->GetBufferDesc()->Type;
  765. if (Type == D3DRTYPE_VERTEXBUFFER ||
  766. Type == D3DRTYPE_INDEXBUFFER)
  767. {
  768. if (lpDevI->VBFailOversDisabled())
  769. {
  770. DPF_ERR("Cannot create Vidmem or Driver managed VB/IB. Will ***NOT*** failover to Sysmem.");
  771. goto exit1;
  772. }
  773. // Fallback to sysmem
  774. DPF(5, "Driver does not support vidmem VB, falling back to sysmem");
  775. CResource *pRes = pMgmtInfo->m_pBackup;
  776. pRes->DeleteRMHandle();
  777. // HACK HACK HACK
  778. ((D3DBUFFER_DESC*)pRes->GetBufferDesc())->Pool = D3DPOOL_SYSTEMMEM;
  779. ddrval = S_OK;
  780. }
  781. else
  782. {
  783. DPF(0, "Unexpected error in Clone %08x", ddrval);
  784. }
  785. goto exit1;
  786. }
  787. }
  788. while (ddrval == D3DERR_OUTOFVIDEOMEMORY);
  789. if (trycount > 1)
  790. {
  791. lpDevI->NeedResourceStateUpdate();
  792. DPF(1, "Allocated texture after %u tries.", trycount);
  793. }
  794. pMgmtInfo->m_pBackup->MarkAllDirty();
  795. ddrval = pMgmtInfo->m_pBackup->UpdateDirtyPortion(pMgmtInfo->m_pRes);
  796. if (FAILED(ddrval))
  797. {
  798. DPF(0, "Unexpected error in UpdateDirtyPortion %08x", ddrval);
  799. goto exit3;
  800. }
  801. ddrval = S_OK;
  802. goto exit1;
  803. exit3:
  804. m_heap_p[pMgmtInfo->m_rmHeap].del(pMgmtInfo);
  805. exit2:
  806. pMgmtInfo->m_pRes->DecrementUseCount();
  807. pMgmtInfo->m_pRes = 0;
  808. exit1:
  809. for (dwStage = 0; dwStage < lpDevI->m_dwMaxTextureBlendStages; ++dwStage)
  810. {
  811. if (lpDevI->m_lpD3DMappedTexI[dwStage])
  812. {
  813. Unlock(lpDevI->m_lpD3DMappedTexI[dwStage]->RMHandle());
  814. }
  815. }
  816. for (dwStream = 0; dwStream < lpDevI->m_dwNumStreams; ++dwStream)
  817. {
  818. if (lpDevI->m_pStream[dwStream].m_pVB != 0)
  819. {
  820. Unlock(lpDevI->m_pStream[dwStream].m_pVB->RMHandle());
  821. }
  822. }
  823. if (lpDevI->m_pIndexStream->m_pVBI != 0)
  824. {
  825. Unlock(lpDevI->m_pIndexStream->m_pVBI->RMHandle());
  826. }
  827. return ddrval;
  828. } // CResourceManager::UpdateVideo
  829. #undef DPF_MODNAME
  830. #define DPF_MODNAME "CResourceManager::OnResourceDirty"
  831. void CResourceManager::OnResourceDirty(RMHANDLE hRMHandle) const
  832. {
  833. static_cast<LPD3DBASE>(m_pD3D8)->NeedResourceStateUpdate();
  834. } // CResourceManager::OnResourceDirty
  835. // End of file : resource.cpp