GSTextureCache.cpp
上传用户:xjjlds
上传日期:2015-12-05
资源大小:22823k
文件大小:30k
源码类别:

多媒体编程

开发平台:

Visual C++

  1. /* 
  2.  * Copyright (C) 2003-2005 Gabest
  3.  * http://www.gabest.org
  4.  *
  5.  *  This Program is free software; you can redistribute it and/or modify
  6.  *  it under the terms of the GNU General Public License as published by
  7.  *  the Free Software Foundation; either version 2, or (at your option)
  8.  *  any later version.
  9.  *   
  10.  *  This Program is distributed in the hope that it will be useful,
  11.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13.  *  GNU General Public License for more details.
  14.  *   
  15.  *  You should have received a copy of the GNU General Public License
  16.  *  along with GNU Make; see the file COPYING.  If not, write to
  17.  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
  18.  *  http://www.gnu.org/copyleft/gpl.html
  19.  *
  20.  */
  21. #include "StdAfx.h"
  22. #include "GSTextureCache.h"
  23. #include "GSHash.h"
  24. #include "GSRendererHW.h"
  25. //
  26. bool IsRenderTarget(IDirect3DTexture9* pTexture)
  27. {
  28. D3DSURFACE_DESC desc;
  29. memset(&desc, 0, sizeof(desc));
  30. return pTexture && S_OK == pTexture->GetLevelDesc(0, &desc) && (desc.Usage&D3DUSAGE_RENDERTARGET);
  31. }
  32. bool HasSharedBits(DWORD sbp, DWORD spsm, DWORD dbp, DWORD dpsm)
  33. {
  34. if(sbp != dbp) return false;
  35. switch(spsm)
  36. {
  37. case PSM_PSMCT32:
  38. case PSM_PSMCT16:
  39. case PSM_PSMCT16S:
  40. case PSM_PSMT8:
  41. case PSM_PSMT4:
  42. return true;
  43. case PSM_PSMCT24:
  44. return !(dpsm == PSM_PSMT8H || dpsm == PSM_PSMT4HL || dpsm == PSM_PSMT4HH);
  45. case PSM_PSMT8H:
  46. return !(dpsm == PSM_PSMCT24);
  47. case PSM_PSMT4HL:
  48. return !(dpsm == PSM_PSMCT24 || dpsm == PSM_PSMT4HH);
  49. case PSM_PSMT4HH:
  50. return !(dpsm == PSM_PSMCT24 || dpsm == PSM_PSMT4HL);
  51. }
  52. return true;
  53. }
  54. //
  55. GSDirtyRect::GSDirtyRect(DWORD PSM, CRect r)
  56. {
  57. m_PSM = PSM;
  58. m_rcDirty = r;
  59. }
  60. CRect GSDirtyRect::GetDirtyRect(const GIFRegTEX0& TEX0)
  61. {
  62. CRect rcDirty = m_rcDirty;
  63. CSize src = GSLocalMemory::m_psmtbl[m_PSM].bs;
  64. rcDirty.left = (rcDirty.left) & ~(src.cx-1);
  65. rcDirty.right = (rcDirty.right + (src.cx-1) /* + 1 */) & ~(src.cx-1);
  66. rcDirty.top = (rcDirty.top) & ~(src.cy-1);
  67. rcDirty.bottom = (rcDirty.bottom + (src.cy-1) /* + 1 */) & ~(src.cy-1);
  68. if(m_PSM != TEX0.PSM)
  69. {
  70. CSize dst = GSLocalMemory::m_psmtbl[TEX0.PSM].bs;
  71. rcDirty.left = MulDiv(m_rcDirty.left, dst.cx, src.cx);
  72. rcDirty.right = MulDiv(m_rcDirty.right, dst.cx, src.cx);
  73. rcDirty.top = MulDiv(m_rcDirty.top, dst.cy, src.cy);
  74. rcDirty.bottom = MulDiv(m_rcDirty.bottom, dst.cy, src.cy);
  75. }
  76. rcDirty &= CRect(0, 0, 1<<TEX0.TW, 1<<TEX0.TH);
  77. return rcDirty;
  78. }
  79. void GSDirtyRectList::operator = (const GSDirtyRectList& l)
  80. {
  81. RemoveAll();
  82. POSITION pos = l.GetHeadPosition();
  83. while(pos) AddTail(l.GetNext(pos));
  84. }
  85. CRect GSDirtyRectList::GetDirtyRect(const GIFRegTEX0& TEX0)
  86. {
  87. if(IsEmpty()) return CRect(0, 0, 0, 0);
  88. CRect r(INT_MAX, INT_MAX, 0, 0);
  89. POSITION pos = GetHeadPosition();
  90. while(pos) r |= GetNext(pos).GetDirtyRect(TEX0);
  91. return r;
  92. }
  93. //
  94. GSTextureBase::GSTextureBase()
  95. {
  96. m_scale = scale_t(1, 1);
  97. m_fRT = false;
  98. memset(&m_desc, 0, sizeof(m_desc));
  99. }
  100. GSTexture::GSTexture()
  101. {
  102. m_TEX0.TBP0 = ~0;
  103. m_rcValid = CRect(0, 0, 0, 0);
  104. m_dwHash = ~0;
  105. m_nHashDiff = m_nHashSame = 0;
  106. m_rcHash = CRect(0, 0, 0, 0);
  107. m_nBytes = 0;
  108. m_nAge = 0;
  109. m_nVsyncs = 0;
  110. m_fTemp = false;
  111. }
  112. //
  113. GSTextureCache::GSTextureCache()
  114. {
  115. }
  116. GSTextureCache::~GSTextureCache()
  117. {
  118. RemoveAll();
  119. }
  120. HRESULT GSTextureCache::CreateTexture(GSState* s, GSTexture* pt, DWORD PSM, DWORD CPSM)
  121. {
  122. if(!pt || pt->m_pTexture) {ASSERT(0); return E_FAIL;}
  123. int w = 1 << pt->m_TEX0.TW;
  124. int h = 1 << pt->m_TEX0.TH;
  125. int bpp = 0;
  126. D3DFORMAT fmt = D3DFMT_UNKNOWN;
  127. D3DFORMAT palfmt = D3DFMT_UNKNOWN;
  128. switch(PSM)
  129. {
  130. default:
  131. case PSM_PSMCT32:
  132. bpp = 32;
  133. fmt = D3DFMT_A8R8G8B8;
  134. break;
  135. case PSM_PSMCT24:
  136. bpp = 32;
  137. fmt = D3DFMT_X8R8G8B8;
  138. break;
  139. case PSM_PSMCT16:
  140. case PSM_PSMCT16S:
  141. bpp = 16;
  142. fmt = D3DFMT_A1R5G5B5;
  143. break;
  144. case PSM_PSMT8:
  145. case PSM_PSMT4:
  146. case PSM_PSMT8H:
  147. case PSM_PSMT4HL:
  148. case PSM_PSMT4HH:
  149. bpp = 8;
  150. fmt = D3DFMT_L8;
  151. palfmt = CPSM == PSM_PSMCT32 ? D3DFMT_A8R8G8B8 : D3DFMT_A1R5G5B5;
  152. break;
  153. }
  154. pt->m_nBytes = w*h*bpp>>3;
  155. POSITION pos = m_pTexturePool.GetHeadPosition();
  156. while(pos)
  157. {
  158. IDirect3DTexture9* pTexture = m_pTexturePool.GetNext(pos);
  159. D3DSURFACE_DESC desc;
  160. memset(&desc, 0, sizeof(desc));
  161. pTexture->GetLevelDesc(0, &desc);
  162. if(w == desc.Width && h == desc.Height && fmt == desc.Format && !IsTextureInCache(pTexture))
  163. {
  164. pt->m_pTexture = pTexture;
  165. pt->m_desc = desc;
  166. break;
  167. }
  168. }
  169. if(!pt->m_pTexture)
  170. {
  171. while(m_pTexturePool.GetCount() > 20)
  172. m_pTexturePool.RemoveTail();
  173. if(FAILED(s->m_pD3DDev->CreateTexture(w, h, 1, 0, fmt, D3DPOOL_MANAGED, &pt->m_pTexture, NULL)))
  174. return E_FAIL;
  175. pt->m_pTexture->GetLevelDesc(0, &pt->m_desc);
  176. m_pTexturePool.AddHead(pt->m_pTexture);
  177. }
  178. if(bpp == 8)
  179. {
  180. if(FAILED(s->m_pD3DDev->CreateTexture(256, 1, 1, 0, palfmt, D3DPOOL_MANAGED, &pt->m_pPalette, NULL)))
  181. {
  182. pt->m_pTexture = NULL;
  183. return E_FAIL;
  184. }
  185. }
  186. return S_OK;
  187. }
  188. bool GSTextureCache::IsTextureInCache(IDirect3DTexture9* pTexture)
  189. {
  190. POSITION pos = GetHeadPosition();
  191. while(pos)
  192. {
  193. if(GetNext(pos)->m_pTexture == pTexture)
  194. return true;
  195. }
  196. return false;
  197. }
  198. void GSTextureCache::RemoveOldTextures(GSState* s)
  199. {
  200. DWORD nBytes = 0;
  201. POSITION pos = GetHeadPosition();
  202. while(pos) nBytes += GetNext(pos)->m_nBytes;
  203. pos = GetTailPosition();
  204. while(pos && nBytes > 96*1024*1024/*s->m_ddcaps.dwVidMemTotal*/)
  205. {
  206. #ifdef DEBUG_LOG
  207. s->LOG(_T("*TC2 too many textures in cache (%d, %.2f MB)n"), GetCount(), 1.0f*nBytes/1024/1024);
  208. #endif
  209. POSITION cur = pos;
  210. GSTexture* pt = GetPrev(pos);
  211. if(!pt->m_fRT)
  212. {
  213. nBytes -= pt->m_nBytes;
  214. RemoveAt(cur);
  215. delete pt;
  216. }
  217. }
  218. }
  219. static bool RectInRect(const RECT& inner, const RECT& outer)
  220. {
  221. return outer.left <= inner.left && inner.right <= outer.right
  222. && outer.top <= inner.top && inner.bottom <= outer.bottom;
  223. }
  224. static bool RectInRectH(const RECT& inner, const RECT& outer)
  225. {
  226. return outer.top <= inner.top && inner.bottom <= outer.bottom;
  227. }
  228. static bool RectInRectV(const RECT& inner, const RECT& outer)
  229. {
  230. return outer.left <= inner.left && inner.right <= outer.right;
  231. }
  232. bool GSTextureCache::GetDirtyRect(GSState* s, GSTexture* pt, CRect& r)
  233. {
  234. int w = 1 << pt->m_TEX0.TW;
  235. int h = 1 << pt->m_TEX0.TH;
  236. r.SetRect(0, 0, w, h);
  237. // FIXME: kyo's left hand after being selected for player one (PS2-SNK_Vs_Capcom_SVC_Chaos_PAL_CDFull.iso)
  238. // return true;
  239. s->MinMaxUV(w, h, r);
  240. CRect rcDirty = pt->m_rcDirty.GetDirtyRect(pt->m_TEX0);
  241. CRect rcValid = pt->m_rcValid;
  242. #ifdef DEBUG_LOG
  243. s->LOG(_T("*TC2 used %d,%d-%d,%d (%dx%d), valid %d,%d-%d,%d, dirty %d,%d-%d,%dn"), r, w, h, rcValid, rcDirty);
  244. #endif
  245. if(RectInRect(r, rcValid))
  246. {
  247. if(rcDirty.IsRectEmpty()) return false;
  248. else if(RectInRect(rcDirty, r)) r = rcDirty;
  249. else if(RectInRect(rcDirty, rcValid)) r |= rcDirty;
  250. else r = rcValid | rcDirty;
  251. }
  252. else
  253. {
  254. if(RectInRectH(r, rcValid) && (r.left >= rcValid.left || r.right <= rcValid.right))
  255. {
  256. r.top = rcValid.top;
  257. r.bottom = rcValid.bottom;
  258. if(r.left < rcValid.left) r.right = rcValid.left;
  259. else /*if(r.right > rcValid.right)*/ r.left = rcValid.right;
  260. }
  261. else if(RectInRectV(r, rcValid) && (r.top >= rcValid.top || r.bottom <= rcValid.bottom))
  262. {
  263. r.left = rcValid.left;
  264. r.right = rcValid.right;
  265. if(r.top < rcValid.top) r.bottom = rcValid.top;
  266. else /*if(r.bottom > rcValid.bottom)*/ r.top = rcValid.bottom;
  267. }
  268. else
  269. {
  270. r |= rcValid;
  271. }
  272. }
  273. return true;
  274. }
  275. DWORD GSTextureCache::HashTexture(const CRect& r, int pitch, void* bits)
  276. {
  277. // TODO: make the hash more unique
  278. BYTE* p = (BYTE*)bits;
  279. DWORD hash = r.left + r.right + r.top + r.bottom + pitch + *(BYTE*)bits;
  280. if(r.Width() > 0)
  281. {
  282. int size = r.Width()*r.Height();
  283. /*
  284. if(size <= 8*8) return rand(); // :P
  285. else 
  286. */
  287. if(size <= 16*16) hash += hash_crc(r, pitch, p);
  288. else if(size <= 32*32) hash += hash_adler(r, pitch, p);
  289. else hash += hash_checksum(r, pitch, p);
  290. }
  291. return hash;
  292. }
  293. HRESULT GSTextureCache::UpdateTexture(GSState* s, GSTexture* pt, GSLocalMemory::readTexture rt)
  294. {
  295. CRect r;
  296. if(!GetDirtyRect(s, pt, r))
  297. return S_OK;
  298. #ifdef DEBUG_LOG
  299. s->LOG(_T("*TC2 updating texture %d,%d-%d,%d (%dx%d)n"), r.left, r.top, r.right, r.bottom, 1 << pt->m_TEX0.TW, 1 << pt->m_TEX0.TH);
  300. #endif
  301. int bpp = 0;
  302. switch(pt->m_desc.Format)
  303. {
  304. case D3DFMT_A8R8G8B8: bpp = 32; break;
  305. case D3DFMT_X8R8G8B8: bpp = 32; break;
  306. case D3DFMT_A1R5G5B5: bpp = 16; break;
  307. case D3DFMT_L8: bpp = 8; break;
  308. default: ASSERT(0); return E_FAIL;
  309. }
  310. D3DLOCKED_RECT lr;
  311. if(FAILED(pt->m_pTexture->LockRect(0, &lr, &r, D3DLOCK_NO_DIRTY_UPDATE))) {ASSERT(0); return E_FAIL;}
  312. (s->m_lm.*rt)(r, (BYTE*)lr.pBits, lr.Pitch, s->m_ctxt->TEX0, s->m_de.TEXA, s->m_ctxt->CLAMP);
  313. s->m_perfmon.IncCounter(GSPerfMon::c_unswizzle, r.Width()*r.Height()*bpp>>3);
  314. pt->m_pTexture->UnlockRect(0);
  315. pt->m_rcValid |= r;
  316. pt->m_rcDirty.RemoveAll();
  317. const static DWORD limit = 7;
  318. if((pt->m_nHashDiff & limit) && pt->m_nHashDiff >= limit && pt->m_rcHash == pt->m_rcValid) // predicted to be dirty
  319. {
  320. pt->m_nHashDiff++;
  321. }
  322. else
  323. {
  324. if(FAILED(pt->m_pTexture->LockRect(0, &lr, &pt->m_rcValid, D3DLOCK_NO_DIRTY_UPDATE|D3DLOCK_READONLY))) {ASSERT(0); return E_FAIL;}
  325. DWORD dwHash = HashTexture(
  326. CRect((pt->m_rcValid.left>>2)*(bpp>>3), pt->m_rcValid.top, (pt->m_rcValid.right>>2)*(bpp>>3), pt->m_rcValid.bottom), 
  327. lr.Pitch, lr.pBits);
  328. pt->m_pTexture->UnlockRect(0);
  329. if(pt->m_rcHash != pt->m_rcValid)
  330. {
  331. pt->m_nHashDiff = 0;
  332. pt->m_nHashSame = 0;
  333. pt->m_rcHash = pt->m_rcValid;
  334. pt->m_dwHash = dwHash;
  335. }
  336. else
  337. {
  338. if(pt->m_dwHash != dwHash)
  339. {
  340. pt->m_nHashDiff++;
  341. pt->m_nHashSame = 0;
  342. pt->m_dwHash = dwHash;
  343. }
  344. else
  345. {
  346. if(pt->m_nHashDiff < limit) r.SetRect(0, 0, 1, 1);
  347. // else pt->m_dwHash is not reliable, must update
  348. pt->m_nHashDiff = 0;
  349. pt->m_nHashSame++;
  350. }
  351. }
  352. }
  353. pt->m_pTexture->AddDirtyRect(&r);
  354. pt->m_pTexture->PreLoad();
  355. s->m_perfmon.IncCounter(GSPerfMon::c_texture, r.Width()*r.Height()*bpp>>3);
  356. #ifdef DEBUG_LOG
  357. s->LOG(_T("*TC2 texture was updated, valid %d,%dx%d,%dn"), pt->m_rcValid);
  358. #endif
  359. #ifdef DEBUG_SAVETEXTURES   
  360. if(s->m_ctxt->FRAME.Block() == 0x00000 && pt->m_TEX0.TBP0 == 0x02800)
  361. {   
  362. CString fn;   
  363. fn.Format(_T("c:\%08I64x_%I64d_%I64d_%I64d_%I64d_%I64d_%I64d_%I64d-%I64d_%I64d-%I64d.bmp"),   
  364. pt->m_TEX0.TBP0, pt->m_TEX0.PSM, pt->m_TEX0.TBW,   
  365. pt->m_TEX0.TW, pt->m_TEX0.TH,   
  366. pt->m_CLAMP.WMS, pt->m_CLAMP.WMT, pt->m_CLAMP.MINU, pt->m_CLAMP.MAXU, pt->m_CLAMP.MINV, pt->m_CLAMP.MAXV);   
  367. D3DXSaveTextureToFile(fn, D3DXIFF_BMP, pt->m_pTexture, NULL);   
  368. }   
  369. #endif 
  370. return S_OK;
  371. }
  372. GSTexture* GSTextureCache::ConvertRTPitch(GSState* s, GSTexture* pt)
  373. {
  374. if(pt->m_TEX0.TBW == s->m_ctxt->TEX0.TBW)
  375. return pt;
  376. // sfex3 uses this trick (bw: 10 -> 5, wraps the right side below the left)
  377. ASSERT(pt->m_TEX0.TBW > s->m_ctxt->TEX0.TBW); // otherwise scale.x need to be reduced to make the larger texture fit (TODO)
  378. int bw = 64;
  379. int bh = s->m_ctxt->TEX0.PSM == PSM_PSMCT32 || s->m_ctxt->TEX0.PSM == PSM_PSMCT24 ? 32 : 64;
  380. int sw = pt->m_TEX0.TBW << 6;
  381. int dw = s->m_ctxt->TEX0.TBW << 6;
  382. int dh = 1 << s->m_ctxt->TEX0.TH;
  383. // TRACE(_T("ConvertRT: %05x %x %d -> %dn"), (DWORD)s->m_ctxt->TEX0.TBP0, (DWORD)s->m_ctxt->TEX0.PSM, (DWORD)pt->m_TEX0.TBW, (DWORD)s->m_ctxt->TEX0.TBW);
  384. HRESULT hr;
  385. /*
  386. if(s->m_perfmon.GetFrame() > 400)
  387. hr = D3DXSaveTextureToFile(_T("g:/1.bmp"), D3DXIFF_BMP, pt->m_pTexture, NULL);
  388. */
  389. D3DSURFACE_DESC desc;
  390. hr = pt->m_pTexture->GetLevelDesc(0, &desc);
  391. if(FAILED(hr)) return NULL;
  392. CComPtr<IDirect3DTexture9> pRT;
  393. if(FAILED(hr = CreateRT(s, desc.Width, desc.Height, &pRT)))
  394. return NULL;
  395. CComPtr<IDirect3DSurface9> pSrc, pDst;
  396. hr = pRT->GetSurfaceLevel(0, &pSrc);
  397. if(FAILED(hr)) return NULL;
  398. hr = pt->m_pTexture->GetSurfaceLevel(0, &pDst);
  399. if(FAILED(hr)) return NULL;
  400. hr = s->m_pD3DDev->StretchRect(pDst, NULL, pSrc, NULL, D3DTEXF_POINT);
  401. if(FAILED(hr)) return NULL;
  402. scale_t scale(pt->m_pTexture);
  403. for(int dy = 0; dy < dh; dy += bh)
  404. {
  405. for(int dx = 0; dx < dw; dx += bw)
  406. {
  407. int o = dy * dw / bh + dx;
  408. int sx = o % sw;
  409. int sy = o / sw;
  410. // TRACE(_T("%d,%d - %d,%d  <=  %d,%d - %d,%dn"), dx, dy, dx + bw, dy + bh, sx, sy, sx + bw, sy + bh);
  411. CRect src, dst;
  412. src.left = (LONG)(scale.x * sx + 0.5f);
  413. src.top = (LONG)(scale.y * sy + 0.5f);
  414. src.right = (LONG)(scale.x * (sx + bw) + 0.5f);
  415. src.bottom = (LONG)(scale.y * (sy + bh) + 0.5f);
  416. dst.left = (LONG)(scale.x * dx + 0.5f);
  417. dst.top = (LONG)(scale.y * dy + 0.5f);
  418. dst.right = (LONG)(scale.x * (dx + bw) + 0.5f);
  419. dst.bottom = (LONG)(scale.y * (dy + bh) + 0.5f);
  420. hr = s->m_pD3DDev->StretchRect(pSrc, src, pDst, dst, D3DTEXF_POINT);
  421. // TODO: this is quite a lot of StretchRect call, do it with one DrawPrimUP
  422. }
  423. }
  424. pt->m_TEX0.TW = s->m_ctxt->TEX0.TW;
  425. pt->m_TEX0.TBW = s->m_ctxt->TEX0.TBW;
  426. /*
  427. if(s->m_perfmon.GetFrame() > 400)
  428. hr = D3DXSaveTextureToFile(_T("g:/2.bmp"), D3DXIFF_BMP, pt->m_pTexture, NULL);
  429. */
  430. return pt;
  431. }
  432. GSTexture* GSTextureCache::ConvertRTWidthHeight(GSState* s, GSTexture* pt)
  433. {
  434. int tw = pt->m_scale.x * (1 << s->m_ctxt->TEX0.TW);
  435. int th = pt->m_scale.y * (1 << s->m_ctxt->TEX0.TH);
  436. int rw = pt->m_desc.Width;
  437. int rh = pt->m_desc.Height;
  438. if(tw != rw || th != rh)
  439. //if(tw < rw && th <= rh || tw <= rw && th < rh)
  440. {
  441. GSTexture* pt2 = new GSTexture();
  442. pt2->m_pPalette = pt->m_pPalette;
  443. pt2->m_fRT = pt->m_pPalette == NULL;
  444. pt2->m_scale = pt->m_scale;
  445. pt2->m_fTemp = true;
  446. POSITION pos = pt->m_pSubTextures.GetHeadPosition();
  447. while(pos)
  448. {
  449. IDirect3DTexture9* pTexture = pt->m_pSubTextures.GetNext(pos);
  450. pTexture->GetLevelDesc(0, &pt2->m_desc);
  451. scale_t scale(pTexture);
  452. if(pt2->m_desc.Width == tw && pt2->m_desc.Height == th
  453. && pt2->m_scale.x == scale.x && pt2->m_scale.y == scale.y)
  454. {
  455. pt2->m_pTexture = pTexture;
  456. break;
  457. }
  458. }
  459. if(!pt2->m_pTexture)
  460. {
  461. CRect dst(0, 0, tw, th);
  462. if(tw > rw)
  463. {
  464. pt2->m_scale.x = pt2->m_scale.x * rw / tw;
  465. dst.right = rw * rw / tw;
  466. tw = rw;
  467. }
  468. if(th > rh)
  469. {
  470. pt2->m_scale.y = pt2->m_scale.y * rh / th;
  471. dst.bottom = rh * rh / th;
  472. th = rh;
  473. }
  474. CRect src(0, 0, tw, th);
  475. HRESULT hr;
  476. if(FAILED(hr = CreateRT(s, tw, th, &pt2->m_pTexture)) || FAILED(hr = pt2->m_pTexture->GetLevelDesc(0, &pt2->m_desc)))
  477. {
  478. delete pt2; 
  479. return false;
  480. }
  481. CComPtr<IDirect3DSurface9> pSrc, pDst;
  482. hr = pt->m_pTexture->GetSurfaceLevel(0, &pSrc);
  483. hr = pt2->m_pTexture->GetSurfaceLevel(0, &pDst);
  484. ASSERT(pSrc);
  485. ASSERT(pDst);
  486. hr = s->m_pD3DDev->StretchRect(pSrc, src, pDst, dst, src == dst ? D3DTEXF_POINT : D3DTEXF_LINEAR);
  487. pt2->m_scale.Set(pt2->m_pTexture);
  488. pt->m_pSubTextures.AddTail(pt2->m_pTexture);
  489. }
  490. pt = pt2;
  491. }
  492. return pt;
  493. }
  494. HRESULT GSTextureCache::CreateRT(GSState* s, int w, int h, IDirect3DTexture9** ppRT)
  495. {
  496. ASSERT(ppRT && *ppRT == NULL);
  497. HRESULT hr;
  498. POSITION pos = m_pRTPool.GetHeadPosition();
  499. while(pos)
  500. {
  501. IDirect3DTexture9* pRT = m_pRTPool.GetNext(pos);
  502. D3DSURFACE_DESC desc;
  503. pRT->GetLevelDesc(0, &desc);
  504. if(desc.Width == w && desc.Height == h)
  505. {
  506. (*ppRT = pRT)->AddRef();
  507. return S_OK;
  508. }
  509. }
  510. hr = s->m_pD3DDev->CreateTexture(w, h, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, ppRT, NULL);
  511. if(FAILED(hr)) return hr;
  512. /**/
  513. m_pRTPool.AddHead(*ppRT);
  514. while(m_pRTPool.GetCount() > 3) m_pRTPool.RemoveTail();
  515. return S_OK;
  516. }
  517. GSTexture* GSTextureCache::ConvertRT(GSState* s, GSTexture* pt)
  518. {
  519. ASSERT(pt->m_fRT);
  520. // FIXME: RT + 8h,4hl,4hh
  521. if(s->m_ctxt->TEX0.PSM == PSM_PSMT8H)
  522. {
  523. if(!pt->m_pPalette)
  524. {
  525. if(FAILED(s->m_pD3DDev->CreateTexture(256, 1, 1, 0, s->m_ctxt->TEX0.CPSM == PSM_PSMCT32 ? D3DFMT_A8R8G8B8 : D3DFMT_A1R5G5B5, D3DPOOL_MANAGED, &pt->m_pPalette, NULL)))
  526. return NULL;
  527. }
  528. }
  529. else if(GSLocalMemory::m_psmtbl[s->m_ctxt->TEX0.PSM].pal)
  530. {
  531. return NULL;
  532. }
  533. pt = ConvertRTPitch(s, pt);
  534. pt = ConvertRTWidthHeight(s, pt);
  535. return pt;
  536. }
  537. bool GSTextureCache::Fetch(GSState* s, GSTextureBase& t)
  538. {
  539. GSTexture* pt = NULL;
  540. int nPaletteEntries = GSLocalMemory::m_psmtbl[s->m_ctxt->TEX0.PSM].pal;
  541. DWORD clut[256];
  542. if(nPaletteEntries)
  543. {
  544. s->m_lm.SetupCLUT32(s->m_ctxt->TEX0, s->m_de.TEXA);
  545. s->m_lm.CopyCLUT32(clut, nPaletteEntries);
  546. }
  547. #ifdef DEBUG_LOG
  548. s->LOG(_T("*TC2 Fetch %dx%d %05I64x %I64d (%d)n"), 
  549. 1 << s->m_ctxt->TEX0.TW, 1 << s->m_ctxt->TEX0.TH, 
  550. s->m_ctxt->TEX0.TBP0, s->m_ctxt->TEX0.PSM, nPaletteEntries);
  551. #endif
  552. enum lookupresult {notfound, needsupdate, found} lr = notfound;
  553. POSITION pos = GetHeadPosition();
  554. while(pos && !pt)
  555. {
  556. POSITION cur = pos;
  557. pt = GetNext(pos);
  558. if(HasSharedBits(pt->m_TEX0.TBP0, pt->m_TEX0.PSM, s->m_ctxt->TEX0.TBP0, s->m_ctxt->TEX0.PSM))
  559. {
  560. if(pt->m_fRT)
  561. {
  562. lr = found;
  563. if(!(pt = ConvertRT(s, pt)))
  564. return false;
  565. }
  566. else if(s->m_ctxt->TEX0.PSM == pt->m_TEX0.PSM && pt->m_TEX0.TBW == s->m_ctxt->TEX0.TBW
  567. && s->m_ctxt->TEX0.TW == pt->m_TEX0.TW && s->m_ctxt->TEX0.TH == pt->m_TEX0.TH
  568. && (!(s->m_ctxt->CLAMP.WMS&2) && !(pt->m_CLAMP.WMS&2) && !(s->m_ctxt->CLAMP.WMT&2) && !(pt->m_CLAMP.WMT&2) || s->m_ctxt->CLAMP.i64 == pt->m_CLAMP.i64)
  569. && s->m_de.TEXA.TA0 == pt->m_TEXA.TA0 && s->m_de.TEXA.TA1 == pt->m_TEXA.TA1 && s->m_de.TEXA.AEM == pt->m_TEXA.AEM
  570. && (!nPaletteEntries || s->m_ctxt->TEX0.CPSM == pt->m_TEX0.CPSM && !memcmp(pt->m_clut, clut, nPaletteEntries*sizeof(clut[0]))))
  571. {
  572. lr = needsupdate;
  573. }
  574. }
  575. if(lr != notfound) {MoveToHead(cur); break;}
  576. pt = NULL;
  577. }
  578. #ifdef DEBUG_LOG
  579. s->LOG(_T("*TC2 lr = %sn"), lr == found ? _T("found") : lr == needsupdate ? _T("needsupdate") : _T("notfound"));
  580. #endif
  581. if(lr == notfound)
  582. {
  583. pt = new GSTexture();
  584. pt->m_TEX0 = s->m_ctxt->TEX0;
  585. pt->m_CLAMP = s->m_ctxt->CLAMP;
  586. pt->m_TEXA = s->m_de.TEXA;
  587. if(!SUCCEEDED(CreateTexture(s, pt, PSM_PSMCT32)))
  588. {
  589. delete pt;
  590. return false;
  591. }
  592. RemoveOldTextures(s);
  593. AddHead(pt);
  594. lr = needsupdate;
  595. }
  596. ASSERT(pt);
  597. if(pt && nPaletteEntries)
  598. {
  599. memcpy(pt->m_clut, clut, nPaletteEntries*sizeof(clut[0]));
  600. }
  601. if(lr == needsupdate)
  602. {
  603. UpdateTexture(s, pt, &GSLocalMemory::ReadTexture);
  604. lr = found;
  605. }
  606. if(lr == found)
  607. {
  608. #ifdef DEBUG_LOG
  609. s->LOG(_T("*TC2 texture was found, age %d -> 0n"), pt->m_nAge);
  610. #endif
  611. pt->m_nAge = 0;
  612. t = *pt;
  613. if(pt->m_fTemp) delete pt;
  614. return true;
  615. }
  616. return false;
  617. }
  618. bool GSTextureCache::FetchP(GSState* s, GSTextureBase& t)
  619. {
  620. GSTexture* pt = NULL;
  621. int nPaletteEntries = GSLocalMemory::m_psmtbl[s->m_ctxt->TEX0.PSM].pal;
  622. #ifdef DEBUG_LOG
  623. s->LOG(_T("*TC2 Fetch %dx%d %05I64x %I64d (%d)n"), 
  624. 1 << s->m_ctxt->TEX0.TW, 1 << s->m_ctxt->TEX0.TH, 
  625. s->m_ctxt->TEX0.TBP0, s->m_ctxt->TEX0.PSM, nPaletteEntries);
  626. #endif
  627. enum lookupresult {notfound, needsupdate, found} lr = notfound;
  628. POSITION pos = GetHeadPosition();
  629. while(pos && !pt)
  630. {
  631. POSITION cur = pos;
  632. pt = GetNext(pos);
  633. if(HasSharedBits(pt->m_TEX0.TBP0, pt->m_TEX0.PSM, s->m_ctxt->TEX0.TBP0, s->m_ctxt->TEX0.PSM))
  634. {
  635. if(pt->m_fRT)
  636. {
  637. lr = found;
  638. if(!(pt = ConvertRT(s, pt)))
  639. return false;
  640. }
  641. else if(s->m_ctxt->TEX0.PSM == pt->m_TEX0.PSM && pt->m_TEX0.TBW == s->m_ctxt->TEX0.TBW
  642. && s->m_ctxt->TEX0.TW == pt->m_TEX0.TW && s->m_ctxt->TEX0.TH == pt->m_TEX0.TH
  643. && (!(s->m_ctxt->CLAMP.WMS&2) && !(pt->m_CLAMP.WMS&2) && !(s->m_ctxt->CLAMP.WMT&2) && !(pt->m_CLAMP.WMT&2) || s->m_ctxt->CLAMP.i64 == pt->m_CLAMP.i64))
  644. {
  645. lr = needsupdate;
  646. }
  647. }
  648. if(lr != notfound) {MoveToHead(cur); break;}
  649. pt = NULL;
  650. }
  651. #ifdef DEBUG_LOG
  652. s->LOG(_T("*TC2 lr = %sn"), lr == found ? _T("found") : lr == needsupdate ? _T("needsupdate") : _T("notfound"));
  653. #endif
  654. if(lr == notfound)
  655. {
  656. pt = new GSTexture();
  657. pt->m_TEX0 = s->m_ctxt->TEX0;
  658. pt->m_CLAMP = s->m_ctxt->CLAMP;
  659. // pt->m_TEXA = s->m_de.TEXA;
  660. if(!SUCCEEDED(CreateTexture(s, pt, s->m_ctxt->TEX0.PSM, PSM_PSMCT32)))
  661. {
  662. delete pt;
  663. return false;
  664. }
  665. RemoveOldTextures(s);
  666. AddHead(pt);
  667. lr = needsupdate;
  668. }
  669. ASSERT(pt);
  670. if(pt && pt->m_pPalette) 
  671. {
  672. D3DLOCKED_RECT r;
  673. if(FAILED(pt->m_pPalette->LockRect(0, &r, NULL, 0)))
  674. return false;
  675. s->m_lm.ReadCLUT32(s->m_ctxt->TEX0, s->m_de.TEXA, (DWORD*)r.pBits);
  676. pt->m_pPalette->UnlockRect(0);
  677. s->m_perfmon.IncCounter(GSPerfMon::c_texture, 256*4);
  678. }
  679. if(lr == needsupdate)
  680. {
  681. UpdateTexture(s, pt, &GSLocalMemory::ReadTextureP);
  682. lr = found;
  683. }
  684. if(lr == found)
  685. {
  686. #ifdef DEBUG_LOG
  687. s->LOG(_T("*TC2 texture was found, age %d -> 0n"), pt->m_nAge);
  688. #endif
  689. pt->m_nAge = 0;
  690. t = *pt;
  691. if(pt->m_fTemp) delete pt;
  692. return true;
  693. }
  694. return false;
  695. }
  696. bool GSTextureCache::FetchNP(GSState* s, GSTextureBase& t)
  697. {
  698. GSTexture* pt = NULL;
  699. int nPaletteEntries = GSLocalMemory::m_psmtbl[s->m_ctxt->TEX0.PSM].pal;
  700. DWORD clut[256];
  701. if(nPaletteEntries)
  702. {
  703. s->m_lm.SetupCLUT(s->m_ctxt->TEX0, s->m_de.TEXA);
  704. s->m_lm.CopyCLUT32(clut, nPaletteEntries);
  705. }
  706. #ifdef DEBUG_LOG
  707. s->LOG(_T("*TC2 Fetch %dx%d %05I64x %I64d (%d)n"), 
  708. 1 << s->m_ctxt->TEX0.TW, 1 << s->m_ctxt->TEX0.TH, 
  709. s->m_ctxt->TEX0.TBP0, s->m_ctxt->TEX0.PSM, nPaletteEntries);
  710. #endif
  711. enum lookupresult {notfound, needsupdate, found} lr = notfound;
  712. POSITION pos = GetHeadPosition();
  713. while(pos && !pt)
  714. {
  715. POSITION cur = pos;
  716. pt = GetNext(pos);
  717. if(HasSharedBits(pt->m_TEX0.TBP0, pt->m_TEX0.PSM, s->m_ctxt->TEX0.TBP0, s->m_ctxt->TEX0.PSM))
  718. {
  719. if(pt->m_fRT)
  720. {
  721. lr = found;
  722. if(!(pt = ConvertRT(s, pt)))
  723. return false;
  724. }
  725. else if(s->m_ctxt->TEX0.PSM == pt->m_TEX0.PSM && pt->m_TEX0.TBW == s->m_ctxt->TEX0.TBW
  726. && s->m_ctxt->TEX0.TW == pt->m_TEX0.TW && s->m_ctxt->TEX0.TH == pt->m_TEX0.TH
  727. && (!(s->m_ctxt->CLAMP.WMS&2) && !(pt->m_CLAMP.WMS&2) && !(s->m_ctxt->CLAMP.WMT&2) && !(pt->m_CLAMP.WMT&2) || s->m_ctxt->CLAMP.i64 == pt->m_CLAMP.i64)
  728. // && s->m_de.TEXA.TA0 == pt->m_TEXA.TA0 && s->m_de.TEXA.TA1 == pt->m_TEXA.TA1 && s->m_de.TEXA.AEM == pt->m_TEXA.AEM
  729. && (!nPaletteEntries || s->m_ctxt->TEX0.CPSM == pt->m_TEX0.CPSM && !memcmp(pt->m_clut, clut, nPaletteEntries*sizeof(clut[0]))))
  730. {
  731. lr = needsupdate;
  732. }
  733. }
  734. if(lr != notfound) {MoveToHead(cur); break;}
  735. pt = NULL;
  736. }
  737. #ifdef DEBUG_LOG
  738. s->LOG(_T("*TC2 lr = %sn"), lr == found ? _T("found") : lr == needsupdate ? _T("needsupdate") : _T("notfound"));
  739. #endif
  740. if(lr == notfound)
  741. {
  742. pt = new GSTexture();
  743. pt->m_TEX0 = s->m_ctxt->TEX0;
  744. pt->m_CLAMP = s->m_ctxt->CLAMP;
  745. // pt->m_TEXA = s->m_de.TEXA;
  746. DWORD psm = s->m_ctxt->TEX0.PSM;
  747. switch(psm)
  748. {
  749. case PSM_PSMT8:
  750. case PSM_PSMT8H:
  751. case PSM_PSMT4:
  752. case PSM_PSMT4HL:
  753. case PSM_PSMT4HH:
  754. psm = s->m_ctxt->TEX0.CPSM;
  755. break;
  756. }
  757. if(!SUCCEEDED(CreateTexture(s, pt, psm)))
  758. {
  759. delete pt;
  760. return false;
  761. }
  762. RemoveOldTextures(s);
  763. AddHead(pt);
  764. lr = needsupdate;
  765. }
  766. ASSERT(pt);
  767. if(pt && nPaletteEntries)
  768. {
  769. memcpy(pt->m_clut, clut, nPaletteEntries*sizeof(clut[0]));
  770. }
  771. if(lr == needsupdate)
  772. {
  773. UpdateTexture(s, pt, &GSLocalMemory::ReadTextureNP);
  774. lr = found;
  775. }
  776. if(lr == found)
  777. {
  778. #ifdef DEBUG_LOG
  779. s->LOG(_T("*TC2 texture was found, age %d -> 0n"), pt->m_nAge);
  780. #endif
  781. pt->m_nAge = 0;
  782. t = *pt;
  783. if(pt->m_fTemp) delete pt;
  784. return true;
  785. }
  786. return false;
  787. }
  788. void GSTextureCache::IncAge(CSurfMap<IDirect3DTexture9>& pRTs)
  789. {
  790. POSITION pos = GetHeadPosition();
  791. while(pos)
  792. {
  793. POSITION cur = pos;
  794. GSTexture* pt = GetNext(pos);
  795. pt->m_nAge++;
  796. pt->m_nVsyncs++;
  797. if(pt->m_nAge > 10 && (!pt->m_fRT || pRTs.GetCount() > 3))
  798. {
  799. pRTs.RemoveKey(pt->m_TEX0.TBP0);
  800. RemoveAt(cur);
  801. delete pt;
  802. }
  803. }
  804. }
  805. void GSTextureCache::ResetAge(DWORD TBP0)
  806. {
  807. POSITION pos = GetHeadPosition();
  808. while(pos)
  809. {
  810. GSTexture* pt = GetNext(pos);
  811. if(pt->m_TEX0.TBP0 == TBP0) pt->m_nAge = 0;
  812. }
  813. }
  814. void GSTextureCache::RemoveAll()
  815. {
  816. while(GetCount()) delete RemoveHead();
  817. m_pTexturePool.RemoveAll();
  818. m_pRTPool.RemoveAll();
  819. }
  820. void GSTextureCache::InvalidateTexture(GSState* s, const GIFRegBITBLTBUF& BITBLTBUF, const CRect& r)
  821. {
  822. GIFRegTEX0 TEX0;
  823. TEX0.TBP0 = BITBLTBUF.DBP;
  824. TEX0.TBW = BITBLTBUF.DBW;
  825. TEX0.PSM = BITBLTBUF.DPSM;
  826. TEX0.TCC = 0;
  827. #ifdef DEBUG_LOG
  828. s->LOG(_T("*TC2 invalidate %05x %x (%d,%d-%d,%d)n"), TEX0.TBP0, TEX0.PSM, r.left, r.top, r.right, r.bottom);
  829. #endif
  830. POSITION pos = GetHeadPosition();
  831. while(pos)
  832. {
  833. POSITION cur = pos;
  834. GSTexture* pt = GetNext(pos);
  835. if(HasSharedBits(TEX0.TBP0, TEX0.PSM, pt->m_TEX0.TBP0, pt->m_TEX0.PSM)) 
  836. {
  837. if(TEX0.TBW != pt->m_TEX0.TBW)
  838. {
  839. // if TEX0.TBW != pt->m_TEX0.TBW then this render target is more likely to 
  840. // be discarded by the game (means it doesn't want to transfer an image over 
  841. // another pre-rendered image) and can be refetched from local mem safely.
  842. RemoveAt(cur);
  843. delete pt;
  844. }
  845. else if(pt->m_fRT) 
  846. {
  847. // TEX0.TBW = pt->m_TEX0.TBW;
  848. TEX0.PSM = pt->m_TEX0.PSM;
  849. if(TEX0.PSM == PSM_PSMCT32 || TEX0.PSM == PSM_PSMCT24 
  850. || TEX0.PSM == PSM_PSMCT16 || TEX0.PSM == PSM_PSMCT16S) 
  851. {
  852. // pt->m_rcDirty.AddHead(GSDirtyRect(PSM, r));
  853. HRESULT hr;
  854. int tw = (r.Width() + 3) & ~3;
  855. int th = r.Height();
  856. CComPtr<IDirect3DTexture9> pSrc;
  857. hr = s->m_pD3DDev->CreateTexture(tw, th, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &pSrc, NULL);
  858. D3DLOCKED_RECT lr;
  859. if(pSrc && SUCCEEDED(pSrc->LockRect(0, &lr, NULL, 0)))
  860. {
  861. GIFRegTEXA TEXA;
  862. TEXA.AEM = 1;
  863. TEXA.TA0 = 0;
  864. TEXA.TA1 = 0x80;
  865. GIFRegCLAMP CLAMP;
  866. CLAMP.WMS = 0;
  867. CLAMP.WMT = 0;
  868. s->m_lm.ReadTexture(r, (BYTE*)lr.pBits, lr.Pitch, TEX0, TEXA, CLAMP);
  869. s->m_perfmon.IncCounter(GSPerfMon::c_unswizzle, r.Width()*r.Height()*4);
  870. pSrc->UnlockRect(0);
  871. scale_t scale(pt->m_pTexture);
  872. CRect dst;
  873. dst.left = (long)(scale.x * r.left + 0.5);
  874. dst.top = (long)(scale.y * r.top + 0.5);
  875. dst.right = (long)(scale.x * r.right + 0.5);
  876. dst.bottom = (long)(scale.y * r.bottom + 0.5);
  877. //
  878. CComPtr<IDirect3DSurface9> pRTSurf;
  879. hr = pt->m_pTexture->GetSurfaceLevel(0, &pRTSurf);
  880. hr = s->m_pD3DDev->SetRenderTarget(0, pRTSurf);
  881. hr = s->m_pD3DDev->SetDepthStencilSurface(NULL);
  882. hr = s->m_pD3DDev->SetTexture(0, pSrc);
  883. hr = s->m_pD3DDev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
  884. hr = s->m_pD3DDev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
  885. hr = s->m_pD3DDev->SetRenderState(D3DRS_ZENABLE, FALSE);
  886. hr = s->m_pD3DDev->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
  887. hr = s->m_pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
  888. hr = s->m_pD3DDev->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
  889. hr = s->m_pD3DDev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
  890. hr = s->m_pD3DDev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ZERO);
  891. hr = s->m_pD3DDev->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
  892. hr = s->m_pD3DDev->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_RGBA);
  893. hr = s->m_pD3DDev->SetPixelShader(NULL);
  894. struct
  895. {
  896. float x, y, z, rhw;
  897. float tu, tv;
  898. }
  899. pVertices[] =
  900. {
  901. {(float)dst.left, (float)dst.top, 0.5f, 2.0f, 0, 0},
  902. {(float)dst.right, (float)dst.top, 0.5f, 2.0f, 1.0f * r.Width() / tw, 0},
  903. {(float)dst.left, (float)dst.bottom, 0.5f, 2.0f, 0, 1},
  904. {(float)dst.right, (float)dst.bottom, 0.5f, 2.0f, 1.0f * r.Width() / tw, 1},
  905. };
  906. hr = s->m_pD3DDev->BeginScene();
  907. hr = s->m_pD3DDev->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1);
  908. hr = s->m_pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, pVertices, sizeof(pVertices[0]));
  909. hr = s->m_pD3DDev->EndScene();
  910. }
  911. }
  912. else
  913. {
  914. RemoveAt(cur);
  915. delete pt;
  916. }
  917. }
  918. else
  919. {
  920. pt->m_rcDirty.AddHead(GSDirtyRect(TEX0.PSM, r));
  921. }
  922. }
  923. }
  924. }
  925. void GSTextureCache::InvalidateLocalMem(GSState* s, DWORD TBP0, DWORD BW, DWORD PSM, const CRect& r)
  926. {
  927. CComPtr<IDirect3DTexture9> pRT;
  928. POSITION pos = GetHeadPosition();
  929. while(pos)
  930. {
  931. POSITION cur = pos;
  932. GSTexture* pt = GetNext(pos);
  933. if(pt->m_TEX0.TBP0 == TBP0 && pt->m_fRT) 
  934. {
  935. pRT = pt->m_pTexture;
  936. break;
  937. }
  938. }
  939. if(!pRT) return;
  940. // TODO: add resizing
  941. /*
  942. HRESULT hr;
  943. D3DSURFACE_DESC desc;
  944. hr = pRT->GetLevelDesc(0, &desc);
  945. if(FAILED(hr)) return;
  946. CComPtr<IDirect3DSurface9> pVidMem;
  947. hr = pRT->GetSurfaceLevel(0, &pVidMem);
  948. if(FAILED(hr)) return;
  949. CComPtr<IDirect3DSurface9> pSysMem;
  950. hr = s->m_pD3DDev->CreateOffscreenPlainSurface(desc.Width, desc.Height, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &pSysMem, NULL);
  951. if(FAILED(hr)) return;
  952. hr = s->m_pD3DDev->GetRenderTargetData(pVidMem, pSysMem);
  953. if(FAILED(hr)) return;
  954. D3DLOCKED_RECT lr;
  955. hr = pSysMem->LockRect(&lr, &r, D3DLOCK_READONLY|D3DLOCK_NO_DIRTY_UPDATE);
  956. if(SUCCEEDED(hr))
  957. {
  958. BYTE* p = (BYTE*)lr.pBits;
  959. if(0 && r.left == 0 && r.top == 0 && PSM == PSM_PSMCT32)
  960. {
  961. }
  962. else
  963. {
  964. GSLocalMemory::writeFrame wf = s->m_lm.GetWriteFrame(PSM);
  965. for(int y = r.top; y < r.bottom; y++, p += lr.Pitch)
  966. {
  967. for(int x = r.left; x < r.right; x++)
  968. {
  969. (s->m_lm.*wf)(x, y, ((DWORD*)p)[x], TBP0, BW);
  970. }
  971. }
  972. }
  973. pSysMem->UnlockRect();
  974. }
  975. */
  976. }
  977. void GSTextureCache::AddRT(GIFRegTEX0& TEX0, IDirect3DTexture9* pRT, scale_t scale)
  978. {
  979. POSITION pos = GetHeadPosition();
  980. while(pos)
  981. {
  982. POSITION cur = pos;
  983. GSTexture* pt = GetNext(pos);
  984. if(HasSharedBits(TEX0.TBP0, TEX0.PSM, pt->m_TEX0.TBP0, pt->m_TEX0.PSM))
  985. {
  986. RemoveAt(cur);
  987. delete pt;
  988. }
  989. }
  990. GSTexture* pt = new GSTexture();
  991. pt->m_TEX0 = TEX0;
  992. pt->m_pTexture = pRT;
  993. pt->m_pTexture->GetLevelDesc(0, &pt->m_desc);
  994. pt->m_scale = scale;
  995. pt->m_fRT = true;
  996. AddHead(pt);
  997. }