Compare commits

..

1 Commits

Author SHA1 Message Date
lightningterror
1f1049f08c GS: Update Shader/texture copies counter handling.
Add the copy counters in the function themselves, easier to track.
This also tracks other shader copies such as setupdate, primid date,
post processing such as shade boost and others which weren't tracked before.
2026-01-29 15:46:23 +01:00
14 changed files with 1107 additions and 1143 deletions

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -139,15 +139,12 @@ The clamp modes are also numerically based.
### GS Hardware Mipmap Fixes
* mipmap [`0` or `1`] {Off, On} Default: On (looks up GameDB)
* mipmap [`0` or `1` or `2`] {Off, Basic, Full} Default: Automatic (No value, looks up GameDB)
* trilinearFiltering [`0` or `1` or `2`] {None, Trilinear, Trilinear Ultra} Default: None (`0`)
### GS Hardware General Fixes
* beforeDraw {`OI` with suffix } {None unless specific game GSC} Default: Automatic (No value, looks up GameDB) with valid variable name (ex. OI_BurnoutGames)
* moveHandler {`MV` with suffix } {None unless specific game GSC} Default: Automatic (No value, looks up GameDB) with valid variable name (ex. MV_Ico)
* afterDraw {`OO` with suffix } {None unless specific game GSC} Default: Automatic (No value, looks up GameDB) with valid variable name
* conservativeFramebuffer [`0` or `1`] {Off or On} Default: On (`1`)
* texturePreloading [`0` or `1` or `2`] {None, Partial or Full Hash Cache} Default: None (`0`)
@@ -156,17 +153,11 @@ The clamp modes are also numerically based.
### GS Hardware Renderer Fixes
* autoFlush [`0` or `1` or `2`] {Disabled, Enabled (Sprites Only), Enabled (All Primitives)} Default: Off (`0`)
* partialTargetInvalidation [`0` or `1`] {Off, On} Default: Off (`0`)
* PCRTCOffsets [`0` or `1`] {Off, On} Default: Off (`0`)
* PCRTCOverscan [`0` or `1`] {Off, On} Default: Off (`0`)
* disableDepthSupport [`0` or `1`] {Off, On} Default: Off (`0`)
* disablePartialInvalidation [`0` or `1`] {Off, On} Default: Off (`0`)
* cpuFramebufferConversion [`0` or `1`] {Off, On} Default: Off (`0`)
* preloadFrameData [`0` or `1`] {Off, On} Default: Off (`0`)
* textureInsideRT [`0` or `1`or `2`] {Disabled, Inside Targets, Merge Targets} Default: Off (`0`)
* PCRTCOverscan [`0` or `1`] {Off, On} Default: Off (`0`)
* textureInsideRT [`0` or `1`] {Disabled, Inside Targets, Merge Targets} Default: Off (`0`)
* PCRTCOverscan [`0` or `1`] {Off, On} Default: Off (`0`)
* cpuCLUTRender [`0` or `1` or `2`] {Disabled, Normal, Aggressive} Default: Disabled (`0`)
* cpuSpriteRenderBW [Value between `0` to `10`] {Disabled, 1 (64), 2 (128), 3 (192), 4 (256), 5 (320), 6 (384), 7 (448), 8 (512), 9 (576), 10 (640)} Default: Off (`0`)

View File

@@ -229,6 +229,11 @@
"minimum": 0,
"maximum": 100000
},
"halfBottomOverride": {
"type": "integer",
"minimum": 0,
"maximum": 1
},
"halfPixelOffset": {
"type": "integer",
"minimum": 0,

View File

@@ -1296,6 +1296,8 @@ void GSDevice11::DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTextur
void GSDevice11::DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ID3D11PixelShader* ps, ID3D11Buffer* ps_cb, ID3D11BlendState* bs, bool linear)
{
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
CommitClear(sTex);
const bool draw_in_depth = dTex && dTex->IsDepthStencil();
@@ -1363,6 +1365,8 @@ void GSDevice11::DoStretchRect(GSTexture* sTex, const GSVector4& sRect, GSTextur
void GSDevice11::PresentRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, PresentShader shader, float shaderTime, bool linear)
{
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
CommitClear(sTex);
GSVector2i ds;
@@ -1522,6 +1526,8 @@ void GSDevice11::DrawMultiStretchRects(const MultiStretchRect* rects, u32 num_re
void GSDevice11::DoMultiStretchRects(const MultiStretchRect* rects, u32 num_rects, const GSVector2& ds)
{
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
// Don't use primitive restart here, it ends up slower on some drivers.
const u32 vertex_reserve_size = num_rects * 4;
const u32 index_reserve_size = num_rects * 6;
@@ -2162,6 +2168,8 @@ void GSDevice11::RenderImGui()
void GSDevice11::SetupDATE(GSTexture* rt, GSTexture* ds, SetDATM datm, const GSVector4i& bbox)
{
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
// sfex3 (after the capcom logo), vf4 (first menu fading in), ffxii shadows, rumble roses shadows, persona4 shadows
CommitClear(rt);
@@ -2604,7 +2612,6 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
const GSVector4 dRect(config.colclip_update_area);
const GSVector4 sRect = dRect / GSVector4(size.x, size.y).xyxy();
StretchRect(colclip_rt, sRect, config.rt, dRect, ShaderConvert::COLCLIP_RESOLVE, false);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
Recycle(colclip_rt);
g_gs_device->SetColorClipTexture(nullptr);
@@ -2633,7 +2640,6 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
const GSVector4 dRect = GSVector4((config.colclip_mode == GSHWDrawConfig::ColClipMode::ConvertOnly) ? GSVector4i::loadh(rtsize) : config.drawarea);
const GSVector4 sRect = dRect / GSVector4(rtsize.x, rtsize.y).xyxy();
StretchRect(config.rt, sRect, colclip_rt, dRect, ShaderConvert::COLCLIP_INIT, false);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
}
}
@@ -2818,7 +2824,6 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
const GSVector4 dRect(config.colclip_update_area);
const GSVector4 sRect = dRect / GSVector4(size.x, size.y).xyxy();
StretchRect(colclip_rt, sRect, config.rt, dRect, ShaderConvert::COLCLIP_RESOLVE, false);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
Recycle(colclip_rt);
g_gs_device->SetColorClipTexture(nullptr);

View File

@@ -1743,6 +1743,8 @@ void GSDevice12::DrawMultiStretchRects(
void GSDevice12::DoMultiStretchRects(
const MultiStretchRect* rects, u32 num_rects, GSTexture12* dTex, ShaderConvert shader)
{
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
// Set up vertices first.
const u32 vertex_reserve_size = num_rects * 4 * sizeof(GSVertexPT1);
const u32 index_reserve_size = num_rects * 6 * sizeof(u16);
@@ -1880,6 +1882,8 @@ void GSDevice12::DoStretchRect(GSTexture12* sTex, const GSVector4& sRect, GSText
void GSDevice12::DrawStretchRect(const GSVector4& sRect, const GSVector4& dRect, const GSVector2i& ds)
{
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
// ia
const float left = dRect.x * 2 / ds.x - 1.0f;
const float top = 1.0f - dRect.y * 2 / ds.y;
@@ -3900,6 +3904,8 @@ void GSDevice12::SetPSConstantBuffer(const GSHWDrawConfig::PSConstantBuffer& cb)
void GSDevice12::SetupDATE(GSTexture* rt, GSTexture* ds, SetDATM datm, const GSVector4i& bbox)
{
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
GL_PUSH("SetupDATE {%d,%d} %dx%d", bbox.left, bbox.top, bbox.width(), bbox.height());
const GSVector2i size(ds->GetSize());
@@ -3932,6 +3938,8 @@ void GSDevice12::SetupDATE(GSTexture* rt, GSTexture* ds, SetDATM datm, const GSV
GSTexture12* GSDevice12::SetupPrimitiveTrackingDATE(GSHWDrawConfig& config, PipelineSelector& pipe)
{
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
// How this is done:
// - can't put a barrier for the image in the middle of the normal render pass, so that's out
// - so, instead of just filling the int texture with INT_MAX, we sample the RT and use -1 for failing values
@@ -4078,7 +4086,6 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
SetPipeline(m_colclip_finish_pipelines[pipe.ds].get());
SetUtilityTexture(colclip_rt, m_point_sampler_cpu);
DrawStretchRect(sRect, GSVector4(config.colclip_update_area), rtsize);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
Recycle(colclip_rt);
g_gs_device->SetColorClipTexture(nullptr);
@@ -4280,7 +4287,6 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
const GSVector4 drawareaf = GSVector4((config.colclip_mode == GSHWDrawConfig::ColClipMode::ConvertOnly) ? GSVector4i::loadh(rtsize) : config.drawarea);
const GSVector4 sRect(drawareaf / GSVector4(rtsize.x, rtsize.y).xyxy());
DrawStretchRect(sRect, GSVector4(drawareaf), rtsize);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
GL_POP();
@@ -4358,7 +4364,6 @@ void GSDevice12::RenderHW(GSHWDrawConfig& config)
SetPipeline(m_colclip_finish_pipelines[pipe.ds].get());
SetUtilityTexture(colclip_rt, m_point_sampler_cpu);
DrawStretchRect(sRect, GSVector4(config.colclip_update_area), rtsize);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
Recycle(colclip_rt);
g_gs_device->SetColorClipTexture(nullptr);

View File

@@ -3846,7 +3846,6 @@ void GSRendererHW::Draw()
GL_CACHE("HW: RT in RT Z copy back draw %d z_vert_offset %d z_offset %d", s_n, z_vertical_offset, vertical_offset);
g_gs_device->StretchRect(g_texture_cache->GetTemporaryZ(), sRect, ds->m_texture, GSVector4(dRect), ShaderConvert::DEPTH_COPY, false);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
}
g_texture_cache->InvalidateTemporaryZ();
@@ -3863,7 +3862,6 @@ void GSRendererHW::Draw()
dRect = dRect.min_u32(GSVector4i(ds->m_unscaled_size.x * ds->m_scale, ds->m_unscaled_size.y * ds->m_scale).xyxy());
g_gs_device->StretchRect(ds->m_texture, sRect, g_texture_cache->GetTemporaryZ(), GSVector4(dRect), ShaderConvert::DEPTH_COPY, false);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
z_address_info.rect_since = GSVector4i::zero();
g_texture_cache->SetTemporaryZInfo(z_address_info);
}
@@ -3911,7 +3909,6 @@ void GSRendererHW::Draw()
if (m_cached_ctx.TEST.ZTST > ZTST_ALWAYS || !dRect.rintersect(GSVector4i(GSVector4(m_r) * ds->m_scale)).eq(dRect))
{
g_gs_device->StretchRect(ds->m_texture, sRect, tex, GSVector4(dRect), ShaderConvert::DEPTH_COPY, false);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
}
g_texture_cache->SetTemporaryZ(tex);
g_texture_cache->SetTemporaryZInfo(ds->m_TEX0.TBP0, page_offset, rt_page_offset);
@@ -4523,7 +4520,6 @@ void GSRendererHW::Draw()
{
const GSVector4i dRect = GSVector4i(0, 0, g_texture_cache->GetTemporaryZ()->GetWidth(), g_texture_cache->GetTemporaryZ()->GetHeight());
g_gs_device->StretchRect(g_texture_cache->GetTemporaryZ(), GSVector4(0.0f, 0.0f, 1.0f, 1.0f), tex, GSVector4(dRect), ShaderConvert::DEPTH_COPY, false);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
g_texture_cache->InvalidateTemporaryZ();
g_texture_cache->SetTemporaryZ(tex);
}
@@ -4830,7 +4826,6 @@ void GSRendererHW::Draw()
GL_CACHE("HW: RT in RT Z copy back draw %d z_vert_offset %d rt_vert_offset %d z_horz_offset %d rt_horz_offset %d", s_n, z_vertical_offset, vertical_offset, z_horizontal_offset, horizontal_offset);
g_gs_device->StretchRect(g_texture_cache->GetTemporaryZ(), sRect, ds->m_texture, GSVector4(dRect), ShaderConvert::DEPTH_COPY, false);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
}
else if (m_temp_z_full_copy)
{
@@ -4843,7 +4838,6 @@ void GSRendererHW::Draw()
GL_CACHE("HW: RT in RT Z copy back draw %d z_vert_offset %d z_offset %d", s_n, z_vertical_offset, vertical_offset);
g_gs_device->StretchRect(g_texture_cache->GetTemporaryZ(), sRect, ds->m_texture, GSVector4(dRect), ShaderConvert::DEPTH_COPY, false);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
}
m_temp_z_full_copy = false;
@@ -5910,7 +5904,6 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, const boo
{
case AccBlendLevel::Maximum:
sw_blending |= true;
accumulation_blend &= (GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].bpp == 32);
[[fallthrough]];
case AccBlendLevel::Full:
sw_blending |= m_conf.ps.blend_a != m_conf.ps.blend_b && alpha_c0_high_max_one;
@@ -7092,8 +7085,6 @@ __ri void GSRendererHW::HandleTextureHazards(const GSTextureCache::Target* rt, c
if (m_downscale_source)
{
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
// Can't use box filtering on depth (yet), or fractional scales.
if (src_target->m_texture->IsDepthStencil() || std::floor(src_target->GetScale()) != src_target->GetScale())
{
@@ -7121,9 +7112,7 @@ __ri void GSRendererHW::HandleTextureHazards(const GSTextureCache::Target* rt, c
}
else
{
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
const GSVector4i offset = copy_range - GSVector4i(copy_dst_offset).xyxy();
// Adjust for bilinear, must be done after calculating offset.
copy_range.x -= 1;
copy_range.y -= 1;
@@ -9230,11 +9219,7 @@ bool GSRendererHW::OI_BlitFMV(GSTextureCache::Target* _rt, GSTextureCache::Sourc
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);
}

View File

@@ -2834,7 +2834,6 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
else
g_gs_device->StretchRect(dst->m_texture, sRect, tex, dRect, (type == RenderTarget) ? ShaderConvert::COPY : ShaderConvert::DEPTH_COPY, type == RenderTarget && !preserve_scale);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
m_target_memory_usage = (m_target_memory_usage - dst->m_texture->GetMemUsage()) + tex->GetMemUsage();
// If we're changing resolution scale, just toss the texture, it's not going to get reused.
@@ -2865,7 +2864,6 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
if (!tex)
return nullptr;
g_gs_device->StretchRect(dst->m_texture, sRect, tex, dRect, ShaderConvert::FLOAT32_TO_FLOAT24, false);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
g_gs_device->Recycle(dst->m_texture);
dst->m_texture = tex;
@@ -2938,7 +2936,6 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
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.
@@ -2962,7 +2959,6 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
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);
@@ -3045,7 +3041,6 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
g_gs_device->StretchRect(dst_match->m_texture, GSVector4(0, 0, 1, 1),
dst->m_texture, GSVector4(dst->GetUnscaledRect()) * GSVector4(dst->GetScale()), shader, false);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
dst_match->m_valid_rgb = !used;
dst_match->m_was_dst_matched = true;
@@ -3326,7 +3321,6 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
{
dst_match->UnscaleRTAlpha();
g_gs_device->StretchRect(dst_match->m_texture, sRect, dst->m_texture, dRect, shader, false);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
}
}
@@ -4022,7 +4016,6 @@ void GSTextureCache::Target::ScaleRTAlpha()
const GSVector4 dRect(m_texture->GetRect().rintersect(valid_rect));
const GSVector4 sRect = dRect / GSVector4(rtsize.x, rtsize.y).xyxy();
g_gs_device->StretchRect(m_texture, sRect, temp_rt, dRect, ShaderConvert::RTA_CORRECTION, false);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
g_gs_device->Recycle(m_texture);
m_texture = temp_rt;
}
@@ -4048,7 +4041,6 @@ void GSTextureCache::Target::UnscaleRTAlpha()
const GSVector4 dRect(m_texture->GetRect().rintersect(valid_rect));
const GSVector4 sRect = dRect / GSVector4(rtsize.x, rtsize.y).xyxy();
g_gs_device->StretchRect(m_texture, sRect, temp_rt, dRect, ShaderConvert::RTA_DECORRECTION, false);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
g_gs_device->Recycle(m_texture);
m_texture = temp_rt;
}
@@ -4108,7 +4100,6 @@ void GSTextureCache::ScaleTargetForDisplay(Target* t, const GIFRegTEX0& dispfb,
// Fill the new texture with the old data, and discard the old texture.
g_gs_device->StretchRect(old_texture, new_texture, GSVector4(old_texture->GetSize()).zwxy(), ShaderConvert::COPY, false);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
m_target_memory_usage = (m_target_memory_usage - old_texture->GetMemUsage()) + new_texture->GetMemUsage();
g_gs_device->Recycle(old_texture);
t->m_texture = new_texture;
@@ -4242,7 +4233,6 @@ bool GSTextureCache::CopyRGBFromDepthToColor(Target* dst, Target* depth_src)
const GSVector4 convert_rect = GSVector4(depth_src->GetUnscaledRect().rintersect(GSVector4i::loadh(new_size)));
g_gs_device->StretchRect(depth_src->m_texture, convert_rect / GSVector4(depth_src->GetUnscaledSize()).xyxy(),
tex, convert_rect * GSVector4(dst->GetScale()), shader, false);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
}
// Copy in alpha if we're a new texture.
@@ -4253,7 +4243,6 @@ bool GSTextureCache::CopyRGBFromDepthToColor(Target* dst, Target* depth_src)
const GSVector4 copy_rect = GSVector4(tex->GetRect().rintersect(dst->m_texture->GetRect()));
g_gs_device->StretchRect(dst->m_texture, copy_rect / GSVector4(GSVector4i(dst->m_texture->GetSize()).xyxy()), tex,
copy_rect, false, false, false, true);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
}
g_gs_device->Recycle(dst->m_texture);
@@ -5291,7 +5280,6 @@ bool GSTextureCache::Move(u32 SBP, u32 SBW, u32 SPSM, int sx, int sy, u32 DBP, u
const GSVector4 src_rect = GSVector4(scaled_sx, scaled_sy, scaled_sx + scaled_w, scaled_sy + scaled_h);
const GSVector4 tmp_rect = src_rect / (GSVector4(tmp_texture->GetSize()).xyxy());
const GSVector4 dst_rect = GSVector4(scaled_dx, scaled_dy, (scaled_dx + scaled_w), (scaled_dy + scaled_h));
g_perfmon.Put(GSPerfMon::TextureCopies, 2);
g_gs_device->StretchRect(src->m_texture, tmp_rect, tmp_texture, src_rect, ShaderConvert::DEPTH_COPY, false);
g_gs_device->StretchRect(tmp_texture, tmp_rect, dst->m_texture, dst_rect, ShaderConvert::DEPTH_COPY, false);
}
@@ -5302,7 +5290,6 @@ bool GSTextureCache::Move(u32 SBP, u32 SBW, u32 SPSM, int sx, int sy, u32 DBP, u
const GSVector4 src_rect = GSVector4(scaled_sx, scaled_sy, scaled_sx + scaled_w, scaled_sy + scaled_h);
const GSVector4 tmp_rect = src_rect / (GSVector4(tmp_texture->GetSize()).xyxy());
const GSVector4 dst_rect = GSVector4(scaled_dx, scaled_dy, (scaled_dx + scaled_w), (scaled_dy + scaled_h));
g_perfmon.Put(GSPerfMon::TextureCopies, 2);
g_gs_device->StretchRect(src->m_texture, tmp_rect, tmp_texture, src_rect, false, false, false, true);
g_gs_device->StretchRect(tmp_texture, tmp_rect, dst->m_texture, dst_rect, false, false, false, true);
}
@@ -5330,7 +5317,6 @@ bool GSTextureCache::Move(u32 SBP, u32 SBW, u32 SPSM, int sx, int sy, u32 DBP, u
{
const ShaderConvert shader = ShaderConvert::COPY;
const GSVector4 dst_rect = GSVector4(scaled_dx, scaled_dy, (scaled_dx + scaled_w), (scaled_dy + scaled_h));
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
g_gs_device->StretchRect(src->m_texture, src_rect, dst->m_texture, dst_rect, false, false, false, true, shader);
}
else if (src->m_type != dst->m_type)
@@ -5348,13 +5334,11 @@ bool GSTextureCache::Move(u32 SBP, u32 SBW, u32 SPSM, int sx, int sy, u32 DBP, u
default:
break;
}
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
g_gs_device->StretchRect(src->m_texture, src_rect, dst->m_texture, scaled_src_rect, shader, false);
}
else if (src->m_texture->IsDepthStencil())
{
const GSVector4 dst_rect = GSVector4(scaled_dx, scaled_dy, (scaled_dx + scaled_w), (scaled_dy + scaled_h));
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
g_gs_device->StretchRect(src->m_texture, src_rect, dst->m_texture, dst_rect, ShaderConvert::DEPTH_COPY, false);
}
else
@@ -6296,7 +6280,6 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con
{
if (dst->m_rt_alpha_scale)
{
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
const GSVector4 sRectF = GSVector4(sRect) / GSVector4(1, 1, sTex->GetWidth(), sTex->GetHeight());
g_gs_device->StretchRect(
sTex, sRectF, dTex, GSVector4(destX, destY, sRect.width(), sRect.height()), ShaderConvert::RTA_DECORRECTION, false);
@@ -6348,8 +6331,6 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con
sTex, sRectF, dTex, GSVector4(destX, destY, new_size.x, new_size.y), shader, false);
}
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
#ifdef PCSX2_DEVBUILD
if (GSConfig.UseDebugDevice)
{
@@ -6799,7 +6780,6 @@ GSTextureCache::Source* GSTextureCache::CreateMergedSource(GIFRegTEX0 TEX0, GIFR
// Sort rect list by the texture, we want to batch as many as possible together.
g_gs_device->SortMultiStretchRects(copy_queue, copy_count);
g_gs_device->DrawMultiStretchRects(copy_queue, copy_count, dtex, ShaderConvert::COPY);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
if (lmtex)
g_gs_device->Recycle(lmtex);
@@ -7090,7 +7070,6 @@ GSTexture* GSTextureCache::LookupPaletteSource(u32 CBP, u32 CPSM, u32 CBW, GSVec
return nullptr;
g_gs_device->StretchRect(t->m_texture, GSVector4(0, 0, 1, 1), tex, GSVector4(GSVector4i::loadh(t->m_unscaled_size)), (t->m_type == RenderTarget) ? ShaderConvert::COPY : ShaderConvert::DEPTH_COPY, false);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
m_target_memory_usage = (m_target_memory_usage - t->m_texture->GetMemUsage()) + tex->GetMemUsage();
g_gs_device->Recycle(t->m_texture);
@@ -7238,7 +7217,6 @@ void GSTextureCache::Read(Target* t, const GSVector4i& r)
if (tmp)
{
g_gs_device->StretchRect(t->m_texture, src, tmp, GSVector4(drc), ps_shader, false);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
dltex->get()->CopyFromTexture(drc, tmp, drc, 0, true);
g_gs_device->Recycle(tmp);
}
@@ -7907,7 +7885,6 @@ void GSTextureCache::Target::Update(bool cannot_scale)
//GL_CACHE("TC: RT in RT Updating Z copy on draw %d z_offset %d", s_n, z_address_info.offset);
const GSVector4i dRect = GSVector4i(total_rect.x * m_scale, (z_address_info.offset + total_rect.y) * m_scale, (total_rect.z + (1.0f / m_scale)) * m_scale, (z_address_info.offset + total_rect.w + (1.0f / m_scale)) * m_scale);
g_gs_device->StretchRect(m_texture, GSVector4(total_rect.x / static_cast<float>(m_unscaled_size.x), total_rect.y / static_cast<float>(m_unscaled_size.y), (total_rect.z + (1.0f / m_scale)) / static_cast<float>(m_unscaled_size.x), (total_rect.w + (1.0f / m_scale)) / static_cast<float>(m_unscaled_size.y)), g_texture_cache->GetTemporaryZ(), GSVector4(dRect), ShaderConvert::DEPTH_COPY, false);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
}
}
}
@@ -8057,14 +8034,12 @@ bool GSTextureCache::Target::ResizeTexture(int new_unscaled_width, int new_unsca
{
// Can't do partial copies in DirectX for depth textures, and it's probably not ideal in other
// APIs either. So use a fullscreen quad setting depth instead.
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
g_gs_device->StretchRect(m_texture, tex, GSVector4(rc), ShaderConvert::DEPTH_COPY, true);
}
else
{
if (require_new_rect)
{
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
g_gs_device->StretchRect(m_texture, tex, GSVector4(rc), ShaderConvert::COPY, false);
}
else

View File

@@ -1587,6 +1587,7 @@ void GSDeviceMTL::DrawStretchRect(const GSVector4& sRect, const GSVector4& dRect
[m_current_render.encoder drawPrimitives:MTLPrimitiveTypeTriangleStrip
vertexStart:0
vertexCount:4];
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
g_perfmon.Put(GSPerfMon::DrawCalls, 1);
}
@@ -1597,6 +1598,7 @@ void GSDeviceMTL::RenderCopy(GSTexture* sTex, id<MTLRenderPipelineState> pipelin
MRESetPipeline(pipeline);
MRESetTexture(sTex, GSMTLTextureIndexNonHW);
[m_current_render.encoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:3];
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
g_perfmon.Put(GSPerfMon::DrawCalls, 1);
}
@@ -2164,7 +2166,6 @@ void GSDeviceMTL::RenderHW(GSHWDrawConfig& config)
{
BeginRenderPass(@"ColorClip Resolve", config.rt, MTLLoadActionLoad, nullptr, MTLLoadActionDontCare);
RenderCopy(colclip_rt, m_colclip_resolve_pipeline, config.colclip_update_area);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
Recycle(colclip_rt);
@@ -2194,7 +2195,6 @@ void GSDeviceMTL::RenderHW(GSHWDrawConfig& config)
case GSTexture::State::Dirty:
BeginRenderPass(@"ColorClip Init", colclip_rt, MTLLoadActionDontCare, nullptr, MTLLoadActionDontCare);
RenderCopy(config.rt, m_colclip_init_pipeline, copy_rect);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
break;
case GSTexture::State::Cleared:
@@ -2306,7 +2306,6 @@ void GSDeviceMTL::RenderHW(GSHWDrawConfig& config)
{
BeginRenderPass(@"ColorClip Resolve", config.rt, MTLLoadActionLoad, nullptr, MTLLoadActionDontCare);
RenderCopy(colclip_rt, m_colclip_resolve_pipeline, config.colclip_update_area);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
Recycle(colclip_rt);

View File

@@ -1423,10 +1423,11 @@ std::string GSDeviceOGL::GetPSSource(const PSSelector& sel)
// Copy a sub part of texture (same as below but force a conversion)
void GSDeviceOGL::BlitRect(GSTexture* sTex, const GSVector4i& r, const GSVector2i& dsize, bool at_origin, bool linear)
{
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
CommitClear(sTex, true);
GL_PUSH(fmt::format("CopyRectConv from {}", static_cast<GSTextureOGL*>(sTex)->GetID()).c_str());
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
// NOTE: This previously used glCopyTextureSubImage2D(), but this appears to leak memory in
// the loading screens of Evolution Snowboarding in Intel/NVIDIA drivers.
@@ -1657,6 +1658,8 @@ void GSDeviceOGL::FilteredDownsampleTexture(GSTexture* sTex, GSTexture* dTex, u3
void GSDeviceOGL::DrawStretchRect(const GSVector4& sRect, const GSVector4& dRect, const GSVector2i& ds)
{
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
// Original code from DX
const float left = dRect.x * 2 / ds.x - 1.0f;
const float right = dRect.z * 2 / ds.x - 1.0f;
@@ -1727,6 +1730,8 @@ void GSDeviceOGL::DrawMultiStretchRects(
void GSDeviceOGL::DoMultiStretchRects(const MultiStretchRect* rects, u32 num_rects, const GSVector2& ds)
{
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
const u32 vertex_reserve_size = num_rects * 4 * sizeof(GSVertexPT1);
const u32 index_reserve_size = num_rects * 6 * sizeof(u16);
auto vertex_map = m_vertex_stream_buffer->Map(sizeof(GSVertexPT1), vertex_reserve_size);
@@ -1922,6 +1927,8 @@ void GSDeviceOGL::DoShadeBoost(GSTexture* sTex, GSTexture* dTex, const float par
void GSDeviceOGL::SetupDATE(GSTexture* rt, GSTexture* ds, SetDATM datm, const GSVector4i& bbox)
{
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
GL_PUSH("DATE First Pass");
// sfex3 (after the capcom logo), vf4 (first menu fading in), ffxii shadows, rumble roses shadows, persona4 shadows
@@ -2458,7 +2465,6 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
const GSVector4 dRect(config.colclip_update_area);
const GSVector4 sRect = dRect / GSVector4(size.x, size.y).xyxy();
StretchRect(colclip_rt, sRect, config.rt, dRect, ShaderConvert::COLCLIP_RESOLVE, false);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
Recycle(colclip_rt);
g_gs_device->SetColorClipTexture(nullptr);
@@ -2493,7 +2499,6 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
const GSVector4 dRect = GSVector4((config.colclip_mode == GSHWDrawConfig::ColClipMode::ConvertOnly) ? GSVector4i::loadh(rtsize) : config.drawarea);
const GSVector4 sRect = dRect / GSVector4(rtsize.x, rtsize.y).xyxy();
StretchRect(config.rt, sRect, colclip_rt, dRect, ShaderConvert::COLCLIP_INIT, false);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
}
}
@@ -2762,7 +2767,6 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
const GSVector4 dRect(config.colclip_update_area);
const GSVector4 sRect = dRect / GSVector4(size.x, size.y).xyxy();
StretchRect(colclip_rt, sRect, config.rt, dRect, ShaderConvert::COLCLIP_RESOLVE, false);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
Recycle(colclip_rt);
g_gs_device->SetColorClipTexture(nullptr);

View File

@@ -2929,6 +2929,8 @@ void GSDeviceVK::DrawMultiStretchRects(
void GSDeviceVK::DoMultiStretchRects(
const MultiStretchRect* rects, u32 num_rects, GSTextureVK* dTex, ShaderConvert shader)
{
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
// Set up vertices first.
const u32 vertex_reserve_size = num_rects * 4 * sizeof(GSVertexPT1);
const u32 index_reserve_size = num_rects * 6 * sizeof(u16);
@@ -3082,6 +3084,8 @@ void GSDeviceVK::DoStretchRect(GSTextureVK* sTex, const GSVector4& sRect, GSText
void GSDeviceVK::DrawStretchRect(const GSVector4& sRect, const GSVector4& dRect, const GSVector2i& ds)
{
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
// ia
const float left = dRect.x * 2 / ds.x - 1.0f;
const float top = 1.0f - dRect.y * 2 / ds.y;
@@ -5468,6 +5472,8 @@ void GSDeviceVK::SetPSConstantBuffer(const GSHWDrawConfig::PSConstantBuffer& cb)
void GSDeviceVK::SetupDATE(GSTexture* rt, GSTexture* ds, SetDATM datm, const GSVector4i& bbox)
{
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
GL_PUSH("SetupDATE {%d,%d} %dx%d", bbox.left, bbox.top, bbox.width(), bbox.height());
const GSVector2i size(ds->GetSize());
@@ -5495,6 +5501,8 @@ void GSDeviceVK::SetupDATE(GSTexture* rt, GSTexture* ds, SetDATM datm, const GSV
GSTextureVK* GSDeviceVK::SetupPrimitiveTrackingDATE(GSHWDrawConfig& config)
{
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
// How this is done:
// - can't put a barrier for the image in the middle of the normal render pass, so that's out
// - so, instead of just filling the int texture with INT_MAX, we sample the RT and use -1 for failing values
@@ -5676,7 +5684,6 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config)
SetPipeline(m_colclip_finish_pipelines[pipe.ds][pipe.IsRTFeedbackLoop()]);
SetUtilityTexture(colclip_rt, m_point_sampler);
DrawStretchRect(sRect, drawareaf, rtsize);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
Recycle(colclip_rt);
g_gs_device->SetColorClipTexture(nullptr);
@@ -5893,7 +5900,6 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config)
const GSVector4 drawareaf = GSVector4((config.colclip_mode == GSHWDrawConfig::ColClipMode::ConvertOnly) ? GSVector4i::loadh(rtsize) : config.drawarea);
const GSVector4 sRect(drawareaf / GSVector4(rtsize).xyxy());
DrawStretchRect(sRect, drawareaf, rtsize);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
GL_POP();
OMSetRenderTargets(draw_rt, draw_ds, config.scissor, static_cast<FeedbackLoopFlag>(pipe.feedback_loop_flags));
@@ -5995,7 +6001,6 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config)
SetPipeline(m_colclip_finish_pipelines[pipe.ds][pipe.IsRTFeedbackLoop()]);
SetUtilityTexture(colclip_rt, m_point_sampler);
DrawStretchRect(sRect, drawareaf, rtsize);
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
Recycle(colclip_rt);
g_gs_device->SetColorClipTexture(nullptr);

View File

@@ -380,6 +380,7 @@ static const char* s_gs_hw_fix_names[] = {
"trilinearFiltering",
"skipDrawStart",
"skipDrawEnd",
"halfBottomOverride",
"halfPixelOffset",
"roundSprite",
"nativeScaling",

View File

@@ -65,6 +65,7 @@ namespace GameDatabaseSchema
TrilinearFiltering,
SkipDrawStart,
SkipDrawEnd,
HalfBottomOverride,
HalfPixelOffset,
RoundSprite,
NativeScaling,

View File

@@ -163,7 +163,7 @@ void V_Core::StartADMAWrite(u16* pMem, u32 sz)
if ((AutoDMACtrl & (Index + 1)) == 0)
{
ActiveTSA = 0x2000 + (Index << 10);
DMAICounter = size * 48;
DMAICounter = size * 4;
LastClock = psxRegs.cycle;
}
else if (size >= 256)
@@ -191,7 +191,7 @@ void V_Core::StartADMAWrite(u16* pMem, u32 sz)
if (SPU2::MsgToConsole())
SPU2::ConLog("ADMA%c Error Size of %x too small\n", GetDmaIndexChar(), size);
InputDataLeft = 0;
DMAICounter = size * 48;
DMAICounter = size * 4;
LastClock = psxRegs.cycle;
}
}
@@ -248,7 +248,7 @@ void V_Core::FinishDMAwrite()
DMA7LogWrite(DMAPtr, ReadSize << 1);
#endif
u32 buff1end = ActiveTSA + std::min(ReadSize, (u32)0x100 + std::abs(DMAICounter / 48));
u32 buff1end = ActiveTSA + std::min(ReadSize, (u32)0x100 + std::abs(DMAICounter / 4));
u32 buff2end = 0;
if (buff1end > 0x100000)
{
@@ -343,7 +343,7 @@ void V_Core::FinishDMAwrite()
DMAPtr += TDA - ActiveTSA;
ReadSize -= TDA - ActiveTSA;
DMAICounter = (DMAICounter - ReadSize) * 48;
DMAICounter = (DMAICounter - ReadSize) * 4;
CounterUpdate(DMAICounter);
@@ -354,7 +354,7 @@ void V_Core::FinishDMAwrite()
void V_Core::FinishDMAread()
{
u32 buff1end = ActiveTSA + std::min(ReadSize, (u32)0x100 + std::abs(DMAICounter / 48));
u32 buff1end = ActiveTSA + std::min(ReadSize, (u32)0x100 + std::abs(DMAICounter / 4));
u32 buff2end = 0;
if (buff1end > 0x100000)
@@ -426,9 +426,9 @@ void V_Core::FinishDMAread()
// DMA Reads are done AFTER the delay, so to get the timing right we need to scheule one last DMA to catch IRQ's
if (ReadSize)
DMAICounter = std::min(ReadSize, (u32)0x100) * 48;
DMAICounter = std::min(ReadSize, (u32)0x100) * 4;
else
DMAICounter = 48;
DMAICounter = 4;
CounterUpdate(DMAICounter);
@@ -446,7 +446,7 @@ void V_Core::DoDMAread(u16* pMem, u32 size)
ReadSize = size;
IsDMARead = true;
LastClock = psxRegs.cycle;
DMAICounter = (std::min(ReadSize, (u32)0x100) * 48);
DMAICounter = std::min(ReadSize, (u32)0x100) * 4;
Regs.STATX &= ~0x80;
Regs.STATX |= 0x400;
//Regs.ATTR |= 0x30;
@@ -470,7 +470,7 @@ void V_Core::DoDMAwrite(u16* pMem, u32 size)
{
Regs.STATX &= ~0x80;
//Regs.ATTR |= 0x30;
DMAICounter = 1 * 48;
DMAICounter = 1 * 4;
LastClock = psxRegs.cycle;
return;
}