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.

442 lines
17 KiB

  1. #include "pch.cpp"
  2. #pragma hdrstop
  3. #undef DPF_MODNAME
  4. #define DPF_MODNAME "TextureCacheManager"
  5. TextureCacheManager::TextureCacheManager(LPDIRECT3DI lpD3DI)
  6. {
  7. for(int i = 0; i < MAXLOGTEXSIZE; tcm_bucket[i++] = NULL);
  8. tcm_ticks = 0;
  9. numvidtex = 0;
  10. lpDirect3DI=lpD3DI;
  11. }
  12. TextureCacheManager::~TextureCacheManager()
  13. {
  14. for(int i = 0; i < MAXLOGTEXSIZE;i++){
  15. LPD3DBUCKET bucket=tcm_bucket[i];
  16. while(bucket){
  17. tcm_bucket[i]=bucket->next;
  18. if (bucket->lpD3DTexI) remove(bucket);
  19. D3DFreeBucket(lpDirect3DI,bucket);
  20. bucket=tcm_bucket[i];
  21. }
  22. }
  23. }
  24. BOOL TextureCacheManager::freeNode(LPD3DI_TEXTUREBLOCK lpBlock, LPD3DBUCKET* lplpBucket)
  25. {
  26. // Starting from the current size, find the LRU texture and remove it.
  27. unsigned int oldest = tcm_ticks;
  28. LPD3DBUCKET bucket,last,target=NULL;
  29. int k=lpBlock->lpD3DTextureI->LogTexSize;
  30. DWORD dwTextureStage=lpBlock->lpD3DTextureI->ddsd.dwTextureStage;
  31. BOOL bSingleMemory = !(lpBlock->lpDevI->lpD3DHALGlobalDriverData->hwCaps.dwDevCaps & D3DDEVCAPS_SEPARATETEXTUREMEMORIES);
  32. D3D_INFO(8,"freeing size %d bSingleMemory=%d",k,bSingleMemory);
  33. for(int i = k; i < MAXLOGTEXSIZE; ++i) {
  34. for(bucket=tcm_bucket[i],last=NULL; bucket;){
  35. if (!bucket->lpD3DTexI){ //invalidated by Tex3I destructors ?
  36. LPD3DBUCKET temp=bucket->next;
  37. D3DFreeBucket(lpDirect3DI,bucket);
  38. bucket=temp;
  39. if (last){ // Yes, but is this the first node on the list
  40. last->next=bucket;
  41. }
  42. else
  43. {
  44. tcm_bucket[i]=bucket;
  45. }
  46. continue;
  47. }
  48. if(bucket->ticks < oldest &&
  49. (bSingleMemory || (bucket->lpD3DTexI->ddsd.dwTextureStage == dwTextureStage)) &&
  50. !bucket->lpD3DTexI->bInUse)
  51. {
  52. oldest = bucket->ticks;
  53. target = bucket;
  54. }
  55. last=bucket;
  56. bucket=last->next;
  57. }
  58. if (oldest != tcm_ticks)
  59. {
  60. if (i==k &&
  61. !(lpBlock->lpD3DTextureI->ddsd.ddsCaps.dwCaps2 &
  62. (DDSCAPS2_HINTSTATIC | DDSCAPS2_OPAQUE)
  63. ) &&
  64. !(target->lpD3DTexI->ddsd.ddsCaps.dwCaps2 &
  65. (DDSCAPS2_HINTSTATIC | DDSCAPS2_OPAQUE)
  66. ) &&
  67. !(!(lpBlock->lpD3DTextureI->ddsd.ddsCaps.dwCaps & DDSCAPS_MIPMAP) && (target->lpD3DTexI->ddsd.ddsCaps.dwCaps & DDSCAPS_MIPMAP)
  68. ) &&
  69. !((DDPF_PALETTEINDEXED1 |
  70. DDPF_PALETTEINDEXED2 | DDPF_PALETTEINDEXED4 | DDPF_PALETTEINDEXED8)
  71. & lpBlock->lpD3DTextureI->ddsd.ddpfPixelFormat.dwFlags)) //workaround of ddraw not updating surface pallete
  72. *lplpBucket=target; //possible candidate for replace
  73. else
  74. remove(target);
  75. return TRUE;
  76. }
  77. }
  78. // If bigger size texture not found, try smaller sizes.
  79. for(i = k - 1; i > 0; --i) {
  80. for(bucket=tcm_bucket[i],last=NULL; bucket;){
  81. if (!bucket->lpD3DTexI){ //invalidated by TexI destructors ?
  82. LPD3DBUCKET temp=bucket->next;
  83. D3DFreeBucket(lpDirect3DI,bucket);
  84. bucket=temp;
  85. if (last){ // Yes, but is this the first node on the list
  86. last->next=bucket;
  87. }
  88. else
  89. {
  90. tcm_bucket[i]=bucket;
  91. }
  92. continue;
  93. }
  94. if(bucket->ticks < oldest &&
  95. (bSingleMemory || (bucket->lpD3DTexI->ddsd.dwTextureStage == dwTextureStage)) &&
  96. !bucket->lpD3DTexI->bInUse)
  97. {
  98. oldest = bucket->ticks;
  99. target = bucket;
  100. }
  101. last=bucket;
  102. bucket=last->next;
  103. }
  104. if (oldest != tcm_ticks)
  105. {
  106. remove(target);
  107. return TRUE;
  108. }
  109. }
  110. return FALSE;
  111. }
  112. HRESULT MarkDirtyPointers(LPDIRECT3DTEXTUREI lpD3DTexI)
  113. {
  114. // Next, we need to loop thru and set pointers to the dirty
  115. // bit in the DDraw surfaces
  116. HRESULT ddrval;
  117. DDSCAPS2 ddscaps;
  118. LPDIRECTDRAWSURFACE4 lpDDSTmp, lpDDS = lpD3DTexI->lpDDS, lpDDSSys = lpD3DTexI->lpDDSSys;
  119. do
  120. {
  121. ((LPDDRAWI_DDRAWSURFACE_INT) lpDDS)->lpLcl->lpSurfMore->lpbDirty = &(lpD3DTexI->bDirty);
  122. ((LPDDRAWI_DDRAWSURFACE_INT) lpDDS)->lpLcl->lpSurfMore->lpRegionList = ((LPDDRAWI_DDRAWSURFACE_INT)lpDDSSys)->lpLcl->lpSurfMore->lpRegionList;
  123. memset(&ddscaps, 0, sizeof(ddscaps));
  124. ddscaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_MIPMAP;
  125. ddrval = lpDDS->GetAttachedSurface(&ddscaps, &lpDDSTmp);
  126. if (lpDDS != lpD3DTexI->lpDDS) lpDDS->Release();
  127. lpDDS = lpDDSTmp;
  128. if (DDERR_NOTFOUND == ddrval)
  129. {
  130. if (lpDDSSys != lpD3DTexI->lpDDSSys) lpDDSSys->Release();
  131. return D3D_OK;
  132. }
  133. else if(DD_OK != ddrval)
  134. {
  135. D3D_ERR("GetAttachedSurface failed unexpectedly in MarkDirtyPointers");
  136. if (lpDDSSys != lpD3DTexI->lpDDSSys) lpDDSSys->Release();
  137. return ddrval;
  138. }
  139. memset(&ddscaps, 0, sizeof(ddscaps));
  140. ddscaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_MIPMAP;
  141. ddrval = lpDDSSys->GetAttachedSurface(&ddscaps, &lpDDSTmp);
  142. if (lpDDSSys != lpD3DTexI->lpDDSSys) lpDDSSys->Release();
  143. lpDDSSys = lpDDSTmp;
  144. }
  145. while(ddrval == DD_OK);
  146. D3D_ERR("GetAttachedSurface failed unexpectedly in MarkDirtyPointers");
  147. if (lpDDS != lpD3DTexI->lpDDS) lpDDS->Release();
  148. return ddrval;
  149. }
  150. #undef DPF_MODNAME
  151. #define DPF_MODNAME "TextureCacheManager::allocNode"
  152. HRESULT TextureCacheManager::allocNode(LPD3DI_TEXTUREBLOCK lpBlock)
  153. {
  154. LPD3DBUCKET lpCachedTexture=NULL;
  155. DWORD pcaps,dwCaps;
  156. HRESULT ddrval;
  157. LPDIRECT3DTEXTUREI lpD3DTexI=lpBlock->lpD3DTextureI;
  158. DDASSERT(!lpBlock->hTex && lpD3DTexI && lpBlock->lpDevI);
  159. if (0 == lpD3DTexI->LogTexSize)
  160. {
  161. DWORD texsize; // in the number of half bytes
  162. // Compute log2 of the texture size. This is the bucket index.
  163. memset(&lpD3DTexI->ddsd, 0, sizeof(lpD3DTexI->ddsd));
  164. lpD3DTexI->ddsd.dwSize = sizeof(lpD3DTexI->ddsd);
  165. if (DD_OK != (ddrval=lpD3DTexI->lpDDSSys->GetSurfaceDesc(&lpD3DTexI->ddsd)))
  166. {
  167. D3D_WARN(1,"GetSurfaceDesc failed in TextureCacheManager::allocNode");
  168. return ddrval;
  169. }
  170. if (DDSD_LINEARSIZE & lpD3DTexI->ddsd.dwFlags)
  171. {
  172. texsize = lpD3DTexI->ddsd.dwLinearSize*2;
  173. }
  174. else
  175. {
  176. texsize = lpD3DTexI->ddsd.dwWidth*lpD3DTexI->ddsd.dwHeight*lpD3DTexI->ddsd.ddpfPixelFormat.dwRGBBitCount/4;
  177. }
  178. if (0 != texsize )
  179. {
  180. for(; (texsize & 1) == 0; texsize >>= 1) ++lpD3DTexI->LogTexSize;
  181. }
  182. else
  183. lpD3DTexI->LogTexSize=1;
  184. D3D_INFO(7,"Managed Texture size=%d",lpD3DTexI->LogTexSize);
  185. DDASSERT(lpD3DTexI->LogTexSize < MAXLOGTEXSIZE );
  186. lpD3DTexI->ddsd.dwFlags &= ~DDSD_PITCH; // DDRAW always give that, but we don't want
  187. lpD3DTexI->ddsd.ddsCaps.dwCaps &= ~DDSCAPS_SYSTEMMEMORY;
  188. lpD3DTexI->ddsd.ddsCaps.dwCaps2 &= ~(DDSCAPS2_TEXTUREMANAGE);
  189. lpD3DTexI->ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
  190. }
  191. // Attempt to allocate a texture. If out of video memory, first try to replace
  192. // an old texture. If replacement not possible, free old textures using an LRU scheme
  193. // till enough memory is available.
  194. do {
  195. ddrval = lpDirect3DI->lpDD4->CreateSurface(&lpD3DTexI->ddsd, &lpD3DTexI->lpDDS, NULL);
  196. if (DD_OK== ddrval) { // No problem, there is enough memory.
  197. if (D3D_OK != (ddrval=MarkDirtyPointers(lpD3DTexI)))
  198. {
  199. lpD3DTexI->lpDDS->Release();
  200. lpD3DTexI->lpDDS=NULL;
  201. return ddrval;
  202. }
  203. if (D3D_OK != (ddrval=D3DMallocBucket(lpDirect3DI,&lpCachedTexture)))
  204. {
  205. lpD3DTexI->lpDDS->Release();
  206. lpD3DTexI->lpDDS=NULL;
  207. return ddrval;
  208. }
  209. lpCachedTexture->next=tcm_bucket[lpD3DTexI->LogTexSize];
  210. lpCachedTexture->lpD3DTexI=lpD3DTexI;
  211. lpCachedTexture->ticks=tcm_ticks;
  212. tcm_bucket[lpD3DTexI->LogTexSize]=lpCachedTexture;
  213. ++numvidtex;
  214. }
  215. else
  216. if(ddrval == DDERR_OUTOFVIDEOMEMORY) { // If out of video memory
  217. if (freeNode(lpBlock,&lpCachedTexture))
  218. {
  219. if (lpCachedTexture)
  220. { //found a replace candidate
  221. replace(lpCachedTexture,lpBlock);
  222. if ( lpD3DTexI->ddsd.dwWidth == lpCachedTexture->lpD3DTexI->ddsd.dwWidth
  223. && lpD3DTexI->ddsd.dwHeight == lpCachedTexture->lpD3DTexI->ddsd.dwHeight
  224. && lpD3DTexI->ddsd.ddpfPixelFormat.dwRBitMask == lpCachedTexture->lpD3DTexI->ddsd.ddpfPixelFormat.dwRBitMask
  225. && lpD3DTexI->ddsd.ddpfPixelFormat.dwFlags == lpCachedTexture->lpD3DTexI->ddsd.ddpfPixelFormat.dwFlags
  226. )
  227. {
  228. lpD3DTexI->lpDDS = lpCachedTexture->lpD3DTexI->lpDDS;
  229. if (DD_OK == CopySurface(lpD3DTexI->lpDDS,lpD3DTexI->lpDDSSys,NULL)
  230. && D3D_OK == MarkDirtyPointers(lpD3DTexI) )
  231. {
  232. lpCachedTexture->lpD3DTexI->lpDDS=NULL;
  233. lpD3DTexI->lpTMBucket=lpCachedTexture;
  234. lpCachedTexture->lpD3DTexI->lpTMBucket=NULL;
  235. lpD3DTexI->lpDDS1Tex = lpCachedTexture->lpD3DTexI->lpDDS1Tex;
  236. lpCachedTexture->lpD3DTexI->lpDDS1Tex=NULL;
  237. lpCachedTexture->lpD3DTexI=lpD3DTexI;
  238. lpCachedTexture->ticks=tcm_ticks;
  239. lpD3DTexI->bDirty=FALSE;
  240. return D3D_OK;
  241. }
  242. lpD3DTexI->lpDDS = NULL;
  243. D3D_WARN(2,"(%d %d %d) matching replace failed in TextureCacheManager::allocNode lpD3DTexI=%08lx with lpDDS=%08lx",
  244. lpD3DTexI->LogTexSize,lpD3DTexI->ddsd.dwWidth,lpD3DTexI->ddsd.dwHeight,lpD3DTexI,lpCachedTexture->lpD3DTexI->lpDDS);
  245. }
  246. if (lpBlock->hTex) //copy failed, therefore clear handle also
  247. {
  248. CLockD3DST lockObject(lpBlock->lpDevI, DPF_MODNAME, REMIND(""));
  249. D3DHAL_TextureDestroy(lpBlock);
  250. }
  251. remove(lpCachedTexture);
  252. lpCachedTexture=NULL;
  253. }
  254. }
  255. else
  256. {
  257. D3D_ERR("all Freed no further video memory available");
  258. #if DBG
  259. D3D_INFO(4,"freeing size %d dwTextureStage=%d tcm_ticks=%08lx dwCaps =%08lx failed",
  260. lpD3DTexI->LogTexSize,lpD3DTexI->ddsd.dwTextureStage,tcm_ticks,lpD3DTexI->ddsd.ddsCaps.dwCaps);
  261. for(int i = 0; i < MAXLOGTEXSIZE; ++i)
  262. {
  263. if (tcm_bucket[i]) D3D_INFO(5,"List of size %d",i);
  264. for(LPD3DBUCKET bucket=tcm_bucket[i];bucket;bucket=bucket->next)
  265. {
  266. if (bucket->lpD3DTexI)
  267. D3D_INFO(5,"ticks=%08lx lpD3DTexI=%08lx InUse=%08lx dwTextureStage=%d",
  268. bucket->ticks,bucket->lpD3DTexI,
  269. bucket->lpD3DTexI->bInUse,
  270. bucket->lpD3DTexI->ddsd.dwTextureStage);
  271. }
  272. }
  273. #endif
  274. return DDERR_OUTOFVIDEOMEMORY; //nothing left
  275. }
  276. }
  277. else{
  278. D3D_ERR("Unexpected error got in allocNode");
  279. return ddrval;
  280. }
  281. }while(ddrval == DDERR_OUTOFVIDEOMEMORY);
  282. if (lpD3DTexI->ddsd.ddpfPixelFormat.dwFlags & (DDPF_PALETTEINDEXED8 | DDPF_PALETTEINDEXED4)) {
  283. LPDIRECTDRAWPALETTE lpDDPal;
  284. if (DD_OK != (ddrval=lpD3DTexI->lpDDSSys->GetPalette(&lpDDPal))) {
  285. lpD3DTexI->lpDDS->Release();
  286. lpD3DTexI->lpDDS=NULL;
  287. lpCachedTexture->lpD3DTexI=NULL;
  288. D3D_ERR("failed to check for palette on texture");
  289. return ddrval;
  290. }
  291. if (DD_OK != (ddrval=lpD3DTexI->lpDDS->SetPalette(lpDDPal))){
  292. lpD3DTexI->lpDDS->Release();
  293. lpD3DTexI->lpDDS=NULL;
  294. lpCachedTexture->lpD3DTexI=NULL;
  295. D3D_ERR("SetPalette returned error");
  296. return ddrval;
  297. }
  298. lpDDPal->Release();
  299. }
  300. if (DD_OK != (ddrval=CopySurface(lpD3DTexI->lpDDS,lpD3DTexI->lpDDSSys,NULL))){
  301. lpD3DTexI->lpDDS->Release();
  302. lpD3DTexI->lpDDS=NULL;
  303. lpCachedTexture->lpD3DTexI=NULL;
  304. D3D_ERR("CopySurface returned error");
  305. return ddrval;
  306. }
  307. lpD3DTexI->bDirty=FALSE;
  308. lpD3DTexI->lpTMBucket=lpCachedTexture;
  309. return D3D_OK;
  310. }
  311. #undef DPF_MODNAME
  312. #define DPF_MODNAME "TextureCacheManager::remove"
  313. //remove all HW handles and release surface
  314. void TextureCacheManager::remove(LPD3DBUCKET bucket)
  315. {
  316. LPDIRECT3DTEXTUREI lpD3DTexI=bucket->lpD3DTexI;
  317. LPD3DI_TEXTUREBLOCK tBlock = LIST_FIRST(&lpD3DTexI->blocks);
  318. while(tBlock){
  319. if (tBlock->hTex)
  320. {
  321. CLockD3DST lockObject(tBlock->lpDevI, DPF_MODNAME, REMIND(""));
  322. D3DHAL_TextureDestroy(tBlock);
  323. }
  324. tBlock=LIST_NEXT(tBlock,list);
  325. }
  326. D3D_INFO(7,"removing lpD3DTexI=%08lx lpDDS=%08lx",lpD3DTexI,lpD3DTexI->lpDDS);
  327. lpD3DTexI->lpDDS1Tex->Release();
  328. lpD3DTexI->lpDDS1Tex=NULL;
  329. lpD3DTexI->lpDDS->Release();
  330. lpD3DTexI->lpDDS=NULL;
  331. lpD3DTexI->lpTMBucket=NULL;
  332. bucket->lpD3DTexI=NULL;
  333. --numvidtex;
  334. }
  335. #undef DPF_MODNAME
  336. #define DPF_MODNAME "TextureCacheManager::replace"
  337. //remove any HW handle that's not with lpBlock->lpDevI,save lpBlock->hTex,keep surface
  338. void TextureCacheManager::replace(LPD3DBUCKET bucket,LPD3DI_TEXTUREBLOCK lpBlock)
  339. {
  340. LPD3DI_TEXTUREBLOCK tBlock = LIST_FIRST(&bucket->lpD3DTexI->blocks);
  341. while(tBlock){
  342. if (tBlock->hTex)
  343. {
  344. if (tBlock->lpDevI == lpBlock->lpDevI)
  345. {
  346. lpBlock->hTex=tBlock->hTex; //save it
  347. //flush before copy
  348. LPD3DBUCKET list = reinterpret_cast<LPD3DBUCKET>(((LPDDRAWI_DDRAWSURFACE_INT)(tBlock->lpD3DTextureI->lpDDS))->lpLcl->lpSurfMore->lpD3DDevIList);
  349. while(list != NULL)
  350. {
  351. if(list->lpD3DDevI == tBlock->lpDevI)
  352. {
  353. if(tBlock->lpDevI->FlushStates() != D3D_OK)
  354. {
  355. D3D_ERR("Error trying to render batched commands in TextureCacheManager::replace");
  356. }
  357. break;
  358. }
  359. list = list->next;
  360. }
  361. tBlock->hTex=0;
  362. }
  363. else
  364. {
  365. CLockD3DST lockObject(tBlock->lpDevI, DPF_MODNAME, REMIND(""));
  366. D3DHAL_TextureDestroy(tBlock);
  367. }
  368. }
  369. tBlock=LIST_NEXT(tBlock,list);
  370. }
  371. D3D_INFO(7,"replacing lpDDS=%08lx from lpD3DTexI=%08lx",bucket->lpD3DTexI->lpDDS,bucket->lpD3DTexI);
  372. }
  373. void TextureCacheManager::EvictTextures()
  374. {
  375. for(int i = 0; i < MAXLOGTEXSIZE;i++){
  376. LPD3DBUCKET bucket=tcm_bucket[i];
  377. while(bucket){
  378. if (bucket->lpD3DTexI)
  379. {
  380. remove(bucket);
  381. }
  382. bucket=bucket->next;
  383. }
  384. }
  385. }
  386. void TextureCacheManager::cleanup()
  387. {
  388. for(int i = 0; i < MAXLOGTEXSIZE;i++){
  389. for(LPD3DBUCKET bucket=tcm_bucket[i],last=NULL; bucket;){
  390. if (!bucket->lpD3DTexI){ //invalidated by Tex3I destructors ?
  391. LPD3DBUCKET temp=bucket->next;
  392. D3DFreeBucket(lpDirect3DI,bucket);
  393. bucket=temp;
  394. if (last){ // Yes, but is this the first node on the list
  395. last->next=bucket;
  396. }
  397. else
  398. {
  399. tcm_bucket[i]=bucket;
  400. }
  401. }
  402. else{
  403. last=bucket;
  404. bucket=last->next;
  405. }
  406. }
  407. }
  408. }
  409. BOOL TextureCacheManager::CheckIfLost()
  410. {
  411. if(numvidtex)
  412. {
  413. for(int i = 0; i < MAXLOGTEXSIZE; ++i)
  414. {
  415. for(LPD3DBUCKET bucket = tcm_bucket[i]; bucket; bucket = bucket->next)
  416. {
  417. if(bucket->lpD3DTexI)
  418. {
  419. if(((LPDDRAWI_DDRAWSURFACE_INT)(bucket->lpD3DTexI->lpDDS))->lpLcl->dwFlags & DDRAWISURF_INVALID)
  420. return TRUE;
  421. else
  422. return FALSE;
  423. }
  424. }
  425. }
  426. }
  427. return FALSE;
  428. }