GSTextureCache.cpp
上传用户:xjjlds
上传日期:2015-12-05
资源大小:22823k
文件大小:30k
- /*
- * Copyright (C) 2003-2005 Gabest
- * http://www.gabest.org
- *
- * This Program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This Program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Make; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- */
- #include "StdAfx.h"
- #include "GSTextureCache.h"
- #include "GSHash.h"
- #include "GSRendererHW.h"
- //
- bool IsRenderTarget(IDirect3DTexture9* pTexture)
- {
- D3DSURFACE_DESC desc;
- memset(&desc, 0, sizeof(desc));
- return pTexture && S_OK == pTexture->GetLevelDesc(0, &desc) && (desc.Usage&D3DUSAGE_RENDERTARGET);
- }
- bool HasSharedBits(DWORD sbp, DWORD spsm, DWORD dbp, DWORD dpsm)
- {
- if(sbp != dbp) return false;
- switch(spsm)
- {
- case PSM_PSMCT32:
- case PSM_PSMCT16:
- case PSM_PSMCT16S:
- case PSM_PSMT8:
- case PSM_PSMT4:
- return true;
- case PSM_PSMCT24:
- return !(dpsm == PSM_PSMT8H || dpsm == PSM_PSMT4HL || dpsm == PSM_PSMT4HH);
- case PSM_PSMT8H:
- return !(dpsm == PSM_PSMCT24);
- case PSM_PSMT4HL:
- return !(dpsm == PSM_PSMCT24 || dpsm == PSM_PSMT4HH);
- case PSM_PSMT4HH:
- return !(dpsm == PSM_PSMCT24 || dpsm == PSM_PSMT4HL);
- }
- return true;
- }
- //
- GSDirtyRect::GSDirtyRect(DWORD PSM, CRect r)
- {
- m_PSM = PSM;
- m_rcDirty = r;
- }
- CRect GSDirtyRect::GetDirtyRect(const GIFRegTEX0& TEX0)
- {
- CRect rcDirty = m_rcDirty;
- CSize src = GSLocalMemory::m_psmtbl[m_PSM].bs;
- rcDirty.left = (rcDirty.left) & ~(src.cx-1);
- rcDirty.right = (rcDirty.right + (src.cx-1) /* + 1 */) & ~(src.cx-1);
- rcDirty.top = (rcDirty.top) & ~(src.cy-1);
- rcDirty.bottom = (rcDirty.bottom + (src.cy-1) /* + 1 */) & ~(src.cy-1);
- if(m_PSM != TEX0.PSM)
- {
- CSize dst = GSLocalMemory::m_psmtbl[TEX0.PSM].bs;
- rcDirty.left = MulDiv(m_rcDirty.left, dst.cx, src.cx);
- rcDirty.right = MulDiv(m_rcDirty.right, dst.cx, src.cx);
- rcDirty.top = MulDiv(m_rcDirty.top, dst.cy, src.cy);
- rcDirty.bottom = MulDiv(m_rcDirty.bottom, dst.cy, src.cy);
- }
- rcDirty &= CRect(0, 0, 1<<TEX0.TW, 1<<TEX0.TH);
- return rcDirty;
- }
- void GSDirtyRectList::operator = (const GSDirtyRectList& l)
- {
- RemoveAll();
- POSITION pos = l.GetHeadPosition();
- while(pos) AddTail(l.GetNext(pos));
- }
- CRect GSDirtyRectList::GetDirtyRect(const GIFRegTEX0& TEX0)
- {
- if(IsEmpty()) return CRect(0, 0, 0, 0);
- CRect r(INT_MAX, INT_MAX, 0, 0);
- POSITION pos = GetHeadPosition();
- while(pos) r |= GetNext(pos).GetDirtyRect(TEX0);
- return r;
- }
- //
- GSTextureBase::GSTextureBase()
- {
- m_scale = scale_t(1, 1);
- m_fRT = false;
- memset(&m_desc, 0, sizeof(m_desc));
- }
- GSTexture::GSTexture()
- {
- m_TEX0.TBP0 = ~0;
- m_rcValid = CRect(0, 0, 0, 0);
- m_dwHash = ~0;
- m_nHashDiff = m_nHashSame = 0;
- m_rcHash = CRect(0, 0, 0, 0);
- m_nBytes = 0;
- m_nAge = 0;
- m_nVsyncs = 0;
- m_fTemp = false;
- }
- //
- GSTextureCache::GSTextureCache()
- {
- }
- GSTextureCache::~GSTextureCache()
- {
- RemoveAll();
- }
- HRESULT GSTextureCache::CreateTexture(GSState* s, GSTexture* pt, DWORD PSM, DWORD CPSM)
- {
- if(!pt || pt->m_pTexture) {ASSERT(0); return E_FAIL;}
- int w = 1 << pt->m_TEX0.TW;
- int h = 1 << pt->m_TEX0.TH;
- int bpp = 0;
- D3DFORMAT fmt = D3DFMT_UNKNOWN;
- D3DFORMAT palfmt = D3DFMT_UNKNOWN;
- switch(PSM)
- {
- default:
- case PSM_PSMCT32:
- bpp = 32;
- fmt = D3DFMT_A8R8G8B8;
- break;
- case PSM_PSMCT24:
- bpp = 32;
- fmt = D3DFMT_X8R8G8B8;
- break;
- case PSM_PSMCT16:
- case PSM_PSMCT16S:
- bpp = 16;
- fmt = D3DFMT_A1R5G5B5;
- break;
- case PSM_PSMT8:
- case PSM_PSMT4:
- case PSM_PSMT8H:
- case PSM_PSMT4HL:
- case PSM_PSMT4HH:
- bpp = 8;
- fmt = D3DFMT_L8;
- palfmt = CPSM == PSM_PSMCT32 ? D3DFMT_A8R8G8B8 : D3DFMT_A1R5G5B5;
- break;
- }
- pt->m_nBytes = w*h*bpp>>3;
- POSITION pos = m_pTexturePool.GetHeadPosition();
- while(pos)
- {
- IDirect3DTexture9* pTexture = m_pTexturePool.GetNext(pos);
- D3DSURFACE_DESC desc;
- memset(&desc, 0, sizeof(desc));
- pTexture->GetLevelDesc(0, &desc);
- if(w == desc.Width && h == desc.Height && fmt == desc.Format && !IsTextureInCache(pTexture))
- {
- pt->m_pTexture = pTexture;
- pt->m_desc = desc;
- break;
- }
- }
- if(!pt->m_pTexture)
- {
- while(m_pTexturePool.GetCount() > 20)
- m_pTexturePool.RemoveTail();
- if(FAILED(s->m_pD3DDev->CreateTexture(w, h, 1, 0, fmt, D3DPOOL_MANAGED, &pt->m_pTexture, NULL)))
- return E_FAIL;
- pt->m_pTexture->GetLevelDesc(0, &pt->m_desc);
- m_pTexturePool.AddHead(pt->m_pTexture);
- }
- if(bpp == 8)
- {
- if(FAILED(s->m_pD3DDev->CreateTexture(256, 1, 1, 0, palfmt, D3DPOOL_MANAGED, &pt->m_pPalette, NULL)))
- {
- pt->m_pTexture = NULL;
- return E_FAIL;
- }
- }
- return S_OK;
- }
- bool GSTextureCache::IsTextureInCache(IDirect3DTexture9* pTexture)
- {
- POSITION pos = GetHeadPosition();
- while(pos)
- {
- if(GetNext(pos)->m_pTexture == pTexture)
- return true;
- }
- return false;
- }
- void GSTextureCache::RemoveOldTextures(GSState* s)
- {
- DWORD nBytes = 0;
- POSITION pos = GetHeadPosition();
- while(pos) nBytes += GetNext(pos)->m_nBytes;
- pos = GetTailPosition();
- while(pos && nBytes > 96*1024*1024/*s->m_ddcaps.dwVidMemTotal*/)
- {
- #ifdef DEBUG_LOG
- s->LOG(_T("*TC2 too many textures in cache (%d, %.2f MB)n"), GetCount(), 1.0f*nBytes/1024/1024);
- #endif
- POSITION cur = pos;
- GSTexture* pt = GetPrev(pos);
- if(!pt->m_fRT)
- {
- nBytes -= pt->m_nBytes;
- RemoveAt(cur);
- delete pt;
- }
- }
- }
- static bool RectInRect(const RECT& inner, const RECT& outer)
- {
- return outer.left <= inner.left && inner.right <= outer.right
- && outer.top <= inner.top && inner.bottom <= outer.bottom;
- }
- static bool RectInRectH(const RECT& inner, const RECT& outer)
- {
- return outer.top <= inner.top && inner.bottom <= outer.bottom;
- }
- static bool RectInRectV(const RECT& inner, const RECT& outer)
- {
- return outer.left <= inner.left && inner.right <= outer.right;
- }
- bool GSTextureCache::GetDirtyRect(GSState* s, GSTexture* pt, CRect& r)
- {
- int w = 1 << pt->m_TEX0.TW;
- int h = 1 << pt->m_TEX0.TH;
- r.SetRect(0, 0, w, h);
- // FIXME: kyo's left hand after being selected for player one (PS2-SNK_Vs_Capcom_SVC_Chaos_PAL_CDFull.iso)
- // return true;
- s->MinMaxUV(w, h, r);
- CRect rcDirty = pt->m_rcDirty.GetDirtyRect(pt->m_TEX0);
- CRect rcValid = pt->m_rcValid;
- #ifdef DEBUG_LOG
- 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);
- #endif
- if(RectInRect(r, rcValid))
- {
- if(rcDirty.IsRectEmpty()) return false;
- else if(RectInRect(rcDirty, r)) r = rcDirty;
- else if(RectInRect(rcDirty, rcValid)) r |= rcDirty;
- else r = rcValid | rcDirty;
- }
- else
- {
- if(RectInRectH(r, rcValid) && (r.left >= rcValid.left || r.right <= rcValid.right))
- {
- r.top = rcValid.top;
- r.bottom = rcValid.bottom;
- if(r.left < rcValid.left) r.right = rcValid.left;
- else /*if(r.right > rcValid.right)*/ r.left = rcValid.right;
- }
- else if(RectInRectV(r, rcValid) && (r.top >= rcValid.top || r.bottom <= rcValid.bottom))
- {
- r.left = rcValid.left;
- r.right = rcValid.right;
- if(r.top < rcValid.top) r.bottom = rcValid.top;
- else /*if(r.bottom > rcValid.bottom)*/ r.top = rcValid.bottom;
- }
- else
- {
- r |= rcValid;
- }
- }
- return true;
- }
- DWORD GSTextureCache::HashTexture(const CRect& r, int pitch, void* bits)
- {
- // TODO: make the hash more unique
- BYTE* p = (BYTE*)bits;
- DWORD hash = r.left + r.right + r.top + r.bottom + pitch + *(BYTE*)bits;
- if(r.Width() > 0)
- {
- int size = r.Width()*r.Height();
- /*
- if(size <= 8*8) return rand(); // :P
- else
- */
- if(size <= 16*16) hash += hash_crc(r, pitch, p);
- else if(size <= 32*32) hash += hash_adler(r, pitch, p);
- else hash += hash_checksum(r, pitch, p);
- }
- return hash;
- }
- HRESULT GSTextureCache::UpdateTexture(GSState* s, GSTexture* pt, GSLocalMemory::readTexture rt)
- {
- CRect r;
- if(!GetDirtyRect(s, pt, r))
- return S_OK;
- #ifdef DEBUG_LOG
- 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);
- #endif
- int bpp = 0;
- switch(pt->m_desc.Format)
- {
- case D3DFMT_A8R8G8B8: bpp = 32; break;
- case D3DFMT_X8R8G8B8: bpp = 32; break;
- case D3DFMT_A1R5G5B5: bpp = 16; break;
- case D3DFMT_L8: bpp = 8; break;
- default: ASSERT(0); return E_FAIL;
- }
- D3DLOCKED_RECT lr;
- if(FAILED(pt->m_pTexture->LockRect(0, &lr, &r, D3DLOCK_NO_DIRTY_UPDATE))) {ASSERT(0); return E_FAIL;}
- (s->m_lm.*rt)(r, (BYTE*)lr.pBits, lr.Pitch, s->m_ctxt->TEX0, s->m_de.TEXA, s->m_ctxt->CLAMP);
- s->m_perfmon.IncCounter(GSPerfMon::c_unswizzle, r.Width()*r.Height()*bpp>>3);
- pt->m_pTexture->UnlockRect(0);
- pt->m_rcValid |= r;
- pt->m_rcDirty.RemoveAll();
- const static DWORD limit = 7;
- if((pt->m_nHashDiff & limit) && pt->m_nHashDiff >= limit && pt->m_rcHash == pt->m_rcValid) // predicted to be dirty
- {
- pt->m_nHashDiff++;
- }
- else
- {
- if(FAILED(pt->m_pTexture->LockRect(0, &lr, &pt->m_rcValid, D3DLOCK_NO_DIRTY_UPDATE|D3DLOCK_READONLY))) {ASSERT(0); return E_FAIL;}
- DWORD dwHash = HashTexture(
- CRect((pt->m_rcValid.left>>2)*(bpp>>3), pt->m_rcValid.top, (pt->m_rcValid.right>>2)*(bpp>>3), pt->m_rcValid.bottom),
- lr.Pitch, lr.pBits);
- pt->m_pTexture->UnlockRect(0);
- if(pt->m_rcHash != pt->m_rcValid)
- {
- pt->m_nHashDiff = 0;
- pt->m_nHashSame = 0;
- pt->m_rcHash = pt->m_rcValid;
- pt->m_dwHash = dwHash;
- }
- else
- {
- if(pt->m_dwHash != dwHash)
- {
- pt->m_nHashDiff++;
- pt->m_nHashSame = 0;
- pt->m_dwHash = dwHash;
- }
- else
- {
- if(pt->m_nHashDiff < limit) r.SetRect(0, 0, 1, 1);
- // else pt->m_dwHash is not reliable, must update
- pt->m_nHashDiff = 0;
- pt->m_nHashSame++;
- }
- }
- }
- pt->m_pTexture->AddDirtyRect(&r);
- pt->m_pTexture->PreLoad();
- s->m_perfmon.IncCounter(GSPerfMon::c_texture, r.Width()*r.Height()*bpp>>3);
- #ifdef DEBUG_LOG
- s->LOG(_T("*TC2 texture was updated, valid %d,%dx%d,%dn"), pt->m_rcValid);
- #endif
- #ifdef DEBUG_SAVETEXTURES
- if(s->m_ctxt->FRAME.Block() == 0x00000 && pt->m_TEX0.TBP0 == 0x02800)
- {
- CString fn;
- fn.Format(_T("c:\%08I64x_%I64d_%I64d_%I64d_%I64d_%I64d_%I64d_%I64d-%I64d_%I64d-%I64d.bmp"),
- pt->m_TEX0.TBP0, pt->m_TEX0.PSM, pt->m_TEX0.TBW,
- pt->m_TEX0.TW, pt->m_TEX0.TH,
- pt->m_CLAMP.WMS, pt->m_CLAMP.WMT, pt->m_CLAMP.MINU, pt->m_CLAMP.MAXU, pt->m_CLAMP.MINV, pt->m_CLAMP.MAXV);
- D3DXSaveTextureToFile(fn, D3DXIFF_BMP, pt->m_pTexture, NULL);
- }
- #endif
- return S_OK;
- }
- GSTexture* GSTextureCache::ConvertRTPitch(GSState* s, GSTexture* pt)
- {
- if(pt->m_TEX0.TBW == s->m_ctxt->TEX0.TBW)
- return pt;
- // sfex3 uses this trick (bw: 10 -> 5, wraps the right side below the left)
- ASSERT(pt->m_TEX0.TBW > s->m_ctxt->TEX0.TBW); // otherwise scale.x need to be reduced to make the larger texture fit (TODO)
- int bw = 64;
- int bh = s->m_ctxt->TEX0.PSM == PSM_PSMCT32 || s->m_ctxt->TEX0.PSM == PSM_PSMCT24 ? 32 : 64;
- int sw = pt->m_TEX0.TBW << 6;
- int dw = s->m_ctxt->TEX0.TBW << 6;
- int dh = 1 << s->m_ctxt->TEX0.TH;
- // 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);
- HRESULT hr;
- /*
- if(s->m_perfmon.GetFrame() > 400)
- hr = D3DXSaveTextureToFile(_T("g:/1.bmp"), D3DXIFF_BMP, pt->m_pTexture, NULL);
- */
- D3DSURFACE_DESC desc;
- hr = pt->m_pTexture->GetLevelDesc(0, &desc);
- if(FAILED(hr)) return NULL;
- CComPtr<IDirect3DTexture9> pRT;
- if(FAILED(hr = CreateRT(s, desc.Width, desc.Height, &pRT)))
- return NULL;
- CComPtr<IDirect3DSurface9> pSrc, pDst;
- hr = pRT->GetSurfaceLevel(0, &pSrc);
- if(FAILED(hr)) return NULL;
- hr = pt->m_pTexture->GetSurfaceLevel(0, &pDst);
- if(FAILED(hr)) return NULL;
- hr = s->m_pD3DDev->StretchRect(pDst, NULL, pSrc, NULL, D3DTEXF_POINT);
- if(FAILED(hr)) return NULL;
- scale_t scale(pt->m_pTexture);
- for(int dy = 0; dy < dh; dy += bh)
- {
- for(int dx = 0; dx < dw; dx += bw)
- {
- int o = dy * dw / bh + dx;
- int sx = o % sw;
- int sy = o / sw;
- // TRACE(_T("%d,%d - %d,%d <= %d,%d - %d,%dn"), dx, dy, dx + bw, dy + bh, sx, sy, sx + bw, sy + bh);
- CRect src, dst;
- src.left = (LONG)(scale.x * sx + 0.5f);
- src.top = (LONG)(scale.y * sy + 0.5f);
- src.right = (LONG)(scale.x * (sx + bw) + 0.5f);
- src.bottom = (LONG)(scale.y * (sy + bh) + 0.5f);
- dst.left = (LONG)(scale.x * dx + 0.5f);
- dst.top = (LONG)(scale.y * dy + 0.5f);
- dst.right = (LONG)(scale.x * (dx + bw) + 0.5f);
- dst.bottom = (LONG)(scale.y * (dy + bh) + 0.5f);
- hr = s->m_pD3DDev->StretchRect(pSrc, src, pDst, dst, D3DTEXF_POINT);
- // TODO: this is quite a lot of StretchRect call, do it with one DrawPrimUP
- }
- }
- pt->m_TEX0.TW = s->m_ctxt->TEX0.TW;
- pt->m_TEX0.TBW = s->m_ctxt->TEX0.TBW;
- /*
- if(s->m_perfmon.GetFrame() > 400)
- hr = D3DXSaveTextureToFile(_T("g:/2.bmp"), D3DXIFF_BMP, pt->m_pTexture, NULL);
- */
- return pt;
- }
- GSTexture* GSTextureCache::ConvertRTWidthHeight(GSState* s, GSTexture* pt)
- {
- int tw = pt->m_scale.x * (1 << s->m_ctxt->TEX0.TW);
- int th = pt->m_scale.y * (1 << s->m_ctxt->TEX0.TH);
- int rw = pt->m_desc.Width;
- int rh = pt->m_desc.Height;
- if(tw != rw || th != rh)
- //if(tw < rw && th <= rh || tw <= rw && th < rh)
- {
- GSTexture* pt2 = new GSTexture();
- pt2->m_pPalette = pt->m_pPalette;
- pt2->m_fRT = pt->m_pPalette == NULL;
- pt2->m_scale = pt->m_scale;
- pt2->m_fTemp = true;
- POSITION pos = pt->m_pSubTextures.GetHeadPosition();
- while(pos)
- {
- IDirect3DTexture9* pTexture = pt->m_pSubTextures.GetNext(pos);
- pTexture->GetLevelDesc(0, &pt2->m_desc);
- scale_t scale(pTexture);
- if(pt2->m_desc.Width == tw && pt2->m_desc.Height == th
- && pt2->m_scale.x == scale.x && pt2->m_scale.y == scale.y)
- {
- pt2->m_pTexture = pTexture;
- break;
- }
- }
- if(!pt2->m_pTexture)
- {
- CRect dst(0, 0, tw, th);
-
- if(tw > rw)
- {
- pt2->m_scale.x = pt2->m_scale.x * rw / tw;
- dst.right = rw * rw / tw;
- tw = rw;
- }
-
- if(th > rh)
- {
- pt2->m_scale.y = pt2->m_scale.y * rh / th;
- dst.bottom = rh * rh / th;
- th = rh;
- }
- CRect src(0, 0, tw, th);
- HRESULT hr;
- if(FAILED(hr = CreateRT(s, tw, th, &pt2->m_pTexture)) || FAILED(hr = pt2->m_pTexture->GetLevelDesc(0, &pt2->m_desc)))
- {
- delete pt2;
- return false;
- }
- CComPtr<IDirect3DSurface9> pSrc, pDst;
- hr = pt->m_pTexture->GetSurfaceLevel(0, &pSrc);
- hr = pt2->m_pTexture->GetSurfaceLevel(0, &pDst);
- ASSERT(pSrc);
- ASSERT(pDst);
- hr = s->m_pD3DDev->StretchRect(pSrc, src, pDst, dst, src == dst ? D3DTEXF_POINT : D3DTEXF_LINEAR);
- pt2->m_scale.Set(pt2->m_pTexture);
- pt->m_pSubTextures.AddTail(pt2->m_pTexture);
- }
-
- pt = pt2;
- }
- return pt;
- }
- HRESULT GSTextureCache::CreateRT(GSState* s, int w, int h, IDirect3DTexture9** ppRT)
- {
- ASSERT(ppRT && *ppRT == NULL);
- HRESULT hr;
- POSITION pos = m_pRTPool.GetHeadPosition();
- while(pos)
- {
- IDirect3DTexture9* pRT = m_pRTPool.GetNext(pos);
- D3DSURFACE_DESC desc;
- pRT->GetLevelDesc(0, &desc);
- if(desc.Width == w && desc.Height == h)
- {
- (*ppRT = pRT)->AddRef();
- return S_OK;
- }
- }
- hr = s->m_pD3DDev->CreateTexture(w, h, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, ppRT, NULL);
- if(FAILED(hr)) return hr;
- /**/
- m_pRTPool.AddHead(*ppRT);
- while(m_pRTPool.GetCount() > 3) m_pRTPool.RemoveTail();
- return S_OK;
- }
- GSTexture* GSTextureCache::ConvertRT(GSState* s, GSTexture* pt)
- {
- ASSERT(pt->m_fRT);
- // FIXME: RT + 8h,4hl,4hh
- if(s->m_ctxt->TEX0.PSM == PSM_PSMT8H)
- {
- if(!pt->m_pPalette)
- {
- 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)))
- return NULL;
- }
- }
- else if(GSLocalMemory::m_psmtbl[s->m_ctxt->TEX0.PSM].pal)
- {
- return NULL;
- }
- pt = ConvertRTPitch(s, pt);
- pt = ConvertRTWidthHeight(s, pt);
- return pt;
- }
- bool GSTextureCache::Fetch(GSState* s, GSTextureBase& t)
- {
- GSTexture* pt = NULL;
- int nPaletteEntries = GSLocalMemory::m_psmtbl[s->m_ctxt->TEX0.PSM].pal;
- DWORD clut[256];
- if(nPaletteEntries)
- {
- s->m_lm.SetupCLUT32(s->m_ctxt->TEX0, s->m_de.TEXA);
- s->m_lm.CopyCLUT32(clut, nPaletteEntries);
- }
- #ifdef DEBUG_LOG
- s->LOG(_T("*TC2 Fetch %dx%d %05I64x %I64d (%d)n"),
- 1 << s->m_ctxt->TEX0.TW, 1 << s->m_ctxt->TEX0.TH,
- s->m_ctxt->TEX0.TBP0, s->m_ctxt->TEX0.PSM, nPaletteEntries);
- #endif
- enum lookupresult {notfound, needsupdate, found} lr = notfound;
- POSITION pos = GetHeadPosition();
- while(pos && !pt)
- {
- POSITION cur = pos;
- pt = GetNext(pos);
- if(HasSharedBits(pt->m_TEX0.TBP0, pt->m_TEX0.PSM, s->m_ctxt->TEX0.TBP0, s->m_ctxt->TEX0.PSM))
- {
- if(pt->m_fRT)
- {
- lr = found;
- if(!(pt = ConvertRT(s, pt)))
- return false;
- }
- else if(s->m_ctxt->TEX0.PSM == pt->m_TEX0.PSM && pt->m_TEX0.TBW == s->m_ctxt->TEX0.TBW
- && s->m_ctxt->TEX0.TW == pt->m_TEX0.TW && s->m_ctxt->TEX0.TH == pt->m_TEX0.TH
- && (!(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)
- && 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
- && (!nPaletteEntries || s->m_ctxt->TEX0.CPSM == pt->m_TEX0.CPSM && !memcmp(pt->m_clut, clut, nPaletteEntries*sizeof(clut[0]))))
- {
- lr = needsupdate;
- }
- }
- if(lr != notfound) {MoveToHead(cur); break;}
- pt = NULL;
- }
- #ifdef DEBUG_LOG
- s->LOG(_T("*TC2 lr = %sn"), lr == found ? _T("found") : lr == needsupdate ? _T("needsupdate") : _T("notfound"));
- #endif
- if(lr == notfound)
- {
- pt = new GSTexture();
- pt->m_TEX0 = s->m_ctxt->TEX0;
- pt->m_CLAMP = s->m_ctxt->CLAMP;
- pt->m_TEXA = s->m_de.TEXA;
- if(!SUCCEEDED(CreateTexture(s, pt, PSM_PSMCT32)))
- {
- delete pt;
- return false;
- }
- RemoveOldTextures(s);
- AddHead(pt);
- lr = needsupdate;
- }
- ASSERT(pt);
- if(pt && nPaletteEntries)
- {
- memcpy(pt->m_clut, clut, nPaletteEntries*sizeof(clut[0]));
- }
- if(lr == needsupdate)
- {
- UpdateTexture(s, pt, &GSLocalMemory::ReadTexture);
- lr = found;
- }
- if(lr == found)
- {
- #ifdef DEBUG_LOG
- s->LOG(_T("*TC2 texture was found, age %d -> 0n"), pt->m_nAge);
- #endif
- pt->m_nAge = 0;
- t = *pt;
- if(pt->m_fTemp) delete pt;
- return true;
- }
- return false;
- }
- bool GSTextureCache::FetchP(GSState* s, GSTextureBase& t)
- {
- GSTexture* pt = NULL;
- int nPaletteEntries = GSLocalMemory::m_psmtbl[s->m_ctxt->TEX0.PSM].pal;
- #ifdef DEBUG_LOG
- s->LOG(_T("*TC2 Fetch %dx%d %05I64x %I64d (%d)n"),
- 1 << s->m_ctxt->TEX0.TW, 1 << s->m_ctxt->TEX0.TH,
- s->m_ctxt->TEX0.TBP0, s->m_ctxt->TEX0.PSM, nPaletteEntries);
- #endif
- enum lookupresult {notfound, needsupdate, found} lr = notfound;
- POSITION pos = GetHeadPosition();
- while(pos && !pt)
- {
- POSITION cur = pos;
- pt = GetNext(pos);
- if(HasSharedBits(pt->m_TEX0.TBP0, pt->m_TEX0.PSM, s->m_ctxt->TEX0.TBP0, s->m_ctxt->TEX0.PSM))
- {
- if(pt->m_fRT)
- {
- lr = found;
- if(!(pt = ConvertRT(s, pt)))
- return false;
- }
- else if(s->m_ctxt->TEX0.PSM == pt->m_TEX0.PSM && pt->m_TEX0.TBW == s->m_ctxt->TEX0.TBW
- && s->m_ctxt->TEX0.TW == pt->m_TEX0.TW && s->m_ctxt->TEX0.TH == pt->m_TEX0.TH
- && (!(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))
- {
- lr = needsupdate;
- }
- }
- if(lr != notfound) {MoveToHead(cur); break;}
-
- pt = NULL;
- }
- #ifdef DEBUG_LOG
- s->LOG(_T("*TC2 lr = %sn"), lr == found ? _T("found") : lr == needsupdate ? _T("needsupdate") : _T("notfound"));
- #endif
- if(lr == notfound)
- {
- pt = new GSTexture();
- pt->m_TEX0 = s->m_ctxt->TEX0;
- pt->m_CLAMP = s->m_ctxt->CLAMP;
- // pt->m_TEXA = s->m_de.TEXA;
- if(!SUCCEEDED(CreateTexture(s, pt, s->m_ctxt->TEX0.PSM, PSM_PSMCT32)))
- {
- delete pt;
- return false;
- }
- RemoveOldTextures(s);
- AddHead(pt);
- lr = needsupdate;
- }
- ASSERT(pt);
- if(pt && pt->m_pPalette)
- {
- D3DLOCKED_RECT r;
- if(FAILED(pt->m_pPalette->LockRect(0, &r, NULL, 0)))
- return false;
- s->m_lm.ReadCLUT32(s->m_ctxt->TEX0, s->m_de.TEXA, (DWORD*)r.pBits);
- pt->m_pPalette->UnlockRect(0);
- s->m_perfmon.IncCounter(GSPerfMon::c_texture, 256*4);
- }
- if(lr == needsupdate)
- {
- UpdateTexture(s, pt, &GSLocalMemory::ReadTextureP);
- lr = found;
- }
- if(lr == found)
- {
- #ifdef DEBUG_LOG
- s->LOG(_T("*TC2 texture was found, age %d -> 0n"), pt->m_nAge);
- #endif
- pt->m_nAge = 0;
- t = *pt;
- if(pt->m_fTemp) delete pt;
- return true;
- }
- return false;
- }
- bool GSTextureCache::FetchNP(GSState* s, GSTextureBase& t)
- {
- GSTexture* pt = NULL;
- int nPaletteEntries = GSLocalMemory::m_psmtbl[s->m_ctxt->TEX0.PSM].pal;
- DWORD clut[256];
- if(nPaletteEntries)
- {
- s->m_lm.SetupCLUT(s->m_ctxt->TEX0, s->m_de.TEXA);
- s->m_lm.CopyCLUT32(clut, nPaletteEntries);
- }
- #ifdef DEBUG_LOG
- s->LOG(_T("*TC2 Fetch %dx%d %05I64x %I64d (%d)n"),
- 1 << s->m_ctxt->TEX0.TW, 1 << s->m_ctxt->TEX0.TH,
- s->m_ctxt->TEX0.TBP0, s->m_ctxt->TEX0.PSM, nPaletteEntries);
- #endif
- enum lookupresult {notfound, needsupdate, found} lr = notfound;
- POSITION pos = GetHeadPosition();
- while(pos && !pt)
- {
- POSITION cur = pos;
- pt = GetNext(pos);
- if(HasSharedBits(pt->m_TEX0.TBP0, pt->m_TEX0.PSM, s->m_ctxt->TEX0.TBP0, s->m_ctxt->TEX0.PSM))
- {
- if(pt->m_fRT)
- {
- lr = found;
- if(!(pt = ConvertRT(s, pt)))
- return false;
- }
- else if(s->m_ctxt->TEX0.PSM == pt->m_TEX0.PSM && pt->m_TEX0.TBW == s->m_ctxt->TEX0.TBW
- && s->m_ctxt->TEX0.TW == pt->m_TEX0.TW && s->m_ctxt->TEX0.TH == pt->m_TEX0.TH
- && (!(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)
- // && 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
- && (!nPaletteEntries || s->m_ctxt->TEX0.CPSM == pt->m_TEX0.CPSM && !memcmp(pt->m_clut, clut, nPaletteEntries*sizeof(clut[0]))))
- {
- lr = needsupdate;
- }
- }
- if(lr != notfound) {MoveToHead(cur); break;}
- pt = NULL;
- }
- #ifdef DEBUG_LOG
- s->LOG(_T("*TC2 lr = %sn"), lr == found ? _T("found") : lr == needsupdate ? _T("needsupdate") : _T("notfound"));
- #endif
- if(lr == notfound)
- {
- pt = new GSTexture();
- pt->m_TEX0 = s->m_ctxt->TEX0;
- pt->m_CLAMP = s->m_ctxt->CLAMP;
- // pt->m_TEXA = s->m_de.TEXA;
- DWORD psm = s->m_ctxt->TEX0.PSM;
- switch(psm)
- {
- case PSM_PSMT8:
- case PSM_PSMT8H:
- case PSM_PSMT4:
- case PSM_PSMT4HL:
- case PSM_PSMT4HH:
- psm = s->m_ctxt->TEX0.CPSM;
- break;
- }
- if(!SUCCEEDED(CreateTexture(s, pt, psm)))
- {
- delete pt;
- return false;
- }
- RemoveOldTextures(s);
- AddHead(pt);
- lr = needsupdate;
- }
- ASSERT(pt);
- if(pt && nPaletteEntries)
- {
- memcpy(pt->m_clut, clut, nPaletteEntries*sizeof(clut[0]));
- }
- if(lr == needsupdate)
- {
- UpdateTexture(s, pt, &GSLocalMemory::ReadTextureNP);
- lr = found;
- }
- if(lr == found)
- {
- #ifdef DEBUG_LOG
- s->LOG(_T("*TC2 texture was found, age %d -> 0n"), pt->m_nAge);
- #endif
- pt->m_nAge = 0;
- t = *pt;
- if(pt->m_fTemp) delete pt;
- return true;
- }
- return false;
- }
- void GSTextureCache::IncAge(CSurfMap<IDirect3DTexture9>& pRTs)
- {
- POSITION pos = GetHeadPosition();
- while(pos)
- {
- POSITION cur = pos;
- GSTexture* pt = GetNext(pos);
- pt->m_nAge++;
- pt->m_nVsyncs++;
- if(pt->m_nAge > 10 && (!pt->m_fRT || pRTs.GetCount() > 3))
- {
- pRTs.RemoveKey(pt->m_TEX0.TBP0);
- RemoveAt(cur);
- delete pt;
- }
- }
- }
- void GSTextureCache::ResetAge(DWORD TBP0)
- {
- POSITION pos = GetHeadPosition();
- while(pos)
- {
- GSTexture* pt = GetNext(pos);
- if(pt->m_TEX0.TBP0 == TBP0) pt->m_nAge = 0;
- }
- }
- void GSTextureCache::RemoveAll()
- {
- while(GetCount()) delete RemoveHead();
- m_pTexturePool.RemoveAll();
- m_pRTPool.RemoveAll();
- }
- void GSTextureCache::InvalidateTexture(GSState* s, const GIFRegBITBLTBUF& BITBLTBUF, const CRect& r)
- {
- GIFRegTEX0 TEX0;
- TEX0.TBP0 = BITBLTBUF.DBP;
- TEX0.TBW = BITBLTBUF.DBW;
- TEX0.PSM = BITBLTBUF.DPSM;
- TEX0.TCC = 0;
- #ifdef DEBUG_LOG
- s->LOG(_T("*TC2 invalidate %05x %x (%d,%d-%d,%d)n"), TEX0.TBP0, TEX0.PSM, r.left, r.top, r.right, r.bottom);
- #endif
- POSITION pos = GetHeadPosition();
- while(pos)
- {
- POSITION cur = pos;
- GSTexture* pt = GetNext(pos);
- if(HasSharedBits(TEX0.TBP0, TEX0.PSM, pt->m_TEX0.TBP0, pt->m_TEX0.PSM))
- {
- if(TEX0.TBW != pt->m_TEX0.TBW)
- {
- // if TEX0.TBW != pt->m_TEX0.TBW then this render target is more likely to
- // be discarded by the game (means it doesn't want to transfer an image over
- // another pre-rendered image) and can be refetched from local mem safely.
- RemoveAt(cur);
- delete pt;
- }
- else if(pt->m_fRT)
- {
- // TEX0.TBW = pt->m_TEX0.TBW;
- TEX0.PSM = pt->m_TEX0.PSM;
- if(TEX0.PSM == PSM_PSMCT32 || TEX0.PSM == PSM_PSMCT24
- || TEX0.PSM == PSM_PSMCT16 || TEX0.PSM == PSM_PSMCT16S)
- {
- // pt->m_rcDirty.AddHead(GSDirtyRect(PSM, r));
- HRESULT hr;
- int tw = (r.Width() + 3) & ~3;
- int th = r.Height();
- CComPtr<IDirect3DTexture9> pSrc;
- hr = s->m_pD3DDev->CreateTexture(tw, th, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &pSrc, NULL);
- D3DLOCKED_RECT lr;
- if(pSrc && SUCCEEDED(pSrc->LockRect(0, &lr, NULL, 0)))
- {
- GIFRegTEXA TEXA;
- TEXA.AEM = 1;
- TEXA.TA0 = 0;
- TEXA.TA1 = 0x80;
- GIFRegCLAMP CLAMP;
- CLAMP.WMS = 0;
- CLAMP.WMT = 0;
- s->m_lm.ReadTexture(r, (BYTE*)lr.pBits, lr.Pitch, TEX0, TEXA, CLAMP);
- s->m_perfmon.IncCounter(GSPerfMon::c_unswizzle, r.Width()*r.Height()*4);
- pSrc->UnlockRect(0);
- scale_t scale(pt->m_pTexture);
- CRect dst;
- dst.left = (long)(scale.x * r.left + 0.5);
- dst.top = (long)(scale.y * r.top + 0.5);
- dst.right = (long)(scale.x * r.right + 0.5);
- dst.bottom = (long)(scale.y * r.bottom + 0.5);
- //
- CComPtr<IDirect3DSurface9> pRTSurf;
- hr = pt->m_pTexture->GetSurfaceLevel(0, &pRTSurf);
- hr = s->m_pD3DDev->SetRenderTarget(0, pRTSurf);
- hr = s->m_pD3DDev->SetDepthStencilSurface(NULL);
- hr = s->m_pD3DDev->SetTexture(0, pSrc);
- hr = s->m_pD3DDev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
- hr = s->m_pD3DDev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
- hr = s->m_pD3DDev->SetRenderState(D3DRS_ZENABLE, FALSE);
- hr = s->m_pD3DDev->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
- hr = s->m_pD3DDev->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
- hr = s->m_pD3DDev->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
- hr = s->m_pD3DDev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
- hr = s->m_pD3DDev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ZERO);
- hr = s->m_pD3DDev->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
- hr = s->m_pD3DDev->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_RGBA);
- hr = s->m_pD3DDev->SetPixelShader(NULL);
- struct
- {
- float x, y, z, rhw;
- float tu, tv;
- }
- pVertices[] =
- {
- {(float)dst.left, (float)dst.top, 0.5f, 2.0f, 0, 0},
- {(float)dst.right, (float)dst.top, 0.5f, 2.0f, 1.0f * r.Width() / tw, 0},
- {(float)dst.left, (float)dst.bottom, 0.5f, 2.0f, 0, 1},
- {(float)dst.right, (float)dst.bottom, 0.5f, 2.0f, 1.0f * r.Width() / tw, 1},
- };
- hr = s->m_pD3DDev->BeginScene();
- hr = s->m_pD3DDev->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1);
- hr = s->m_pD3DDev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, pVertices, sizeof(pVertices[0]));
- hr = s->m_pD3DDev->EndScene();
- }
- }
- else
- {
- RemoveAt(cur);
- delete pt;
- }
- }
- else
- {
- pt->m_rcDirty.AddHead(GSDirtyRect(TEX0.PSM, r));
- }
- }
- }
- }
- void GSTextureCache::InvalidateLocalMem(GSState* s, DWORD TBP0, DWORD BW, DWORD PSM, const CRect& r)
- {
- CComPtr<IDirect3DTexture9> pRT;
- POSITION pos = GetHeadPosition();
- while(pos)
- {
- POSITION cur = pos;
- GSTexture* pt = GetNext(pos);
- if(pt->m_TEX0.TBP0 == TBP0 && pt->m_fRT)
- {
- pRT = pt->m_pTexture;
- break;
- }
- }
- if(!pRT) return;
- // TODO: add resizing
- /*
- HRESULT hr;
- D3DSURFACE_DESC desc;
- hr = pRT->GetLevelDesc(0, &desc);
- if(FAILED(hr)) return;
- CComPtr<IDirect3DSurface9> pVidMem;
- hr = pRT->GetSurfaceLevel(0, &pVidMem);
- if(FAILED(hr)) return;
- CComPtr<IDirect3DSurface9> pSysMem;
- hr = s->m_pD3DDev->CreateOffscreenPlainSurface(desc.Width, desc.Height, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &pSysMem, NULL);
- if(FAILED(hr)) return;
- hr = s->m_pD3DDev->GetRenderTargetData(pVidMem, pSysMem);
- if(FAILED(hr)) return;
- D3DLOCKED_RECT lr;
- hr = pSysMem->LockRect(&lr, &r, D3DLOCK_READONLY|D3DLOCK_NO_DIRTY_UPDATE);
- if(SUCCEEDED(hr))
- {
- BYTE* p = (BYTE*)lr.pBits;
- if(0 && r.left == 0 && r.top == 0 && PSM == PSM_PSMCT32)
- {
- }
- else
- {
- GSLocalMemory::writeFrame wf = s->m_lm.GetWriteFrame(PSM);
- for(int y = r.top; y < r.bottom; y++, p += lr.Pitch)
- {
- for(int x = r.left; x < r.right; x++)
- {
- (s->m_lm.*wf)(x, y, ((DWORD*)p)[x], TBP0, BW);
- }
- }
- }
- pSysMem->UnlockRect();
- }
- */
- }
- void GSTextureCache::AddRT(GIFRegTEX0& TEX0, IDirect3DTexture9* pRT, scale_t scale)
- {
- POSITION pos = GetHeadPosition();
- while(pos)
- {
- POSITION cur = pos;
- GSTexture* pt = GetNext(pos);
- if(HasSharedBits(TEX0.TBP0, TEX0.PSM, pt->m_TEX0.TBP0, pt->m_TEX0.PSM))
- {
- RemoveAt(cur);
- delete pt;
- }
- }
- GSTexture* pt = new GSTexture();
- pt->m_TEX0 = TEX0;
- pt->m_pTexture = pRT;
- pt->m_pTexture->GetLevelDesc(0, &pt->m_desc);
- pt->m_scale = scale;
- pt->m_fRT = true;
- AddHead(pt);
- }