mirror of https://github.com/PCSX2/pcsx2.git
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:
parent
72d43b2e56
commit
eec74fd963
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue