mirror of https://github.com/PCSX2/pcsx2.git
GS/HW: More RT in RT regression fixes and adjustments
Restored the Z clear CRC hack for Battlefield 2, it's probably the least invasive one and the most difficult one to emulate, it was still problematic.
This commit is contained in:
parent
9f98e28b08
commit
045bcbc7da
|
@ -13621,6 +13621,7 @@ SLED-53731:
|
|||
halfPixelOffset: 2 # Offset post-processing.
|
||||
texturePreloading: 1 # Improves performance.
|
||||
textureInsideRT: 1 # Fixes per line drawing.
|
||||
getSkipCount: "GSC_Battlefield2" # Depth clear.
|
||||
SLED-53732:
|
||||
name: "Spartan - Total Warrior [Demo]"
|
||||
region: "PAL"
|
||||
|
@ -23621,6 +23622,7 @@ SLES-53729:
|
|||
halfPixelOffset: 2 # Offset post-processing.
|
||||
texturePreloading: 1 # Improves performance.
|
||||
textureInsideRT: 1 # Fixes per line drawing.
|
||||
getSkipCount: "GSC_Battlefield2" # Depth clear.
|
||||
SLES-53730:
|
||||
name: "Battlefield 2 - Modern Combat"
|
||||
region: "PAL-M3"
|
||||
|
@ -23630,6 +23632,7 @@ SLES-53730:
|
|||
halfPixelOffset: 2 # Offset post-processing.
|
||||
texturePreloading: 1 # Improves performance.
|
||||
textureInsideRT: 1 # Fixes per line drawing.
|
||||
getSkipCount: "GSC_Battlefield2" # Depth clear.
|
||||
SLES-53734:
|
||||
name: "50 Cent - Bulletproof"
|
||||
region: "PAL-E"
|
||||
|
@ -31306,6 +31309,7 @@ SLKA-25330:
|
|||
halfPixelOffset: 2 # Offset post-processing.
|
||||
texturePreloading: 1 # Improves performance.
|
||||
textureInsideRT: 1 # Fixes per line drawing.
|
||||
getSkipCount: "GSC_Battlefield2" # Depth clear.
|
||||
SLKA-25331:
|
||||
name: "Marc Ecko's Getting Up - Contents Under Pressure"
|
||||
region: "NTSC-K"
|
||||
|
@ -32194,6 +32198,7 @@ SLPM-55034:
|
|||
halfPixelOffset: 2 # Offset post-processing.
|
||||
texturePreloading: 1 # Improves performance.
|
||||
textureInsideRT: 1 # Fixes per line drawing.
|
||||
getSkipCount: "GSC_Battlefield2" # Depth clear.
|
||||
SLPM-55035:
|
||||
name: "ファイトナイト ラウンド2 [EA:SY! 1980]"
|
||||
name-sort: "ふぁいとないと らうんど2 [EA:SY! 1980]"
|
||||
|
@ -46305,6 +46310,7 @@ SLPM-66206:
|
|||
halfPixelOffset: 2 # Offset post-processing.
|
||||
texturePreloading: 1 # Improves performance.
|
||||
textureInsideRT: 1 # Fixes per line drawing.
|
||||
getSkipCount: "GSC_Battlefield2" # Depth clear.
|
||||
SLPM-66207:
|
||||
name: "どろろ [SEGA THE BEST 2800]"
|
||||
name-sort: "どろろ [SEGA THE BEST 2800]"
|
||||
|
@ -49096,6 +49102,7 @@ SLPM-66651:
|
|||
halfPixelOffset: 2 # Offset post-processing.
|
||||
texturePreloading: 1 # Improves performance.
|
||||
textureInsideRT: 1 # Fixes per line drawing.
|
||||
getSkipCount: "GSC_Battlefield2" # Depth clear.
|
||||
SLPM-66652:
|
||||
name: "バーンアウト リベンジ [EA BEST HITS]"
|
||||
name-sort: "ばーんあうと りべんじ [EA BEST HITS]"
|
||||
|
@ -66986,6 +66993,7 @@ SLUS-21026:
|
|||
halfPixelOffset: 2 # Offset post-processing.
|
||||
texturePreloading: 1 # Improves performance.
|
||||
textureInsideRT: 1 # Fixes per line drawing.
|
||||
getSkipCount: "GSC_Battlefield2" # Depth clear.
|
||||
SLUS-21027:
|
||||
name: "The Lord of the Rings - The Third Age"
|
||||
name-sort: "Lord of the Rings, The - The Third Age"
|
||||
|
@ -72938,6 +72946,7 @@ SLUS-29117:
|
|||
halfPixelOffset: 2 # Offset post-processing.
|
||||
texturePreloading: 1 # Improves performance.
|
||||
textureInsideRT: 1 # Fixes per line drawing.
|
||||
getSkipCount: "GSC_Battlefield2" # Depth clear.
|
||||
SLUS-29118:
|
||||
name: "Need for Speed - Underground 2 [Demo]"
|
||||
region: "NTSC-U"
|
||||
|
@ -73090,6 +73099,7 @@ SLUS-29152:
|
|||
halfPixelOffset: 2 # Offset post-processing.
|
||||
texturePreloading: 1 # Improves performance.
|
||||
textureInsideRT: 1 # Fixes per line drawing.
|
||||
getSkipCount: "GSC_Battlefield2" # Depth clear.
|
||||
SLUS-29153:
|
||||
name: "Burnout Revenge [Demo]"
|
||||
region: "NTSC-U"
|
||||
|
@ -73205,6 +73215,7 @@ SLUS-29172:
|
|||
halfPixelOffset: 2 # Offset post-processing.
|
||||
texturePreloading: 1 # Improves performance.
|
||||
textureInsideRT: 1 # Fixes per line drawing.
|
||||
getSkipCount: "GSC_Battlefield2" # Depth clear.
|
||||
SLUS-29173:
|
||||
name: "The Sims 2 [Demo]"
|
||||
name-sort: "Sims 2, The [Demo]"
|
||||
|
|
|
@ -4468,7 +4468,7 @@ bool GSState::GSTransferBuffer::Update(int tw, int th, int bpp, int& len)
|
|||
{
|
||||
if (len > packet_size)
|
||||
{
|
||||
#if defined(PCSX2_DEVBUILD) || defined(_DEBUG)
|
||||
#if defined(_DEBUG)
|
||||
Console.Warning("GS transfer buffer overflow len %d remaining %d, tex_size %d tw %d th %d bpp %d", len, remaining, tex_size, tw, th, bpp);
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -742,7 +742,7 @@ bool GSHwHack::GSC_PolyphonyDigitalGames(GSRendererHW& r, int& skip)
|
|||
|
||||
for (u32 channel = 0; channel < 3; channel++)
|
||||
{
|
||||
const GIFRegTEX0 TEX0 = GIFRegTEX0::Create(base + channel * page_offset, RTEX0.TBW, PSMCT32);
|
||||
const GIFRegTEX0 TEX0 = GIFRegTEX0::Create(base + channel * page_offset, 10, PSMCT32);
|
||||
GSTextureCache::Target* dst = g_texture_cache->LookupTarget(TEX0, src->GetUnscaledSize(), src->GetScale(), GSTextureCache::RenderTarget, true, fbmsk);
|
||||
if (!dst)
|
||||
{
|
||||
|
@ -775,6 +775,35 @@ bool GSHwHack::GSC_PolyphonyDigitalGames(GSRendererHW& r, int& skip)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
bool GSHwHack::GSC_Battlefield2(GSRendererHW& r, int& skip)
|
||||
{
|
||||
if (skip == 0)
|
||||
{
|
||||
if (RZBP >= RFBP && RFBP >= 0x2000 && RZBP >= 0x2700 && ((RZBP - RFBP) == 0x700))
|
||||
{
|
||||
skip = 7;
|
||||
|
||||
GIFRegTEX0 TEX0 = {};
|
||||
TEX0.TBP0 = RFBP;
|
||||
TEX0.TBW = 8;
|
||||
GSTextureCache::Target* dst = g_texture_cache->LookupTarget(TEX0, r.GetTargetSize(), r.GetTextureScaleFactor(), GSTextureCache::DepthStencil);
|
||||
|
||||
if (!dst)
|
||||
dst = g_texture_cache->CreateTarget(TEX0, r.GetTargetSize(), r.GetValidSize(nullptr), r.GetTextureScaleFactor(), GSTextureCache::DepthStencil,
|
||||
true, 0, false, false, false, GSVector4i(0,0,1,1), nullptr);
|
||||
|
||||
if (dst)
|
||||
{
|
||||
float dc = r.m_vertex.buff[1].XYZ.Z;
|
||||
g_gs_device->ClearDepth(dst->m_texture, dc * std::exp2(-32.0f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GSHwHack::GSC_BlueTongueGames(GSRendererHW& r, int& skip)
|
||||
{
|
||||
GSDrawingContext* context = r.m_context;
|
||||
|
@ -1064,16 +1093,29 @@ bool GSHwHack::OI_SonicUnleashed(GSRendererHW& r, GSTexture* rt, GSTexture* ds,
|
|||
GSTextureCache::Target* rt_again = g_texture_cache->LookupTarget(Frame, src_size, src->m_scale, GSTextureCache::RenderTarget);
|
||||
if ((rt_again->m_TEX0.PSM & 0x3) == PSMCT16)
|
||||
{
|
||||
GSVector4i dRect = rt_again->m_valid;
|
||||
GSVector4 dRect;
|
||||
|
||||
dRect = GSVector4i(GSVector4(GSVector4i::loadh(rt_again->m_unscaled_size)) * rt_again->m_scale);
|
||||
GSVector4 source_rect = GSVector4(static_cast<float>(rt_again->m_valid.x) / static_cast<float>(rt_again->m_unscaled_size.x), static_cast<float>(rt_again->m_valid.y) / static_cast<float>(rt_again->m_unscaled_size.y),
|
||||
static_cast<float>(rt_again->m_valid.z) / static_cast<float>(rt_again->m_unscaled_size.x), static_cast<float>(rt_again->m_valid.w) / static_cast<float>(rt_again->m_unscaled_size.y));
|
||||
|
||||
dRect = GSVector4(rt_again->m_valid) * rt_again->m_scale;
|
||||
dRect.y /= 2;
|
||||
dRect.w /= 2;
|
||||
rt_again->m_valid.y /= 2;
|
||||
rt_again->m_valid.w /= 2;
|
||||
rt_again->m_TEX0.PSM = PSMCT32;
|
||||
rt_again->ResizeTexture(rt_again->m_unscaled_size.x, rt_again->m_unscaled_size.y / 2, true, true, dRect, false);
|
||||
rt = rt_again->m_texture;
|
||||
GSTexture* tex = g_gs_device->CreateRenderTarget(rt_again->m_unscaled_size.x * rt_again->m_scale, rt_again->m_unscaled_size.y * rt_again->m_scale, GSTexture::Format::Color, false);
|
||||
|
||||
if (!tex)
|
||||
return false;
|
||||
|
||||
|
||||
g_gs_device->StretchRect(rt_again->m_texture, source_rect, tex, dRect, ShaderConvert::COPY, false);
|
||||
|
||||
|
||||
g_gs_device->Recycle(rt_again->m_texture);
|
||||
rt_again->m_texture = tex;
|
||||
rt = tex;
|
||||
}
|
||||
|
||||
GSVector2i rt_size(rt->GetSize());
|
||||
|
@ -1457,6 +1499,7 @@ const GSHwHack::Entry<GSRendererHW::GSC_Ptr> GSHwHack::s_get_skip_count_function
|
|||
CRC_F(GSC_PolyphonyDigitalGames),
|
||||
CRC_F(GSC_MetalGearSolid3),
|
||||
CRC_F(GSC_HitmanBloodMoney),
|
||||
CRC_F(GSC_Battlefield2),
|
||||
|
||||
// Channel Effect
|
||||
CRC_F(GSC_SteambotChronicles),
|
||||
|
|
|
@ -26,6 +26,7 @@ public:
|
|||
static bool GSC_SteambotChronicles(GSRendererHW& r, int& skip);
|
||||
static bool GSC_BlueTongueGames(GSRendererHW& r, int& skip);
|
||||
static bool GSC_NFSUndercover(GSRendererHW& r, int& skip);
|
||||
static bool GSC_Battlefield2(GSRendererHW& r, int& skip);
|
||||
static bool GSC_PolyphonyDigitalGames(GSRendererHW& r, int& skip);
|
||||
static bool GSC_MetalGearSolid3(GSRendererHW& r, int& skip);
|
||||
static bool GSC_HitmanBloodMoney(GSRendererHW& r, int& skip);
|
||||
|
|
|
@ -2252,19 +2252,29 @@ void GSRendererHW::Draw()
|
|||
//DevCon.Warning("Skipped %d draw %d was abort %d", num_skipped_channel_shuffle_draws, s_n, (int)m_channel_shuffle_abort);
|
||||
// Some games like Tomb raider abort early, we're never going to know the real height, and the system doesn't work right for partials.
|
||||
// But it's good enough for games like Hitman Blood Money which only shuffle part of the screen
|
||||
const int width = std::max(static_cast<int>(m_last_rt->m_TEX0.TBW) * 64, 64);
|
||||
const int shuffle_height = (((num_skipped_channel_shuffle_draws + 1 + (std::max(1, (width / 64) - 1))) * 64) / width) * 32;
|
||||
const int shuffle_width = std::min((num_skipped_channel_shuffle_draws + 1) * 64, static_cast<u32>(width));
|
||||
GSVector4i valid_area = GSVector4i::loadh(GSVector2i(shuffle_width, shuffle_height));
|
||||
const int offset = (((m_last_channel_shuffle_fbp + 0x20) - m_last_rt->m_TEX0.TBP0) >> 5) - (num_skipped_channel_shuffle_draws + 1);
|
||||
|
||||
if (offset)
|
||||
{
|
||||
int vertical_offset = (offset / std::max(1U, m_channel_shuffle_width)) * 32;
|
||||
valid_area.y += vertical_offset;
|
||||
valid_area.w += vertical_offset;
|
||||
}
|
||||
|
||||
if (!m_full_screen_shuffle)
|
||||
{
|
||||
const u32 width_pages = ((num_skipped_channel_shuffle_draws + 1) % std::max(1U, m_channel_shuffle_width) % std::max(1U, m_channel_shuffle_width)) * 64;
|
||||
;
|
||||
m_conf.scissor.w = m_conf.scissor.y + (((num_skipped_channel_shuffle_draws + 1 + (m_channel_shuffle_width - 1)) / std::max(1U, m_channel_shuffle_width)) * 32) * m_conf.cb_ps.ScaleFactor.z;
|
||||
if (width_pages)
|
||||
m_conf.scissor.z = m_conf.scissor.x + (((num_skipped_channel_shuffle_draws + 1) % std::max(1U, m_channel_shuffle_width) % std::max(1U, m_channel_shuffle_width)) * 64) * m_conf.cb_ps.ScaleFactor.z;
|
||||
|
||||
m_last_rt->UpdateValidity(GSVector4i::loadh(m_last_rt->m_unscaled_size).rintersect(GSVector4i(GSVector4(m_conf.scissor) / m_conf.cb_ps.ScaleFactor.z)), true);
|
||||
m_conf.scissor.w = m_conf.scissor.y + shuffle_height * m_conf.cb_ps.ScaleFactor.z;
|
||||
if (shuffle_width)
|
||||
m_conf.scissor.z = m_conf.scissor.x + (shuffle_width * m_conf.cb_ps.ScaleFactor.z);
|
||||
else
|
||||
m_conf.scissor.z = std::min(m_conf.scissor.z, static_cast<int>((m_channel_shuffle_width * 64) * m_conf.cb_ps.ScaleFactor.z));
|
||||
}
|
||||
else
|
||||
m_last_rt->UpdateValidity(m_channel_shuffle_src_valid);
|
||||
|
||||
m_last_rt->UpdateValidity(valid_area);
|
||||
|
||||
g_gs_device->RenderHW(m_conf);
|
||||
|
||||
|
@ -2303,6 +2313,7 @@ void GSRendererHW::Draw()
|
|||
m_channel_shuffle_width = 0;
|
||||
m_full_screen_shuffle = false;
|
||||
m_channel_shuffle_abort = false;
|
||||
m_channel_shuffle_src_valid = GSVector4i::zero();
|
||||
|
||||
GL_PUSH("HW Draw %d (Context %u)", s_n, PRIM->CTXT);
|
||||
GL_INS("FLUSH REASON: %s%s", GetFlushReasonString(m_state_flush_reason),
|
||||
|
@ -3092,7 +3103,7 @@ void GSRendererHW::Draw()
|
|||
// FBW is going to be wrong for channel shuffling into a new target, so take it from the source.
|
||||
FRAME_TEX0.U64 = 0;
|
||||
FRAME_TEX0.TBP0 = ((m_last_channel_shuffle_end_block + 1) == m_cached_ctx.FRAME.Block() && possible_shuffle) ? m_last_channel_shuffle_fbp : m_cached_ctx.FRAME.Block();
|
||||
FRAME_TEX0.TBW = (possible_horizontal_texture_shuffle || (possible_shuffle && src && src->m_from_target && IsPossibleChannelShuffle())) ? src->m_from_target_TEX0.TBW : m_cached_ctx.FRAME.FBW;
|
||||
FRAME_TEX0.TBW = (possible_horizontal_texture_shuffle || (possible_shuffle && src && src->m_from_target && IsPossibleChannelShuffle()&& m_cached_ctx.FRAME.FBW <= 2)) ? src->m_from_target_TEX0.TBW : m_cached_ctx.FRAME.FBW;
|
||||
FRAME_TEX0.PSM = m_cached_ctx.FRAME.PSM;
|
||||
|
||||
// Don't clamp on shuffle, the height cache may troll us with the REAL height.
|
||||
|
@ -3189,6 +3200,11 @@ void GSRendererHW::Draw()
|
|||
CleanupDraw(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsPageCopy() && m_cached_ctx.FRAME.FBW == 1)
|
||||
{
|
||||
rt->UpdateValidity(GSVector4i::loadh(GSVector2i(GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].pgs.x, GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].pgs.y)), true);
|
||||
}
|
||||
}
|
||||
else if (rt->m_TEX0.TBP0 != m_cached_ctx.FRAME.Block())
|
||||
{
|
||||
|
@ -3220,6 +3236,15 @@ void GSRendererHW::Draw()
|
|||
rt->m_drawn_since_read.y += new_offset;
|
||||
rt->m_drawn_since_read.w += new_offset;
|
||||
|
||||
if (rt->m_dirty.size())
|
||||
{
|
||||
for (int i = 0; i < rt->m_dirty.size(); i++)
|
||||
{
|
||||
rt->m_dirty[i].r.y += new_offset;
|
||||
rt->m_dirty[i].r.w += new_offset;
|
||||
}
|
||||
}
|
||||
|
||||
t_size.y += std::abs(vertical_offset);
|
||||
vertical_offset = 0;
|
||||
}
|
||||
|
@ -3231,63 +3256,66 @@ void GSRendererHW::Draw()
|
|||
rt->m_TEX0.TBP0 += horizontal_offset;
|
||||
horizontal_offset = 0;
|
||||
}
|
||||
// Z isn't offset but RT is, so we need a temp Z to align it, hopefully nothing will ever write to the Z too, right??
|
||||
if (ds && vertical_offset && (m_cached_ctx.ZBUF.Block() - ds->m_TEX0.TBP0) != (m_cached_ctx.FRAME.Block() - rt->m_TEX0.TBP0))
|
||||
|
||||
if (vertical_offset || horizontal_offset)
|
||||
{
|
||||
// Z isn't offset but RT is, so we need a temp Z to align it, hopefully nothing will ever write to the Z too, right??
|
||||
if (ds && vertical_offset && (m_cached_ctx.ZBUF.Block() - ds->m_TEX0.TBP0) != (m_cached_ctx.FRAME.Block() - rt->m_TEX0.TBP0))
|
||||
{
|
||||
|
||||
const int z_vertical_offset = ((static_cast<int>(m_cached_ctx.ZBUF.Block() - ds->m_TEX0.TBP0) / 32) / std::max(rt->m_TEX0.TBW, 1U)) * GSLocalMemory::m_psm[m_cached_ctx.ZBUF.PSM].pgs.y;
|
||||
GL_CACHE("RT in RT Z copy on draw %d z_vert_offset %d z_offset %d", s_n, z_vertical_offset, vertical_offset);
|
||||
GSVector4i dRect = GSVector4i(0, vertical_offset * ds->m_scale, ds->m_unscaled_size.x * ds->m_scale, std::min(vertical_offset + m_r.w + 1, vertical_offset + ds->m_unscaled_size.y) * ds->m_scale);
|
||||
const int new_height = std::max(static_cast<int>(ds->m_unscaled_size.y * ds->m_scale), dRect.w);
|
||||
GSTexture* tex = g_gs_device->CreateDepthStencil(ds->m_unscaled_size.x * ds->m_scale, new_height, GSTexture::Format::DepthStencil, true);
|
||||
g_gs_device->StretchRect(ds->m_texture, GSVector4(0.0f, z_vertical_offset / static_cast<float>(ds->m_unscaled_size.y), 1.0f, std::min(z_vertical_offset + m_r.w + 1, ds->m_unscaled_size.y) / static_cast<float>(ds->m_unscaled_size.y)), tex, GSVector4(dRect), ShaderConvert::DEPTH_COPY, false);
|
||||
const int z_vertical_offset = ((static_cast<int>(m_cached_ctx.ZBUF.Block() - ds->m_TEX0.TBP0) / 32) / std::max(rt->m_TEX0.TBW, 1U)) * GSLocalMemory::m_psm[m_cached_ctx.ZBUF.PSM].pgs.y;
|
||||
GL_CACHE("RT in RT Z copy on draw %d z_vert_offset %d z_offset %d", s_n, z_vertical_offset, vertical_offset);
|
||||
GSVector4i dRect = GSVector4i(0, vertical_offset * ds->m_scale, ds->m_unscaled_size.x * ds->m_scale, std::min(vertical_offset + m_r.w + 1, vertical_offset + ds->m_unscaled_size.y) * ds->m_scale);
|
||||
const int new_height = std::max(static_cast<int>(ds->m_unscaled_size.y * ds->m_scale), dRect.w);
|
||||
GSTexture* tex = g_gs_device->CreateDepthStencil(ds->m_unscaled_size.x * ds->m_scale, new_height, GSTexture::Format::DepthStencil, true);
|
||||
g_gs_device->StretchRect(ds->m_texture, GSVector4(0.0f, z_vertical_offset / static_cast<float>(ds->m_unscaled_size.y), 1.0f, std::min(z_vertical_offset + m_r.w + 1, ds->m_unscaled_size.y) / static_cast<float>(ds->m_unscaled_size.y)), tex, GSVector4(dRect), ShaderConvert::DEPTH_COPY, false);
|
||||
|
||||
g_texture_cache->SetTemporaryZ(tex);
|
||||
}
|
||||
|
||||
GSVertex* v = &m_vertex.buff[0];
|
||||
|
||||
for (u32 i = 0; i < m_vertex.tail; i++)
|
||||
{
|
||||
v[i].XYZ.X += horizontal_offset << 4;
|
||||
v[i].XYZ.Y += vertical_offset << 4;
|
||||
}
|
||||
|
||||
if (texture_offset && src && src->m_from_target && src->m_target_direct && src->m_from_target == rt)
|
||||
{
|
||||
GSVector4i src_region = src->GetRegionRect();
|
||||
|
||||
if (src_region.rempty())
|
||||
{
|
||||
src_region = GSVector4i::loadh(rt->m_unscaled_size);
|
||||
src_region.y += texture_offset;
|
||||
g_texture_cache->SetTemporaryZ(tex);
|
||||
}
|
||||
else
|
||||
|
||||
GSVertex* v = &m_vertex.buff[0];
|
||||
|
||||
for (u32 i = 0; i < m_vertex.tail; i++)
|
||||
{
|
||||
src_region.y += texture_offset;
|
||||
src_region.w += texture_offset;
|
||||
v[i].XYZ.X += horizontal_offset << 4;
|
||||
v[i].XYZ.Y += vertical_offset << 4;
|
||||
}
|
||||
src->m_region.SetX(src_region.x, src_region.z);
|
||||
src->m_region.SetY(src_region.y, src_region.w);
|
||||
|
||||
if (texture_offset && src && src->m_from_target && src->m_target_direct && src->m_from_target == rt)
|
||||
{
|
||||
GSVector4i src_region = src->GetRegionRect();
|
||||
|
||||
if (src_region.rempty())
|
||||
{
|
||||
src_region = GSVector4i::loadh(rt->m_unscaled_size);
|
||||
src_region.y += texture_offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
src_region.y += texture_offset;
|
||||
src_region.w += texture_offset;
|
||||
}
|
||||
src->m_region.SetX(src_region.x, src_region.z);
|
||||
src->m_region.SetY(src_region.y, src_region.w);
|
||||
}
|
||||
|
||||
m_context->scissor.in.x += horizontal_offset;
|
||||
m_context->scissor.in.z += horizontal_offset;
|
||||
m_context->scissor.in.y += vertical_offset;
|
||||
m_context->scissor.in.w += vertical_offset;
|
||||
m_r.y += vertical_offset;
|
||||
m_r.w += vertical_offset;
|
||||
m_r.x += horizontal_offset;
|
||||
m_r.z += horizontal_offset;
|
||||
m_in_target_draw = rt->m_TEX0.TBP0 != m_cached_ctx.FRAME.Block();
|
||||
m_vt.m_min.p.x += horizontal_offset;
|
||||
m_vt.m_max.p.x += horizontal_offset;
|
||||
m_vt.m_min.p.y += vertical_offset;
|
||||
m_vt.m_max.p.y += vertical_offset;
|
||||
|
||||
t_size.x = rt->m_unscaled_size.x - horizontal_offset;
|
||||
t_size.y = rt->m_unscaled_size.y - vertical_offset;
|
||||
}
|
||||
|
||||
m_context->scissor.in.x += horizontal_offset;
|
||||
m_context->scissor.in.z += horizontal_offset;
|
||||
m_context->scissor.in.y += vertical_offset;
|
||||
m_context->scissor.in.w += vertical_offset;
|
||||
m_r.y += vertical_offset;
|
||||
m_r.w += vertical_offset;
|
||||
m_r.x += horizontal_offset;
|
||||
m_r.z += horizontal_offset;
|
||||
m_in_target_draw = rt->m_TEX0.TBP0 != m_cached_ctx.FRAME.Block();
|
||||
m_vt.m_min.p.x += horizontal_offset;
|
||||
m_vt.m_max.p.x += horizontal_offset;
|
||||
m_vt.m_min.p.y += vertical_offset;
|
||||
m_vt.m_max.p.y += vertical_offset;
|
||||
|
||||
t_size.x = rt->m_unscaled_size.x - horizontal_offset;
|
||||
t_size.y = rt->m_unscaled_size.y - vertical_offset;
|
||||
|
||||
// Don't resize if the BPP don't match.
|
||||
if (frame_psm.bpp == GSLocalMemory::m_psm[rt->m_TEX0.PSM].bpp)
|
||||
{
|
||||
|
@ -3304,6 +3332,10 @@ void GSRendererHW::Draw()
|
|||
rt->UpdateValidity(m_r, !frame_masked);
|
||||
rt->UpdateDrawn(m_r, !frame_masked);
|
||||
}
|
||||
else if (IsPageCopy() && m_cached_ctx.FRAME.FBW == 1)
|
||||
{
|
||||
rt->UpdateValidity(GSVector4i::loadh(GSVector2i(GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].pgs.x, GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].pgs.y + vertical_offset)), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3320,6 +3352,7 @@ void GSRendererHW::Draw()
|
|||
if (ds && ds->m_scale != target_scale)
|
||||
{
|
||||
const GSVector2i unscaled_size(ds->m_unscaled_size.x, ds->m_unscaled_size.y);
|
||||
ds->m_scale = 1;
|
||||
ds->ResizeTexture(ds->m_unscaled_size.x * target_scale, ds->m_unscaled_size.y * target_scale, true);
|
||||
// Slightly abusing the texture resize.
|
||||
ds->m_scale = target_scale;
|
||||
|
@ -3668,7 +3701,7 @@ void GSRendererHW::Draw()
|
|||
// The FBW should also be okay, since it's coming from the source.
|
||||
if (rt)
|
||||
{
|
||||
const bool update_fbw = !m_in_target_draw && (m_channel_shuffle && src->m_target) && (!PRIM->ABE || IsOpaque() || m_context->ALPHA.IsBlack());
|
||||
const bool update_fbw = (FRAME_TEX0.TBW != rt->m_TEX0.TBW || rt->m_TEX0.TBW == 1) && !m_in_target_draw && (m_channel_shuffle && src->m_target) && (!PRIM->ABE || IsOpaque() || m_context->ALPHA.IsBlack());
|
||||
rt->m_TEX0.TBW = update_fbw ? ((src && src->m_from_target && src->m_32_bits_fmt) ? src->m_from_target->m_TEX0.TBW : FRAME_TEX0.TBW) : std::max(rt->m_TEX0.TBW, FRAME_TEX0.TBW);
|
||||
rt->m_TEX0.PSM = FRAME_TEX0.PSM;
|
||||
}
|
||||
|
@ -3799,8 +3832,8 @@ void GSRendererHW::Draw()
|
|||
g_texture_cache->GetTargetSize(rt->m_TEX0.TBP0, rt->m_TEX0.TBW, rt->m_TEX0.PSM, 0, new_h);
|
||||
}
|
||||
|
||||
rt->ResizeValidity(rt->GetUnscaledRect());
|
||||
rt->ResizeDrawn(rt->GetUnscaledRect());
|
||||
rt->ResizeValidity(rt->m_valid.rintersect(rt->GetUnscaledRect()));
|
||||
rt->ResizeDrawn(rt->m_drawn_since_read.rintersect(rt->GetUnscaledRect()));
|
||||
}
|
||||
|
||||
const bool rt_update = can_update_size || (m_texture_shuffle && (src && rt && src->m_from_target != rt));
|
||||
|
@ -3917,6 +3950,7 @@ void GSRendererHW::Draw()
|
|||
src->m_shared_texture = false;
|
||||
src->m_texture = new_tex;
|
||||
src->m_unscaled_size = new_size;
|
||||
src->m_TEX0.PSM = m_cached_ctx.TEX0.PSM;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3958,8 +3992,8 @@ void GSRendererHW::Draw()
|
|||
|
||||
if (GSConfig.SaveTexture && src)
|
||||
{
|
||||
s = GetDrawDumpPath("%05d_f%05lld_itex_%05x_%s_%d%d_%02x_%02x_%02x_%02x.dds",
|
||||
s_n, frame, static_cast<int>(m_cached_ctx.TEX0.TBP0), psm_str(m_cached_ctx.TEX0.PSM),
|
||||
s = GetDrawDumpPath("%05d_f%05lld_itex_%s_%05x(%05x)_%s_%d%d_%02x_%02x_%02x_%02x.dds",
|
||||
s_n, frame, (src->m_from_target ? "tgt" : "gs"), static_cast<int>(m_cached_ctx.TEX0.TBP0), (src->m_from_target ? src->m_from_target->m_TEX0.TBP0 : src->m_TEX0.TBP0), psm_str(m_cached_ctx.TEX0.PSM),
|
||||
static_cast<int>(m_cached_ctx.CLAMP.WMS), static_cast<int>(m_cached_ctx.CLAMP.WMT),
|
||||
static_cast<int>(m_cached_ctx.CLAMP.MINU), static_cast<int>(m_cached_ctx.CLAMP.MAXU),
|
||||
static_cast<int>(m_cached_ctx.CLAMP.MINV), static_cast<int>(m_cached_ctx.CLAMP.MAXV));
|
||||
|
@ -4134,7 +4168,7 @@ void GSRendererHW::Draw()
|
|||
|
||||
if (rt && GSConfig.SaveRT && !m_last_rt)
|
||||
{
|
||||
s = GetDrawDumpPath("%05d_f%05lld_rt1_%05x_%s.bmp", s_n, frame, m_cached_ctx.FRAME.Block(), psm_str(m_cached_ctx.FRAME.PSM));
|
||||
s = GetDrawDumpPath("%05d_f%05lld_rt1_%05x_(%05x)_%s.bmp", s_n, frame, m_cached_ctx.FRAME.Block(), rt->m_TEX0.TBP0, psm_str(m_cached_ctx.FRAME.PSM));
|
||||
|
||||
rt->m_texture->Save(s);
|
||||
}
|
||||
|
@ -4790,7 +4824,7 @@ __ri bool GSRendererHW::EmulateChannelShuffle(GSTextureCache::Target* src, bool
|
|||
const GSLocalMemory::psm_t frame_psm = GSLocalMemory::m_psm[m_context->FRAME.PSM];
|
||||
m_full_screen_shuffle = (m_r.height() > frame_psm.pgs.y) || (m_r.width() > frame_psm.pgs.x) || GSConfig.UserHacks_TextureInsideRt == GSTextureInRtMode::Disabled;
|
||||
m_channel_shuffle_src_valid = src->m_valid;
|
||||
if (GSConfig.UserHacks_TextureInsideRt == GSTextureInRtMode::Disabled || (!m_in_target_draw && IsPageCopy()) || m_conf.ps.urban_chaos_hle || m_conf.ps.tales_of_abyss_hle)
|
||||
if (GSConfig.UserHacks_TextureInsideRt == GSTextureInRtMode::Disabled || ((src->m_TEX0.TBW == rt->m_TEX0.TBW) && (!m_in_target_draw && IsPageCopy())) || m_conf.ps.urban_chaos_hle || m_conf.ps.tales_of_abyss_hle)
|
||||
{
|
||||
GSVertex* s = &m_vertex.buff[0];
|
||||
s[0].XYZ.X = static_cast<u16>(m_context->XYOFFSET.OFX + 0);
|
||||
|
@ -4859,9 +4893,15 @@ __ri bool GSRendererHW::EmulateChannelShuffle(GSTextureCache::Target* src, bool
|
|||
GSVector4i new_valid = rt->m_valid;
|
||||
int offset_height = static_cast<int>((((frame_offset - rt->m_TEX0.TBP0) >> 5) / rt->m_TEX0.TBW) * frame_psm.pgs.y) + frame_psm.pgs.y;
|
||||
|
||||
const int get_next_ctx = (m_state_flush_reason == CONTEXTCHANGE) ? m_env.PRIM.CTXT : m_backed_up_ctx;
|
||||
const GSDrawingContext& next_ctx = m_env.CTXT[get_next_ctx];
|
||||
const u32 safe_TBW = std::max(rt->m_TEX0.TBW, 1U);
|
||||
// This is an annoying case where the draw is offset to draw on the right hand side of a texture (Hitman Blood Money pause screen).
|
||||
if (!IsPageCopy() && NextDrawMatchesShuffle() && ((frame_offset >> 5) + 1) % rt->m_TEX0.TBW == 0)
|
||||
if (m_state_flush_reason == GSFlushReason::CONTEXTCHANGE && !IsPageCopy() && NextDrawMatchesShuffle() && next_ctx.FRAME.FBP > m_cached_ctx.FRAME.FBP && (next_ctx.FRAME.FBP < (m_cached_ctx.FRAME.FBP + safe_TBW)) &&
|
||||
(next_ctx.FRAME.FBP - m_cached_ctx.FRAME.FBP) < safe_TBW && (next_ctx.FRAME.FBP % safe_TBW) != ((m_cached_ctx.FRAME.FBP % safe_TBW) + 1))
|
||||
{
|
||||
offset_height += frame_psm.pgs.y;
|
||||
}
|
||||
|
||||
new_valid.w = std::max(new_valid.w, offset_height);
|
||||
rt->UpdateValidity(new_valid, true);
|
||||
|
|
|
@ -309,7 +309,7 @@ GSVector4i GSTextureCache::TranslateAlignedRectByPage(u32 tbp, u32 tebp, u32 tbw
|
|||
const int vertical_offset = in_rect.y / t_psm.pgs.y;
|
||||
const int horizontal_offset = in_rect.x / t_psm.pgs.x;
|
||||
const int rect_offset = horizontal_offset + (vertical_offset * src_pgw);
|
||||
const int rect_pages = ((in_rect.width() / t_psm.pgs.x) % src_pgw) + ((in_rect.height() / t_psm.pgs.y) * src_pgw);
|
||||
const int rect_pages = std::max(((in_rect.width() / t_psm.pgs.x) % src_pgw) + ((in_rect.height() / t_psm.pgs.y) * src_pgw), 1);
|
||||
page_offset += rect_offset;
|
||||
in_rect -= GSVector4i(horizontal_offset * t_psm.pgs.x, vertical_offset * t_psm.pgs.y).xyxy();
|
||||
|
||||
|
@ -387,7 +387,6 @@ GSVector4i GSTextureCache::TranslateAlignedRectByPage(u32 tbp, u32 tebp, u32 tbw
|
|||
{
|
||||
//TODO: Maybe control dirty blocks directly and add them page at a time for better granularity.
|
||||
const GSVector2i start_page = GSVector2i((page_offset + rect_offset) % dst_pgw, page_offset / dst_pgw);
|
||||
DevCon.Warning("Fudging start position");
|
||||
// Not easily translatable full pages and make sure the height is rounded upto encompass the half row.
|
||||
new_rect.x = start_page.x * dst_page_size.x;
|
||||
new_rect.z = new_rect.x + in_rect.z;
|
||||
|
@ -1646,6 +1645,12 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
|
|||
DevCon.Warning("BP %x - 8bit bad match for target bp %x bw %d src %d format %d", bp, t->m_TEX0.TBP0, t->m_TEX0.TBW, bw, t->m_TEX0.PSM);
|
||||
continue;
|
||||
}
|
||||
else if (!possible_shuffle && GSLocalMemory::m_psm[psm].trbpp == 8 && TEX0.TBW == 1)
|
||||
{
|
||||
DevCon.Warning("Too small for relocation, skipping");
|
||||
continue;
|
||||
}
|
||||
|
||||
// PSM equality needed because CreateSource does not handle PSM conversion.
|
||||
// Only inclusive hit to limit false hits.
|
||||
GSVector4i rect = block_boundary_rect;
|
||||
|
@ -1672,6 +1677,12 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
|
|||
}
|
||||
if (bp > t->m_TEX0.TBP0)
|
||||
{
|
||||
if (!region.HasEither() && GSLocalMemory::m_psm[psm].bpp == 32 && (t->m_TEX0.TBW - (((bp - t->m_TEX0.TBP0) >> 5) % t->m_TEX0.TBW)) < static_cast<u32>((block_boundary_rect.width() + 63) / 64))
|
||||
{
|
||||
DevCon.Warning("Bad alignmenet");
|
||||
continue;
|
||||
}
|
||||
|
||||
GSVector4i new_rect = (GSLocalMemory::m_psm[color_psm].bpp != GSLocalMemory::m_psm[t->m_TEX0.PSM].bpp && (psm & 0x7) != PSMCT16) ? block_boundary_rect : rect;
|
||||
|
||||
// Check if it is possible to hit with valid <x,y> offset on the given Target.
|
||||
|
@ -2089,7 +2100,6 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
|
|||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// if It's an old target and it's being completely overwritten, kill it.
|
||||
// Dragon Quest 8 reuses a render-target sized buffer as a single-page buffer, without clearing it. But,
|
||||
// it does dirty it by writing over the 64x64 region. So while we can't use this heuristic for tossing
|
||||
|
@ -2107,7 +2117,23 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
|
|||
can_use = !t->m_dirty.GetTotalRect(TEX0, size).rintersect(size_rect).eq(size_rect);
|
||||
}
|
||||
}
|
||||
else if (type == RenderTarget && (fbmask == 0xffffff && !t->m_was_dst_matched && TEX0.TBW != t->m_TEX0.TBW))
|
||||
{
|
||||
// When returning to being matched with the Z buffer in width, we need to make sure the RGB is up to date as it could get used later (Hitman Contracts).
|
||||
auto& rev_list = m_dst[1 - type];
|
||||
Target* dst_match = nullptr;
|
||||
for (auto j = rev_list.begin(); j != rev_list.end(); ++j)
|
||||
{
|
||||
Target* ds = *j;
|
||||
|
||||
if (t->m_TEX0.TBP0 != ds->m_TEX0.TBP0 || !ds->m_valid_rgb || TEX0.TBW != ds->m_TEX0.TBW)
|
||||
continue;
|
||||
|
||||
t->m_was_dst_matched = true;
|
||||
t->m_valid_rgb = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// TODO: What might be a nicer solution than this, is to rearrange the targets to match the new layout, however this comes with some caviets:
|
||||
// 1. They can draw wider than the FBW
|
||||
// 2. The dirty+valid rects will need to also be rearranged
|
||||
|
@ -2175,7 +2201,7 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
|
|||
const GSLocalMemory::psm_t& s_psm = GSLocalMemory::m_psm[TEX0.PSM];
|
||||
|
||||
// I know what you're thinking, and I hate the guy who wrote it too (me). Project Snowblind, Tomb Raider etc decide to offset where they're drawing using a channel shuffle, and this gets messy, so best just to kill the old target.
|
||||
if (is_shuffle && src->m_TEX0.PSM == PSMT8 && GSRendererHW::GetInstance()->m_context->FRAME.FBW == 1 && t->m_last_draw != (GSState::s_n - 1) && src && src->m_from_target && src->m_from_target->m_TEX0.TBP0 == src->m_TEX0.TBP0 && widthpage_offset && src->m_from_target != t)
|
||||
if (is_shuffle && src->m_TEX0.PSM == PSMT8 && GSRendererHW::GetInstance()->m_context->FRAME.FBW == 1 && t->m_last_draw != (GSState::s_n - 1) && src && src->m_from_target && (src->m_from_target->m_TEX0.TBP0 == src->m_TEX0.TBP0 || (((src->m_TEX0.TBP0 - src->m_from_target->m_TEX0.TBP0) >> 5) % std::max(src->m_from_target->m_TEX0.TBW, 1U) == 0)) && widthpage_offset && src->m_from_target != t)
|
||||
{
|
||||
GL_INS("TC: Deleting RT BP 0x%x BW %d PSM %s offset overwrite shuffle", t->m_TEX0.TBP0, t->m_TEX0.TBW, psm_str(t->m_TEX0.PSM));
|
||||
InvalidateSourcesFromTarget(t);
|
||||
|
@ -2195,7 +2221,7 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
|
|||
|
||||
continue;
|
||||
}
|
||||
else if (t->m_dirty.empty())
|
||||
else if (t->m_dirty.empty() || (t->m_TEX0.TBP0 <= bp && t->m_dirty.GetTotalRect(t->m_TEX0, t->m_unscaled_size).rintersect(GSVector4i(0, 0, 0, 0) .max_i32(TranslateAlignedRectByPage(t, TEX0.TBP0, TEX0.PSM, TEX0.TBW, min_rect))).rempty()))
|
||||
{
|
||||
if (TEX0.TBW == t->m_TEX0.TBW && !is_shuffle && widthpage_offset == 0 && ((min_rect.w + 63)/ 64) > 1)
|
||||
{
|
||||
|
@ -2362,7 +2388,7 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
|
|||
dst->m_unscaled_size = new_size;
|
||||
dst->m_downscaled = scale == 1.0f && g_gs_renderer->GetUpscaleMultiplier() > 1.0f;
|
||||
|
||||
if (src && src->m_target && src->m_from_target == dst)
|
||||
if (src && src->m_target && src->m_from_target == dst && src->m_shared_texture)
|
||||
{
|
||||
src->m_texture = dst->m_texture;
|
||||
src->m_scale = dst->m_scale;
|
||||
|
@ -2391,32 +2417,39 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
|
|||
dst->Update(dst->m_alpha_max <= 128);
|
||||
|
||||
const bool scale_down = GSLocalMemory::m_psm[dst->m_TEX0.PSM].bpp > GSLocalMemory::m_psm[TEX0.PSM].bpp;
|
||||
bool req_copy = true;
|
||||
new_size = dst->m_unscaled_size;
|
||||
new_scaled_size = ScaleRenderTargetSize(dst->m_unscaled_size, dst->m_scale);
|
||||
|
||||
dRect = (GSVector4(GSVector4i::loadh(dst->m_unscaled_size)) * GSVector4(dst->m_scale)).ceil();
|
||||
dRect = (GSVector4(dst->m_valid) * GSVector4(dst->m_scale)).ceil();
|
||||
GSVector4 source_rect = GSVector4(static_cast<float>(dst->m_valid.x) / static_cast<float>(dst->m_unscaled_size.x), static_cast<float>(dst->m_valid.y) / static_cast<float>(dst->m_unscaled_size.y),
|
||||
static_cast<float>(dst->m_valid.z) / static_cast<float>(dst->m_unscaled_size.x), static_cast<float>(dst->m_valid.w) / static_cast<float>(dst->m_unscaled_size.y));
|
||||
if (!is_shuffle || GSLocalMemory::m_psm[dst->m_TEX0.PSM].bpp == 16)
|
||||
{
|
||||
if (scale_down)
|
||||
{
|
||||
new_scaled_size.y *= 2;
|
||||
dst->m_valid.y *= 2;
|
||||
dst->m_valid.w *= 2;
|
||||
dRect.y *= 2;
|
||||
dRect.w *= 2;
|
||||
|
||||
new_size.y *= 2;
|
||||
new_size.y = std::max(dst->m_valid.w, new_size.y);
|
||||
if (new_size.y < dst->m_valid.w)
|
||||
{
|
||||
new_size.y = dst->m_valid.w;
|
||||
new_scaled_size = ScaleRenderTargetSize(new_size, dst->m_scale);
|
||||
// Using our resize texture only really works if we're scaling exactly.
|
||||
req_copy = source_rect.w != 1.0f;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
new_scaled_size.y /= 2;
|
||||
new_size.y /= 2;
|
||||
dRect.y /= 2;
|
||||
dRect.w /= 2;
|
||||
dst->m_valid.y /= 2;
|
||||
dst->m_valid.w /= 2;
|
||||
new_size.y = std::max(dst->m_valid.w, new_size.y);
|
||||
req_copy = true;
|
||||
/*new_size.y /= 2;
|
||||
new_scaled_size.y = new_size.y * dst->m_scale;*/
|
||||
}
|
||||
}
|
||||
if (!is_shuffle)
|
||||
|
@ -2431,11 +2464,49 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
|
|||
src->m_target_direct = false;
|
||||
src->m_shared_texture = false;
|
||||
|
||||
dst->ResizeTexture(new_size.x, new_size.y, true, true, GSVector4i(dRect), true);
|
||||
if(!req_copy)
|
||||
dst->ResizeTexture(new_size.x, new_size.y, true, true, GSVector4i(dRect), true);
|
||||
else
|
||||
{
|
||||
GSTexture* tex = type == RenderTarget ? g_gs_device->CreateRenderTarget(new_scaled_size.x, new_scaled_size.y, GSTexture::Format::Color, clear) :
|
||||
g_gs_device->CreateDepthStencil(new_scaled_size.x, new_scaled_size.y, GSTexture::Format::DepthStencil, clear);
|
||||
if (!tex)
|
||||
return nullptr;
|
||||
|
||||
g_gs_device->StretchRect(dst->m_texture, source_rect, tex, dRect, (type == RenderTarget) ? ShaderConvert::COPY : ShaderConvert::DEPTH_COPY, false);
|
||||
|
||||
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
|
||||
m_target_memory_usage = m_target_memory_usage + tex->GetMemUsage();
|
||||
|
||||
// Don't kill the target here as it's being used for the source.
|
||||
dst->m_texture = tex;
|
||||
dst->m_unscaled_size = new_size;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dst->ResizeTexture(new_size.x, new_size.y, true, true, GSVector4i(dRect));
|
||||
if (!req_copy)
|
||||
dst->ResizeTexture(new_size.x, new_size.y, true, true, GSVector4i(dRect));
|
||||
else
|
||||
{
|
||||
GSTexture* tex = type == RenderTarget ? g_gs_device->CreateRenderTarget(new_scaled_size.x, new_scaled_size.y, GSTexture::Format::Color, clear) :
|
||||
g_gs_device->CreateDepthStencil(new_scaled_size.x, new_scaled_size.y, GSTexture::Format::DepthStencil, clear);
|
||||
if (!tex)
|
||||
return nullptr;
|
||||
|
||||
if (scale_down)
|
||||
g_gs_device->StretchRect(dst->m_texture, source_rect, tex, dRect, (type == RenderTarget) ? ShaderConvert::COPY : ShaderConvert::DEPTH_COPY, false);
|
||||
else
|
||||
g_gs_device->StretchRect(dst->m_texture, source_rect, tex, dRect, (type == RenderTarget) ? ShaderConvert::COPY : ShaderConvert::DEPTH_COPY, false);
|
||||
|
||||
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
|
||||
m_target_memory_usage = (m_target_memory_usage - dst->m_texture->GetMemUsage()) + tex->GetMemUsage();
|
||||
|
||||
g_gs_device->Recycle(dst->m_texture);
|
||||
|
||||
dst->m_texture = tex;
|
||||
dst->m_unscaled_size = new_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2540,7 +2611,7 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
|
|||
}
|
||||
else
|
||||
{
|
||||
if (!dst->m_dirty.empty())
|
||||
if (!dst->m_dirty.empty() && bp == dst->m_TEX0.TBP0)
|
||||
{
|
||||
GL_INS("TC: Clearing dirty list for %s[%x] because we're overwriting the whole target.", to_string(type), dst->m_TEX0.TBP0);
|
||||
dst->m_dirty.clear();
|
||||
|
@ -2797,8 +2868,10 @@ GSTextureCache::Target* GSTextureCache::CreateTarget(GIFRegTEX0 TEX0, const GSVe
|
|||
|
||||
if (!is_frame)
|
||||
{
|
||||
// Not *strictly* correct if RGB is masked, but we won't use it as a texture if not..
|
||||
dst->m_valid_rgb = true;
|
||||
// Not having this valid could make things explode, but I do enjoy watching the world burn (and this is actually more correct).
|
||||
dst->m_valid_rgb =true;
|
||||
|
||||
const u32 mask = GSLocalMemory::m_psm[TEX0.PSM].fmsk;
|
||||
|
||||
// If there is an opposite target without valid RGB, we need to match them up
|
||||
auto& rev_list = m_dst[1 - type];
|
||||
|
@ -2807,15 +2880,19 @@ GSTextureCache::Target* GSTextureCache::CreateTarget(GIFRegTEX0 TEX0, const GSVe
|
|||
Target* const rev_t = *j;
|
||||
if (rev_t->m_TEX0.TBP0 == dst->m_TEX0.TBP0 && GSLocalMemory::m_psm[rev_t->m_TEX0.PSM].bpp == GSLocalMemory::m_psm[dst->m_TEX0.PSM].bpp)
|
||||
{
|
||||
if (!rev_t->m_valid_rgb)
|
||||
if (GSLocalMemory::m_psm[rev_t->m_TEX0.PSM].trbpp == 24 && ((fbmask & 0x00FFFFFF) & mask) == (mask & 0x00FFFFFF))
|
||||
dst->m_valid_rgb = false;
|
||||
|
||||
if (!rev_t->m_valid_rgb && dst->m_valid_rgb)
|
||||
rev_t->m_was_dst_matched = true;
|
||||
|
||||
break;
|
||||
}
|
||||
++j;
|
||||
}
|
||||
|
||||
const int bpp = GSLocalMemory::m_psm[TEX0.PSM].trbpp;
|
||||
const u32 mask = GSLocalMemory::m_psm[TEX0.PSM].fmsk;
|
||||
|
||||
// If the alpha is masked and preloaded, we need to say it's valid else textures might fail to use the whole texture if RGB is valid.
|
||||
if (((fbmask & 0xFF000000) & mask) != (mask & 0xFF000000) && bpp != 24)
|
||||
{
|
||||
|
@ -7060,7 +7137,7 @@ void GSTextureCache::Target::UpdateValidity(const GSVector4i& rect, bool can_res
|
|||
|
||||
bool GSTextureCache::Target::ResizeTexture(int new_unscaled_width, int new_unscaled_height, bool recycle_old, bool require_new_rect, GSVector4i new_rect, bool keep_old)
|
||||
{
|
||||
if (m_unscaled_size.x == new_unscaled_width && m_unscaled_size.y == new_unscaled_height)
|
||||
if (m_unscaled_size.x == new_unscaled_width && m_unscaled_size.y == new_unscaled_height && !require_new_rect)
|
||||
return true;
|
||||
|
||||
const GSVector2i size = m_texture->GetSize();
|
||||
|
|
Loading…
Reference in New Issue