gsdx hw: Add an alternate draw call for FMV rendering

The long story:
Game blits FMV far aways of the RT which is actually the input of the RO texture...
Currently GSdx suffers of 2 bugs.
1/ RT is too small
2/ texture isn't properly updated with the rendered value. Texture is invalidated
but it reads back the pixels from the GS memory whereas the correct
value is located on the GPU.

This commit will replace the standard draw by a manual blit. Therefore it avoid
size issue and bad upscaling issue.

v2:
* Use various copy to be more compatible with dx api
* Move all part of the hack info the BlitFMV function

v3: add log message
This commit is contained in:
Gregory Hainaut 2016-03-19 11:43:27 +01:00
parent 72d43b2e56
commit eec74fd963
2 changed files with 83 additions and 8 deletions

View File

@ -484,9 +484,20 @@ void GSRendererHW::Draw()
} }
#endif #endif
// The rectangle of the draw
GSVector4i r = GSVector4i(m_vt.m_min.p.xyxy(m_vt.m_max.p)).rintersect(GSVector4i(context->scissor.in));
if(m_hacks.m_oi && !(this->*m_hacks.m_oi)(rt_tex, ds_tex, tex)) if(m_hacks.m_oi && !(this->*m_hacks.m_oi)(rt_tex, ds_tex, tex))
{ {
s_n += 1; // keep counter sync s_n += 1; // keep counter sync
GL_INS("Warning skipping a draw call (%d)", s_n);
GL_POP();
return;
}
if (!OI_BlitFMV(rt, tex, r)) {
s_n += 1; // keep counter sync
GL_INS("Warning skipping a draw call (%d)", s_n);
GL_POP(); GL_POP();
return; return;
} }
@ -565,8 +576,6 @@ void GSRendererHW::Draw()
// //
GSVector4i r = GSVector4i(m_vt.m_min.p.xyxy(m_vt.m_max.p)).rintersect(GSVector4i(context->scissor.in));
// Help to detect rendering outside of the framebuffer // Help to detect rendering outside of the framebuffer
#if _DEBUG #if _DEBUG
if (m_upscale_multiplier * r.z > m_width) { if (m_upscale_multiplier * r.z > m_width) {
@ -815,6 +824,71 @@ void GSRendererHW::OI_GsMemClear()
} }
} }
bool GSRendererHW::OI_BlitFMV(GSTextureCache::Target* _rt, GSTextureCache::Source* tex, const GSVector4i& r_draw)
{
if (r_draw.w > 1024 && (m_vt.m_primclass == GS_SPRITE_CLASS) && (m_vertex.next == 2) && PRIM->TME && !PRIM->ABE) {
GL_PUSH("OI_BlitFMV");
GL_INS("OI_BlitFMV");
// The draw is done past the RT at the location of the texture. To avoid various upscaling mess
// We will blit the data from the top to the bottom of the texture manually.
// Expected memory representation
// -----------------------------------------------------------------
// RT (2 half frame)
// -----------------------------------------------------------------
// Top of Texture (full height frame)
//
// Bottom of Texture (half height frame, will be the copy of Top texture after the draw)
// -----------------------------------------------------------------
// sRect is the top of texture
int tw = (int)(1 << m_context->TEX0.TW);
int th = (int)(1 << m_context->TEX0.TH);
GSVector4 sRect;
sRect.x = m_vt.m_min.t.x / tw;
sRect.y = m_vt.m_min.t.y / th;
sRect.z = m_vt.m_max.t.x / tw;
sRect.w = m_vt.m_max.t.y / th;
// Compute the Bottom of texture rectangle
ASSERT(m_context->TEX0.TBP0 > m_context->FRAME.Block());
int offset = (m_context->TEX0.TBP0 - m_context->FRAME.Block()) / m_context->TEX0.TBW;
GSVector4i r_texture(r_draw);
r_texture.y -= offset;
r_texture.w -= offset;
GSVector4 dRect(r_texture);
// Do the blit. With a Copy mess to avoid issue with limited API (dx)
// m_dev->StretchRect(tex->m_texture, sRect, tex->m_texture, dRect);
GSVector4i r_full(0, 0, tw, th);
if (GSTexture* rt = m_dev->CreateRenderTarget(tw, th, false)) {
m_dev->CopyRect(tex->m_texture, rt, r_full);
m_dev->StretchRect(tex->m_texture, sRect, rt, dRect);
m_dev->CopyRect(rt, tex->m_texture, r_full);
m_dev->Recycle(rt);
}
// Copy back the texture into the GS mem. I don't know why but it will be
// reuploaded again later
m_tc->Read(tex, r_texture);
m_tc->InvalidateVideoMemSubTarget(_rt);
GL_POP();
return false; // skip current draw
}
// Nothing to see keep going
return true;
}
// OI (others input?/implementation?) hacks replace current draw call // OI (others input?/implementation?) hacks replace current draw call
bool GSRendererHW::OI_FFXII(GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t) bool GSRendererHW::OI_FFXII(GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t)

View File

@ -47,6 +47,7 @@ private:
typedef bool (GSRendererHW::*CU_Ptr)(); typedef bool (GSRendererHW::*CU_Ptr)();
// Require special argument // Require special argument
bool OI_BlitFMV(GSTextureCache::Target* _rt, GSTextureCache::Source* t, const GSVector4i& r_draw);
void OI_GsMemClear(); // always on void OI_GsMemClear(); // always on
bool OI_DoubleHalfClear(GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t); bool OI_DoubleHalfClear(GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t);