mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-01-31 01:15:24 +01:00
Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
35093c3e37 | ||
|
|
4e5dac3e25 | ||
|
|
c52e84ac41 | ||
|
|
7f8488771d | ||
|
|
57ff271f4b | ||
|
|
43703755f8 | ||
|
|
17b6cc00ab | ||
|
|
a03563b366 | ||
|
|
ff9da17498 | ||
|
|
722bc94270 | ||
|
|
d51a5db5b1 | ||
|
|
04541ae2ab | ||
|
|
c58a67815b | ||
|
|
085f964cd9 | ||
|
|
a8b6e448eb | ||
|
|
78ab8381d9 | ||
|
|
49a5d82086 | ||
|
|
4ed129ccac | ||
|
|
ed09dca17e |
1
.github/workflows/linux_build_qt.yml
vendored
1
.github/workflows/linux_build_qt.yml
vendored
@@ -144,6 +144,7 @@ jobs:
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DENABLE_SETCAP=OFF \
|
||||
-DDISABLE_ADVANCE_SIMD=TRUE \
|
||||
-DUSE_LINKED_FFMPEG=ON \
|
||||
-DCMAKE_DISABLE_PRECOMPILE_HEADERS=ON \
|
||||
$ADDITIONAL_CMAKE_ARGS
|
||||
|
||||
|
||||
@@ -905,6 +905,8 @@ PCPX-96323:
|
||||
name-sort: "とろときゅうじつ [でも]"
|
||||
name-en: "Toro to Kyuujitsu [Demo Movie]"
|
||||
region: "NTSC-J"
|
||||
gsHWFixes:
|
||||
textureInsideRT: 1 # Fixes depth shadow stenciling effects.
|
||||
PCPX-96324:
|
||||
name: "デュアルハーツ [体験版]"
|
||||
name-sort: "でゅあるはーつ [たいけんばん]"
|
||||
@@ -6074,6 +6076,8 @@ SCES-53409:
|
||||
SCES-53422:
|
||||
name: "Stuart Little 3 - Big Photo Adventure"
|
||||
region: "PAL-M9"
|
||||
gameFixes:
|
||||
- InstantDMAHack # Fixes loading screen corruption.
|
||||
gsHWFixes:
|
||||
autoFlush: 2 # Fixes missing effects.
|
||||
SCES-53449:
|
||||
@@ -7551,8 +7555,11 @@ SCKA-20066:
|
||||
name: "EyeToy - Play 3"
|
||||
region: "NTSC-K"
|
||||
SCKA-20067:
|
||||
name: "Stuart Little 3 - Big Photo Adventure"
|
||||
name: "스튜어트 리틀 3 - 빅 포토 어드벤처"
|
||||
name-en: "Stuart Little 3 - Big Photo Adventure"
|
||||
region: "NTSC-K"
|
||||
gameFixes:
|
||||
- InstantDMAHack # Fixes loading screen corruption.
|
||||
gsHWFixes:
|
||||
autoFlush: 2 # Fixes missing effects.
|
||||
SCKA-20068:
|
||||
@@ -7940,6 +7947,7 @@ SCKA-20142:
|
||||
region: "NTSC-K"
|
||||
gsHWFixes:
|
||||
textureInsideRT: 1 # Needed for mipmapping to function correctly.
|
||||
mipmap: 0 # Currently causes texture corruption.
|
||||
SCKA-20171:
|
||||
name: "Let's Bravo Music"
|
||||
region: "NTSC-K"
|
||||
@@ -8455,6 +8463,8 @@ SCPS-15015:
|
||||
name-en: "Toro to Kyuujitsu"
|
||||
region: "NTSC-J"
|
||||
compat: 5
|
||||
gsHWFixes:
|
||||
textureInsideRT: 1 # Fixes depth shadow stenciling effects.
|
||||
SCPS-15016:
|
||||
name: "みんなのGOLF 3"
|
||||
name-sort: "みんなのごるふ 3"
|
||||
@@ -12799,6 +12809,7 @@ SCUS-97657:
|
||||
compat: 5
|
||||
gsHWFixes:
|
||||
textureInsideRT: 1 # Needed for mipmapping to function correctly.
|
||||
mipmap: 0 # Currently causes texture corruption.
|
||||
SCUS-97660:
|
||||
name: "SingStar - Latino"
|
||||
region: "NTSC-U"
|
||||
@@ -21812,7 +21823,6 @@ SLES-53028:
|
||||
halfPixelOffset: 5 # Fixes alignment of shuffles and post-processing.
|
||||
autoFlush: 1 # Fixes sun intensity.
|
||||
textureInsideRT: 1 # Fixes post-processing.
|
||||
getSkipCount: "GSC_HitmanBloodMoney"
|
||||
SLES-53029:
|
||||
name: "Hitman - Blood Money"
|
||||
region: "PAL-F"
|
||||
@@ -21823,7 +21833,6 @@ SLES-53029:
|
||||
halfPixelOffset: 5 # Fixes alignment of shuffles and post-processing.
|
||||
autoFlush: 1 # Fixes sun intensity.
|
||||
textureInsideRT: 1 # Fixes post-processing.
|
||||
getSkipCount: "GSC_HitmanBloodMoney"
|
||||
SLES-53030:
|
||||
name: "Hitman - Blood Money"
|
||||
region: "PAL-G"
|
||||
@@ -21834,7 +21843,6 @@ SLES-53030:
|
||||
halfPixelOffset: 5 # Fixes alignment of shuffles and post-processing.
|
||||
autoFlush: 1 # Fixes sun intensity.
|
||||
textureInsideRT: 1 # Fixes post-processing.
|
||||
getSkipCount: "GSC_HitmanBloodMoney"
|
||||
SLES-53031:
|
||||
name: "Hitman - Blood Money"
|
||||
region: "PAL-I"
|
||||
@@ -21845,7 +21853,6 @@ SLES-53031:
|
||||
halfPixelOffset: 5 # Fixes alignment of shuffles and post-processing.
|
||||
autoFlush: 1 # Fixes sun intensity.
|
||||
textureInsideRT: 1 # Fixes post-processing.
|
||||
getSkipCount: "GSC_HitmanBloodMoney"
|
||||
SLES-53032:
|
||||
name: "Hitman - Blood Money"
|
||||
region: "PAL-S"
|
||||
@@ -21856,7 +21863,6 @@ SLES-53032:
|
||||
halfPixelOffset: 5 # Fixes alignment of shuffles and post-processing.
|
||||
autoFlush: 1 # Fixes sun intensity.
|
||||
textureInsideRT: 1 # Fixes post-processing.
|
||||
getSkipCount: "GSC_HitmanBloodMoney"
|
||||
SLES-53035:
|
||||
name: "Masters of the Universe - He-Man - Defender of Greyskull"
|
||||
region: "PAL-E"
|
||||
@@ -27980,6 +27986,10 @@ SLES-54996:
|
||||
name: "The Golden Compass"
|
||||
name-sort: "Golden Compass, The"
|
||||
region: "PAL-M5"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 4 # Aligns post processing.
|
||||
autoFlush: 1 # Fixes light penetrating objects and intensity.
|
||||
nativeScaling: 2 # Aligns post processing.
|
||||
SLES-54997:
|
||||
name: "Mercenaries 2 - World in Flames"
|
||||
region: "PAL-E"
|
||||
@@ -28187,7 +28197,11 @@ SLES-55011:
|
||||
SLES-55012:
|
||||
name: "The Golden Compass"
|
||||
name-sort: "Golden Compass, The"
|
||||
region: "PAL-M5"
|
||||
region: "PAL-SC"
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 4 # Aligns post processing.
|
||||
autoFlush: 1 # Fixes light penetrating objects and intensity.
|
||||
nativeScaling: 2 # Aligns post processing.
|
||||
SLES-55013:
|
||||
name: "Iridium Runners"
|
||||
region: "PAL-M5"
|
||||
@@ -68432,7 +68446,6 @@ SLUS-21108:
|
||||
halfPixelOffset: 5 # Fixes alignment of shuffles and post-processing.
|
||||
autoFlush: 1 # Fixes sun intensity.
|
||||
textureInsideRT: 1 # Fixes post-processing.
|
||||
getSkipCount: "GSC_HitmanBloodMoney"
|
||||
SLUS-21109:
|
||||
name: "Drive to Survive"
|
||||
region: "NTSC-U"
|
||||
@@ -69996,6 +70009,8 @@ SLUS-21341:
|
||||
name: "Stuart Little 3 - Big Photo Adventure"
|
||||
region: "NTSC-U"
|
||||
compat: 5
|
||||
gameFixes:
|
||||
- InstantDMAHack # Fixes loading screen corruption.
|
||||
gsHWFixes:
|
||||
autoFlush: 2 # Fixes missing effects.
|
||||
SLUS-21342:
|
||||
@@ -71944,6 +71959,10 @@ SLUS-21677:
|
||||
name-sort: "Golden Compass, The"
|
||||
region: "NTSC-U"
|
||||
compat: 5
|
||||
gsHWFixes:
|
||||
halfPixelOffset: 4 # Aligns post processing.
|
||||
autoFlush: 1 # Fixes light penetrating objects and intensity.
|
||||
nativeScaling: 2 # Aligns post processing.
|
||||
SLUS-21678:
|
||||
name: "Dragon Ball Z - Budokai Tenkaichi 3"
|
||||
region: "NTSC-U"
|
||||
@@ -74353,8 +74372,8 @@ SLUS-29191:
|
||||
vuClampMode: 0 # Fixes bump mapping issues
|
||||
gsHWFixes:
|
||||
textureInsideRT: 1 # Fixes post-processing.
|
||||
autoFlush: 1 # Fixes sun intensity in Hitman.
|
||||
halfPixelOffset: 5 # Fixes alignment of shuffles and post-processing in Hitman.
|
||||
getSkipCount: "GSC_HitmanBloodMoney"
|
||||
SLUS-29192:
|
||||
name: "Test Drive Unlimited [Public Beta Vol.1.0]"
|
||||
region: "NTSC-U"
|
||||
|
||||
@@ -329,6 +329,7 @@
|
||||
030000000d0f0000ee00000000000000,Horipad Mini 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
|
||||
030000000d0f0000c100000000000000,Horipad Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
|
||||
030000000d0f0000f600000000000000,Horipad Nintendo Switch Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
|
||||
030000000d0f00000202000000000000,Horipad O Nintendo Switch 2 Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,misc2:b14,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows,
|
||||
030000000d0f00006700000000000000,Horipad One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
|
||||
030000000d0f00009601000000000000,Horipad Steam,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,misc2:b2,paddle1:b5,paddle2:b15,paddle3:b18,paddle4:b19,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
|
||||
030000000d0f0000dc00000000000000,Horipad Switch,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1105,14 +1105,14 @@ float GSDevice11::GetAndResetAccumulatedGPUTime()
|
||||
void GSDevice11::DrawPrimitive()
|
||||
{
|
||||
g_perfmon.Put(GSPerfMon::DrawCalls, 1);
|
||||
PSUpdateShaderState();
|
||||
PSUpdateShaderState(true, true);
|
||||
m_ctx->Draw(m_vertex.count, m_vertex.start);
|
||||
}
|
||||
|
||||
void GSDevice11::DrawIndexedPrimitive()
|
||||
{
|
||||
g_perfmon.Put(GSPerfMon::DrawCalls, 1);
|
||||
PSUpdateShaderState();
|
||||
PSUpdateShaderState(true, true);
|
||||
m_ctx->DrawIndexed(m_index.count, m_index.start, m_vertex.start);
|
||||
}
|
||||
|
||||
@@ -1120,7 +1120,7 @@ void GSDevice11::DrawIndexedPrimitive(int offset, int count)
|
||||
{
|
||||
pxAssert(offset + count <= (int)m_index.count);
|
||||
g_perfmon.Put(GSPerfMon::DrawCalls, 1);
|
||||
PSUpdateShaderState();
|
||||
PSUpdateShaderState(true, true);
|
||||
m_ctx->DrawIndexed(count, m_index.start + offset, m_vertex.start);
|
||||
}
|
||||
|
||||
@@ -1280,8 +1280,10 @@ void GSDevice11::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture*
|
||||
GSVector2i ds;
|
||||
if (dTex)
|
||||
{
|
||||
// ps unbind conflicting srvs
|
||||
PSUnbindConflictingSRVs(dTex);
|
||||
|
||||
ds = dTex->GetSize();
|
||||
PSUnbindConflictingSRVs(dTex, nullptr);
|
||||
if (draw_in_depth)
|
||||
OMSetRenderTargets(nullptr, dTex);
|
||||
else
|
||||
@@ -1293,6 +1295,7 @@ void GSDevice11::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture*
|
||||
}
|
||||
|
||||
// om
|
||||
|
||||
if (draw_in_depth)
|
||||
OMSetDepthStencilState(m_convert.dss_write.get(), 0);
|
||||
else
|
||||
@@ -1342,6 +1345,9 @@ void GSDevice11::PresentRect(GSTexture* sTex, const GSVector4& sRect, GSTexture*
|
||||
GSVector2i ds;
|
||||
if (dTex)
|
||||
{
|
||||
// ps unbind conflicting srvs
|
||||
PSUnbindConflictingSRVs(dTex);
|
||||
|
||||
ds = dTex->GetSize();
|
||||
OMSetRenderTargets(dTex, nullptr);
|
||||
}
|
||||
@@ -1357,6 +1363,7 @@ void GSDevice11::PresentRect(GSTexture* sTex, const GSVector4& sRect, GSTexture*
|
||||
m_ctx->UpdateSubresource(m_present.ps_cb.get(), 0, nullptr, &cb, 0, 0);
|
||||
|
||||
// om
|
||||
|
||||
OMSetDepthStencilState(m_convert.dss.get(), 0);
|
||||
OMSetBlendState(m_convert.bs[D3D11_COLOR_WRITE_ENABLE_ALL].get(), 0);
|
||||
|
||||
@@ -1455,6 +1462,7 @@ void GSDevice11::DrawMultiStretchRects(const MultiStretchRect* rects, u32 num_re
|
||||
|
||||
VSSetShader(m_convert.vs.get(), nullptr);
|
||||
PSSetShader(m_convert.ps[static_cast<int>(shader)].get(), nullptr);
|
||||
PSUnbindConflictingSRVs(dTex);
|
||||
|
||||
OMSetDepthStencilState(dTex->IsRenderTarget() ? m_convert.dss.get() : m_convert.dss_write.get(), 0);
|
||||
OMSetRenderTargets(dTex->IsRenderTarget() ? dTex : nullptr, dTex->IsDepthStencil() ? dTex : nullptr);
|
||||
@@ -2111,7 +2119,7 @@ void GSDevice11::RenderImGui()
|
||||
|
||||
// Since we don't have the GSTexture...
|
||||
m_state.ps_sr_views[0] = reinterpret_cast<ID3D11ShaderResourceView*>(pcmd->GetTexID());
|
||||
PSUpdateShaderState();
|
||||
PSUpdateShaderState(true, true);
|
||||
|
||||
m_ctx->DrawIndexed(pcmd->ElemCount, m_index.start + pcmd->IdxOffset, vertex_offset + pcmd->VtxOffset);
|
||||
}
|
||||
@@ -2131,6 +2139,10 @@ void GSDevice11::SetupDATE(GSTexture* rt, GSTexture* ds, const GSVertexPT1* vert
|
||||
|
||||
m_ctx->ClearDepthStencilView(*static_cast<GSTexture11*>(ds), D3D11_CLEAR_STENCIL, 0.0f, 0);
|
||||
|
||||
// ps unbind conflicting srvs
|
||||
|
||||
PSUnbindConflictingSRVs(ds);
|
||||
|
||||
// om
|
||||
|
||||
OMSetDepthStencilState(m_date.dss.get(), 1);
|
||||
@@ -2359,19 +2371,55 @@ void GSDevice11::PSSetShader(ID3D11PixelShader* ps, ID3D11Buffer* ps_cb)
|
||||
}
|
||||
}
|
||||
|
||||
void GSDevice11::PSUpdateShaderState()
|
||||
void GSDevice11::PSUpdateShaderState(const bool sr_update, const bool ss_update)
|
||||
{
|
||||
m_ctx->PSSetShaderResources(0, m_state.ps_sr_views.size(), m_state.ps_sr_views.data());
|
||||
m_ctx->PSSetSamplers(0, m_state.ps_ss.size(), m_state.ps_ss.data());
|
||||
// Shader resource caching requires srv/rtv hazards to be resolved, ensure PSUnbindConflictingSRVs handle.
|
||||
if (sr_update)
|
||||
{
|
||||
bool sr_changed = false;
|
||||
for (size_t i = 0; i < m_state.ps_sr_views.size(); ++i)
|
||||
{
|
||||
if (m_state.ps_cached_sr_views[i] != m_state.ps_sr_views[i])
|
||||
{
|
||||
sr_changed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (sr_changed)
|
||||
{
|
||||
m_state.ps_cached_sr_views = m_state.ps_sr_views;
|
||||
m_ctx->PSSetShaderResources(0, m_state.ps_sr_views.size(), m_state.ps_sr_views.data());
|
||||
}
|
||||
}
|
||||
|
||||
if (ss_update)
|
||||
{
|
||||
bool ss_changed = false;
|
||||
for (size_t i = 0; i < m_state.ps_ss.size(); ++i)
|
||||
{
|
||||
if (m_state.ps_cached_ss[i] != m_state.ps_ss[i])
|
||||
{
|
||||
ss_changed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ss_changed)
|
||||
{
|
||||
m_state.ps_cached_ss = m_state.ps_ss;
|
||||
m_ctx->PSSetSamplers(0, m_state.ps_ss.size(), m_state.ps_ss.data());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GSDevice11::PSUnbindConflictingSRVs(GSTexture* rt, GSTexture* ds)
|
||||
void GSDevice11::PSUnbindConflictingSRVs(GSTexture* tex1, GSTexture* tex2)
|
||||
{
|
||||
// Make sure no SRVs are bound using the same texture before binding it to a RTV.
|
||||
bool changed = false;
|
||||
for (size_t i = 0; i < m_state.ps_sr_views.size(); i++)
|
||||
{
|
||||
if ((rt && m_state.ps_sr_views[i] == *(GSTexture11*)rt) || (ds && m_state.ps_sr_views[i] == *(GSTexture11*)ds))
|
||||
if ((tex1 && m_state.ps_sr_views[i] == *(GSTexture11*)tex1) || (tex2 && m_state.ps_sr_views[i] == *(GSTexture11*)tex2))
|
||||
{
|
||||
m_state.ps_sr_views[i] = nullptr;
|
||||
changed = true;
|
||||
@@ -2379,7 +2427,7 @@ void GSDevice11::PSUnbindConflictingSRVs(GSTexture* rt, GSTexture* ds)
|
||||
}
|
||||
|
||||
if (changed)
|
||||
PSUpdateShaderState();
|
||||
PSUpdateShaderState(true, false);
|
||||
}
|
||||
|
||||
void GSDevice11::OMSetDepthStencilState(ID3D11DepthStencilState* dss, u8 sref)
|
||||
|
||||
@@ -145,9 +145,11 @@ private:
|
||||
ID3D11VertexShader* vs;
|
||||
ID3D11Buffer* vs_cb;
|
||||
std::array<ID3D11ShaderResourceView*, MAX_TEXTURES> ps_sr_views;
|
||||
std::array<ID3D11ShaderResourceView*, MAX_TEXTURES> ps_cached_sr_views;
|
||||
ID3D11PixelShader* ps;
|
||||
ID3D11Buffer* ps_cb;
|
||||
std::array<ID3D11SamplerState*, MAX_SAMPLERS> ps_ss;
|
||||
std::array<ID3D11SamplerState*, MAX_SAMPLERS> ps_cached_ss;
|
||||
GSVector2i viewport;
|
||||
GSVector4i scissor;
|
||||
u32 vb_stride;
|
||||
@@ -324,8 +326,8 @@ public:
|
||||
|
||||
void PSSetShaderResource(int i, GSTexture* sr);
|
||||
void PSSetShader(ID3D11PixelShader* ps, ID3D11Buffer* ps_cb);
|
||||
void PSUpdateShaderState();
|
||||
void PSUnbindConflictingSRVs(GSTexture* rt, GSTexture* ds);
|
||||
void PSUpdateShaderState(const bool sr_update, const bool ss_update);
|
||||
void PSUnbindConflictingSRVs(GSTexture* tex1 = nullptr, GSTexture* tex2 = nullptr);
|
||||
void PSSetSamplerState(ID3D11SamplerState* ss0);
|
||||
|
||||
void OMSetDepthStencilState(ID3D11DepthStencilState* dss, u8 sref);
|
||||
|
||||
@@ -2230,6 +2230,7 @@ void GSRendererHW::Draw()
|
||||
// We mess with this state as an optimization, so take a copy and use that instead.
|
||||
const GSDrawingContext* context = m_context;
|
||||
m_cached_ctx.TEX0 = context->TEX0;
|
||||
m_cached_ctx.TEXA = m_draw_env->TEXA;
|
||||
m_cached_ctx.CLAMP = context->CLAMP;
|
||||
m_cached_ctx.TEST = context->TEST;
|
||||
m_cached_ctx.FRAME = context->FRAME;
|
||||
@@ -2363,7 +2364,7 @@ void GSRendererHW::Draw()
|
||||
const GSLocalMemory::psm_t& tex_psm = GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM];
|
||||
if (PRIM->TME && tex_psm.pal > 0)
|
||||
{
|
||||
m_mem.m_clut.Read32(m_cached_ctx.TEX0, env.TEXA);
|
||||
m_mem.m_clut.Read32(m_cached_ctx.TEX0, m_cached_ctx.TEXA);
|
||||
if (m_mem.m_clut.GetGPUTexture())
|
||||
{
|
||||
CalcAlphaMinMax(0, 255);
|
||||
@@ -2672,6 +2673,48 @@ void GSRendererHW::Draw()
|
||||
GSVector2i(1, 1));
|
||||
height_invalid = false;
|
||||
}
|
||||
const u32 vert_index = (m_vt.m_primclass == GS_TRIANGLE_CLASS) ? 2 : 1;
|
||||
u32 const_color = m_vertex.buff[m_index.buff[vert_index]].RGBAQ.U32[0];
|
||||
u32 fb_mask = m_cached_ctx.FRAME.FBMSK;
|
||||
|
||||
// If we could just check the colour, it would be great, but Echo Night decided it's going to set the alpha and green to 128, for some reason, and actually be 32bit, so it ruined my day.
|
||||
GSTextureCache::Target* rt_tgt = g_texture_cache->GetExactTarget(m_cached_ctx.FRAME.Block(), m_cached_ctx.FRAME.FBW, GSTextureCache::RenderTarget, m_cached_ctx.FRAME.Block() + 1);
|
||||
const bool clear_16bit_likely = !(context->FRAME.PSM & 0x2) && ((rt_tgt && (rt_tgt->m_TEX0.PSM & 2)) || (!rt_tgt && ((static_cast<int>(context->FRAME.FBW) * 64) <= (PCRTCDisplays.GetResolution().x >> 1) || m_r.height() <= (PCRTCDisplays.GetResolution().y >> 1))));
|
||||
|
||||
rt_tgt = nullptr;
|
||||
|
||||
if (clear_16bit_likely && ((const_color != 0 && (const_color >> 16) == (const_color & 0xFFFF) && ((const_color >> 8) & 0xFF) != (const_color & 0xFF)) ||
|
||||
(fb_mask != 0 && (fb_mask >> 16) == (fb_mask & 0xFFFF) && ((fb_mask >> 8) & 0xFF) != (fb_mask & 0xFF))))
|
||||
{
|
||||
const int get_next_ctx = m_env.PRIM.CTXT;
|
||||
const GSDrawingContext& next_ctx = m_env.CTXT[get_next_ctx];
|
||||
|
||||
GL_CACHE("Clear 16bit with 32bit %d", s_n);
|
||||
|
||||
// May have already been resized through the split draw checks.
|
||||
if (!(m_cached_ctx.FRAME.PSM & 2))
|
||||
{
|
||||
if (next_ctx.FRAME.FBW == (m_cached_ctx.FRAME.FBW * 2))
|
||||
{
|
||||
m_cached_ctx.FRAME.FBW *= 2;
|
||||
m_r.z *= 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_r.w *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Convert colour and masks to 16bit and set a custom TEXA for this draw.
|
||||
const_color = ((const_color & 0x1F) << 3) | ((const_color & 0x3E0) << 6) | ((const_color & 0x7C00) << 9) | ((const_color & 0x8000) << 16);
|
||||
m_cached_ctx.FRAME.FBMSK = ((fb_mask & 0x1F) << 3) | ((fb_mask & 0x3E0) << 6) | ((fb_mask & 0x7C00) << 9) | ((fb_mask & 0x8000) << 16);
|
||||
m_cached_ctx.TEXA.AEM = 0;
|
||||
m_cached_ctx.TEXA.TA0 = 0;
|
||||
m_cached_ctx.TEXA.TA1 = 128;
|
||||
m_cached_ctx.FRAME.PSM = (m_cached_ctx.FRAME.PSM & 2) ? m_cached_ctx.FRAME.PSM : PSMCT16;
|
||||
m_vertex.buff[m_index.buff[1]].RGBAQ.U32[0] = const_color;
|
||||
ReplaceVerticesWithSprite(m_r, GSVector2i(m_r.width(), m_r.height()));
|
||||
}
|
||||
|
||||
// Be careful of being 1 pixel from filled.
|
||||
const bool page_aligned = (m_r.w % pgs.y) == (pgs.y - 1) || (m_r.w % pgs.y) == 0;
|
||||
@@ -2936,7 +2979,7 @@ void GSRendererHW::Draw()
|
||||
}
|
||||
|
||||
possible_shuffle = !no_rt && (((shuffle_target /*&& GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].bpp == 16*/) /*|| (m_cached_ctx.FRAME.Block() == m_cached_ctx.TEX0.TBP0 && ((m_cached_ctx.TEX0.PSM & 0x6) || m_cached_ctx.FRAME.PSM != m_cached_ctx.TEX0.PSM))*/) || IsPossibleChannelShuffle());
|
||||
const bool need_aem_color = GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].trbpp <= 24 && GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].pal == 0 && ((NeedsBlending() && m_context->ALPHA.C == 0) || IsDiscardingDstAlpha()) && m_draw_env->TEXA.AEM;
|
||||
const bool need_aem_color = GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].trbpp <= 24 && GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].pal == 0 && ((NeedsBlending() && m_context->ALPHA.C == 0) || IsDiscardingDstAlpha()) && m_cached_ctx.TEXA.AEM;
|
||||
const u32 color_mask = (m_vt.m_max.c > GSVector4i::zero()).mask();
|
||||
const bool texture_function_color = m_cached_ctx.TEX0.TFX == TFX_DECAL || (color_mask & 0xFFF) || (m_cached_ctx.TEX0.TFX > TFX_DECAL && (color_mask & 0xF000));
|
||||
const bool texture_function_alpha = m_cached_ctx.TEX0.TFX != TFX_MODULATE || (color_mask & 0xF000);
|
||||
@@ -2953,8 +2996,8 @@ void GSRendererHW::Draw()
|
||||
}
|
||||
else
|
||||
{
|
||||
src = tex_psm.depth ? g_texture_cache->LookupDepthSource(true, TEX0, env.TEXA, MIP_CLAMP, tmm.coverage, possible_shuffle, m_vt.IsLinear(), m_cached_ctx.FRAME, req_color, req_alpha) :
|
||||
g_texture_cache->LookupSource(true, TEX0, env.TEXA, MIP_CLAMP, tmm.coverage, (GSConfig.HWMipmap || GSConfig.TriFilter == TriFiltering::Forced) ? &hash_lod_range : nullptr,
|
||||
src = tex_psm.depth ? g_texture_cache->LookupDepthSource(true, TEX0, m_cached_ctx.TEXA, MIP_CLAMP, tmm.coverage, possible_shuffle, m_vt.IsLinear(), m_cached_ctx.FRAME, req_color, req_alpha) :
|
||||
g_texture_cache->LookupSource(true, TEX0, m_cached_ctx.TEXA, MIP_CLAMP, tmm.coverage, (GSConfig.HWMipmap || GSConfig.TriFilter == TriFiltering::Forced) ? &hash_lod_range : nullptr,
|
||||
possible_shuffle, m_vt.IsLinear(), m_cached_ctx.FRAME, req_color, req_alpha);
|
||||
|
||||
if (!src) [[unlikely]]
|
||||
@@ -3603,17 +3646,18 @@ void GSRendererHW::Draw()
|
||||
if (ds && rt && (m_cached_ctx.ZBUF.Block() - ds->m_TEX0.TBP0) != (m_cached_ctx.FRAME.Block() - rt->m_TEX0.TBP0))
|
||||
{
|
||||
m_using_temp_z = true;
|
||||
const int page_offset = (static_cast<int>(m_cached_ctx.ZBUF.Block() - ds->m_TEX0.TBP0) / 32);
|
||||
const int z_vertical_offset = (page_offset / std::max(ds->m_TEX0.TBW, 1U)) * GSLocalMemory::m_psm[m_cached_ctx.ZBUF.PSM].pgs.y;
|
||||
const int z_horizontal_offset = (page_offset % std::max(ds->m_TEX0.TBW, 1U)) * GSLocalMemory::m_psm[m_cached_ctx.ZBUF.PSM].pgs.x;
|
||||
const int page_offset = static_cast<int>(m_cached_ctx.ZBUF.Block() - ds->m_TEX0.TBP0) / 32;
|
||||
const int rt_page_offset = static_cast<int>(m_cached_ctx.FRAME.Block() - rt->m_TEX0.TBP0) / 32;
|
||||
const int z_vertical_offset = (page_offset / std::max(static_cast<int>(ds->m_TEX0.TBW), 1)) * GSLocalMemory::m_psm[m_cached_ctx.ZBUF.PSM].pgs.y;
|
||||
const int z_horizontal_offset = (page_offset % std::max(static_cast<int>(ds->m_TEX0.TBW), 1)) * GSLocalMemory::m_psm[m_cached_ctx.ZBUF.PSM].pgs.x;
|
||||
if (g_texture_cache->GetTemporaryZ() != nullptr)
|
||||
{
|
||||
GSTextureCache::TempZAddress z_address_info = g_texture_cache->GetTemporaryZInfo();
|
||||
|
||||
const int old_z_vertical_offset = (page_offset / std::max(ds->m_TEX0.TBW, 1U)) * GSLocalMemory::m_psm[m_cached_ctx.ZBUF.PSM].pgs.y;
|
||||
const int old_z_horizontal_offset = (page_offset % std::max(ds->m_TEX0.TBW, 1U)) * GSLocalMemory::m_psm[m_cached_ctx.ZBUF.PSM].pgs.x;
|
||||
const int old_z_vertical_offset = (z_address_info.offset / std::max(static_cast<int>(ds->m_TEX0.TBW), 1)) * GSLocalMemory::m_psm[m_cached_ctx.ZBUF.PSM].pgs.y;
|
||||
const int old_z_horizontal_offset = (z_address_info.offset % std::max(static_cast<int>(ds->m_TEX0.TBW), 1)) * GSLocalMemory::m_psm[m_cached_ctx.ZBUF.PSM].pgs.x;
|
||||
|
||||
if (ds->m_TEX0.TBP0 != z_address_info.ZBP || z_address_info.offset != page_offset)
|
||||
if (ds->m_TEX0.TBP0 != z_address_info.ZBP || z_address_info.offset != page_offset || z_address_info.rt_offset != rt_page_offset)
|
||||
g_texture_cache->InvalidateTemporaryZ();
|
||||
else if (!m_r.rintersect(z_address_info.rect_since).rempty() && m_cached_ctx.TEST.ZTST > ZTST_ALWAYS)
|
||||
{
|
||||
@@ -3633,10 +3677,11 @@ void GSRendererHW::Draw()
|
||||
|
||||
if (g_texture_cache->GetTemporaryZ() == nullptr)
|
||||
{
|
||||
ds->Update(); // We need to update any dirty bits of Z before the copy
|
||||
|
||||
m_temp_z_full_copy = false;
|
||||
const int get_next_ctx = m_env.PRIM.CTXT;
|
||||
const GSDrawingContext& next_ctx = m_env.CTXT[get_next_ctx];
|
||||
const int rt_page_offset = (static_cast<int>(m_cached_ctx.FRAME.Block() - rt->m_TEX0.TBP0) / 32);
|
||||
const int vertical_page_offset = (rt_page_offset / std::max(static_cast<int>(rt->m_TEX0.TBW), 1));
|
||||
const int vertical_offset = vertical_page_offset * frame_psm.pgs.y;
|
||||
const int horizontal_offset = (rt_page_offset - (vertical_page_offset * std::max(static_cast<int>(rt->m_TEX0.TBW), 1))) * frame_psm.pgs.x;
|
||||
@@ -3644,36 +3689,21 @@ void GSRendererHW::Draw()
|
||||
const u32 horizontal_size = std::max(rt->m_unscaled_size.x, ds->m_unscaled_size.x);
|
||||
const u32 vertical_size = std::max(rt->m_unscaled_size.y, ds->m_unscaled_size.y);
|
||||
|
||||
GSVector4i dRect = GSVector4i(horizontal_offset * ds->m_scale, vertical_offset * ds->m_scale, ds->m_unscaled_size.x * ds->m_scale, ds->m_unscaled_size.y * ds->m_scale);
|
||||
GSVector4i dRect = GSVector4i(horizontal_offset * ds->m_scale, vertical_offset * ds->m_scale, (horizontal_offset + (ds->m_unscaled_size.x - z_horizontal_offset)) * ds->m_scale, (vertical_offset + (ds->m_unscaled_size.y - z_vertical_offset)) * ds->m_scale);
|
||||
|
||||
|
||||
const int new_height = std::max(static_cast<int>(vertical_size * ds->m_scale), dRect.w);
|
||||
const int new_width = std::max(static_cast<int>(horizontal_size * ds->m_scale), dRect.z);
|
||||
// Size here should match whichever is biggest, since that's probably what's going to happen with it further down.
|
||||
const int new_height = std::min(2048, std::max(t_size.y, static_cast<int>(vertical_size))) * ds->m_scale;
|
||||
const int new_width = std::min(2048, std::max(t_size.x, static_cast<int>(horizontal_size))) * ds->m_scale;
|
||||
const int height_diff = new_height - (ds->m_unscaled_size.y * ds->m_scale);
|
||||
const int width_diff = new_width - (ds->m_unscaled_size.x * ds->m_scale);
|
||||
|
||||
if (GSTexture* tex = g_gs_device->CreateDepthStencil(new_width, new_height, GSTexture::Format::DepthStencil, true))
|
||||
{
|
||||
GSVector4 sRect = GSVector4(static_cast<float>(z_horizontal_offset) / static_cast<float>(ds->m_unscaled_size.x), static_cast<float>(z_vertical_offset) / static_cast<float>(ds->m_unscaled_size.y), 1.0f - (static_cast<float>(horizontal_offset - z_horizontal_offset) / static_cast<float>(ds->m_unscaled_size.x)), 1.0f - (static_cast<float>(vertical_offset - z_vertical_offset) / static_cast<float>(ds->m_unscaled_size.y)));
|
||||
GSVector4 sRect = GSVector4(static_cast<float>(z_horizontal_offset) / static_cast<float>(ds->m_unscaled_size.x), static_cast<float>(z_vertical_offset) / static_cast<float>(ds->m_unscaled_size.y), 1.0f , 1.0f);
|
||||
|
||||
const bool restricted_copy = !(((next_ctx.ZBUF.ZBP == m_context->ZBUF.ZBP && next_ctx.FRAME.FBP == m_context->FRAME.FBP)) && !(IsPossibleChannelShuffle() && !IsPageCopy()));
|
||||
|
||||
if (!restricted_copy)
|
||||
{
|
||||
if (height_diff)
|
||||
{
|
||||
const int adjust = std::min(height_diff, (vertical_offset - z_vertical_offset));
|
||||
sRect.w += static_cast<float>(adjust) / static_cast<float>(ds->m_unscaled_size.y);
|
||||
dRect.w += adjust;
|
||||
}
|
||||
if (width_diff)
|
||||
{
|
||||
const int adjust = std::min(width_diff, (horizontal_offset - z_horizontal_offset));
|
||||
sRect.z += static_cast<float>(adjust) / static_cast<float>(ds->m_unscaled_size.x);
|
||||
dRect.z += adjust;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (restricted_copy)
|
||||
{
|
||||
// m_r already has horizontal_offset (rt offset) applied)
|
||||
dRect = GSVector4i(m_r.x * ds->m_scale, m_r.y * ds->m_scale, ((1 + m_r.z) * ds->m_scale), ((1 + m_r.w) * ds->m_scale));
|
||||
@@ -3686,10 +3716,13 @@ void GSRendererHW::Draw()
|
||||
|
||||
GL_CACHE("HW: RT in RT Z copy on draw %d z_vert_offset %d", s_n, page_offset);
|
||||
|
||||
g_gs_device->StretchRect(ds->m_texture, sRect, tex, GSVector4(dRect), ShaderConvert::DEPTH_COPY, false);
|
||||
g_perfmon.Put(GSPerfMon::TextureCopies, 1);
|
||||
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);
|
||||
g_texture_cache->SetTemporaryZInfo(ds->m_TEX0.TBP0, page_offset, rt_page_offset);
|
||||
t_size.y = std::max(static_cast<int>(new_height / ds->m_scale), t_size.y);
|
||||
}
|
||||
else
|
||||
@@ -4328,7 +4361,10 @@ void GSRendererHW::Draw()
|
||||
const GSLocalMemory::psm_t& z_psm = GSLocalMemory::m_psm[m_cached_ctx.ZBUF.PSM];
|
||||
const int vertical_offset = ((static_cast<int>(m_cached_ctx.FRAME.Block() - rt->m_TEX0.TBP0) / 32) / std::max(static_cast<int>(rt->m_TEX0.TBW), 1)) * frame_psm.pgs.y;
|
||||
const int z_vertical_offset = ((static_cast<int>(m_cached_ctx.ZBUF.Block() - ds->m_TEX0.TBP0) / 32) / std::max(static_cast<int>(ds->m_TEX0.TBW), 1)) * z_psm.pgs.y;
|
||||
const GSVector4i ds_rect = m_r - GSVector4i(vertical_offset - z_vertical_offset);
|
||||
const int z_horizontal_offset = ((static_cast<int>(m_cached_ctx.ZBUF.Block() - ds->m_TEX0.TBP0) / 32) % std::max(rt->m_TEX0.TBW, 1U)) * z_psm.pgs.x;
|
||||
const int horizontal_offset = ((static_cast<int>(m_cached_ctx.FRAME.Block() - rt->m_TEX0.TBP0) / 32) % std::max(static_cast<int>(rt->m_TEX0.TBW), 1)) * frame_psm.pgs.x;
|
||||
|
||||
const GSVector4i ds_rect = m_r - GSVector4i(horizontal_offset - z_horizontal_offset, vertical_offset - z_vertical_offset).xyxy();
|
||||
ds->UpdateValidity(ds_rect, z_update && (can_update_size || (ds_rect.w <= (resolution.y * 2) && !m_texture_shuffle)));
|
||||
ds->UpdateDrawn(ds_rect, z_update && (can_update_size || (ds_rect.w <= (resolution.y * 2) && !m_texture_shuffle)));
|
||||
}
|
||||
@@ -4573,14 +4609,14 @@ void GSRendererHW::Draw()
|
||||
{
|
||||
const int get_next_ctx = m_env.PRIM.CTXT;
|
||||
const GSDrawingContext& next_ctx = m_env.CTXT[get_next_ctx];
|
||||
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;
|
||||
const int z_horizontal_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.x;
|
||||
const int z_vertical_offset = ((static_cast<int>(m_cached_ctx.ZBUF.Block() - ds->m_TEX0.TBP0) / 32) / std::max(static_cast<int>(rt->m_TEX0.TBW), 1)) * GSLocalMemory::m_psm[m_cached_ctx.ZBUF.PSM].pgs.y;
|
||||
const int z_horizontal_offset = ((static_cast<int>(m_cached_ctx.ZBUF.Block() - ds->m_TEX0.TBP0) / 32) % std::max(static_cast<int>(rt->m_TEX0.TBW), 1)) * GSLocalMemory::m_psm[m_cached_ctx.ZBUF.PSM].pgs.x;
|
||||
const int vertical_offset = ((static_cast<int>(m_cached_ctx.FRAME.Block() - rt->m_TEX0.TBP0) / 32) / std::max(static_cast<int>(rt->m_TEX0.TBW), 1)) * frame_psm.pgs.y;
|
||||
const int horizontal_offset = ((static_cast<int>(m_cached_ctx.FRAME.Block() - rt->m_TEX0.TBP0) / 32) % std::max(static_cast<int>(rt->m_TEX0.TBW), 1)) * frame_psm.pgs.x;
|
||||
|
||||
if (was_written)
|
||||
{
|
||||
const GSVector4i ds_real_rect = real_rect - GSVector4i(vertical_offset - z_vertical_offset);
|
||||
const GSVector4i ds_real_rect = real_rect - GSVector4i(horizontal_offset - z_horizontal_offset, vertical_offset - z_vertical_offset).xyxy();
|
||||
ds->UpdateValidity(ds_real_rect, !z_masked && (can_update_size || (ds_real_rect.w <= (resolution.y * 2) && !m_texture_shuffle)));
|
||||
}
|
||||
|
||||
@@ -6344,7 +6380,7 @@ __ri void GSRendererHW::EmulateTextureSampler(const GSTextureCache::Target* rt,
|
||||
// 2/ Only keep aem when it is useful (avoid useless shader permutation)
|
||||
if (m_conf.ps.shuffle)
|
||||
{
|
||||
const GIFRegTEXA& TEXA = m_draw_env->TEXA;
|
||||
const GIFRegTEXA& TEXA = m_cached_ctx.TEXA;
|
||||
|
||||
// Force a 32 bits access (normally shuffle is done on 16 bits)
|
||||
// m_ps_sel.tex_fmt = 0; // removed as an optimization
|
||||
@@ -6398,7 +6434,7 @@ __ri void GSRendererHW::EmulateTextureSampler(const GSTextureCache::Target* rt,
|
||||
}
|
||||
else if (tex->m_target)
|
||||
{
|
||||
const GIFRegTEXA& TEXA = m_draw_env->TEXA;
|
||||
const GIFRegTEXA& TEXA = m_cached_ctx.TEXA;
|
||||
|
||||
// Use an old target. AEM and index aren't resolved it must be done
|
||||
// on the GPU
|
||||
@@ -7235,13 +7271,13 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta
|
||||
const GSVector4i shuffle_rect = GSVector4i(m_vt.m_min.p.x, m_vt.m_min.p.y, m_vt.m_max.p.x, m_vt.m_max.p.y);
|
||||
if (!rt->m_valid.rintersect(shuffle_rect).eq(rt->m_valid) || (m_cached_ctx.FRAME.FBMSK & 0xFFFC0000))
|
||||
{
|
||||
rt_new_alpha_max = std::max(static_cast<int>((std::max(m_draw_env->TEXA.TA1, m_draw_env->TEXA.TA0) & 0x80) + 127), rt_new_alpha_max) | fba_value;
|
||||
rt_new_alpha_min = std::min(static_cast<int>(std::min(m_draw_env->TEXA.TA1, m_draw_env->TEXA.TA0) & 0x80), rt_new_alpha_min);
|
||||
rt_new_alpha_max = std::max(static_cast<int>((std::max(m_cached_ctx.TEXA.TA1, m_cached_ctx.TEXA.TA0) & 0x80) + 127), rt_new_alpha_max) | fba_value;
|
||||
rt_new_alpha_min = std::min(static_cast<int>(std::min(m_cached_ctx.TEXA.TA1, m_cached_ctx.TEXA.TA0) & 0x80), rt_new_alpha_min);
|
||||
}
|
||||
else
|
||||
{
|
||||
rt_new_alpha_max = (std::max(m_draw_env->TEXA.TA1, m_draw_env->TEXA.TA0) & 0x80) + 127 | fba_value;
|
||||
rt_new_alpha_min = (std::min(m_draw_env->TEXA.TA1, m_draw_env->TEXA.TA0) & 0x80) | fba_value;
|
||||
rt_new_alpha_max = (std::max(m_cached_ctx.TEXA.TA1, m_cached_ctx.TEXA.TA0) & 0x80) + 127 | fba_value;
|
||||
rt_new_alpha_min = (std::min(m_cached_ctx.TEXA.TA1, m_cached_ctx.TEXA.TA0) & 0x80) | fba_value;
|
||||
}
|
||||
rt->m_alpha_range = true;
|
||||
}
|
||||
@@ -8156,7 +8192,7 @@ bool GSRendererHW::CanUseSwPrimRender(bool no_rt, bool no_ds, bool draw_sprite_t
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool need_aem_color = GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].trbpp <= 24 && GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].pal == 0 && ((NeedsBlending() && m_context->ALPHA.C == 0) || IsDiscardingDstAlpha()) && m_draw_env->TEXA.AEM;
|
||||
const bool need_aem_color = GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].trbpp <= 24 && GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].pal == 0 && ((NeedsBlending() && m_context->ALPHA.C == 0) || IsDiscardingDstAlpha()) && m_cached_ctx.TEXA.AEM;
|
||||
const u32 color_mask = (m_vt.m_max.c > GSVector4i::zero()).mask();
|
||||
const bool texture_function_color = m_cached_ctx.TEX0.TFX == TFX_DECAL || (color_mask & 0xFFF) || (m_cached_ctx.TEX0.TFX > TFX_DECAL && (color_mask & 0xF000));
|
||||
const bool texture_function_alpha = m_cached_ctx.TEX0.TFX != TFX_MODULATE || (color_mask & 0xF000);
|
||||
@@ -8336,8 +8372,8 @@ bool GSRendererHW::DetectDoubleHalfClear(bool& no_rt, bool& no_ds)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Z and color must be constant and the same
|
||||
if (m_vt.m_eq.rgba != 0xFFFF || !m_vt.m_eq.z)
|
||||
// Z and color must be constant and the same and both are enabled.
|
||||
if (m_vt.m_eq.rgba != 0xFFFF || !m_vt.m_eq.z || (no_ds != no_rt))
|
||||
return false;
|
||||
|
||||
const u32 write_color = GetConstantDirectWriteMemClearColor();
|
||||
@@ -8416,7 +8452,7 @@ bool GSRendererHW::DetectDoubleHalfClear(bool& no_rt, bool& no_ds)
|
||||
// bang up next to each other, or a double half clear. The two are really difficult to differentiate.
|
||||
// Have to check both contexts, because God of War 2 likes to do this in-between setting TRXDIR, which
|
||||
// causes a flush, and we don't have the next context backed up index set.
|
||||
bool horizontal = false;
|
||||
bool horizontal = std::abs(static_cast<int>(m_cached_ctx.FRAME.FBP) - static_cast<int>(m_cached_ctx.ZBUF.ZBP)) == (m_cached_ctx.FRAME.FBW >> 1);
|
||||
const bool possible_next_clear = !m_env.PRIM.TME && !(m_env.SCANMSK.MSK & 2) && !m_env.CTXT[next_ctx].TEST.ATE && !m_env.CTXT[next_ctx].TEST.DATE &&
|
||||
(!m_env.CTXT[next_ctx].TEST.ZTE || m_env.CTXT[next_ctx].TEST.ZTST == ZTST_ALWAYS);
|
||||
|
||||
@@ -8499,6 +8535,14 @@ bool GSRendererHW::DetectDoubleHalfClear(bool& no_rt, bool& no_ds)
|
||||
else
|
||||
{
|
||||
const int height = m_r.height();
|
||||
|
||||
// We don't want to double half clear already full sized targets, making them double the size, this could be very bad.
|
||||
// This gets triggered by Monster Lab which clears the Z and FRAME in one go, butted up against each other.
|
||||
// It's highly unlikely that it will actually require a > 600 high framebuffer, but check with the display height first.
|
||||
const int display_height = PCRTCDisplays.GetResolution().y;
|
||||
if ((display_height != 0 && height >= (display_height - 1)) || height > 300)
|
||||
return false;
|
||||
|
||||
m_r.w = ((half - base) / m_cached_ctx.FRAME.FBW) * frame_psm.pgs.y;
|
||||
m_r.w += m_r.y + height;
|
||||
}
|
||||
|
||||
@@ -140,6 +140,7 @@ private:
|
||||
struct HWCachedCtx
|
||||
{
|
||||
GIFRegTEX0 TEX0;
|
||||
GIFRegTEXA TEXA;
|
||||
GIFRegCLAMP CLAMP;
|
||||
GIFRegTEST TEST;
|
||||
GIFRegFRAME FRAME;
|
||||
|
||||
@@ -1792,7 +1792,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
|
||||
|
||||
//rect = rect.rintersect(t->m_valid);
|
||||
|
||||
if (rect.rintersect(t->m_valid).rempty())
|
||||
if (rect.rintersect(t->m_valid - GSVector4i(0, 1).xyxy()).rempty())
|
||||
continue;
|
||||
|
||||
if (!t->m_dirty.empty())
|
||||
@@ -2382,6 +2382,15 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
|
||||
// Probably pointing to half way through the target
|
||||
else if (!min_rect.rempty() && GSConfig.UserHacks_TextureInsideRt >= GSTextureInRtMode::InsideTargets)
|
||||
{
|
||||
// Some games misuse the scissor so it ends up valid 1 pixel over, which causes hell for us. So check if it still overlaps without the extra pixel.
|
||||
const GSVector4i adjusted_valid = GSVector4i(t->m_valid.x, t->m_valid.y, std::min(t->m_valid.z, static_cast<int>(t->m_TEX0.TBW) * 64), t->m_valid.w - 1);
|
||||
const u32 adjusted_endblock = GSLocalMemory::GetEndBlockAddress(t->m_TEX0.TBP0, t->m_TEX0.TBW, t->m_TEX0.PSM, adjusted_valid);
|
||||
if (adjusted_endblock <= bp)
|
||||
{
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
const u32 widthpage_offset = (std::abs(static_cast<int>(bp - t->m_TEX0.TBP0)) >> 5) % std::max(t->m_TEX0.TBW, 1U);
|
||||
const bool is_aligned_ok = widthpage_offset == 0 || ((min_rect.width() <= static_cast<int>((t->m_TEX0.TBW - widthpage_offset) * 64) && (t->m_TEX0.TBW == TEX0.TBW || TEX0.TBW == 1)) && bp >= t->m_TEX0.TBP0);
|
||||
const bool no_target_or_newer = (!dst || ((GSState::s_n - dst->m_last_draw) < (GSState::s_n - t->m_last_draw)));
|
||||
@@ -2389,10 +2398,11 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
|
||||
const bool ds_offset = !ds || offset != 0;
|
||||
const bool is_double_buffer = TEX0.TBP0 == ((((t->m_end_block + 1) - t->m_TEX0.TBP0) / 2) + t->m_TEX0.TBP0);
|
||||
const bool source_match = src && src->m_TEX0.TBP0 == bp && src->m_TEX0.TBW == TEX0.TBW && src->m_from_target && src->m_from_target == t;
|
||||
const bool was_used_last_draw = t->m_last_draw == (GSState::s_n - 1);
|
||||
// if it's a shuffle, some games tend to offset back by a page, such as Tomb Raider, for no disernable reason, but it then causes problems.
|
||||
// This can also happen horizontally (Catwoman moves everything one page left with shuffles), but this is too messy to deal with right now.
|
||||
const bool overlaps = t->Overlaps(bp, TEX0.TBW, TEX0.PSM, min_rect) || (is_shuffle && src && GSLocalMemory::m_psm[src->m_TEX0.PSM].bpp == 8 && t->Overlaps(bp, TEX0.TBW, TEX0.PSM, min_rect + GSVector4i(0, 0, 0, 32)));
|
||||
if (source_match || (no_target_or_newer && is_aligned_ok && width_match && overlaps && (is_shuffle || ds_offset || is_double_buffer)))
|
||||
if (source_match || (no_target_or_newer && is_aligned_ok && width_match && overlaps && (is_shuffle || ds_offset || is_double_buffer || was_used_last_draw)))
|
||||
{
|
||||
const GSLocalMemory::psm_t& s_psm = GSLocalMemory::m_psm[TEX0.PSM];
|
||||
|
||||
@@ -2400,9 +2410,10 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe
|
||||
// 896 is just 448 * 2,just gives the buffer chance to be larger than normal, in case they do something like 640x640, or something ridiculous.
|
||||
if (!is_shuffle && (ds && offset == 0 && (t->m_valid.w >= 896) && ((((t->m_end_block + 1) - t->m_TEX0.TBP0) >> 1) + t->m_TEX0.TBP0) <= bp))
|
||||
{
|
||||
t->m_valid.w /= 2;
|
||||
t->m_end_block = ((((t->m_end_block + 1) - t->m_TEX0.TBP0) >> 1) + t->m_TEX0.TBP0) - 1;
|
||||
continue;
|
||||
u32 offset = (((bp - t->m_TEX0.TBP0) >> 5) / std::max(t->m_TEX0.TBW, 1U)) * s_psm.pgs.y;
|
||||
dst = CreateTarget(TEX0, GSVector2i(t->m_valid.z, t->m_valid.w - offset), GSVector2i(t->m_valid.z, t->m_valid.w - offset), scale, type, true, fbmask, false, false, preserve_rgb || preserve_alpha, GSVector4i::zero(), src);
|
||||
dst->m_32_bits_fmt |= (psm_s.bpp != 16);
|
||||
break;
|
||||
}
|
||||
|
||||
// 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.
|
||||
@@ -3404,7 +3415,7 @@ bool GSTextureCache::PreloadTarget(GIFRegTEX0 TEX0, const GSVector2i& size, cons
|
||||
Target* t = *j;
|
||||
|
||||
if (dst != t && t->m_TEX0.PSM == dst->m_TEX0.PSM && t->Overlaps(dst->m_TEX0.TBP0, dst->m_TEX0.TBW, dst->m_TEX0.PSM, dst_valid) &&
|
||||
static_cast<int>(((t->m_TEX0.TBP0 - dst->m_TEX0.TBP0) / 32) % std::max(dst->m_TEX0.TBW, 1U)) <= std::max(0, static_cast<int>(dst->m_TEX0.TBW - t->m_TEX0.TBW)))
|
||||
((std::abs(static_cast<int>(t->m_TEX0.TBP0 - dst->m_TEX0.TBP0)) >> 5) % std::max(static_cast<int>(dst->m_TEX0.TBW), 1)) <= std::max(0, static_cast<int>(dst->m_TEX0.TBW - t->m_TEX0.TBW)))
|
||||
{
|
||||
const u32 buffer_width = std::max(1U, dst->m_TEX0.TBW);
|
||||
|
||||
@@ -3427,7 +3438,7 @@ bool GSTextureCache::PreloadTarget(GIFRegTEX0 TEX0, const GSVector2i& size, cons
|
||||
}
|
||||
// If the two targets are misaligned, it's likely a relocation, so we can just kill the old target.
|
||||
// Kill targets that are overlapping new targets, but ignore the copy if the old target is dirty because we favour GS memory.
|
||||
if (((((t->m_TEX0.TBP0 - dst->m_TEX0.TBP0) >> 5) % buffer_width) != 0) && !t->m_dirty.empty())
|
||||
if (((std::abs(static_cast<int>(t->m_TEX0.TBP0 - dst->m_TEX0.TBP0) >> 5) % buffer_width) != 0) && !t->m_dirty.empty())
|
||||
{
|
||||
InvalidateSourcesFromTarget(t);
|
||||
i = list.erase(j);
|
||||
@@ -3441,6 +3452,23 @@ bool GSTextureCache::PreloadTarget(GIFRegTEX0 TEX0, const GSVector2i& size, cons
|
||||
{
|
||||
GSVector4i new_valid = t->m_valid;
|
||||
new_valid.w /= 2;
|
||||
if (preserve_target && t->m_scale == dst->m_scale && dst->m_type == t->m_type && dst->m_dirty.empty() && !t->m_drawn_since_read.rintersect(new_valid).eq(t->m_drawn_since_read))
|
||||
{
|
||||
// Clamp the copy inside the source and destination.
|
||||
const GSVector4i copy_rect = GSVector4i(GSVector4((new_valid + GSVector4i(0, new_valid.w).xyxy()).rintersect(t->m_drawn_since_read).rintersect(GSVector4i(0, 0, dst->m_unscaled_size.x, new_valid.w + dst->m_unscaled_size.y))) * dst->m_scale);
|
||||
// Copy over the double buffer data, in case we need it.
|
||||
// Clear the dirty first
|
||||
t->Update();
|
||||
|
||||
dst->m_valid_rgb = t->m_valid_rgb;
|
||||
dst->m_valid_alpha_low = t->m_valid_alpha_low;
|
||||
dst->m_valid_alpha_high = t->m_valid_alpha_high;
|
||||
dst->m_alpha_max = t->m_alpha_max;
|
||||
dst->m_alpha_min = t->m_alpha_min;
|
||||
dst->m_rt_alpha_scale = t->m_rt_alpha_scale;
|
||||
|
||||
g_gs_device->CopyRect(t->m_texture, dst->m_texture, copy_rect, 0, 0);
|
||||
}
|
||||
GL_INS("TC: RT resize buffer for FBP 0x%x, %dx%d => %d,%d", t->m_TEX0.TBP0, t->m_valid.width(), t->m_valid.height(), new_valid.width(), new_valid.height());
|
||||
t->ResizeValidity(new_valid);
|
||||
return hw_clear.value_or(false);
|
||||
@@ -3850,6 +3878,9 @@ void GSTextureCache::ScaleTargetForDisplay(Target* t, const GIFRegTEX0& dispfb,
|
||||
{
|
||||
const GSVector4i right(old_width, 0, preload_width, needed_height);
|
||||
const GSVector4i bottom(0, old_height, old_width, needed_height);
|
||||
|
||||
t->UpdateValidity(right.rintersect(bottom));
|
||||
|
||||
AddDirtyRectTarget(t, right, t->m_TEX0.PSM, t->m_TEX0.TBW, rgba);
|
||||
AddDirtyRectTarget(t, bottom, t->m_TEX0.PSM, t->m_TEX0.TBW, rgba);
|
||||
}
|
||||
@@ -3858,6 +3889,9 @@ void GSTextureCache::ScaleTargetForDisplay(Target* t, const GIFRegTEX0& dispfb,
|
||||
const GSVector4i newrect = GSVector4i((old_height < new_height) ? 0 : old_width,
|
||||
(old_width < preload_width) ? 0 : old_height,
|
||||
preload_width, needed_height);
|
||||
|
||||
t->UpdateValidity(newrect);
|
||||
|
||||
AddDirtyRectTarget(t, newrect, t->m_TEX0.PSM, t->m_TEX0.TBW, rgba);
|
||||
}
|
||||
|
||||
@@ -8057,10 +8091,11 @@ GSTextureCache::TempZAddress GSTextureCache::GetTemporaryZInfo()
|
||||
return m_temporary_z_info;
|
||||
}
|
||||
|
||||
void GSTextureCache::SetTemporaryZInfo(u32 address, u32 offset)
|
||||
void GSTextureCache::SetTemporaryZInfo(u32 address, u32 offset, u32 rt_offset)
|
||||
{
|
||||
m_temporary_z_info.ZBP = address;
|
||||
m_temporary_z_info.offset = offset;
|
||||
m_temporary_z_info.rt_offset = rt_offset;
|
||||
m_temporary_z_info.rect_since = GSVector4i::zero();
|
||||
}
|
||||
void GSTextureCache::SetTemporaryZInfo(TempZAddress address_info)
|
||||
|
||||
@@ -213,6 +213,7 @@ public:
|
||||
{
|
||||
u32 ZBP;
|
||||
int offset;
|
||||
int rt_offset;
|
||||
GSVector4i rect_since;
|
||||
};
|
||||
|
||||
@@ -567,7 +568,7 @@ public:
|
||||
void SetTemporaryZ(GSTexture* temp_z);
|
||||
GSTexture* GetTemporaryZ();
|
||||
TempZAddress GetTemporaryZInfo();
|
||||
void SetTemporaryZInfo(u32 address, u32 offset);
|
||||
void SetTemporaryZInfo(u32 address, u32 offset, u32 rt_offset);
|
||||
void SetTemporaryZInfo(TempZAddress address_info);
|
||||
/// Invalidates a temporary Z, a partial copy only created from the current DS for the current draw when Z is not offset but RT is.
|
||||
void InvalidateTemporaryZ();
|
||||
|
||||
@@ -2585,6 +2585,7 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
|
||||
{
|
||||
// Ensure all depth writes are finished before sampling
|
||||
GL_INS("GL: Texture barrier to flush depth or rt before reading");
|
||||
g_perfmon.Put(GSPerfMon::Barriers, 1);
|
||||
glTextureBarrier();
|
||||
}
|
||||
// additional non-pipeline config stuff
|
||||
|
||||
@@ -6507,24 +6507,46 @@ void FullscreenUI::DrawGameList(const ImVec2& heading_size)
|
||||
|
||||
if (BeginFullscreenColumnWindow(-530.0f, 0.0f, "game_list_info", UIPrimaryDarkColor))
|
||||
{
|
||||
const ImVec2 image_size = LayoutScale(ImVec2(275.0f, 400.0f));
|
||||
ImGui::SetCursorPos(LayoutScale(ImVec2(128.0f, 20.0f)));
|
||||
const float img_padding_y = LayoutScale(20.0f);
|
||||
// Spacing between each text item
|
||||
const float text_spacing_y = LayoutScale(8.0f);
|
||||
// Space between title/serial and details, is in addition to text_spacing_y
|
||||
const float title_padding_below_y = LayoutScale(12.0f);
|
||||
|
||||
// Estimate how much space is needed for text
|
||||
// Do this even when nothing is selected, to ensure cover/icon is in a consistant size/position
|
||||
const float title_detail_height =
|
||||
LayoutScale(LAYOUT_LARGE_FONT_SIZE) + text_spacing_y + // Title
|
||||
LayoutScale(LAYOUT_MEDIUM_FONT_SIZE) + text_spacing_y + // Serial
|
||||
title_padding_below_y +
|
||||
7.0f * (LayoutScale(LAYOUT_MEDIUM_FONT_SIZE) + text_spacing_y) + // File, CRC, Region, Compat, Time/Last Played, Size
|
||||
LayoutScale(12.0f); // Extra padding
|
||||
|
||||
// Limit cover height to avoid pushing text off the screen
|
||||
const ImGuiWindow* window = ImGui::GetCurrentWindow();
|
||||
// Based on ImGui code for WorkRect, with scrolling logic removed
|
||||
const float window_height = std::trunc(window->InnerRect.GetHeight() - 2.0f * std::max(window->WindowPadding.y, window->WindowBorderSize));
|
||||
|
||||
const float free_height = window_height - title_detail_height;
|
||||
const float img_height = std::min(free_height - 2.0f * img_padding_y, LayoutScale(400.0f));
|
||||
|
||||
const ImVec2 image_size = ImVec2(LayoutScale(275.0f), img_height);
|
||||
ImGui::SetCursorPos(ImVec2(LayoutScale(128.0f), img_padding_y));
|
||||
|
||||
if (selected_entry)
|
||||
DrawGameCover(selected_entry, image_size);
|
||||
else
|
||||
DrawFallbackCover(image_size);
|
||||
|
||||
const float work_width = ImGui::GetCurrentWindow()->WorkRect.GetWidth();
|
||||
constexpr float field_margin_y = 10.0f;
|
||||
constexpr float start_x = 50.0f;
|
||||
float text_y = 440.0f;
|
||||
const float work_width = window->WorkRect.GetWidth();
|
||||
const float start_x = LayoutScale(50.0f);
|
||||
const float text_y = img_height + 2.0f * img_padding_y;
|
||||
float text_width;
|
||||
|
||||
PushPrimaryColor();
|
||||
ImGui::SetCursorPos(LayoutScale(start_x, text_y));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, field_margin_y));
|
||||
ImGui::PushTextWrapPos(LayoutScale(480.0f));
|
||||
ImGui::SetCursorPos(ImVec2(start_x, text_y));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, text_spacing_y));
|
||||
ImGui::PushTextWrapPos(LayoutScale(490.0f));
|
||||
ImGui::BeginGroup();
|
||||
|
||||
if (selected_entry)
|
||||
@@ -6533,6 +6555,8 @@ void FullscreenUI::DrawGameList(const ImVec2& heading_size)
|
||||
ImGui::PushFont(g_large_font);
|
||||
const std::string_view title(std::string_view(selected_entry->GetTitle(true)).substr(0, 37));
|
||||
text_width = ImGui::CalcTextSize(title.data(), title.data() + title.length(), false, work_width).x;
|
||||
if (title.length() != selected_entry->GetTitle(true).length())
|
||||
text_width += ImGui::CalcTextSize("...", nullptr, false, -1.0f).x;
|
||||
ImGui::SetCursorPosX((work_width - text_width) / 2.0f);
|
||||
ImGui::TextWrapped(
|
||||
"%.*s%s", static_cast<int>(title.size()), title.data(), (title.length() == selected_entry->GetTitle(true).length()) ? "" : "...");
|
||||
@@ -6544,7 +6568,7 @@ void FullscreenUI::DrawGameList(const ImVec2& heading_size)
|
||||
text_width = ImGui::CalcTextSize(selected_entry->serial.c_str(), nullptr, false, work_width).x;
|
||||
ImGui::SetCursorPosX((work_width - text_width) / 2.0f);
|
||||
ImGui::TextWrapped("%s", selected_entry->serial.c_str());
|
||||
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 15.0f);
|
||||
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + title_padding_below_y);
|
||||
|
||||
// file tile
|
||||
ImGui::TextWrapped("%s", SmallString::from_format(FSUI_FSTR("File: {}"), Path::GetFileName(selected_entry->path)).c_str());
|
||||
|
||||
Reference in New Issue
Block a user