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.

593 lines
18 KiB

  1. #include "pch.cpp"
  2. #pragma hdrstop
  3. #undef DPF_MODNAME
  4. #define DPF_MODNAME "TextureHeap::TextureHeap"
  5. TextureHeap::TextureHeap(DWORD size)
  6. {
  7. m_next = 1;
  8. m_size = size + 1;
  9. }
  10. #undef DPF_MODNAME
  11. #define DPF_MODNAME "TextureHeap::~TextureHeap"
  12. TextureHeap::~TextureHeap()
  13. {
  14. delete[] m_data_p;
  15. }
  16. #undef DPF_MODNAME
  17. #define DPF_MODNAME "TextureHeap::Initialize"
  18. bool TextureHeap::Initialize()
  19. {
  20. m_data_p = new LPDIRECT3DTEXTUREI[m_size];
  21. if(m_data_p == 0)
  22. {
  23. D3D_ERR("Failed to allocate texture heap.");
  24. return false;
  25. }
  26. memset(m_data_p, 0, sizeof(LPDIRECT3DTEXTUREI) * m_size);
  27. return true;
  28. }
  29. #undef DPF_MODNAME
  30. #define DPF_MODNAME "TextureHeap::heapify"
  31. void TextureHeap::heapify(DWORD k)
  32. {
  33. while(true)
  34. {
  35. DWORD smallest;
  36. DWORD l = lchild(k);
  37. DWORD r = rchild(k);
  38. if(l < m_next)
  39. if(m_data_p[l]->Cost() < m_data_p[k]->Cost())
  40. smallest = l;
  41. else
  42. smallest = k;
  43. else
  44. smallest = k;
  45. if(r < m_next)
  46. if(m_data_p[r]->Cost() < m_data_p[smallest]->Cost())
  47. smallest = r;
  48. if(smallest != k)
  49. {
  50. LPDIRECT3DTEXTUREI t = m_data_p[k];
  51. m_data_p[k] = m_data_p[smallest];
  52. m_data_p[k]->m_dwHeapIndex = k;
  53. m_data_p[smallest] = t;
  54. m_data_p[smallest]->m_dwHeapIndex = smallest;
  55. k = smallest;
  56. }
  57. else
  58. break;
  59. }
  60. }
  61. #undef DPF_MODNAME
  62. #define DPF_MODNAME "TextureHeap::add"
  63. bool TextureHeap::add(LPDIRECT3DTEXTUREI lpD3DTexI)
  64. {
  65. if(m_next == m_size)
  66. {
  67. m_size = m_size * 2 - 1;
  68. LPDIRECT3DTEXTUREI *p = new LPDIRECT3DTEXTUREI[m_size];
  69. if(p == 0)
  70. {
  71. D3D_ERR("Failed to allocate memory to grow heap.");
  72. m_size = (m_size + 1) / 2; // restore size
  73. return false;
  74. }
  75. memcpy(p + 1, m_data_p + 1, sizeof(LPDIRECT3DTEXTUREI) * (m_next - 1));
  76. delete[] m_data_p;
  77. m_data_p = p;
  78. }
  79. ULONGLONG Cost = lpD3DTexI->Cost();
  80. for(DWORD k = m_next; k > 1; k = parent(k))
  81. if(Cost < m_data_p[parent(k)]->Cost())
  82. {
  83. m_data_p[k] = m_data_p[parent(k)];
  84. m_data_p[k]->m_dwHeapIndex = k;
  85. }
  86. else
  87. break;
  88. m_data_p[k] = lpD3DTexI;
  89. m_data_p[k]->m_dwHeapIndex = k;
  90. ++m_next;
  91. return true;
  92. }
  93. #undef DPF_MODNAME
  94. #define DPF_MODNAME "TextureHeap::extractMin"
  95. LPDIRECT3DTEXTUREI TextureHeap::extractMin()
  96. {
  97. LPDIRECT3DTEXTUREI lpD3DTexI = m_data_p[1];
  98. --m_next;
  99. m_data_p[1] = m_data_p[m_next];
  100. m_data_p[1]->m_dwHeapIndex = 1;
  101. heapify(1);
  102. lpD3DTexI->m_dwHeapIndex = 0;
  103. return lpD3DTexI;
  104. }
  105. #undef DPF_MODNAME
  106. #define DPF_MODNAME "TextureHeap::extractMax"
  107. LPDIRECT3DTEXTUREI TextureHeap::extractMax()
  108. {
  109. // When extracting the max element from the heap, we don't need to
  110. // search the entire heap, but just the leafnodes. This is because
  111. // it is guaranteed that parent nodes are cheaper than the leaf nodes
  112. // so once you have looked through the leaves, you won't find anything
  113. // cheaper.
  114. // NOTE: (lchild(i) >= m_next) is true only for leaf nodes.
  115. // ALSO NOTE: You cannot have a rchild without a lchild, so simply
  116. // checking for lchild is sufficient.
  117. unsigned max = m_next - 1;
  118. ULONGLONG maxcost = 0;
  119. for(unsigned i = max; lchild(i) >= m_next; --i)
  120. {
  121. ULONGLONG Cost = m_data_p[i]->Cost();
  122. if(maxcost < Cost)
  123. {
  124. maxcost = Cost;
  125. max = i;
  126. }
  127. }
  128. LPDIRECT3DTEXTUREI lpD3DTexI = m_data_p[max];
  129. if(lpD3DTexI->m_bInUse)
  130. {
  131. max = 0;
  132. maxcost = 0;
  133. for(i = m_next - 1; i > 0; --i)
  134. {
  135. ULONGLONG Cost = m_data_p[i]->Cost();
  136. if(maxcost < Cost && !m_data_p[i]->m_bInUse)
  137. {
  138. maxcost = Cost;
  139. max = i;
  140. }
  141. }
  142. if(max == 0) // All textures in use
  143. return NULL;
  144. lpD3DTexI = m_data_p[max];
  145. }
  146. del(max);
  147. return lpD3DTexI;
  148. }
  149. #undef DPF_MODNAME
  150. #define DPF_MODNAME "TextureHeap::extractNotInScene"
  151. LPDIRECT3DTEXTUREI TextureHeap::extractNotInScene(DWORD dwScene)
  152. {
  153. for(unsigned i = 1; i < m_next; ++i)
  154. {
  155. if(m_data_p[i]->m_dwScene != dwScene)
  156. {
  157. LPDIRECT3DTEXTUREI lpD3DTexI = m_data_p[i];
  158. del(i);
  159. return lpD3DTexI;
  160. }
  161. }
  162. return NULL;
  163. }
  164. #undef DPF_MODNAME
  165. #define DPF_MODNAME "TextureHeap::del"
  166. void TextureHeap::del(DWORD k)
  167. {
  168. LPDIRECT3DTEXTUREI lpD3DTexI = m_data_p[k];
  169. --m_next;
  170. ULONGLONG Cost = m_data_p[m_next]->Cost();
  171. if(Cost < lpD3DTexI->Cost())
  172. {
  173. while(k > 1)
  174. {
  175. if(Cost < m_data_p[parent(k)]->Cost())
  176. {
  177. m_data_p[k] = m_data_p[parent(k)];
  178. m_data_p[k]->m_dwHeapIndex = k;
  179. }
  180. else
  181. break;
  182. k = parent(k);
  183. }
  184. m_data_p[k] = m_data_p[m_next];
  185. m_data_p[k]->m_dwHeapIndex = k;
  186. }
  187. else
  188. {
  189. m_data_p[k] = m_data_p[m_next];
  190. m_data_p[k]->m_dwHeapIndex = k;
  191. heapify(k);
  192. }
  193. lpD3DTexI->m_dwHeapIndex = 0;
  194. }
  195. #undef DPF_MODNAME
  196. #define DPF_MODNAME "TextureHeap::update"
  197. void TextureHeap::update(DWORD k, BOOL inuse, DWORD priority, DWORD ticks)
  198. {
  199. LPDIRECT3DTEXTUREI lpD3DTexI = m_data_p[k];
  200. ULONGLONG Cost;
  201. #ifdef _X86_
  202. _asm
  203. {
  204. mov edx, inuse;
  205. shl edx, 31;
  206. mov eax, priority;
  207. mov ecx, eax;
  208. shr eax, 1;
  209. or edx, eax;
  210. mov DWORD PTR Cost + 4, edx;
  211. shl ecx, 31;
  212. mov eax, ticks;
  213. shr eax, 1;
  214. or eax, ecx;
  215. mov DWORD PTR Cost, eax;
  216. }
  217. #else
  218. Cost = ((ULONGLONG)inuse << 63) + ((ULONGLONG)priority << 31) + ((ULONGLONG)(ticks >> 1));
  219. #endif
  220. if(Cost < lpD3DTexI->Cost())
  221. {
  222. while(k > 1)
  223. {
  224. if(Cost < m_data_p[parent(k)]->Cost())
  225. {
  226. m_data_p[k] = m_data_p[parent(k)];
  227. m_data_p[k]->m_dwHeapIndex = k;
  228. }
  229. else
  230. break;
  231. k = parent(k);
  232. }
  233. lpD3DTexI->m_bInUse = inuse;
  234. lpD3DTexI->m_dwPriority = priority;
  235. lpD3DTexI->m_dwTicks = ticks;
  236. lpD3DTexI->m_dwHeapIndex = k;
  237. m_data_p[k] = lpD3DTexI;
  238. }
  239. else
  240. {
  241. lpD3DTexI->m_bInUse = inuse;
  242. lpD3DTexI->m_dwPriority = priority;
  243. lpD3DTexI->m_dwTicks = ticks;
  244. heapify(k);
  245. }
  246. }
  247. #undef DPF_MODNAME
  248. #define DPF_MODNAME "TextureHeap::resetAllTimeStamps"
  249. void TextureHeap::resetAllTimeStamps(DWORD ticks)
  250. {
  251. for(unsigned i = 1; i < m_next; ++i)
  252. {
  253. update(i, m_data_p[i]->m_bInUse, m_data_p[i]->m_dwPriority, ticks);
  254. }
  255. }
  256. #undef DPF_MODNAME
  257. #define DPF_MODNAME "TextureCacheManager::TextureCacheManager"
  258. TextureCacheManager::TextureCacheManager(LPDIRECT3DI lpD3DI)
  259. {
  260. tcm_ticks = 0;
  261. m_dwScene = 0;
  262. m_dwNumHeaps = 0;
  263. lpDirect3DI=lpD3DI;
  264. #if COLLECTSTATS
  265. m_stats.dwWorkingSet = 0;
  266. m_stats.dwWorkingSetBytes = 0;
  267. m_stats.dwTotalManaged = 0;
  268. m_stats.dwTotalBytes = 0;
  269. m_stats.dwLastPri = 0;
  270. #endif
  271. }
  272. #undef DPF_MODNAME
  273. #define DPF_MODNAME "TextureCacheManager::~TextureCacheManager"
  274. TextureCacheManager::~TextureCacheManager()
  275. {
  276. EvictTextures();
  277. delete[] m_heap_p;
  278. }
  279. #undef DPF_MODNAME
  280. #define DPF_MODNAME "TextureCacheManager::Initialize"
  281. HRESULT TextureCacheManager::Initialize()
  282. {
  283. DDASSERT(((LPDDRAWI_DIRECTDRAW_INT)(lpDirect3DI->lpDD7))->lpLcl);
  284. LPD3DHAL_GLOBALDRIVERDATA lpD3DHALGlobalDriverData = ((LPDDRAWI_DIRECTDRAW_INT)(lpDirect3DI->lpDD7))->lpLcl->lpGbl->lpD3DGlobalDriverData;
  285. if(lpD3DHALGlobalDriverData != NULL)
  286. if(lpD3DHALGlobalDriverData->hwCaps.dwDevCaps & D3DDEVCAPS_SEPARATETEXTUREMEMORIES)
  287. {
  288. m_dwNumHeaps = ((LPDDRAWI_DIRECTDRAW_INT)(lpDirect3DI->lpDD7))->lpLcl->lpGbl->lpD3DExtendedCaps->wMaxSimultaneousTextures;
  289. DDASSERT(m_dwNumHeaps);
  290. if(m_dwNumHeaps < 1)
  291. {
  292. D3D_ERR("Max simultaneous textures not set. Forced to 1.");
  293. m_dwNumHeaps = 1;
  294. }
  295. D3D_INFO(2, "Number of heaps set to %u.", m_dwNumHeaps);
  296. }
  297. else
  298. m_dwNumHeaps = 1;
  299. else
  300. m_dwNumHeaps = 1;
  301. m_heap_p = new TextureHeap[m_dwNumHeaps];
  302. if(m_heap_p == 0)
  303. {
  304. D3D_ERR("Out of memory allocating texture heap.");
  305. return E_OUTOFMEMORY;
  306. }
  307. for(DWORD i = 0; i < m_dwNumHeaps; ++i)
  308. {
  309. if(m_heap_p[i].Initialize() == FALSE)
  310. return E_OUTOFMEMORY;
  311. }
  312. return D3D_OK;
  313. }
  314. #undef DPF_MODNAME
  315. #define DPF_MODNAME "TextureCacheManager::FreeTextures"
  316. BOOL TextureCacheManager::FreeTextures(DWORD dwStage, DWORD dwBytes)
  317. {
  318. if(m_heap_p[dwStage].length() == 0)
  319. return false;
  320. LPDIRECT3DTEXTUREI rc;
  321. for(unsigned i = 0; m_heap_p[dwStage].length() != 0 && i < dwBytes; i += rc->m_dwVidBytes)
  322. {
  323. // Find the LRU texture and remove it.
  324. rc = m_heap_p[dwStage].minCost();
  325. if(rc->m_bInUse)
  326. return false;
  327. if(rc->m_dwScene == m_dwScene)
  328. {
  329. if(((LPDDRAWI_DIRECTDRAW_INT)(lpDirect3DI->lpDD7))->lpLcl->lpGbl->lpD3DGlobalDriverData->hwCaps.dpcTriCaps.dwRasterCaps & D3DPRASTERCAPS_ZBUFFERLESSHSR)
  330. {
  331. D3D_WARN(0, "Trying to locate texture not used in current scene...");
  332. rc = m_heap_p[dwStage].extractNotInScene(m_dwScene);
  333. if(rc == NULL)
  334. {
  335. D3D_ERR("No such texture found. Cannot evict textures used in current scene.");
  336. return false;
  337. }
  338. D3D_WARN(0, "Texture found!");
  339. remove(rc);
  340. #if COLLECTSTATS
  341. m_stats.dwLastPri = rc->m_dwPriority;
  342. ++m_stats.dwNumEvicts;
  343. #endif
  344. }
  345. else
  346. {
  347. D3D_WARN(1, "Texture cache thrashing. Removing MRU texture.");
  348. rc = m_heap_p[dwStage].extractMax();
  349. if(rc == NULL)
  350. {
  351. D3D_ERR("All textures in use, cannot evict texture.");
  352. return false;
  353. }
  354. remove(rc);
  355. #if COLLECTSTATS
  356. m_stats.bThrashing = TRUE;
  357. m_stats.dwLastPri = rc->m_dwPriority;
  358. ++m_stats.dwNumEvicts;
  359. #endif
  360. }
  361. }
  362. else
  363. {
  364. rc = m_heap_p[dwStage].extractMin();
  365. remove(rc);
  366. #if COLLECTSTATS
  367. m_stats.dwLastPri = rc->m_dwPriority;
  368. ++m_stats.dwNumEvicts;
  369. #endif
  370. }
  371. D3D_INFO(2, "Removed texture with timestamp %u,%u (current = %u).", rc->m_dwPriority, rc->m_dwTicks, tcm_ticks);
  372. }
  373. return true;
  374. }
  375. #undef DPF_MODNAME
  376. #define DPF_MODNAME "TextureCacheManager::allocNode"
  377. HRESULT TextureCacheManager::allocNode(LPDIRECT3DTEXTUREI lpD3DTexI, LPDIRECT3DDEVICEI lpDevI)
  378. {
  379. HRESULT ddrval;
  380. DWORD trycount = 0, bytecount = lpD3DTexI->m_dwBytes;
  381. // We need to make sure that we don't evict any mapped textures
  382. for(DWORD dwStage = 0; dwStage < lpDevI->dwMaxTextureBlendStages; ++dwStage)
  383. {
  384. if(lpDevI->lpD3DMappedTexI[dwStage])
  385. {
  386. lpDevI->lpD3DMappedTexI[dwStage]->m_bInUse = TRUE;
  387. UpdatePriority(lpDevI->lpD3DMappedTexI[dwStage]);
  388. }
  389. }
  390. // Attempt to allocate a texture.
  391. do
  392. {
  393. ++trycount;
  394. DDASSERT(lpD3DTexI->lpDDS == NULL);
  395. ddrval = lpDirect3DI->lpDD7->CreateSurface(&lpD3DTexI->ddsd, &lpD3DTexI->lpDDS, NULL);
  396. if (DD_OK == ddrval) // No problem, there is enough memory.
  397. {
  398. static_cast<DIRECT3DTEXTURED3DM*>(lpD3DTexI)->MarkDirtyPointers();
  399. lpD3DTexI->m_dwScene = m_dwScene;
  400. lpD3DTexI->m_dwTicks = tcm_ticks;
  401. DDASSERT(lpD3DTexI->m_dwHeapIndex == 0);
  402. if(!m_heap_p[lpD3DTexI->ddsd.dwTextureStage].add(lpD3DTexI))
  403. {
  404. ddrval = DDERR_OUTOFMEMORY;
  405. goto exit2;
  406. }
  407. #if COLLECTSTATS
  408. ++m_stats.dwWorkingSet;
  409. m_stats.dwWorkingSetBytes += lpD3DTexI->m_dwVidBytes;
  410. ++m_stats.dwNumVidCreates;
  411. #endif
  412. }
  413. else if(ddrval == DDERR_OUTOFVIDEOMEMORY) // If out of video memory
  414. {
  415. if (!FreeTextures(lpD3DTexI->ddsd.dwTextureStage, bytecount))
  416. {
  417. D3D_ERR("all Freed no further video memory available");
  418. ddrval = DDERR_OUTOFVIDEOMEMORY; //nothing left
  419. goto exit1;
  420. }
  421. bytecount <<= 1;
  422. }
  423. else
  424. {
  425. D3D_ERR("Unexpected error got in allocNode %08x", ddrval);
  426. goto exit1;
  427. }
  428. }
  429. while(ddrval == DDERR_OUTOFVIDEOMEMORY);
  430. if(trycount > 1)
  431. {
  432. D3DTextureUpdate(static_cast<LPUNKNOWN>(&(lpDirect3DI->mD3DUnk)));
  433. D3D_WARN(1, "Allocated texture after %u tries.", trycount);
  434. }
  435. if (lpD3DTexI->ddsd.ddpfPixelFormat.dwFlags & (DDPF_PALETTEINDEXED8 | DDPF_PALETTEINDEXED4 | DDPF_PALETTEINDEXED2 | DDPF_PALETTEINDEXED1))
  436. {
  437. LPDIRECTDRAWPALETTE lpDDPal;
  438. if (DD_OK != (ddrval = lpD3DTexI->lpDDSSys->GetPalette(&lpDDPal)))
  439. {
  440. D3D_ERR("failed to check for palette on texture");
  441. goto exit3;
  442. }
  443. if (DD_OK != (ddrval = lpD3DTexI->lpDDS->SetPalette(lpDDPal)))
  444. {
  445. lpDDPal->Release();
  446. D3D_ERR("SetPalette returned error");
  447. goto exit3;
  448. }
  449. lpDDPal->Release();
  450. }
  451. { // scope for CLockD3DST
  452. // Mark everything dirty before copying sysmem to vidmem
  453. // else CopySurface will not copy anything
  454. lpD3DTexI->bDirty = TRUE;
  455. CLockD3DST lockObject(lpDevI, DPF_MODNAME, REMIND("")); // we access DDraw gbl in CopySurface
  456. // 0xFFFFFFFF is equivalent to ALL_FACES, but in addition indicates to CopySurface
  457. // that this is a sysmem -> vidmem transfer.
  458. if (DD_OK != (ddrval = lpDevI->CopySurface(lpD3DTexI->lpDDS, NULL, lpD3DTexI->lpDDSSys, NULL, 0xFFFFFFFF)))
  459. {
  460. D3D_ERR("CopySurface returned error");
  461. goto exit3;
  462. }
  463. lpD3DTexI->bDirty = FALSE;
  464. }
  465. lpD3DTexI->DDS1Tex.lpLcl = ((LPDDRAWI_DDRAWSURFACE_INT)(lpD3DTexI->lpDDS))->lpLcl;
  466. lpD3DTexI->m_hTex = ((LPDDRAWI_DDRAWSURFACE_INT)lpD3DTexI->lpDDS)->lpLcl->lpSurfMore->dwSurfaceHandle;
  467. ddrval = D3D_OK;
  468. goto exit1;
  469. exit3:
  470. m_heap_p[lpD3DTexI->ddsd.dwTextureStage].del(lpD3DTexI->m_dwHeapIndex);
  471. exit2:
  472. lpD3DTexI->lpDDS->Release();
  473. lpD3DTexI->lpDDS = NULL;
  474. exit1:
  475. for(dwStage = 0; dwStage < lpDevI->dwMaxTextureBlendStages; ++dwStage)
  476. {
  477. if(lpDevI->lpD3DMappedTexI[dwStage])
  478. {
  479. lpDevI->lpD3DMappedTexI[dwStage]->m_bInUse = FALSE;
  480. UpdatePriority(lpDevI->lpD3DMappedTexI[dwStage]);
  481. }
  482. }
  483. return ddrval;
  484. }
  485. #undef DPF_MODNAME
  486. #define DPF_MODNAME "TextureCacheManager::remove"
  487. //remove all HW handles and release surface
  488. void TextureCacheManager::remove(LPDIRECT3DTEXTUREI lpD3DTexI)
  489. {
  490. LPD3DI_TEXTUREBLOCK tBlock = LIST_FIRST(&lpD3DTexI->blocks);
  491. while(tBlock)
  492. {
  493. CLockD3DST lockObject(tBlock->lpDevI, DPF_MODNAME, REMIND(""));
  494. D3DI_RemoveTextureHandle(tBlock);
  495. tBlock=LIST_NEXT(tBlock,list);
  496. }
  497. D3D_INFO(7,"removing lpD3DTexI=%08lx lpDDS=%08lx",lpD3DTexI,lpD3DTexI->lpDDS);
  498. lpD3DTexI->lpDDS->Release();
  499. lpD3DTexI->lpDDS = NULL;
  500. lpD3DTexI->m_hTex = 0;
  501. #if COLLECTSTATS
  502. --m_stats.dwWorkingSet;
  503. m_stats.dwWorkingSetBytes -= lpD3DTexI->m_dwVidBytes;
  504. #endif
  505. }
  506. #undef DPF_MODNAME
  507. #define DPF_MODNAME "TextureCacheManager::EvictTextures"
  508. void TextureCacheManager::EvictTextures()
  509. {
  510. for(DWORD i = 0; i < m_dwNumHeaps; ++i)
  511. while(m_heap_p[i].length())
  512. {
  513. LPDIRECT3DTEXTUREI lpD3DTexI = m_heap_p[i].extractMin();
  514. remove(lpD3DTexI);
  515. }
  516. D3DTextureUpdate(static_cast<LPUNKNOWN>(&(lpDirect3DI->mD3DUnk)));
  517. tcm_ticks = 0;
  518. m_dwScene = 0;
  519. }
  520. #undef DPF_MODNAME
  521. #define DPF_MODNAME "TextureCacheManager::CheckIfLost"
  522. BOOL TextureCacheManager::CheckIfLost()
  523. {
  524. for(DWORD i = 0; i < m_dwNumHeaps; ++i)
  525. {
  526. if(m_heap_p[i].length())
  527. {
  528. if(((LPDDRAWI_DDRAWSURFACE_INT)(m_heap_p[i].minCost()->lpDDS))->lpLcl->dwFlags & DDRAWISURF_INVALID)
  529. return TRUE;
  530. else
  531. return FALSE;
  532. }
  533. }
  534. return FALSE;
  535. }
  536. #undef DPF_MODNAME
  537. #define DPF_MODNAME "TextureCacheManager::TimeStamp"
  538. void TextureCacheManager::TimeStamp(LPDIRECT3DTEXTUREI lpD3DTexI)
  539. {
  540. lpD3DTexI->m_dwScene = m_dwScene;
  541. m_heap_p[lpD3DTexI->ddsd.dwTextureStage].update(lpD3DTexI->m_dwHeapIndex, lpD3DTexI->m_bInUse, lpD3DTexI->m_dwPriority, tcm_ticks);
  542. unsigned tickp2 = tcm_ticks + 2;
  543. if(tickp2 > tcm_ticks)
  544. {
  545. tcm_ticks = tickp2;
  546. }
  547. else // counter has overflowed. Let's reset all timestamps to zero
  548. {
  549. D3D_INFO(2, "Timestamp counter overflowed. Reseting timestamps for all textures.");
  550. tcm_ticks = 0;
  551. for(DWORD i = 0; i < m_dwNumHeaps; ++i)
  552. m_heap_p[i].resetAllTimeStamps(0);
  553. }
  554. }