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.

1137 lines
40 KiB

  1. /******************************Module*Header**********************************\
  2. *
  3. * *******************
  4. * * D3D SAMPLE CODE *
  5. * *******************
  6. *
  7. * Module Name: d3dtxman.c
  8. *
  9. * Content: D3D Texture cache manager
  10. *
  11. * Copyright (c) 1995-2003 Microsoft Corporation. All rights Reserved.
  12. \*****************************************************************************/
  13. #include "glint.h"
  14. #include "dma.h"
  15. #if DX7_TEXMANAGEMENT
  16. //-----------------------------------------------------------------------------
  17. // The driver can optionally manage textures which have been marked as
  18. // manageable. These DirectDraw surfaces are marked as manageable with the
  19. // DDSCAPS2_TEXTUREMANAGE flag in the dwCaps2 field of the structure refered to
  20. // by lpSurfMore->ddCapsEx.
  21. //
  22. // The driver makes explicit its support for driver-managed textures by setting
  23. // DDCAPS2_CANMANAGETEXTURE in the dwCaps2 field of the DD_HALINFO structure.
  24. // DD_HALINFO is returned in response to the initialization of the DirectDraw
  25. // component of the driver, DrvGetDirectDrawInfo.
  26. //
  27. // The driver can then create the necessary surfaces in video or non-local
  28. // memory in a lazy fashion. That is, the driver leaves them in system memory
  29. // until it requires them, which is just before rasterizing a primitive that
  30. // makes use of the texture.
  31. //
  32. // Surfaces should be evicted primarily by their priority assignment. The driver
  33. // should respond to the D3DDP2OP_SETPRIORITY token in the D3dDrawPrimitives2
  34. // command stream, which sets the priority for a given surface. As a secondary
  35. // measure, it is expected that the driver will use a least recently used (LRU)
  36. // scheme. This scheme should be used as a tie breaker, whenever the priority of
  37. // two or more textures is identical in a particular scenario. Logically, any
  38. // surface that is in use shouldn't be evicted at all.
  39. //
  40. // The driver must be cautious of honoring DdBlt calls and DdLock calls when
  41. // managing textures. This is because any change to the system memory image of
  42. // the surface must be propagated into the video memory copy of it before the
  43. // texture is used again. The driver should determine if it is better to update
  44. // just a portion of the surface or all of it.
  45. //
  46. // The driver is allowed to perform texture management in order to perform
  47. // optimization transformations on the textures or to decide for itself where
  48. // and when to transfer textures in memory.
  49. //-----------------------------------------------------------------------------
  50. //-----------------------------------------------------------------------------
  51. //
  52. // Porting to your hardware/driver
  53. //
  54. // The following structures/functions/symbols are specific to this
  55. // implementation. You should supply your own if needed:
  56. //
  57. // P3_SURF_INTERNAL
  58. // P3_D3DCONTEXT
  59. // DISPDBG
  60. // HEAP_ALLOC ALLOC_TAG_DX
  61. // _D3D_TM_HW_FreeVidmemSurface
  62. // _D3D_TM_HW_AllocVidmemSurface
  63. //
  64. //-----------------------------------------------------------------------------
  65. //-----------------------------------------------------------------------------
  66. // Global texture management object and ref count
  67. //-----------------------------------------------------------------------------
  68. DWORD g_TMCount = 0;
  69. TextureCacheManager g_TextureManager;
  70. //-----------------------------------------------------------------------------
  71. // Macros and definitions
  72. //-----------------------------------------------------------------------------
  73. // Number of pointers to DX surfaces for first allocated heap
  74. #define TM_INIT_HEAP_SIZE 1024
  75. // Subsequent increments
  76. #define TM_GROW_HEAP_SIZE(n) ((n)*2)
  77. // Access to binary-tree structure in the heap. The heap is really just a
  78. // linear array of pointers (to P3_SURF_INTERNAL structures) which is
  79. // accessed as if it were a binary tree: m_data_p[1] is the root of the tree
  80. // and the its immediate children are [2] and [3]. The children/parents of
  81. // element are uniquely defined by the below macros.
  82. #define parent(k) ((k) / 2)
  83. #define lchild(k) ((k) * 2)
  84. #define rchild(k) ((k) * 2 + 1)
  85. //-----------------------------------------------------------------------------
  86. //
  87. // void __TM_TextureHeapFindSlot
  88. //
  89. // Starting at element k in the TM heap, search the heap (towards the root node)
  90. // for an element whose parent is cheaper than llCost. Return the value of it.
  91. //
  92. // An important difference between __TM_TextureHeapFindSlot and
  93. // __TM_TextureHeapHeapify is that the former searches upwards in the tree
  94. // whereas the latter searches downwards through the tree.
  95. //
  96. //-----------------------------------------------------------------------------
  97. DWORD
  98. __TM_TextureHeapFindSlot(
  99. PTextureHeap pTextureHeap,
  100. ULONGLONG llCost,
  101. DWORD k)
  102. {
  103. // Starting with element k, traverse the (binary-tree) heap upwards until
  104. // you find an element whose parent is less expensive (cost-wise)
  105. // than llCost . (Short circuited && expression below!)
  106. while( (k > 1) &&
  107. (llCost < TextureCost(pTextureHeap->m_data_p[parent(k)])) )
  108. {
  109. // Slot k is assumed to be empty. So since we are looking for
  110. // slot where to put things, we need to move downwards the
  111. // parent slot before we go on in order for the new k to be
  112. // available
  113. pTextureHeap->m_data_p[k] = pTextureHeap->m_data_p[parent(k)];
  114. pTextureHeap->m_data_p[k]->m_dwHeapIndex = k; // update surf reference
  115. k = parent(k); // look now at parent
  116. }
  117. return k;
  118. } // __TM_TextureHeapFindSlot
  119. //-----------------------------------------------------------------------------
  120. //
  121. // void __TM_TextureHeapHeapify
  122. //
  123. // Starting at element k in the TM heap, make sure the heap is well-ordered
  124. // (parents are always lower cost than their children). This algorithm assumes
  125. // the heap is well ordered with the possible exception of element k
  126. //
  127. //-----------------------------------------------------------------------------
  128. void
  129. __TM_TextureHeapHeapify(
  130. PTextureHeap pTextureHeap,
  131. DWORD k)
  132. {
  133. while(TRUE)
  134. {
  135. DWORD smallest;
  136. DWORD l = lchild(k);
  137. DWORD r = rchild(k);
  138. // Figure out who has the smallest TextureCost, either k,l or r.
  139. if(l < pTextureHeap->m_next)
  140. {
  141. if(TextureCost(pTextureHeap->m_data_p[l]) <
  142. TextureCost(pTextureHeap->m_data_p[k]))
  143. {
  144. smallest = l;
  145. }
  146. else
  147. {
  148. smallest = k;
  149. }
  150. }
  151. else
  152. {
  153. smallest = k;
  154. }
  155. if(r < pTextureHeap->m_next)
  156. {
  157. if(TextureCost(pTextureHeap->m_data_p[r]) <
  158. TextureCost(pTextureHeap->m_data_p[smallest]))
  159. {
  160. smallest = r;
  161. }
  162. }
  163. if(smallest != k)
  164. {
  165. // it wasn't k. So now swap k with the smallest of the three
  166. // and repeat the loop in order with the new position of k
  167. // in order to keep the order right (parents are always lower
  168. // cost than children)
  169. P3_SURF_INTERNAL* ptempD3DSurf = pTextureHeap->m_data_p[k];
  170. pTextureHeap->m_data_p[k] = pTextureHeap->m_data_p[smallest];
  171. pTextureHeap->m_data_p[k]->m_dwHeapIndex = k;
  172. pTextureHeap->m_data_p[smallest] = ptempD3DSurf;
  173. ptempD3DSurf->m_dwHeapIndex = smallest;
  174. k = smallest;
  175. }
  176. else
  177. {
  178. // it was k, so the order is now all right, leave here
  179. break;
  180. }
  181. }
  182. } // __TM_TextureHeapHeapify
  183. //-----------------------------------------------------------------------------
  184. //
  185. // BOOL __TM_TextureHeapAddSurface
  186. //
  187. // Add a DX surface to a texture management heap.
  188. // Returns success or failure status
  189. //
  190. //-----------------------------------------------------------------------------
  191. BOOL
  192. __TM_TextureHeapAddSurface(
  193. PTextureHeap pTextureHeap,
  194. P3_SURF_INTERNAL* pD3DSurf)
  195. {
  196. P3_SURF_INTERNAL* *ppD3DSurf;
  197. ULONGLONG llCost;
  198. DWORD k;
  199. if(pTextureHeap->m_next == pTextureHeap->m_size)
  200. {
  201. // Heap is full, we must grow it
  202. DWORD dwNewSize = TM_GROW_HEAP_SIZE(pTextureHeap->m_size);
  203. ppD3DSurf = (P3_SURF_INTERNAL* *)
  204. HEAP_ALLOC( FL_ZERO_MEMORY,
  205. sizeof(P3_SURF_INTERNAL*) * dwNewSize,
  206. ALLOC_TAG_DX(B));
  207. if(ppD3DSurf == 0)
  208. {
  209. DISPDBG((ERRLVL,"Failed to allocate memory to grow heap."));
  210. return FALSE;
  211. }
  212. // Transfer data
  213. memcpy(ppD3DSurf + 1, pTextureHeap->m_data_p + 1,
  214. sizeof(P3_SURF_INTERNAL*) * (pTextureHeap->m_next - 1));
  215. // Free previous heap
  216. HEAP_FREE( pTextureHeap->m_data_p);
  217. // Update texture heap structure
  218. pTextureHeap->m_size = dwNewSize;
  219. pTextureHeap->m_data_p = ppD3DSurf;
  220. }
  221. // Get the cost of the surface we are about to add
  222. llCost = TextureCost(pD3DSurf);
  223. // Starting at the last element in the heap (where we can theoretically
  224. // place our new element) search upwards for an appropriate place to put
  225. // it in. This will also maintain our tree/heap balanced
  226. k = __TM_TextureHeapFindSlot(pTextureHeap, llCost, pTextureHeap->m_next);
  227. // Add the new surface to the heap in the [k] place
  228. pTextureHeap->m_data_p[k] = pD3DSurf;
  229. ++pTextureHeap->m_next;
  230. //Update the surface's reference to its place on the heap
  231. pD3DSurf->m_dwHeapIndex = k;
  232. return TRUE;
  233. } // __TM_TextureHeapAddSurface
  234. //-----------------------------------------------------------------------------
  235. //
  236. // void __TM_TextureHeapDelSurface
  237. //
  238. // Delete the k element from the TM heap
  239. //
  240. //-----------------------------------------------------------------------------
  241. void __TM_TextureHeapDelSurface(PTextureHeap pTextureHeap, DWORD k)
  242. {
  243. P3_SURF_INTERNAL* pD3DSurf = pTextureHeap->m_data_p[k];
  244. ULONGLONG llCost;
  245. // (virtually) delete the heaps last element and get its cost
  246. --pTextureHeap->m_next;
  247. llCost = TextureCost(pTextureHeap->m_data_p[pTextureHeap->m_next]);
  248. if(llCost < TextureCost(pD3DSurf))
  249. {
  250. // If the cost of the last element is less than that of the surface
  251. // we are really trying to delete (k), look for a new place where
  252. // to put the m_next element based on its cost.
  253. // Starting at the k element in the heap (where we can theoretically
  254. // place our new element) search upwards for an appropriate place to
  255. // put it in
  256. k = __TM_TextureHeapFindSlot(pTextureHeap, llCost, k);
  257. // Overwrite the data of k with the data of the last element
  258. pTextureHeap->m_data_p[k] = pTextureHeap->m_data_p[pTextureHeap->m_next];
  259. pTextureHeap->m_data_p[k]->m_dwHeapIndex = k;
  260. }
  261. else
  262. {
  263. // If the cost of the last element is greather than that of the surface
  264. // we are really trying to delete (k), replace (k) by (m_next)
  265. pTextureHeap->m_data_p[k] = pTextureHeap->m_data_p[pTextureHeap->m_next];
  266. pTextureHeap->m_data_p[k]->m_dwHeapIndex = k;
  267. // Now make sure we keep the heap correctly ordered
  268. __TM_TextureHeapHeapify(pTextureHeap,k);
  269. }
  270. pD3DSurf->m_dwHeapIndex = 0;
  271. } // __TM_TextureHeapDelSurface
  272. //-----------------------------------------------------------------------------
  273. //
  274. // P3_SURF_INTERNAL* __TM_TextureHeapExtractMin
  275. //
  276. // Extract
  277. //
  278. //-----------------------------------------------------------------------------
  279. P3_SURF_INTERNAL*
  280. __TM_TextureHeapExtractMin(
  281. PTextureHeap pTextureHeap)
  282. {
  283. // Obtaint pointer to surface we are extracting from the heap
  284. // (the root node, which is the least expensive element of the
  285. // whole heap because of the way we build the heap).
  286. P3_SURF_INTERNAL* pD3DSurf = pTextureHeap->m_data_p[1];
  287. // Update heap internal counter and move last
  288. // element now to first position.
  289. --pTextureHeap->m_next;
  290. pTextureHeap->m_data_p[1] = pTextureHeap->m_data_p[pTextureHeap->m_next];
  291. pTextureHeap->m_data_p[1]->m_dwHeapIndex = 1;
  292. // Now make sure we keep the heap correctly ordered
  293. __TM_TextureHeapHeapify(pTextureHeap,1);
  294. // Clear the deleted surface's reference to its place on the heap (deleted)
  295. pD3DSurf->m_dwHeapIndex = 0;
  296. return pD3DSurf;
  297. } // __TM_TextureHeapExtractMin
  298. //-----------------------------------------------------------------------------
  299. //
  300. // P3_SURF_INTERNAL* __TM_TextureHeapExtractMax
  301. //
  302. //-----------------------------------------------------------------------------
  303. P3_SURF_INTERNAL*
  304. __TM_TextureHeapExtractMax(
  305. PTextureHeap pTextureHeap)
  306. {
  307. // When extracting the max element from the heap, we don't need to
  308. // search the entire heap, but just the leafnodes. This is because
  309. // it is guaranteed that parent nodes are cheaper than the leaf nodes
  310. // so once you have looked through the leaves, you won't find anything
  311. // cheaper.
  312. // NOTE: (lchild(i) >= m_next) is true only for leaf nodes.
  313. // ALSO NOTE: You cannot have a rchild without a lchild, so simply
  314. // checking for lchild is sufficient.
  315. unsigned max = pTextureHeap->m_next - 1;
  316. ULONGLONG llMaxCost = 0;
  317. ULONGLONG llCost;
  318. unsigned i;
  319. P3_SURF_INTERNAL* pD3DSurf;
  320. // Search all the terminal nodes of the binary-tree (heap)
  321. // for the most expensive element and store its index in max
  322. for(i = max; lchild(i) >= pTextureHeap->m_next; --i)
  323. {
  324. llCost = TextureCost(pTextureHeap->m_data_p[i]);
  325. if(llMaxCost < llCost)
  326. {
  327. llMaxCost = llCost;
  328. max = i;
  329. }
  330. }
  331. // Return the surface associated to this maximum cost heap element
  332. pD3DSurf = pTextureHeap->m_data_p[max];
  333. // Delete it from the heap ( will automatically maintain heap ordered)
  334. __TM_TextureHeapDelSurface(pTextureHeap, max);
  335. return pD3DSurf;
  336. } // __TM_TextureHeapExtractMax
  337. //-----------------------------------------------------------------------------
  338. //
  339. // void __TM_TextureHeapUpdate
  340. //
  341. // Updates the priority & number of of ticks of surface # k in the heap
  342. //
  343. //-----------------------------------------------------------------------------
  344. void
  345. __TM_TextureHeapUpdate(
  346. PTextureHeap pTextureHeap,
  347. DWORD k,
  348. DWORD dwPriority,
  349. DWORD dwTicks)
  350. {
  351. P3_SURF_INTERNAL* pD3DSurf = pTextureHeap->m_data_p[k];
  352. ULONGLONG llCost = 0;
  353. #ifdef _X86_
  354. _asm
  355. {
  356. mov edx, 0;
  357. shl edx, 31;
  358. mov eax, dwPriority;
  359. mov ecx, eax;
  360. shr eax, 1;
  361. or edx, eax;
  362. mov DWORD PTR llCost + 4, edx;
  363. shl ecx, 31;
  364. mov eax, dwTicks;
  365. shr eax, 1;
  366. or eax, ecx;
  367. mov DWORD PTR llCost, eax;
  368. }
  369. #else
  370. llCost = ((ULONGLONG)dwPriority << 31) + ((ULONGLONG)(dwTicks >> 1));
  371. #endif
  372. if(llCost < TextureCost(pD3DSurf))
  373. {
  374. // Starting at the k element in the heap (where we can theoretically
  375. // place our new element) search upwards for an appropriate place
  376. // to move it to in order to keep the tree well ordered.
  377. k = __TM_TextureHeapFindSlot(pTextureHeap, llCost, k);
  378. pD3DSurf->m_dwPriority = dwPriority;
  379. pD3DSurf->m_dwTicks = dwTicks;
  380. pD3DSurf->m_dwHeapIndex = k;
  381. pTextureHeap->m_data_p[k] = pD3DSurf;
  382. }
  383. else
  384. {
  385. pD3DSurf->m_dwPriority = dwPriority;
  386. pD3DSurf->m_dwTicks = dwTicks;
  387. // Now make sure we keep the heap correctly ordered
  388. __TM_TextureHeapHeapify(pTextureHeap,k);
  389. }
  390. }
  391. //-----------------------------------------------------------------------------
  392. //
  393. // BOOL __TM_FreeTextures
  394. //
  395. // Free the LRU texture
  396. //
  397. //-----------------------------------------------------------------------------
  398. BOOL
  399. __TM_FreeTextures(
  400. P3_D3DCONTEXT* pContext,
  401. DWORD dwBytes)
  402. {
  403. P3_SURF_INTERNAL* pD3DSurf;
  404. DWORD k;
  405. PTextureCacheManager pTextureCacheManager = pContext->pTextureManager;
  406. P3_THUNKEDDATA* pThisDisplay = pContext->pThisDisplay;
  407. // No textures left to be freed
  408. if(pTextureCacheManager->m_heap.m_next <= 1)
  409. return FALSE;
  410. // Keep remove textures until we accunulate dwBytes of removed stuff
  411. // or we have no more surfaces left to be removed.
  412. for(k = 0;
  413. (pTextureCacheManager->m_heap.m_next > 1) && (k < dwBytes);
  414. k += pD3DSurf->m_dwBytes)
  415. {
  416. // Find the LRU texture (the one with lowest cost) and remove it.
  417. pD3DSurf = __TM_TextureHeapExtractMin(&pTextureCacheManager->m_heap);
  418. _D3D_TM_RemoveTexture(pThisDisplay, pD3DSurf);
  419. #if DX7_TEXMANAGEMENT_STATS
  420. // Update stats
  421. pTextureCacheManager->m_stats.dwLastPri = pD3DSurf->m_dwPriority;
  422. ++pTextureCacheManager->m_stats.dwNumEvicts;
  423. #endif
  424. DISPDBG((WRNLVL, "Removed texture with timestamp %u,%u (current = %u).",
  425. pD3DSurf->m_dwPriority,
  426. pD3DSurf->m_dwTicks,
  427. pTextureCacheManager->tcm_ticks));
  428. }
  429. return TRUE;
  430. } // __TM_FreeTextures
  431. //-----------------------------------------------------------------------------
  432. //
  433. // HRESULT __TM_TextureHeapInitialize
  434. //
  435. // Allocate the heap and initialize
  436. //
  437. //-----------------------------------------------------------------------------
  438. HRESULT
  439. __TM_TextureHeapInitialize(
  440. PTextureCacheManager pTextureCacheManager)
  441. {
  442. pTextureCacheManager->m_heap.m_next = 1;
  443. pTextureCacheManager->m_heap.m_size = TM_INIT_HEAP_SIZE;
  444. pTextureCacheManager->m_heap.m_data_p = (P3_SURF_INTERNAL* *)
  445. HEAP_ALLOC( FL_ZERO_MEMORY,
  446. sizeof(P3_SURF_INTERNAL*) *
  447. pTextureCacheManager->m_heap.m_size,
  448. ALLOC_TAG_DX(C));
  449. if(pTextureCacheManager->m_heap.m_data_p == 0)
  450. {
  451. DISPDBG((ERRLVL,"Failed to allocate texture heap."));
  452. return E_OUTOFMEMORY;
  453. }
  454. memset(pTextureCacheManager->m_heap.m_data_p,
  455. 0,
  456. sizeof(P3_SURF_INTERNAL*) * pTextureCacheManager->m_heap.m_size);
  457. return DD_OK;
  458. } // __TM_TextureHeapInitialize
  459. //-----------------------------------------------------------------------------
  460. //
  461. // HRESULT _D3D_TM_Ctx_Initialize
  462. //
  463. // Initialize texture management for this context
  464. // Should be called when the context is being created
  465. //
  466. //-----------------------------------------------------------------------------
  467. HRESULT
  468. _D3D_TM_Ctx_Initialize(
  469. P3_D3DCONTEXT* pContext)
  470. {
  471. HRESULT hr = DD_OK;
  472. if (0 == g_TMCount)
  473. {
  474. // first use - must initialize
  475. hr = __TM_TextureHeapInitialize(&g_TextureManager);
  476. // init ticks count for LRU policy
  477. g_TextureManager.tcm_ticks = 0;
  478. }
  479. if (SUCCEEDED(hr))
  480. {
  481. // Initialization succesful or uneccesary.
  482. // Increment the reference count and make the context
  483. // remember where the texture management object is.
  484. g_TMCount++;
  485. pContext->pTextureManager = &g_TextureManager;
  486. }
  487. return hr;
  488. } // _D3D_TM_Ctx_Initialize
  489. //-----------------------------------------------------------------------------
  490. //
  491. // void _D3D_TM_Ctx_Destroy
  492. //
  493. // Clean up texture management for this context
  494. // Should be called when the context is being destroyed
  495. //
  496. //-----------------------------------------------------------------------------
  497. void
  498. _D3D_TM_Ctx_Destroy(
  499. P3_D3DCONTEXT* pContext)
  500. {
  501. // clean up texture manager stuff if it
  502. // is already allocated for this context
  503. if (pContext->pTextureManager)
  504. {
  505. // Decrement reference count for the
  506. // driver global texture manager object
  507. g_TMCount--;
  508. // If necessary, deallocate the texture manager heap;
  509. if (0 == g_TMCount)
  510. {
  511. if (0 != g_TextureManager.m_heap.m_data_p)
  512. {
  513. _D3D_TM_EvictAllManagedTextures(pContext);
  514. HEAP_FREE(g_TextureManager.m_heap.m_data_p);
  515. g_TextureManager.m_heap.m_data_p = NULL;
  516. }
  517. }
  518. pContext->pTextureManager = NULL;
  519. }
  520. } // _D3D_TM_Ctx_Destroy
  521. //-----------------------------------------------------------------------------
  522. //
  523. // HRESULT _D3D_TM_AllocTexture
  524. //
  525. // add a new HW handle and create a surface (for a managed texture) in vidmem
  526. //
  527. //-----------------------------------------------------------------------------
  528. HRESULT
  529. _D3D_TM_AllocTexture(
  530. P3_D3DCONTEXT* pContext,
  531. P3_SURF_INTERNAL* pTexture)
  532. {
  533. DWORD trycount = 0, bytecount = pTexture->m_dwBytes;
  534. PTextureCacheManager pTextureCacheManager = pContext->pTextureManager;
  535. P3_THUNKEDDATA* pThisDisplay = pContext->pThisDisplay;
  536. INT iLOD;
  537. // Decide the largest level to allocate video memory based on what
  538. // is specified through D3DDP2OP_SETTEXLOD token
  539. iLOD = pTexture->m_dwTexLOD;
  540. if (iLOD > (pTexture->iMipLevels - 1))
  541. {
  542. iLOD = pTexture->iMipLevels - 1;
  543. }
  544. // Attempt to allocate a texture. (do until the texture is in vidmem)
  545. while((FLATPTR)NULL == pTexture->MipLevels[iLOD].fpVidMemTM)
  546. {
  547. _D3D_TM_HW_AllocVidmemSurface(pContext, pTexture);
  548. ++trycount;
  549. DISPDBG((DBGLVL,"Got fpVidMemTM = %08lx",
  550. pTexture->MipLevels[0].fpVidMemTM));
  551. // We were able to allocate the vidmem surface
  552. if ((FLATPTR)NULL != pTexture->MipLevels[iLOD].fpVidMemTM)
  553. {
  554. // No problem, there is enough memory.
  555. pTexture->m_dwTicks = pTextureCacheManager->tcm_ticks;
  556. // Add texture to manager's heap to track it
  557. if(!__TM_TextureHeapAddSurface(&pTextureCacheManager->m_heap,
  558. pTexture))
  559. {
  560. // Failed - undo vidmem allocation
  561. // This call will set all MipLevels[i].fpVidMemTM to NULL
  562. _D3D_TM_HW_FreeVidmemSurface(pThisDisplay, pTexture);
  563. DISPDBG((ERRLVL,"Out of memory"));
  564. return DDERR_OUTOFMEMORY;
  565. }
  566. // Mark surface as needing update from sysmem before use
  567. pTexture->m_bTMNeedUpdate = TRUE;
  568. break;
  569. }
  570. else
  571. {
  572. // we weren't able to allocate the vidmem surface
  573. // we will now try to free some managed surfaces to make space
  574. if (!__TM_FreeTextures(pContext, bytecount))
  575. {
  576. DISPDBG((ERRLVL,"all Freed no further video memory available"));
  577. return DDERR_OUTOFVIDEOMEMORY; //nothing left
  578. }
  579. bytecount <<= 1;
  580. }
  581. }
  582. if(trycount > 1)
  583. {
  584. DISPDBG((DBGLVL, "Allocated texture after %u tries.", trycount));
  585. }
  586. __TM_STAT_Inc_TotSz(pTextureCacheManager, pTexture);
  587. __TM_STAT_Inc_WrkSet(pTextureCacheManager, pTexture);
  588. #if DX7_TEXMANAGEMENT_STATS
  589. ++pTextureCacheManager->m_stats.dwNumVidCreates;
  590. #endif // DX7_TEXMANAGEMENT_STATS
  591. return DD_OK;
  592. } // _D3D_TM_AllocTexture
  593. //-----------------------------------------------------------------------------
  594. //
  595. // void _D3D_TM_RemoveTexture
  596. //
  597. // remove all HW handles and release the managed surface
  598. // (usually done for every surface in vidmem when D3DDestroyDDLocal is called)
  599. //
  600. //-----------------------------------------------------------------------------
  601. void
  602. _D3D_TM_RemoveTexture(
  603. P3_THUNKEDDATA *pThisDisplay,
  604. P3_SURF_INTERNAL* pTexture)
  605. {
  606. //@@BEGIN_DDKSPLIT
  607. // azn - we should attach the g_TextureManager ptr to pThisDisplay,
  608. // NOT to pContext !!!
  609. //@@END_DDKSPLIT
  610. PTextureCacheManager pTextureCacheManager = &g_TextureManager;
  611. int i;
  612. // Check if surface is currently in video memory
  613. for (i = 0; i < pTexture->iMipLevels; i++)
  614. {
  615. if (pTexture->MipLevels[i].fpVidMemTM != (FLATPTR)NULL)
  616. {
  617. // Free (deallocate) the surface from video memory
  618. // and mark the texture as not longer in vidmem
  619. _D3D_TM_HW_FreeVidmemSurface(pThisDisplay, pTexture);
  620. // Update statistics
  621. __TM_STAT_Dec_TotSz(pTextureCacheManager, pTexture);
  622. __TM_STAT_Dec_WrkSet(pTextureCacheManager, pTexture);
  623. // The job is done
  624. break;
  625. }
  626. }
  627. // Remove heap references to this surface
  628. if (pTexture->m_dwHeapIndex && pTextureCacheManager->m_heap.m_data_p)
  629. {
  630. __TM_TextureHeapDelSurface(&pTextureCacheManager->m_heap,
  631. pTexture->m_dwHeapIndex);
  632. }
  633. } // _D3D_TM_RemoveTexture
  634. //-----------------------------------------------------------------------------
  635. //
  636. // void _D3D_TM_RemoveDDSurface
  637. //
  638. // remove all HW handles and release the managed surface
  639. // (usually done for every surface in vidmem when D3DDestroyDDLocal is called)
  640. //
  641. //-----------------------------------------------------------------------------
  642. void
  643. _D3D_TM_RemoveDDSurface(
  644. P3_THUNKEDDATA *pThisDisplay,
  645. LPDDRAWI_DDRAWSURFACE_LCL pDDSLcl)
  646. {
  647. // We don't know which D3D context this is so we have to do a search
  648. // through them (if there are any at all)
  649. if (pThisDisplay->pDirectDrawLocalsHashTable != NULL)
  650. {
  651. DWORD dwSurfaceHandle = pDDSLcl->lpSurfMore->dwSurfaceHandle;
  652. PointerArray* pSurfaceArray;
  653. // Get a pointer to an array of surface pointers associated to this lpDD
  654. // The PDD_DIRECTDRAW_LOCAL was stored at D3DCreateSurfaceEx call time
  655. // in PDD_SURFACE_LOCAL->dwReserved1
  656. pSurfaceArray = (PointerArray*)
  657. HT_GetEntry(pThisDisplay->pDirectDrawLocalsHashTable,
  658. pDDSLcl->dwReserved1);
  659. if (pSurfaceArray)
  660. {
  661. // Found a surface array associated to this lpDD !
  662. P3_SURF_INTERNAL* pSurfInternal;
  663. // Check the surface in this array associated to this surface handle
  664. pSurfInternal = PA_GetEntry(pSurfaceArray, dwSurfaceHandle);
  665. if (pSurfInternal)
  666. {
  667. // Got it! remove it
  668. _D3D_TM_RemoveTexture(pThisDisplay, pSurfInternal);
  669. }
  670. }
  671. }
  672. } // _D3D_TM_RemoveDDSurface
  673. //-----------------------------------------------------------------------------
  674. //
  675. // void _D3D_TM_EvictAllManagedTextures
  676. //
  677. // Remove all managed surfaces from video memory
  678. //
  679. //-----------------------------------------------------------------------------
  680. void
  681. _D3D_TM_EvictAllManagedTextures(
  682. P3_D3DCONTEXT* pContext)
  683. {
  684. PTextureCacheManager pTextureCacheManager = pContext->pTextureManager;
  685. P3_THUNKEDDATA* pThisDisplay = pContext->pThisDisplay;
  686. P3_SURF_INTERNAL* pD3DSurf;
  687. while(pTextureCacheManager->m_heap.m_next > 1)
  688. {
  689. pD3DSurf = __TM_TextureHeapExtractMin(&pTextureCacheManager->m_heap);
  690. _D3D_TM_RemoveTexture(pThisDisplay, pD3DSurf);
  691. }
  692. pTextureCacheManager->tcm_ticks = 0;
  693. } // _D3D_TM_EvictAllManagedTextures
  694. //-----------------------------------------------------------------------------
  695. //
  696. // void _DD_TM_EvictAllManagedTextures
  697. //
  698. // Remove all managed surfaces from video memory
  699. //
  700. //-----------------------------------------------------------------------------
  701. void
  702. _DD_TM_EvictAllManagedTextures(
  703. P3_THUNKEDDATA* pThisDisplay)
  704. {
  705. PTextureCacheManager pTextureCacheManager = &g_TextureManager;
  706. P3_SURF_INTERNAL* pD3DSurf;
  707. while(pTextureCacheManager->m_heap.m_next > 1)
  708. {
  709. pD3DSurf = __TM_TextureHeapExtractMin(&pTextureCacheManager->m_heap);
  710. _D3D_TM_RemoveTexture(pThisDisplay, pD3DSurf);
  711. }
  712. pTextureCacheManager->tcm_ticks = 0;
  713. } // _D3D_TM_EvictAllManagedTextures
  714. //-----------------------------------------------------------------------------
  715. //
  716. // void _D3D_TM_TimeStampTexture
  717. //
  718. //-----------------------------------------------------------------------------
  719. void
  720. _D3D_TM_TimeStampTexture(
  721. PTextureCacheManager pTextureCacheManager,
  722. P3_SURF_INTERNAL* pD3DSurf)
  723. {
  724. __TM_TextureHeapUpdate(&pTextureCacheManager->m_heap,
  725. pD3DSurf->m_dwHeapIndex,
  726. pD3DSurf->m_dwPriority,
  727. pTextureCacheManager->tcm_ticks);
  728. pTextureCacheManager->tcm_ticks += 2;
  729. } // _D3D_TM_TimeStampTexture
  730. //-----------------------------------------------------------------------------
  731. //
  732. // void _D3D_TM_HW_FreeVidmemSurface
  733. //
  734. // This is a hw/driver dependent function which takes care of evicting a
  735. // managed texture that's living in videomemory out of it.
  736. // After this all mipmaps fpVidMemTM should be NULL.
  737. //
  738. //-----------------------------------------------------------------------------
  739. void
  740. _D3D_TM_HW_FreeVidmemSurface(
  741. P3_THUNKEDDATA* pThisDisplay,
  742. P3_SURF_INTERNAL* pD3DSurf)
  743. {
  744. INT i, iLimit;
  745. if (pD3DSurf->bMipMap)
  746. {
  747. iLimit = pD3DSurf->iMipLevels;
  748. }
  749. else
  750. {
  751. iLimit = 1;
  752. }
  753. for(i = 0; i < iLimit; i++)
  754. {
  755. if (pD3DSurf->MipLevels[i].fpVidMemTM != (FLATPTR)NULL)
  756. {
  757. // NOTE: if we weren't managing our own vidmem we would need to
  758. // get the address of the VidMemFree callback using
  759. // EngFindImageProcAddress and use this callback into Ddraw to
  760. // do the video memory management. The declaration of
  761. // VidMemFree is
  762. //
  763. // void VidMemFree(LPVMEMHEAP pvmh, FLATPTR ptr);
  764. //
  765. // You can find more information on this callback in the
  766. // Graphics Drivers DDK documentation
  767. _DX_LIN_FreeLinearMemory(
  768. &pThisDisplay->LocalVideoHeap0Info,
  769. (DWORD)(pD3DSurf->MipLevels[i].fpVidMemTM));
  770. pD3DSurf->MipLevels[i].fpVidMemTM = (FLATPTR)NULL;
  771. }
  772. }
  773. } // _D3D_TM_HW_FreeVidmemSurface
  774. //-----------------------------------------------------------------------------
  775. //
  776. // void _D3D_TM_HW_AllocVidmemSurface
  777. //
  778. // This is a hw/driver dependent function which takes care of allocating a
  779. // managed texture that's living only in system memory into videomemory.
  780. // After this fpVidMemTM should not be NULL. This is also the way to
  781. // check if the call failed or was succesful (notice we don't return a
  782. // function result)
  783. //
  784. //-----------------------------------------------------------------------------
  785. void
  786. _D3D_TM_HW_AllocVidmemSurface(
  787. P3_D3DCONTEXT* pContext,
  788. P3_SURF_INTERNAL* pD3DSurf)
  789. {
  790. INT i, iLimit, iStart;
  791. P3_THUNKEDDATA* pThisDisplay;
  792. pThisDisplay = pContext->pThisDisplay;
  793. if (pD3DSurf->bMipMap)
  794. {
  795. // Load only the necessary levels given any D3DDP2OP_SETTEXLOD command
  796. iStart = pD3DSurf->m_dwTexLOD;
  797. if (iStart > (pD3DSurf->iMipLevels - 1))
  798. {
  799. // we should at least load the smallest mipmap if we're loading
  800. // the texture into vidmem (and make sure we never try to use any
  801. // other than these levels), otherwise we won't be able to render
  802. iStart = pD3DSurf->iMipLevels - 1;
  803. }
  804. iLimit = pD3DSurf->iMipLevels;
  805. }
  806. else
  807. {
  808. iStart = 0;
  809. iLimit = 1;
  810. }
  811. for(i = iStart; i < iLimit; i++)
  812. {
  813. if (pD3DSurf->MipLevels[i].fpVidMemTM == (FLATPTR)NULL)
  814. {
  815. // NOTE: if we weren't managing our own vidmem we would need to
  816. // get the address of the HeapVidMemAllocAligned callback
  817. // using EngFindImageProcAddress and use this callback into
  818. // Ddraw to do the video off-screen allocation. The
  819. // declaration of HeapVidMemAllocAligned is
  820. //
  821. // FLATPTR HeapVidMemAllocAligned(LPVIDMEM lpVidMem,
  822. // DWORD dwWidth,
  823. // DWORD dwHeight,
  824. // LPSURFACEALIGNEMENT lpAlign,
  825. // LPLONG lpNewPitch);
  826. //
  827. // You can find more information on this callback in the
  828. // Graphics Drivers DDK documentation
  829. P3_MEMREQUEST mmrq;
  830. DWORD dwResult;
  831. memset(&mmrq, 0, sizeof(P3_MEMREQUEST));
  832. mmrq.dwSize = sizeof(P3_MEMREQUEST);
  833. mmrq.dwBytes = pD3DSurf->MipLevels[i].lPitch *
  834. pD3DSurf->MipLevels[i].wHeight;
  835. mmrq.dwAlign = 8;
  836. mmrq.dwFlags = MEM3DL_FIRST_FIT;
  837. mmrq.dwFlags |= MEM3DL_FRONT;
  838. dwResult = _DX_LIN_AllocateLinearMemory(
  839. &pThisDisplay->LocalVideoHeap0Info,
  840. &mmrq);
  841. if (dwResult == GLDD_SUCCESS)
  842. {
  843. // Record the new vidmem addr for this managed mip level
  844. pD3DSurf->MipLevels[i].fpVidMemTM = mmrq.pMem;
  845. }
  846. else
  847. {
  848. // Failure, we'll need to deallocate any mipmap
  849. // allocated up to this point.
  850. _D3D_TM_HW_FreeVidmemSurface(pThisDisplay, pD3DSurf);
  851. break; // don't do the loop anymore
  852. }
  853. }
  854. }
  855. } // _D3D_TM_HW_AllocVidmemSurface
  856. //-----------------------------------------------------------------------------
  857. //
  858. // void _D3D_TM_Preload_Tex_IntoVidMem
  859. //
  860. // Transfer a texture from system memory into videomemory. If the texture
  861. // still hasn't been allocated videomemory we try to do so (even evicting
  862. // uneeded textures if necessary!).
  863. //
  864. //-----------------------------------------------------------------------------
  865. BOOL
  866. _D3D_TM_Preload_Tex_IntoVidMem(
  867. P3_D3DCONTEXT* pContext,
  868. P3_SURF_INTERNAL* pD3DSurf)
  869. {
  870. P3_THUNKEDDATA* pThisDisplay = pContext->pThisDisplay;
  871. INT iLOD;
  872. // Decide the largest level to load based on what
  873. // is specified through D3DDP2OP_SETTEXLOD token
  874. iLOD = pD3DSurf->m_dwTexLOD;
  875. if (iLOD > (pD3DSurf->iMipLevels - 1))
  876. {
  877. iLOD = pD3DSurf->iMipLevels - 1;
  878. }
  879. if (!(pD3DSurf->dwCaps2 & DDSCAPS2_TEXTUREMANAGE))
  880. {
  881. DISPDBG((ERRLVL,"Must be a managed texture to do texture preload"));
  882. return FALSE; // INVALIDPARAMS
  883. }
  884. // Check if the largest required mipmap level has been allocated vidmem
  885. // (only required mipmap levels are ever allocated vidmem)
  886. if ((FLATPTR)NULL == pD3DSurf->MipLevels[iLOD].fpVidMemTM)
  887. {
  888. // add a new HW handle and create a surface
  889. // (for a managed texture) in vidmem
  890. if ((FAILED(_D3D_TM_AllocTexture(pContext, pD3DSurf))) ||
  891. ((FLATPTR)NULL == pD3DSurf->MipLevels[iLOD].fpVidMemTM))
  892. {
  893. DISPDBG((ERRLVL,"_D3D_OP_TextureBlt unable to "
  894. "allocate memory from heap"));
  895. return FALSE; // OUTOFVIDEOMEMORY
  896. }
  897. pD3DSurf->m_bTMNeedUpdate = TRUE;
  898. }
  899. if (pD3DSurf->m_bTMNeedUpdate)
  900. {
  901. // texture download
  902. DWORD iLimit, iCurrLOD;
  903. if (pD3DSurf->bMipMap)
  904. {
  905. iLimit = pD3DSurf->iMipLevels;
  906. }
  907. else
  908. {
  909. iLimit = 1;
  910. }
  911. // Switch to the DirectDraw context
  912. DDRAW_OPERATION(pContext, pThisDisplay);
  913. // Blt managed texture's required mipmap levels into vid mem
  914. for (iCurrLOD = iLOD; iCurrLOD < iLimit ; iCurrLOD++)
  915. {
  916. RECTL rect;
  917. rect.left=rect.top = 0;
  918. rect.right = pD3DSurf->MipLevels[iCurrLOD].wWidth;
  919. rect.bottom = pD3DSurf->MipLevels[iCurrLOD].wHeight;
  920. _DD_P3Download(pThisDisplay,
  921. pD3DSurf->MipLevels[iCurrLOD].fpVidMem,
  922. pD3DSurf->MipLevels[iCurrLOD].fpVidMemTM,
  923. pD3DSurf->dwPatchMode,
  924. pD3DSurf->dwPatchMode,
  925. pD3DSurf->MipLevels[iCurrLOD].lPitch,
  926. pD3DSurf->MipLevels[iCurrLOD].lPitch,
  927. pD3DSurf->MipLevels[iCurrLOD].P3RXTextureMapWidth.Width,
  928. pD3DSurf->dwPixelSize,
  929. &rect,
  930. &rect);
  931. DISPDBG((DBGLVL, "Copy from %08lx to %08lx"
  932. " w=%08lx h=%08lx p=%08lx",
  933. pD3DSurf->MipLevels[iCurrLOD].fpVidMem,
  934. pD3DSurf->MipLevels[iCurrLOD].fpVidMemTM,
  935. pD3DSurf->MipLevels[iCurrLOD].wWidth,
  936. pD3DSurf->MipLevels[iCurrLOD].wHeight,
  937. pD3DSurf->MipLevels[iCurrLOD].lPitch));
  938. }
  939. // Switch back to the Direct3D context
  940. D3D_OPERATION(pContext, pThisDisplay);
  941. // Texture updated in vidmem
  942. pD3DSurf->m_bTMNeedUpdate = FALSE;
  943. }
  944. return TRUE;
  945. } // _D3D_TM_Preload_Tex_IntoVidMem
  946. //-----------------------------------------------------------------------------
  947. //
  948. // void _D3D_TM_MarkDDSurfaceAsDirty
  949. //
  950. // Help mark a DD surface as dirty given that we need to search for it
  951. // based on its lpSurfMore->dwSurfaceHandle and the lpDDLcl.
  952. //
  953. //-----------------------------------------------------------------------------
  954. void
  955. _D3D_TM_MarkDDSurfaceAsDirty(
  956. P3_THUNKEDDATA* pThisDisplay,
  957. LPDDRAWI_DDRAWSURFACE_LCL pDDSLcl,
  958. BOOL bDirty)
  959. {
  960. // We don't know which D3D context this is so we have to do a search
  961. // through them (if there are any at all)
  962. if (pThisDisplay->pDirectDrawLocalsHashTable != NULL)
  963. {
  964. DWORD dwSurfaceHandle = pDDSLcl->lpSurfMore->dwSurfaceHandle;
  965. PointerArray* pSurfaceArray;
  966. // Get a pointer to an array of surface pointers associated to this lpDD
  967. // The PDD_DIRECTDRAW_LOCAL was stored at D3DCreateSurfaceEx call time
  968. // in PDD_SURFACE_LOCAL->dwReserved1
  969. pSurfaceArray = (PointerArray*)
  970. HT_GetEntry(pThisDisplay->pDirectDrawLocalsHashTable,
  971. pDDSLcl->dwReserved1);
  972. if (pSurfaceArray)
  973. {
  974. // Found a surface array associated to this lpDD !
  975. P3_SURF_INTERNAL* pSurfInternal;
  976. // Check the surface in this array associated to this surface handle
  977. pSurfInternal = PA_GetEntry(pSurfaceArray, dwSurfaceHandle);
  978. if (pSurfInternal)
  979. {
  980. // Got it! Now update dirty TM value
  981. pSurfInternal->m_bTMNeedUpdate = bDirty;
  982. }
  983. }
  984. }
  985. } // _D3D_TM_MarkDDSurfaceAsDirty
  986. #endif // DX7_TEXMANAGEMENT