mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-01-31 01:15:24 +01:00
GS/HW: Optimize source sizes when using CLAMP_CLAMP
This commit is contained in:
@@ -9070,8 +9070,9 @@ bool GSRendererHW::OI_BlitFMV(GSTextureCache::Target* _rt, GSTextureCache::Sourc
|
||||
// Bottom of Texture (half height frame, will be the copy of Top texture after the draw)
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
const int tw = static_cast<int>(1 << m_cached_ctx.TEX0.TW);
|
||||
const int th = static_cast<int>(1 << m_cached_ctx.TEX0.TH);
|
||||
// Do not use tw and th, if it has been optimized to not be the TEX0 size, it will crash.
|
||||
const int tw = tex->m_unscaled_size.x;
|
||||
int th = tex->m_unscaled_size.y;
|
||||
|
||||
// Compute the Bottom of texture rectangle
|
||||
pxAssert(m_cached_ctx.TEX0.TBP0 > m_cached_ctx.FRAME.Block());
|
||||
@@ -9079,30 +9080,48 @@ bool GSRendererHW::OI_BlitFMV(GSTextureCache::Target* _rt, GSTextureCache::Sourc
|
||||
GSVector4i r_texture(r_draw);
|
||||
r_texture.y -= offset;
|
||||
r_texture.w -= offset;
|
||||
const int new_height = std::max(r_texture.w, th);
|
||||
|
||||
if (GSTexture* rt = g_gs_device->CreateRenderTarget(tw, th, GSTexture::Format::Color))
|
||||
GSTexture* temp_tex = g_gs_device->CreateTexture(tw, new_height, 1, tex->m_texture->GetFormat(), true);
|
||||
|
||||
if (temp_tex)
|
||||
{
|
||||
// sRect is the top of texture
|
||||
// Need to half pixel offset the dest tex coordinates as draw pixels are top left instead of centre for texel reads.
|
||||
const GSVector4 sRect(m_vt.m_min.t.x / tw, m_vt.m_min.t.y / th, m_vt.m_max.t.x / tw, m_vt.m_max.t.y / th);
|
||||
const GSVector4 dRect = GSVector4(r_texture) + GSVector4(0.5f);
|
||||
const GSVector4i r_full(0, 0, tw, th);
|
||||
if (GSTexture* rt = g_gs_device->CreateRenderTarget(tw, new_height, GSTexture::Format::Color))
|
||||
{
|
||||
// sRect is the top of texture
|
||||
// Need to half pixel offset the dest tex coordinates as draw pixels are top left instead of centre for texel reads.
|
||||
const GSVector4 dRect = GSVector4(r_texture) + GSVector4(0.5f);
|
||||
const GSVector4i r_full(0, 0, tw, th);
|
||||
|
||||
g_gs_device->CopyRect(tex->m_texture, rt, r_full, 0, 0);
|
||||
g_gs_device->CopyRect(tex->m_texture, rt, r_full, 0, 0);
|
||||
|
||||
g_gs_device->StretchRect(tex->m_texture, sRect, rt, dRect, ShaderConvert::COPY, m_vt.IsRealLinear());
|
||||
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
|
||||
g_texture_cache->ReplaceSourceTexture(tex, temp_tex, tex->m_scale, GSVector2i(tw, new_height), nullptr, false);
|
||||
|
||||
g_gs_device->CopyRect(rt, tex->m_texture, r_full, 0, 0);
|
||||
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
|
||||
if (tex->m_region.HasY())
|
||||
{
|
||||
if (tex->m_region.GetMaxY() == th)
|
||||
{
|
||||
tex->m_region.bits &= ~(0xFFFF0000ULL << 32);
|
||||
tex->m_region.SetY(tex->m_region.GetMinY(), new_height);
|
||||
}
|
||||
}
|
||||
th = new_height;
|
||||
const GSVector4 sRect(m_vt.m_min.t.x / tw, m_vt.m_min.t.y / th, m_vt.m_max.t.x / tw, m_vt.m_max.t.y / th);
|
||||
const GSVector4i r_full_new(0, 0, tw, th);
|
||||
g_gs_device->StretchRect(tex->m_texture, sRect, rt, dRect, ShaderConvert::COPY, m_vt.IsRealLinear());
|
||||
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
|
||||
|
||||
g_gs_device->CopyRect(rt, tex->m_texture, r_full_new, 0, 0);
|
||||
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
|
||||
|
||||
g_gs_device->Recycle(rt);
|
||||
}
|
||||
|
||||
// Copy back the texture into the GS mem. I don't know why but it will be
|
||||
// reuploaded again later
|
||||
g_texture_cache->Read(tex, r_texture.rintersect(tex->m_texture->GetRect()));
|
||||
|
||||
g_gs_device->Recycle(rt);
|
||||
}
|
||||
|
||||
// Copy back the texture into the GS mem. I don't know why but it will be
|
||||
// reuploaded again later
|
||||
g_texture_cache->Read(tex, r_texture.rintersect(tex->m_texture->GetRect()));
|
||||
|
||||
g_texture_cache->InvalidateVideoMemSubTarget(_rt);
|
||||
|
||||
return false; // skip current draw
|
||||
|
||||
@@ -1059,12 +1059,13 @@ void GSTextureCache::DirtyRectByPage(u32 sbp, u32 spsm, u32 sbw, Target* t, GSVe
|
||||
|
||||
__ri static GSTextureCache::Source* FindSourceInMap(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA,
|
||||
const GSLocalMemory::psm_t& psm_s, const u32* clut, const GSTexture* gpu_clut, const GSVector2i& compare_lod,
|
||||
const GSTextureCache::SourceRegion& region, u32 fixed_tex0, FastList<GSTextureCache::Source*>& map)
|
||||
const GSTextureCache::SourceRegion& region, u32 fixed_tex0, FastList<GSTextureCache::Source*>& map, const GIFRegCLAMP& CLAMP, GSVector4i read_area)
|
||||
{
|
||||
GSTextureCache::Source* best_s = nullptr;
|
||||
|
||||
for (auto i = map.begin(); i != map.end(); ++i)
|
||||
{
|
||||
GSTextureCache::Source* s = *i;
|
||||
|
||||
if (((TEX0.U32[0] ^ s->m_TEX0.U32[0]) | ((TEX0.U32[1] ^ s->m_TEX0.U32[1]) & 3)) != 0) // TBP0 TBW PSM TW TH
|
||||
continue;
|
||||
|
||||
@@ -1094,8 +1095,23 @@ __ri static GSTextureCache::Source* FindSourceInMap(const GIFRegTEX0& TEX0, cons
|
||||
// When fixed tex0 is used, we must find a matching region texture. The base likely
|
||||
// doesn't contain to the correct region. Bit cheeky here, avoid a logical or by
|
||||
// adding the invalid tex0 bit in.
|
||||
if (((s->m_region.bits | fixed_tex0) != 0) && s->m_region.bits != region.bits)
|
||||
continue;
|
||||
|
||||
if (((s->m_region.bits | fixed_tex0) != 0))
|
||||
{
|
||||
const bool is_clamped = CLAMP.WMS == CLAMP_CLAMP && CLAMP.WMT == CLAMP_CLAMP;
|
||||
if (is_clamped && s->m_region.GetMinX() == 0 && s->m_region.GetMinY() == 0)
|
||||
{
|
||||
const GSVector4i read_region = GSVector4i(0, 0, read_area.z, read_area.w);
|
||||
const GSVector4i region_area = GSVector4i(s->m_region.GetMinX(), s->m_region.GetMinY(), s->m_region.HasX() ? s->m_region.GetMaxX() : (1 << s->m_TEX0.TW), s->m_region.HasY() ? s->m_region.GetMaxY() : (1 << s->m_TEX0.TW));
|
||||
|
||||
if (!region_area.rintersect(read_region).eq(read_region))
|
||||
continue;
|
||||
}
|
||||
else if (((s->m_region.bits | fixed_tex0) != 0) && s->m_region.bits != region.bits)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Same base mip texture, but we need to check that MXL was the same as well.
|
||||
// When mipmapping is off, this will be 0,0 vs 0,0.
|
||||
@@ -1107,7 +1123,10 @@ __ri static GSTextureCache::Source* FindSourceInMap(const GIFRegTEX0& TEX0, cons
|
||||
return s;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
if (best_s != nullptr)
|
||||
return best_s;
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GSTextureCache::Source* GSTextureCache::LookupDepthSource(const bool is_depth, const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GIFRegCLAMP& CLAMP, const GSVector4i& r, const bool possible_shuffle, const bool linear, const GIFRegFRAME& frame, bool req_color, bool req_alpha, bool palette)
|
||||
@@ -1127,7 +1146,7 @@ GSTextureCache::Source* GSTextureCache::LookupDepthSource(const bool is_depth, c
|
||||
const u32* const clut = g_gs_renderer->m_mem.m_clut;
|
||||
GSTexture* const gpu_clut = (psm_s.pal > 0) ? g_gs_renderer->m_mem.m_clut.GetGPUTexture() : nullptr;
|
||||
Source* src = FindSourceInMap(TEX0, TEXA, psm_s, clut, gpu_clut, GSVector2i(0, 0), region,
|
||||
region.IsFixedTEX0(TEX0), m_src.m_map[TEX0.TBP0 >> 5]);
|
||||
region.IsFixedTEX0(TEX0), m_src.m_map[TEX0.TBP0 >> 5], CLAMP, r);
|
||||
if (src)
|
||||
{
|
||||
GL_CACHE("TC: src hit: (0x%x, %s)", TEX0.TBP0, GSUtil::GetPSMName(TEX0.PSM));
|
||||
@@ -1332,10 +1351,10 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
|
||||
const GSOffset offset(psm_s.info, TEX0.TBP0, TEX0.TBW, TEX0.PSM);
|
||||
const u32 region_page = offset.bn(region.GetMinX(), region.GetMinY()) >> 5;
|
||||
if (lookup_page != region_page)
|
||||
src = FindSourceInMap(TEX0, TEXA, psm_s, clut, gpu_clut, compare_lod, region, is_fixed_tex0, m_src.m_map[region_page]);
|
||||
src = FindSourceInMap(TEX0, TEXA, psm_s, clut, gpu_clut, compare_lod, region, is_fixed_tex0, m_src.m_map[region_page], CLAMP, r);
|
||||
}
|
||||
if (!src)
|
||||
src = FindSourceInMap(TEX0, TEXA, psm_s, clut, gpu_clut, compare_lod, region, is_fixed_tex0, m_src.m_map[lookup_page]);
|
||||
src = FindSourceInMap(TEX0, TEXA, psm_s, clut, gpu_clut, compare_lod, region, is_fixed_tex0, m_src.m_map[lookup_page], CLAMP, r);
|
||||
|
||||
if (src && src->m_from_target && GSConfig.UserHacks_TextureInsideRt >= GSTextureInRtMode::MergeTargets && GSLocalMemory::GetUnwrappedEndBlockAddress(TEX0.TBP0, TEX0.TBW, TEX0.PSM, r) > src->m_from_target->m_end_block)
|
||||
{
|
||||
@@ -2186,7 +2205,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
|
||||
}
|
||||
}
|
||||
|
||||
src = CreateSource(src_TEX0, TEXA, dst, x_offset, y_offset, lod, &rect, gpu_clut, region, target_bp_hit_outside_valid_area && TEX0.PSM != PSMT8);
|
||||
src = CreateSource(src_TEX0, TEXA, CLAMP, dst, x_offset, y_offset, lod, &rect, gpu_clut, region, target_bp_hit_outside_valid_area && TEX0.PSM != PSMT8);
|
||||
if (!src) [[unlikely]]
|
||||
return nullptr;
|
||||
}
|
||||
@@ -5733,10 +5752,7 @@ void GSTextureCache::ReplaceSourceTexture(Source* s, GSTexture* new_texture, flo
|
||||
if (s->m_from_hash_cache)
|
||||
s->m_from_hash_cache->refcount++;
|
||||
else if (!s->m_shared_texture)
|
||||
{
|
||||
DevCon.Warning("replace %d", m_source_memory_usage);
|
||||
m_source_memory_usage += s->m_texture->GetMemUsage();
|
||||
}
|
||||
}
|
||||
|
||||
void GSTextureCache::IncAge()
|
||||
@@ -5816,7 +5832,7 @@ void GSTextureCache::IncAge()
|
||||
}
|
||||
|
||||
//Fixme: Several issues in here. Not handling depth stencil, pitch conversion doesnt work.
|
||||
GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, Target* dst, int x_offset, int y_offset, const GSVector2i* lod, const GSVector4i* src_range, GSTexture* gpu_clut, SourceRegion region, bool force_temp)
|
||||
GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GIFRegCLAMP& CLAMP, Target* dst, int x_offset, int y_offset, const GSVector2i* lod, const GSVector4i* src_range, GSTexture* gpu_clut, SourceRegion region, bool force_temp)
|
||||
{
|
||||
const GSLocalMemory::psm_t& psm = GSLocalMemory::m_psm[TEX0.PSM];
|
||||
Source* src = new Source(TEX0, TEXA);
|
||||
@@ -6296,6 +6312,41 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con
|
||||
m_temporary_source = src;
|
||||
}
|
||||
|
||||
// We can check for a recent upload to see if we can find out out what the actual size is.
|
||||
if (!region.HasEither() && m_temporary_source == nullptr && CLAMP.WMS == CLAMP_CLAMP && CLAMP.WMT == CLAMP_CLAMP)
|
||||
{
|
||||
if (src_range->z < tw && src_range->w < th)
|
||||
{
|
||||
auto& transfers = GSRendererHW::GetInstance()->m_draw_transfers;
|
||||
|
||||
if (transfers.size() > 0)
|
||||
{
|
||||
const int last_draw = transfers.back().draw;
|
||||
|
||||
for (auto iter = transfers.rbegin(); iter != transfers.rend(); ++iter)
|
||||
{
|
||||
if (last_draw - iter->draw > 10)
|
||||
break;
|
||||
|
||||
// If the format, and location doesn't overlap
|
||||
if (iter->blit.DBP == TEX0.TBP0 && iter->blit.DBW == TEX0.TBW && iter->blit.DPSM == TEX0.PSM)
|
||||
{
|
||||
const int new_max_x = std::min(tw, std::max(iter->rect.z, Common::AlignUpPow2(src_range->z, psm.pgs.x)));
|
||||
const int new_max_y = std::min(th, std::max(iter->rect.w, Common::AlignUpPow2(src_range->w, psm.pgs.y)));
|
||||
|
||||
if (new_max_x != tw && new_max_y != th)
|
||||
{
|
||||
region.SetX(0, new_max_x);
|
||||
region.SetY(0, new_max_y);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// maintain the clut even when paltex is on for the dump/replacement texture lookup
|
||||
bool paltex = (GSConfig.GPUPaletteConversion && psm.pal > 0) || gpu_clut;
|
||||
const u32* clut = (psm.pal > 0) ? static_cast<const u32*>(g_gs_renderer->m_mem.m_clut) : nullptr;
|
||||
@@ -8650,6 +8701,7 @@ GSTextureCache::SourceRegion GSTextureCache::SourceRegion::Create(GIFRegTEX0 TEX
|
||||
GL_CACHE("TC: Region repeat optimization: %d width -> %d", 1 << TEX0.TW, region.GetWidth());
|
||||
}
|
||||
}
|
||||
|
||||
if (CLAMP.WMT == CLAMP_REGION_CLAMP && CLAMP.MAXV >= CLAMP.MINV)
|
||||
{
|
||||
const u32 rh = CLAMP.MAXV - CLAMP.MINV + 1;
|
||||
|
||||
@@ -445,7 +445,7 @@ protected:
|
||||
std::unique_ptr<GSDownloadTexture> m_uint16_download_texture;
|
||||
std::unique_ptr<GSDownloadTexture> m_uint32_download_texture;
|
||||
|
||||
Source* CreateSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, Target* t, int x_offset, int y_offset, const GSVector2i* lod, const GSVector4i* src_range, GSTexture* gpu_clut, SourceRegion region, bool force_temporary = false);
|
||||
Source* CreateSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GIFRegCLAMP& CLAMP, Target* t, int x_offset, int y_offset, const GSVector2i* lod, const GSVector4i* src_range, GSTexture* gpu_clut, SourceRegion region, bool force_temporary = false);
|
||||
|
||||
bool PreloadTarget(GIFRegTEX0 TEX0, const GSVector2i& size, const GSVector2i& valid_size, bool is_frame,
|
||||
bool preload, bool preserve_target, const GSVector4i draw_rect, Target* dst, GSTextureCache::Source* src = nullptr);
|
||||
|
||||
Reference in New Issue
Block a user