mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-01-31 01:15:24 +01:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bc51537080 | ||
|
|
b7dfcb282b | ||
|
|
78a9411766 | ||
|
|
4724f67596 | ||
|
|
e0851bb86f | ||
|
|
08e68d9563 | ||
|
|
0b6dccae51 | ||
|
|
60adfd5046 | ||
|
|
3e782d355d | ||
|
|
22a7324b69 | ||
|
|
f3b4c50909 | ||
|
|
a45f27e6e9 | ||
|
|
2f84bf0cca | ||
|
|
3e2c3e5075 | ||
|
|
154259d0a6 |
2
.github/ISSUE_TEMPLATE/app_bug_report.yaml
vendored
2
.github/ISSUE_TEMPLATE/app_bug_report.yaml
vendored
@@ -70,6 +70,8 @@ body:
|
||||
- Windows 11
|
||||
- Windows 10 (64bit)
|
||||
- Linux (64bit) - Specify distro below
|
||||
- macOS 26 (Tahoe)
|
||||
- macOS 15 (Sequoia)
|
||||
- macOS 14 (Sonoma)
|
||||
- macOS 13 (Ventura)
|
||||
- macOS 12 (Monterey)
|
||||
|
||||
6
.github/ISSUE_TEMPLATE/emu_bug_report.yaml
vendored
6
.github/ISSUE_TEMPLATE/emu_bug_report.yaml
vendored
@@ -87,6 +87,8 @@ body:
|
||||
- Windows 11
|
||||
- Windows 10 (64bit)
|
||||
- Linux (64bit) - Specify distro below
|
||||
- macOS 26 (Tahoe)
|
||||
- macOS 15 (Sequoia)
|
||||
- macOS 14 (Sonoma)
|
||||
- macOS 13 (Ventura)
|
||||
- macOS 12 (Monterey)
|
||||
@@ -104,14 +106,14 @@ body:
|
||||
id: cpu
|
||||
attributes:
|
||||
label: CPU
|
||||
placeholder: "Example: i5-7600"
|
||||
placeholder: "Example: Intel i5 12400F"
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: gpu
|
||||
attributes:
|
||||
label: GPU
|
||||
placeholder: "Example: GTX 1070"
|
||||
placeholder: "Example: Nvidia RTX 4060"
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
<li><a href="#googletest">GoogleTest</a></li>
|
||||
<li><a href="#harfbuzz">HarfBuzz</a></li>
|
||||
<li><a href="#jsonformoderncpp">JSON for Modern C++</a></li>
|
||||
<li><a href="#kdbindings">KDBindings</a></li>
|
||||
<li><a href="#kddockwidgets">KDDockWidgets</a></li>
|
||||
<li><a href="#kissfft">kissfft</a></li>
|
||||
<li><a href="#libbacktrace">libbacktrace</a></li>
|
||||
@@ -1910,6 +1911,7 @@ PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<!-- Transitive dependency of KDDockWidgets. -->
|
||||
<div id="jsonformoderncpp">
|
||||
<h3>JSON for Modern C++ - <a href="https://json.nlohmann.me">https://json.nlohmann.me</a></h3>
|
||||
<pre>
|
||||
@@ -1937,6 +1939,34 @@ SOFTWARE.
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<!-- Transitive dependency of KDDockWidgets. -->
|
||||
<div id="kdbindings">
|
||||
<h3>KDBindings - <a href="https://github.com/KDAB/KDBindings">https://github.com/KDAB/KDBindings</a></h3>
|
||||
<pre>
|
||||
MIT License
|
||||
|
||||
Copyright 2021 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
|
||||
Copyright 2021 Jeremy Burns
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<div id="kddockwidgets">
|
||||
<h3>KDDockWidgets - <a href="https://github.com/KDAB/KDDockWidgets">https://github.com/KDAB/KDDockWidgets</a></h3>
|
||||
<pre>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -110,48 +110,24 @@ uint ps_convert_rgba8_16bits(PS_INPUT input) : SV_Target0
|
||||
return ((i.x & 0x00F8u) >> 3) | ((i.y & 0x00F8u) << 2) | ((i.z & 0x00f8u) << 7) | ((i.w & 0x80u) << 8);
|
||||
}
|
||||
|
||||
PS_OUTPUT ps_datm1(PS_INPUT input)
|
||||
void ps_datm1(PS_INPUT input)
|
||||
{
|
||||
PS_OUTPUT output;
|
||||
|
||||
clip(sample_c(input.t).a - 127.5f / 255); // >= 0x80 pass
|
||||
|
||||
output.c = 0;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
PS_OUTPUT ps_datm0(PS_INPUT input)
|
||||
void ps_datm0(PS_INPUT input)
|
||||
{
|
||||
PS_OUTPUT output;
|
||||
|
||||
clip(127.5f / 255 - sample_c(input.t).a); // < 0x80 pass (== 0x80 should not pass)
|
||||
|
||||
output.c = 0;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
PS_OUTPUT ps_datm1_rta_correction(PS_INPUT input)
|
||||
void ps_datm1_rta_correction(PS_INPUT input)
|
||||
{
|
||||
PS_OUTPUT output;
|
||||
|
||||
clip(sample_c(input.t).a - 254.5f / 255); // >= 0x80 pass
|
||||
|
||||
output.c = 0;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
PS_OUTPUT ps_datm0_rta_correction(PS_INPUT input)
|
||||
void ps_datm0_rta_correction(PS_INPUT input)
|
||||
{
|
||||
PS_OUTPUT output;
|
||||
|
||||
clip(254.5f / 255 - sample_c(input.t).a); // < 0x80 pass (== 0x80 should not pass)
|
||||
|
||||
output.c = 0;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
PS_OUTPUT ps_rta_correction(PS_INPUT input)
|
||||
|
||||
@@ -104,7 +104,6 @@ void ps_datm1()
|
||||
{
|
||||
if(sample_c(v_tex).a < (127.5f / 255.0f)) // >= 0x80 pass
|
||||
discard;
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -10806,47 +10806,47 @@ Do you want to load this save and continue?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/Renderers/Common/GSRenderer.cpp" line="659"/>
|
||||
<location filename="../../pcsx2/GS/Renderers/Common/GSRenderer.cpp" line="658"/>
|
||||
<source>CAS is not available, your graphics driver does not support the required functionality.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/Renderers/Common/GSRenderer.cpp" line="714"/>
|
||||
<location filename="../../pcsx2/GS/Renderers/Common/GSRenderer.cpp" line="713"/>
|
||||
<source>with no compression</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/Renderers/Common/GSRenderer.cpp" line="721"/>
|
||||
<location filename="../../pcsx2/GS/Renderers/Common/GSRenderer.cpp" line="720"/>
|
||||
<source>with LZMA compression</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/Renderers/Common/GSRenderer.cpp" line="728"/>
|
||||
<location filename="../../pcsx2/GS/Renderers/Common/GSRenderer.cpp" line="727"/>
|
||||
<source>with Zstandard compression</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/Renderers/Common/GSRenderer.cpp" line="734"/>
|
||||
<location filename="../../pcsx2/GS/Renderers/Common/GSRenderer.cpp" line="733"/>
|
||||
<source>Saving {0} GS dump {1} to '{2}'</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/Renderers/Common/GSRenderer.cpp" line="735"/>
|
||||
<location filename="../../pcsx2/GS/Renderers/Common/GSRenderer.cpp" line="734"/>
|
||||
<source>single frame</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/Renderers/Common/GSRenderer.cpp" line="735"/>
|
||||
<location filename="../../pcsx2/GS/Renderers/Common/GSRenderer.cpp" line="734"/>
|
||||
<source>multi-frame</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/Renderers/Common/GSRenderer.cpp" line="755"/>
|
||||
<location filename="../../pcsx2/GS/Renderers/Common/GSRenderer.cpp" line="754"/>
|
||||
<source>Failed to render/download screenshot.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../pcsx2/GS/Renderers/Common/GSRenderer.cpp" line="766"/>
|
||||
<location filename="../../pcsx2/GS/Renderers/Common/GSRenderer.cpp" line="765"/>
|
||||
<source>Saved GS dump to '{}'.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
|
||||
@@ -4237,7 +4237,10 @@ void GSState::CalcAlphaMinMax(const int tex_alpha_min, const int tex_alpha_max)
|
||||
|
||||
if (IsCoverageAlpha())
|
||||
{
|
||||
min = 128;
|
||||
// HW renderer doesn't currently support AA, so its min is 128.
|
||||
// If we add AA support to the HW renderer, this will need to be changed.
|
||||
// (Will probably only be supported with ROV/FBFetch so we would want to check for that.)
|
||||
min = GSIsHardwareRenderer() ? 128 : 0;
|
||||
max = 128;
|
||||
}
|
||||
else
|
||||
|
||||
@@ -822,23 +822,6 @@ bool GSHwHack::GSC_MetalGearSolid3(GSRendererHW& r, int& skip)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GSHwHack::GSC_HitmanBloodMoney(GSRendererHW& r, int& skip)
|
||||
{
|
||||
// The game does a stupid thing where it backs up the last 2 pages of the framebuffer with shuffles, uploads a CT32 texture to it
|
||||
// then copies the RGB back (keeping the new alpha only). It's pretty gross, I have no idea why they didn't just upload a new alpha.
|
||||
// This is a real pain to emulate with the current state of things, so let's just clear the dirty area from the upload and pretend it wasn't there.
|
||||
|
||||
// Catch the first draw of the copy back.
|
||||
if (RFBP > 0 && RTPSM == PSMT8H && RFPSM == PSMCT32)
|
||||
{
|
||||
GSTextureCache::Target* target = g_texture_cache->FindOverlappingTarget(RFBP, RFBP + 1);
|
||||
if (target)
|
||||
target->m_dirty.clear();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GSHwHack::OI_PointListPalette(GSRendererHW& r, GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t)
|
||||
{
|
||||
const u32 n_vertices = r.m_vertex.next;
|
||||
@@ -1328,7 +1311,6 @@ const GSHwHack::Entry<GSRendererHW::GSC_Ptr> GSHwHack::s_get_skip_count_function
|
||||
CRC_F(GSC_NFSUndercover),
|
||||
CRC_F(GSC_PolyphonyDigitalGames),
|
||||
CRC_F(GSC_MetalGearSolid3),
|
||||
CRC_F(GSC_HitmanBloodMoney),
|
||||
CRC_F(GSC_Battlefield2),
|
||||
|
||||
// Channel Effect
|
||||
|
||||
@@ -26,7 +26,6 @@ public:
|
||||
static bool GSC_Battlefield2(GSRendererHW& r, int& skip);
|
||||
static bool GSC_PolyphonyDigitalGames(GSRendererHW& r, int& skip);
|
||||
static bool GSC_MetalGearSolid3(GSRendererHW& r, int& skip);
|
||||
static bool GSC_HitmanBloodMoney(GSRendererHW& r, int& skip);
|
||||
|
||||
static bool OI_PointListPalette(GSRendererHW& r, GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t);
|
||||
static bool OI_DBZBTGames(GSRendererHW& r, GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t);
|
||||
|
||||
@@ -3045,19 +3045,19 @@ void GSRendererHW::Draw()
|
||||
if (scale_draw == 1)
|
||||
{
|
||||
target_scale = 1.0f;
|
||||
m_downscale_source = src->m_from_target->GetScale() > 1.0f;
|
||||
m_downscale_source = src->m_from_target ? src->m_from_target->GetScale() > 1.0f : false;
|
||||
}
|
||||
else
|
||||
m_downscale_source = GSConfig.UserHacks_NativeScaling != GSNativeScaling::Aggressive ? false : src->m_from_target->GetScale() > 1.0f; // Bad for GTA + Full Spectrum Warrior, good for Sacred Blaze + Parappa.
|
||||
m_downscale_source = (GSConfig.UserHacks_NativeScaling != GSNativeScaling::Aggressive || !src->m_from_target) ? false : src->m_from_target->GetScale() > 1.0f; // Bad for GTA + Full Spectrum Warrior, good for Sacred Blaze + Parappa.
|
||||
}
|
||||
else
|
||||
{
|
||||
// if it's directly copying keep the scale - Ratchet and clank hits this, stops edge garbage happening.
|
||||
// Keep it to small targets of 256 or lower.
|
||||
if (scale_draw == -1 && src && src->m_from_target && src->m_from_target->m_downscaled && ((static_cast<int>(m_cached_ctx.FRAME.FBW * 64) <= (PCRTCDisplays.GetResolution().x >> 1) &&
|
||||
if (scale_draw == -1 && src && (!src->m_from_target || (src->m_from_target && src->m_from_target->m_downscaled)) && ((static_cast<int>(m_cached_ctx.FRAME.FBW * 64) <= (PCRTCDisplays.GetResolution().x >> 1) &&
|
||||
(GSVector4i(m_vt.m_min.p).xyxy() == GSVector4i(m_vt.m_min.t).xyxy()).alltrue() && (GSVector4i(m_vt.m_max.p).xyxy() == GSVector4i(m_vt.m_max.t).xyxy()).alltrue()) || possible_shuffle))
|
||||
{
|
||||
target_scale = src->m_from_target->GetScale();
|
||||
target_scale = src->m_from_target ? src->m_from_target->GetScale() : 1.0f;
|
||||
scale_draw = 1;
|
||||
scaled_copy = true;
|
||||
}
|
||||
@@ -3073,7 +3073,7 @@ void GSRendererHW::Draw()
|
||||
// This upscaling hack is for games which construct P8 textures by drawing a bunch of small sprites in C32,
|
||||
// then reinterpreting it as P8. We need to keep the off-screen intermediate textures at native resolution,
|
||||
// but not propagate that through to the normal render targets. Test Case: Crash Wrath of Cortex.
|
||||
if (no_ds && src && !m_channel_shuffle && src->m_from_target && (GSConfig.UserHacks_NativePaletteDraw || (src->m_from_target->m_downscaled && scale_draw <= 1)) &&
|
||||
if (no_ds && src && !m_channel_shuffle && src->m_from_target && (GSConfig.UserHacks_NativePaletteDraw || (src->m_target_direct && src->m_from_target->m_downscaled && scale_draw <= 1)) &&
|
||||
src->m_scale == 1.0f && (src->m_TEX0.PSM == PSMT8 || src->m_TEX0.TBP0 == m_cached_ctx.FRAME.Block()))
|
||||
{
|
||||
GL_CACHE("HW: Using native resolution for target based on texture source");
|
||||
@@ -3405,7 +3405,7 @@ void GSRendererHW::Draw()
|
||||
return;
|
||||
}
|
||||
|
||||
rt = g_texture_cache->CreateTarget(FRAME_TEX0, t_size, GetValidSize(src, possible_shuffle), (GSConfig.UserHacks_NativeScaling != GSNativeScaling::Off && scale_draw < 0 && is_possible_mem_clear != ClearType::NormalClear) ? src->m_from_target->GetScale() : target_scale,
|
||||
rt = g_texture_cache->CreateTarget(FRAME_TEX0, t_size, GetValidSize(src, possible_shuffle), (GSConfig.UserHacks_NativeScaling != GSNativeScaling::Off && scale_draw < 0 && is_possible_mem_clear != ClearType::NormalClear) ? ((src && src->m_from_target) ? src->m_from_target->GetScale() : (ds ? ds->m_scale : 1.0f)) : target_scale,
|
||||
GSTextureCache::RenderTarget, true, fm, false, force_preload, preserve_rt_color || possible_shuffle, lookup_rect, src);
|
||||
|
||||
if (!rt) [[unlikely]]
|
||||
@@ -4039,7 +4039,8 @@ void GSRendererHW::Draw()
|
||||
bool valid_width_change = false;
|
||||
if (rt && ((!is_possible_mem_clear || blending_cd) || rt->m_TEX0.PSM != FRAME_TEX0.PSM) && !m_in_target_draw)
|
||||
{
|
||||
valid_width_change = rt->m_TEX0.TBW != FRAME_TEX0.TBW;
|
||||
const u32 frame_mask = (m_cached_ctx.FRAME.FBMSK & frame_psm.fmsk);
|
||||
valid_width_change = rt->m_TEX0.TBW != FRAME_TEX0.TBW && (frame_mask != (frame_psm.fmsk & 0x00FFFFFF) || rt->m_valid_rgb == false);
|
||||
if (valid_width_change && !m_cached_ctx.ZBUF.ZMSK && (m_cached_ctx.FRAME.FBMSK & 0xFF000000))
|
||||
{
|
||||
// Alpha could be a font, and since the width is changing it's no longer valid.
|
||||
@@ -4178,6 +4179,10 @@ void GSRendererHW::Draw()
|
||||
|
||||
const int new_w = std::min(2048, std::max(new_size.x, std::max(rt ? rt->m_unscaled_size.x : 0, ds ? ds_size.x : 0)));
|
||||
const int new_h = std::min(2048, std::max(new_size.y, std::max(rt ? rt->m_unscaled_size.y : 0, ds ? ds_size.y : 0)));
|
||||
|
||||
const bool full_cover_clear = is_possible_mem_clear && GSLocalMemory::IsPageAligned(m_cached_ctx.FRAME.PSM, m_r) && m_r.x == 0 && m_r.y == 0 && !preserve_rt_rgb &&
|
||||
!IsPageCopy() && m_r.width() == (m_cached_ctx.FRAME.FBW * 64);
|
||||
|
||||
if (rt)
|
||||
{
|
||||
const u32 old_end_block = rt->m_end_block;
|
||||
@@ -4224,9 +4229,9 @@ void GSRendererHW::Draw()
|
||||
g_texture_cache->AddDirtyRectTarget(rt, GSVector4i(rt->m_valid.x, rt->m_valid.w, rt->m_valid.z, new_h), rt->m_TEX0.PSM, rt->m_TEX0.TBW, mask, false);
|
||||
g_texture_cache->GetTargetSize(rt->m_TEX0.TBP0, rt->m_TEX0.TBW, rt->m_TEX0.PSM, 0, new_h);
|
||||
}
|
||||
|
||||
rt->ResizeValidity(rt->m_valid.rintersect(rt->GetUnscaledRect()));
|
||||
rt->ResizeDrawn(rt->m_drawn_since_read.rintersect(rt->GetUnscaledRect()));
|
||||
const bool rt_cover = full_cover_clear && (m_r.height() + frame_psm.pgs.y) >= rt->m_valid.height();
|
||||
rt->ResizeValidity(rt_cover ? update_rect : rt->m_valid.rintersect(rt->GetUnscaledRect()));
|
||||
rt->ResizeDrawn(rt_cover ? update_rect : rt->m_drawn_since_read.rintersect(rt->GetUnscaledRect()));
|
||||
}
|
||||
|
||||
const bool rt_update = can_update_size || (m_texture_shuffle && (src && rt && src->m_from_target != rt));
|
||||
@@ -4234,7 +4239,7 @@ void GSRendererHW::Draw()
|
||||
// If it's updating from a texture shuffle, limit the size to the source size.
|
||||
if (rt_update && !can_update_size)
|
||||
{
|
||||
if(src->m_from_target)
|
||||
if (src->m_from_target)
|
||||
update_rect = update_rect.rintersect(src->m_from_target->m_valid);
|
||||
|
||||
update_rect = update_rect.rintersect(GSVector4i::loadh(GSVector2i(new_w, new_h)));
|
||||
@@ -4304,16 +4309,18 @@ void GSRendererHW::Draw()
|
||||
DevCon.Warning("HW: Temporary depth buffer creation failed.");
|
||||
}
|
||||
}
|
||||
const bool z_masked = m_cached_ctx.ZBUF.ZMSK;
|
||||
|
||||
if (!m_texture_shuffle && !m_channel_shuffle)
|
||||
{
|
||||
ds->ResizeValidity(ds->GetUnscaledRect());
|
||||
ds->ResizeDrawn(ds->GetUnscaledRect());
|
||||
const bool z_cover = full_cover_clear && (m_r.height() + GSLocalMemory::m_psm[m_cached_ctx.ZBUF.PSM].pgs.y) >= ds->m_valid.height();
|
||||
ds->ResizeValidity(z_cover ? m_r : ds->GetUnscaledRect());
|
||||
ds->ResizeDrawn(z_cover ? m_r : ds->GetUnscaledRect());
|
||||
}
|
||||
|
||||
// Limit to 2x the vertical height of the resolution (for double buffering)
|
||||
// Dark cloud writes to 424 when the buffer is only 416 high, but masks the Z.
|
||||
// Updating the valid causes the Z to overlap the framebuffer, which is obviously incorrect.
|
||||
const bool z_masked = m_cached_ctx.ZBUF.ZMSK;
|
||||
const bool z_update = can_update_size && !z_masked;
|
||||
|
||||
if (rt && m_using_temp_z)
|
||||
@@ -8974,6 +8981,9 @@ bool GSRendererHW::TextureCoversWithoutGapsNotEqual()
|
||||
|
||||
int GSRendererHW::IsScalingDraw(GSTextureCache::Source* src, bool no_gaps)
|
||||
{
|
||||
if (GSConfig.UserHacks_NativeScaling == GSNativeScaling::Off)
|
||||
return 0;
|
||||
|
||||
const GSVector2i draw_size = GSVector2i(m_vt.m_max.p.x - m_vt.m_min.p.x, m_vt.m_max.p.y - m_vt.m_min.p.y);
|
||||
GSVector2i tex_size = GSVector2i(m_vt.m_max.t.x - m_vt.m_min.t.x, m_vt.m_max.t.y - m_vt.m_min.t.y);
|
||||
|
||||
@@ -8984,10 +8994,13 @@ int GSRendererHW::IsScalingDraw(GSTextureCache::Source* src, bool no_gaps)
|
||||
|
||||
// Try to catch cases of stupid draws like Manhunt and Syphon Filter where they sample a single pixel.
|
||||
// Also make sure it's grabbing most of the texture.
|
||||
if (tex_size.x == 0 || tex_size.y == 0 || draw_size.x == 0 || draw_size.y == 0 || !is_target_src)
|
||||
if (tex_size.x == 0 || tex_size.y == 0 || draw_size.x == 0 || draw_size.y == 0)
|
||||
return 0;
|
||||
|
||||
if (is_target_src && src->m_from_target->m_downscaled && std::abs(draw_size.x - tex_size.x) <= 1 && std::abs(draw_size.y - tex_size.y) <= 1)
|
||||
const bool no_resize = (std::abs(draw_size.x - tex_size.x) <= 1 && std::abs(draw_size.y - tex_size.y) <= 1);
|
||||
const bool can_maintain = no_resize || (!is_target_src && m_index.tail == 2);
|
||||
|
||||
if (!src || ((!is_target_src || src->m_from_target->m_downscaled) && can_maintain))
|
||||
return -1;
|
||||
|
||||
const GSDrawingContext& next_ctx = m_env.CTXT[m_env.PRIM.CTXT];
|
||||
@@ -9000,8 +9013,9 @@ int GSRendererHW::IsScalingDraw(GSTextureCache::Source* src, bool no_gaps)
|
||||
const bool is_downscale = m_cached_ctx.TEX0.TBW >= m_cached_ctx.FRAME.FBW && draw_size.x <= (tex_size.x * 0.75f) && draw_size.y <= (tex_size.y * 0.75f);
|
||||
// Check we're getting most of the texture and not just stenciling a part of it.
|
||||
// Only allow non-bilineared downscales if it's most of the target (misdetections of shadows in Naruto, Transformers etc), otherwise it's fine.
|
||||
const GSVector2i tex_size_half = GSVector2i((src->GetRegion().HasX() ? src->GetRegionSize().x : src->m_from_target->m_valid.width()) / 2, (src->GetRegion().HasY() ? src->GetRegionSize().y : src->m_from_target->m_valid.height()) / 2);
|
||||
const bool possible_downscale = m_context->TEX1.MMAG == 1 || src->m_from_target->m_downscaled || tex_size.x >= tex_size_half.x || tex_size.y >= tex_size_half.y;
|
||||
const GSVector4i src_valid = src->m_from_target ? src->m_from_target->m_valid : src->m_valid_rect;
|
||||
const GSVector2i tex_size_half = GSVector2i((src->GetRegion().HasX() ? src->GetRegionSize().x : src_valid.width()) / 2, (src->GetRegion().HasY() ? src->GetRegionSize().y : src_valid.height()) / 2);
|
||||
const bool possible_downscale = m_context->TEX1.MMIN == 1 || !src->m_from_target || src->m_from_target->m_downscaled || tex_size.x >= tex_size_half.x || tex_size.y >= tex_size_half.y;
|
||||
|
||||
if (is_downscale && (draw_size.x >= PCRTCDisplays.GetResolution().x || !possible_downscale))
|
||||
return 0;
|
||||
@@ -9019,6 +9033,39 @@ int GSRendererHW::IsScalingDraw(GSTextureCache::Source* src, bool no_gaps)
|
||||
return is_upscale ? 2 : 1;
|
||||
}
|
||||
|
||||
// Last ditched check if it's doing a lot of small draws exactly the same which could be recursive lighting bloom.
|
||||
if (m_vt.m_primclass == GS_SPRITE_CLASS && m_index.tail > 2 && !no_gaps_or_single_sprite && m_context->TEX1.MMAG == 1 && !m_context->ALPHA.IsOpaque())
|
||||
{
|
||||
GSVertex* v = &m_vertex.buff[0];
|
||||
float tw = 1 << src->m_TEX0.TW;
|
||||
float th = 1 << src->m_TEX0.TH;
|
||||
|
||||
const int first_u = (PRIM->FST) ? (v[1].U - v[0].U) >> 4 : std::floor(static_cast<int>(tw * v[1].ST.S) - static_cast<int>(tw * v[0].ST.S));
|
||||
const int first_v = (PRIM->FST) ? (v[1].V - v[0].V) >> 4 : std::floor(static_cast<int>(th * v[1].ST.T) - static_cast<int>(th * v[0].ST.T));
|
||||
const int first_x = (v[1].XYZ.X - v[0].XYZ.X) >> 4;
|
||||
const int first_y = (v[1].XYZ.Y - v[0].XYZ.Y) >> 4;
|
||||
|
||||
if (first_x > first_u && first_y > first_v && !no_resize && std::abs(draw_size.x - first_x) <= 4 && std::abs(draw_size.y - first_y) <= 4)
|
||||
{
|
||||
for (u32 i = 2; i < m_index.tail; i += 2)
|
||||
{
|
||||
const int next_u = (PRIM->FST) ? (v[i + 1].U - v[i].U) >> 4 : std::floor(static_cast<int>(tw * v[i + 1].ST.S) - static_cast<int>(tw * v[i].ST.S));
|
||||
const int next_v = (PRIM->FST) ? (v[i + 1].V - v[i].V) >> 4 : std::floor(static_cast<int>(th * v[i + 1].ST.T) - static_cast<int>(th * v[i].ST.T));
|
||||
const int next_x = (v[i + 1].XYZ.X - v[i].XYZ.X) >> 4;
|
||||
const int next_y = (v[i + 1].XYZ.Y - v[i].XYZ.Y) >> 4;
|
||||
|
||||
if (std::abs(draw_size.x - next_x) > 4 || std::abs(draw_size.y - next_y) > 4)
|
||||
break;
|
||||
|
||||
if (next_u != first_u || next_v != first_v || next_x != first_x || next_y != first_y)
|
||||
break;
|
||||
|
||||
if (i + 2 >= m_index.tail)
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -424,7 +424,7 @@ GSVector4i GSTextureCache::TranslateAlignedRectByPage(u32 tbp, u32 tebp, u32 tbw
|
||||
}
|
||||
}
|
||||
}
|
||||
else // Widths match
|
||||
else if (!block_offset) // Widths match
|
||||
{
|
||||
const int horizontal_dst_page_offset = page_offset % clamped_tbw;
|
||||
const int vertical_dst_page_offset = page_offset / clamped_tbw;
|
||||
@@ -1626,14 +1626,12 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
|
||||
{
|
||||
// It is a complex to convert the code in shader. As a reference, let's do it on the CPU,
|
||||
// it will be slow but can work even with upscaling, also fine tune it so it's not enabled when not needed.
|
||||
if (psm == PSMT4 || (GSConfig.UserHacks_CPUFBConversion && psm == PSMT8 && (!possible_shuffle || GSLocalMemory::m_psm[t->m_TEX0.PSM].bpp != 32)) ||
|
||||
(psm == PSMT8H && GSLocalMemory::m_psm[t->m_TEX0.PSM].bpp == 16))
|
||||
if (psm == PSMT4 || (psm == PSMT8H && GSLocalMemory::m_psm[t->m_TEX0.PSM].bpp == 16))
|
||||
{
|
||||
// Forces 4-bit and 8-bit frame buffer conversion to be done on the CPU instead of the GPU, but performance will be slower.
|
||||
// There is no dedicated shader to handle 4-bit conversion (Beyond Good and Evil and Stuntman).
|
||||
// Enable readbacks on PSMT4 as we don't have a dedicated shader (Beyond Good and Evil and Stuntman).
|
||||
// Enable readbacks on PSMT8H 16bit as we don't have a dedicated shader (History Channel - Battle for the Pacific, Sea World - Shamu's Big Adventure).
|
||||
// Note: Stuntman no longer hits the PSMT4 code path.
|
||||
// Direct3D10/11 and OpenGL support 8-bit fb conversion but don't render some corner cases properly (Harry Potter games).
|
||||
// The hack can fix glitches in some games.
|
||||
// Note2: Harry Potter is now properly handled with shader conversion and no need to enable frame buffer conversion.
|
||||
if (!t->m_drawn_since_read.rempty())
|
||||
{
|
||||
t->UnscaleRTAlpha();
|
||||
@@ -2043,11 +2041,29 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
|
||||
{
|
||||
rect.y /= 2;
|
||||
rect.w /= 2;
|
||||
|
||||
if (region.HasY())
|
||||
{
|
||||
const u32 min_y = region.GetMinY() / 2;
|
||||
const u32 max_y = region.GetMaxY() / 2;
|
||||
|
||||
region.ClearY();
|
||||
region.SetY(min_y, max_y);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rect.x /= 2;
|
||||
rect.z /= 2;
|
||||
|
||||
if (region.HasX())
|
||||
{
|
||||
const u32 min_x = region.GetMinX() / 2;
|
||||
const u32 max_x = region.GetMaxX() / 2;
|
||||
|
||||
region.ClearX();
|
||||
region.SetX(min_x, max_x);
|
||||
}
|
||||
}
|
||||
if (TEX0.TBP0 == frame.Block())
|
||||
{
|
||||
|
||||
@@ -45,6 +45,9 @@ public:
|
||||
bool HasY() const { return static_cast<u32>(bits >> 32) != 0; }
|
||||
bool HasEither() const { return (bits != 0); }
|
||||
|
||||
void ClearX() { bits &= ~0xFFFFFFFFULL; }
|
||||
void ClearY() { bits &= 0xFFFFFFFFULL; }
|
||||
|
||||
void SetX(s32 min, s32 max) { bits |= (static_cast<u64>(static_cast<u16>(min)) | (static_cast<u64>(static_cast<u16>(max) << 16))); }
|
||||
void SetY(s32 min, s32 max) { bits |= ((static_cast<u64>(static_cast<u16>(min)) << 32) | (static_cast<u64>(static_cast<u16>(max)) << 48)); }
|
||||
|
||||
|
||||
@@ -416,10 +416,10 @@ __ri void ImGuiManager::DrawSettingsOverlay(float scale, float margin, float spa
|
||||
|
||||
APPEND("B={} PL={} ", static_cast<unsigned>(GSConfig.AccurateBlendingUnit), static_cast<unsigned>(GSConfig.TexturePreloading));
|
||||
if (GSConfig.GPUPaletteConversion)
|
||||
APPEND("PT ");
|
||||
APPEND("PLTX ");
|
||||
|
||||
if (GSConfig.HWDownloadMode != GSHardwareDownloadMode::Enabled)
|
||||
APPEND("DL={} ", static_cast<unsigned>(GSConfig.HWDownloadMode));
|
||||
APPEND("HWDM={} ", static_cast<unsigned>(GSConfig.HWDownloadMode));
|
||||
|
||||
if (GSConfig.HWMipmap)
|
||||
APPEND("MM ");
|
||||
@@ -466,7 +466,7 @@ __ri void ImGuiManager::DrawSettingsOverlay(float scale, float margin, float spa
|
||||
if (GSConfig.UserHacks_CPUFBConversion)
|
||||
APPEND("FBC ");
|
||||
if (GSConfig.UserHacks_ReadTCOnClose)
|
||||
APPEND("FTC ");
|
||||
APPEND("RTOC ");
|
||||
if (GSConfig.UserHacks_DisableDepthSupport)
|
||||
APPEND("DDC ");
|
||||
if (GSConfig.UserHacks_DisablePartialInvalidation)
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
|
||||
/// Version number for GS and other shaders. Increment whenever any of the contents of the
|
||||
/// shaders change, to invalidate the cache.
|
||||
static constexpr u32 SHADER_CACHE_VERSION = 66;
|
||||
static constexpr u32 SHADER_CACHE_VERSION = 67;
|
||||
|
||||
Reference in New Issue
Block a user