gsdx tc: re-implement frame lookup

Try to avoid random black screen frame

v2: don't force the preload hack on the frame
It creates a ghost image over FMV

v3: support offset within a frame
This commit is contained in:
Gregory Hainaut 2016-03-19 12:37:25 +01:00
parent eec74fd963
commit 063d2e568a
12 changed files with 73 additions and 15 deletions

View File

@ -192,19 +192,22 @@ bool GSRenderer::Merge(int field)
GSVector2i ds(0, 0); GSVector2i ds(0, 0);
GSTexture* tex[2] = {NULL, NULL}; GSTexture* tex[2] = {NULL, NULL};
int y_offset[2] = {0, 0};
if(samesrc && fr[0].bottom == fr[1].bottom) if(samesrc && fr[0].bottom == fr[1].bottom)
{ {
tex[0] = GetOutput(0); tex[0] = GetOutput(0, y_offset[0]);
tex[1] = tex[0]; // saves one texture fetch tex[1] = tex[0]; // saves one texture fetch
y_offset[1] = y_offset[0];
} }
else else
{ {
if(en[0]) tex[0] = GetOutput(0); if(en[0]) tex[0] = GetOutput(0, y_offset[0]);
if(en[1]) tex[1] = GetOutput(1); if(en[1]) tex[1] = GetOutput(1, y_offset[1]);
} }
GSVector4 src[2]; GSVector4 src[2];
GSVector4 src_hw[2];
GSVector4 dst[2]; GSVector4 dst[2];
for(int i = 0; i < 2; i++) for(int i = 0; i < 2; i++)
@ -224,6 +227,7 @@ bool GSRenderer::Merge(int field)
GSVector4 scale = GSVector4(tex[i]->GetScale()).xyxy(); GSVector4 scale = GSVector4(tex[i]->GetScale()).xyxy();
src[i] = GSVector4(r) * scale / GSVector4(tex[i]->GetSize()).xyxy(); src[i] = GSVector4(r) * scale / GSVector4(tex[i]->GetSize()).xyxy();
src_hw[i] = (GSVector4(r) + GSVector4 (0, y_offset[i], 0, y_offset[i])) * scale / GSVector4(tex[i]->GetSize()).xyxy();
GSVector2 off(0, 0); GSVector2 off(0, 0);
@ -264,7 +268,7 @@ bool GSRenderer::Merge(int field)
GSVector4 c = GSVector4((int)m_regs->BGCOLOR.R, (int)m_regs->BGCOLOR.G, (int)m_regs->BGCOLOR.B, (int)m_regs->PMODE.ALP) / 255; GSVector4 c = GSVector4((int)m_regs->BGCOLOR.R, (int)m_regs->BGCOLOR.G, (int)m_regs->BGCOLOR.B, (int)m_regs->PMODE.ALP) / 255;
m_dev->Merge(tex, src, dst, fs, slbg, mmod, c); m_dev->Merge(tex, src_hw, dst, fs, slbg, mmod, c);
if(m_regs->SMODE2.INT && m_interlace > 0) if(m_regs->SMODE2.INT && m_interlace > 0)
{ {

View File

@ -50,7 +50,7 @@ protected:
bool m_shadeboost; bool m_shadeboost;
bool m_texture_shuffle; bool m_texture_shuffle;
virtual GSTexture* GetOutput(int i) = 0; virtual GSTexture* GetOutput(int i, int& y_offset) = 0;
public: public:
GSWnd* m_wnd; GSWnd* m_wnd;

View File

@ -157,7 +157,7 @@ void GSRendererCL::ResetDevice()
} }
} }
GSTexture* GSRendererCL::GetOutput(int i) GSTexture* GSRendererCL::GetOutput(int i, int& y_offset)
{ {
const GSRegDISPFB& DISPFB = m_regs->DISP[i].DISPFB; const GSRegDISPFB& DISPFB = m_regs->DISP[i].DISPFB;

View File

@ -251,7 +251,7 @@ protected:
void Reset(); void Reset();
void VSync(int field); void VSync(int field);
void ResetDevice(); void ResetDevice();
GSTexture* GetOutput(int i); GSTexture* GetOutput(int i, int& y_offset);
void Draw(); void Draw();
void Sync(int reason); void Sync(int reason);

View File

@ -338,7 +338,7 @@ void GSRendererCS::VSync(int field)
//printf("%lld\n", m_perfmon.GetFrame()); //printf("%lld\n", m_perfmon.GetFrame());
} }
GSTexture* GSRendererCS::GetOutput(int i) GSTexture* GSRendererCS::GetOutput(int i, int& y_offset)
{ {
// TODO: create a compute shader which unswizzles the frame from m_vm to the output texture // TODO: create a compute shader which unswizzles the frame from m_vm to the output texture

View File

@ -134,7 +134,7 @@ protected:
bool CreateDevice(GSDevice* dev); bool CreateDevice(GSDevice* dev);
void ResetDevice(); void ResetDevice();
void VSync(int field); void VSync(int field);
GSTexture* GetOutput(int i); GSTexture* GetOutput(int i, int& y_offset);
void Draw(); void Draw();
void InvalidateVideoMem(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r); void InvalidateVideoMem(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r);
void InvalidateLocalMem(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r, bool clut); void InvalidateLocalMem(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r, bool clut);

View File

@ -151,7 +151,7 @@ void GSRendererHW::ResetDevice()
GSRenderer::ResetDevice(); GSRenderer::ResetDevice();
} }
GSTexture* GSRendererHW::GetOutput(int i) GSTexture* GSRendererHW::GetOutput(int i, int& y_offset)
{ {
const GSRegDISPFB& DISPFB = m_regs->DISP[i].DISPFB; const GSRegDISPFB& DISPFB = m_regs->DISP[i].DISPFB;
@ -169,6 +169,13 @@ GSTexture* GSRendererHW::GetOutput(int i)
{ {
t = rt->m_texture; t = rt->m_texture;
int delta = TEX0.TBP0 - rt->m_TEX0.TBP0;
if (delta > 0) {
ASSERT(DISPFB.PSM == PSM_PSMCT32 || DISPFB.PSM == PSM_PSMCT24);
y_offset = delta / DISPFB.FBW;
GL_CACHE("Frame y offset %d pixels, unit %d", y_offset, i);
}
#ifndef NDEBUG #ifndef NDEBUG
if(s_dump) if(s_dump)
{ {

View File

@ -165,7 +165,7 @@ public:
void Reset(); void Reset();
void VSync(int field); void VSync(int field);
void ResetDevice(); void ResetDevice();
GSTexture* GetOutput(int i); GSTexture* GetOutput(int i, int& y_offset);
void InvalidateVideoMem(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r); void InvalidateVideoMem(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r);
void InvalidateLocalMem(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r, bool clut = false); void InvalidateLocalMem(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r, bool clut = false);
void Draw(); void Draw();

View File

@ -36,7 +36,7 @@ protected:
{ {
} }
GSTexture* GetOutput(int i) GSTexture* GetOutput(int i, int& y_offset)
{ {
return NULL; return NULL;
} }

View File

@ -231,7 +231,7 @@ void GSRendererSW::ResetDevice()
} }
} }
GSTexture* GSRendererSW::GetOutput(int i) GSTexture* GSRendererSW::GetOutput(int i, int& y_offset)
{ {
Sync(1); Sync(1);

View File

@ -78,7 +78,7 @@ protected:
void Reset(); void Reset();
void VSync(int field); void VSync(int field);
void ResetDevice(); void ResetDevice();
GSTexture* GetOutput(int i); GSTexture* GetOutput(int i, int& y_offset);
void Draw(); void Draw();
void Queue(shared_ptr<GSRasterizerData>& item); void Queue(shared_ptr<GSRasterizerData>& item);

View File

@ -416,6 +416,52 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(const GIFRegTEX0& TEX0, int
Target* dst = NULL; Target* dst = NULL;
#if 0
// Dump the list of targets for debug
for(auto t : m_dst[RenderTarget]) {
GL_INS("TC: frame 0x%x -> 0x%x : %d (age %d)", t->m_TEX0.TBP0, t->m_end_block, t->m_texture->GetID(), t->m_age);
}
#endif
// Let's try to find a perfect frame that contains valid data
for(auto t : m_dst[RenderTarget]) {
if(bp == t->m_TEX0.TBP0 && t->m_end_block > bp) {
dst = t;
GL_CACHE("TC: Lookup Frame %dx%d, perfect hit: %d (0x%x -> 0x%x)", w, h, dst->m_texture->GetID(), bp, t->m_end_block);
break;
}
}
// 2nd try ! Try to find a frame that include the bp
if (dst == NULL) {
for(auto t : m_dst[RenderTarget]) {
if (t->m_TEX0.TBP0 < bp && bp < t->m_end_block) {
dst = t;
GL_CACHE("TC: Lookup Frame %dx%d, inclusive hit: %d (0x%x, took 0x%x -> 0x%x)", w, h, t->m_texture->GetID(), bp, t->m_TEX0.TBP0, t->m_end_block);
break;
}
}
}
// 3rd try ! Try to find a frame that doesn't contain valid data (honestly I'm not sure we need to do it)
if (dst == NULL) {
for(auto t : m_dst[RenderTarget]) {
if(bp == t->m_TEX0.TBP0) {
dst = t;
GL_CACHE("TC: Lookup Frame %dx%d, empty hit: %d (0x%x -> 0x%x)", w, h, dst->m_texture->GetID(), bp, t->m_end_block);
break;
}
}
}
#if 0
for(list<Target*>::iterator i = m_dst[RenderTarget].begin(); i != m_dst[RenderTarget].end(); i++) for(list<Target*>::iterator i = m_dst[RenderTarget].begin(); i != m_dst[RenderTarget].end(); i++)
{ {
Target* t = *i; Target* t = *i;
@ -439,6 +485,7 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(const GIFRegTEX0& TEX0, int
} }
} }
} }
#endif
if(dst == NULL) if(dst == NULL)
{ {