Compare commits

...

18 Commits

Author SHA1 Message Date
refractionpcsx2
cbe20c0eed GS/HW: Fix dirty check on SWPrimRenderer check 2025-06-23 06:27:41 +02:00
refractionpcsx2
ec288ffa62 GS/TC: Fix CanTranslate rect BWs, disallow block inside target lookup 2025-06-23 06:27:41 +02:00
JordanTheToaster
7e18c02c7e GameDB: Xenosaga Episode III fixes 2025-06-23 06:27:13 +02:00
twingofan
4a505cc239 GameDB: Add memcardFilters to Armored Core: Last Raven NTSC-U SLUS-21338. (#12891) 2025-06-23 06:26:16 +02:00
Kuan-Wei Chiu
35c81106c6 Fix invalid comparator in FullscreenUI game list sort
The game list comparator previously used >= when sorting by CRC in
descending order. This violates the requirements of a strict weak
ordering, as defined by the C++ standard, which mandates that the
comparator must be irreflexive: comp(x, x) must always return false.

Using >= causes comp(a, b) and comp(b, a) to both return true when
a == b, which breaks the irreflexivity and can invalidate the
assumptions made by std::sort. This may lead to undefined behavior,
including memory corruption or segmentation faults.

Replace >= with > to ensure the comparator satisfies the strict weak
ordering requirement, restoring correctness and stability in game list
sorting behavior.
2025-06-22 14:44:34 -04:00
Ziemas
1094222d3f Debugger: Don't check frame count in isAlive 2025-06-22 20:19:13 +02:00
TheLastRar
065d0db4c9 FSUI: Replace various icons with SVG files
Co-Authored-By: KamFretoZ <14798312+kamfretoz@users.noreply.github.com>
2025-06-22 20:15:03 +02:00
JordanTheToaster
bc51537080 GS/HW: Purge Hitman Blood Money CRC 2025-06-22 20:14:09 +02:00
JordanTheToaster
b7dfcb282b ImGuiOverlays: Minor OSD text changes 2025-06-22 20:14:09 +02:00
JordanTheToaster
78a9411766 GameDB: Various Fixes Part 5 2025-06-22 20:14:09 +02:00
TellowKrinkle
4724f67596 GS: Min alpha for AA1 is 0, not 128 2025-06-22 20:13:15 +02:00
JordanTheToaster
e0851bb86f [ci skip] Github: Update app bug report OS list 2025-06-21 22:00:10 -04:00
JordanTheToaster
08e68d9563 GitHub: Update bug report OS list 2025-06-21 15:50:02 -04:00
refractionpcsx2
0b6dccae51 GS/HW: Resize validity to draw size when most of target is covered 2025-06-21 05:52:50 +02:00
refractionpcsx2
60adfd5046 GS/TC: Fix region area on new source interpreted for shuffle 2025-06-21 05:52:50 +02:00
chaoticgd
3e782d355d Docs: Add missing third party license for KDBindings 2025-06-20 22:22:51 +02:00
PCSX2 Bot
22a7324b69 [ci skip] Qt: Update Base Translation. 2025-06-20 02:02:47 +02:00
refractionpcsx2
f3b4c50909 GS/HW: Improve Native Scaling detection + Include direct mem reads 2025-06-20 02:02:30 +02:00
34 changed files with 1551 additions and 1159 deletions

View File

@@ -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)

View File

@@ -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

View File

@@ -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 &lt;info@kdab.com&gt;
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 &quot;Software&quot;), 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 &quot;AS IS&quot;, 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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

View File

@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg
fill="#000000"
width="800px"
height="800px"
viewBox="0 0 32 32"
version="1.1"
id="svg1"
sodipodi:docname="applications-system.svg"
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#505050"
bordercolor="#ffffff"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="1"
inkscape:deskcolor="#505050"
inkscape:zoom="0.97875"
inkscape:cx="399.48914"
inkscape:cy="400"
inkscape:window-width="1920"
inkscape:window-height="1010"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg1" />
<defs
id="defs1" />
<path
d="M30.015 12.97l-2.567-0.569c-0.2-0.64-0.462-1.252-0.762-1.841l1.389-2.313c0.518-0.829 0.78-2.047 0-2.829l-1.415-1.414c-0.78-0.781-2.098-0.64-2.894-0.088l-2.251 1.434c-0.584-0.303-1.195-0.563-1.829-0.768l-0.576-2.598c-0.172-0.953-1.005-1.984-2.11-1.984h-2c-1.104 0-1.781 1.047-2 2l-0.642 2.567c-0.678 0.216-1.328 0.492-1.948 0.819l-2.308-1.47c-0.795-0.552-2.114-0.692-2.894 0.088l-1.415 1.414c-0.781 0.782-0.519 2 0 2.828l1.461 2.435c-0.274 0.552-0.517 1.123-0.705 1.72l-2.566 0.569c-0.953 0.171-1.984 1.005-1.984 2.109v2c0 1.105 1.047 1.782 2 2l2.598 0.649c0.179 0.551 0.404 1.080 0.658 1.593l-1.462 2.438c-0.518 0.828-0.78 2.047 0 2.828l1.415 1.414c0.78 0.782 2.098 0.64 2.894 0.089l2.313-1.474c0.623 0.329 1.277 0.608 1.96 0.823l0.64 2.559c0.219 0.953 0.896 2 2 2h2c1.105 0 1.938-1.032 2.11-1.985l0.577-2.604c0.628-0.203 1.23-0.459 1.808-0.758l2.256 1.438c0.796 0.552 2.114 0.692 2.895-0.089l1.415-1.414c0.78-0.782 0.518-2 0-2.828l-1.39-2.317c0.279-0.549 0.521-1.12 0.716-1.714l2.599-0.649c0.953-0.219 2-0.895 2-2v-2c0-1.104-1.031-1.938-1.985-2.11zM30.001 16.939c-0.085 0.061-0.245 0.145-0.448 0.192l-3.708 0.926-0.344 1.051c-0.155 0.474-0.356 0.954-0.597 1.428l-0.502 0.986 1.959 3.267c0.125 0.2 0.183 0.379 0.201 0.485l-1.316 1.314c-0.127-0.040-0.271-0.092-0.341-0.14l-3.292-2.099-1.023 0.529c-0.493 0.256-0.999 0.468-1.503 0.631l-1.090 0.352-0.824 3.723c-0.038 0.199-0.145 0.36-0.218 0.417h-1.8c-0.061-0.085-0.145-0.245-0.191-0.448l-0.921-3.681-1.066-0.338c-0.549-0.173-1.097-0.404-1.63-0.684l-1.028-0.543-3.293 2.099c-0.135 0.091-0.279 0.143-0.409 0.143l-1.311-1.276c0.018-0.104 0.072-0.274 0.181-0.449l2.045-3.408-0.487-0.98c-0.227-0.462-0.407-0.895-0.547-1.325l-0.343-1.052-3.671-0.918c-0.231-0.052-0.398-0.139-0.485-0.2v-1.86c0.001 0.001 0.002 0.001 0.005 0.001 0.034 0 0.198-0.117 0.335-0.142l3.772-0.835 0.346-1.103c0.141-0.449 0.333-0.917 0.588-1.43l0.487-0.98-2.024-3.373c-0.125-0.201-0.184-0.38-0.201-0.485l1.315-1.314c0.128 0.041 0.271 0.093 0.34 0.14l3.354 2.138 1.027-0.542c0.527-0.278 1.073-0.507 1.622-0.682l1.063-0.338 0.912-3.649c0.053-0.231 0.138-0.398 0.2-0.485h1.859c-0.014 0.020 0.115 0.195 0.142 0.339l0.84 3.794 1.089 0.352c0.511 0.165 1.023 0.38 1.523 0.639l1.023 0.532 3.224-2.053c0.135-0.092 0.279-0.143 0.409-0.143l1.313 1.276c-0.017 0.104-0.072 0.276-0.181 0.45l-1.98 3.296 0.505 0.988c0.273 0.533 0.48 1.033 0.635 1.529l0.346 1.104 3.697 0.82c0.224 0.041 0.398 0.171 0.434 0.241zM16.013 9.99c-3.321 0-6.023 2.697-6.023 6.010s2.702 6.010 6.023 6.010 6.023-2.697 6.023-6.009c0-3.313-2.702-6.010-6.023-6.010zM16 20c-2.205 0-4-1.794-4-4s1.794-4 4-4c2.206 0 4 1.794 4 4s-1.794 4-4 4z"
id="path1"
style="fill:#ffffff" />
</svg>

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

View File

@@ -0,0 +1,7 @@
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools -->
<svg fill="#ffffff" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="800px" height="800px" viewBox="0 0 72 72" enable-background="new 0 0 72 72" xml:space="preserve">
<g id="SVGRepo_bgCarrier" stroke-width="0"/>
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -0,0 +1,7 @@
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools -->
<svg fill="#ffffff" width="800px" height="800px" viewBox="0 0 16 16" id="window-16px" xmlns="http://www.w3.org/2000/svg">
<g id="SVGRepo_bgCarrier" stroke-width="0"/>
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -0,0 +1,7 @@
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools -->
<svg fill="#ffffff" height="800px" width="800px" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 512 512" xml:space="preserve">
<g id="SVGRepo_bgCarrier" stroke-width="0"/>
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

View File

@@ -0,0 +1,7 @@
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools -->
<svg width="800px" height="800px" viewBox="0 0 24 24" id="SVGRoot" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:svg="http://www.w3.org/2000/svg" fill="#ffffff">
<g id="SVGRepo_bgCarrier" stroke-width="0"/>
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

View File

@@ -0,0 +1,7 @@
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools -->
<svg height="800px" width="800px" version="1.1" id="_x32_" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 512 512" xml:space="preserve" fill="#ffffff">
<g id="SVGRepo_bgCarrier" stroke-width="0"/>
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 KiB

View File

@@ -0,0 +1,7 @@
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools -->
<svg fill="#ffffff" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="800px" height="800px" viewBox="0 0 72 72" enable-background="new 0 0 72 72" xml:space="preserve">
<g id="SVGRepo_bgCarrier" stroke-width="0"/>
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -0,0 +1,9 @@
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools -->
<svg fill="#ffffff" width="800px" height="800px" viewBox="-2 -2 24 24" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMinYMin" class="jam jam-microchip">
<g id="SVGRepo_bgCarrier" stroke-width="0"/>
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>
<g id="SVGRepo_iconCarrier">

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

View File

@@ -0,0 +1,7 @@
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools -->
<svg width="800px" height="800px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#000000">
<g id="SVGRepo_bgCarrier" stroke-width="0"/>
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -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 &apos;{2}&apos;</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 &apos;{}&apos;.</source>
<translation type="unfinished"></translation>
</message>

View File

@@ -44,7 +44,7 @@ bool DebugInterface::m_pause_on_entry = false;
bool DebugInterface::isAlive()
{
return VMManager::HasValidVM() && g_FrameCount > 0;
return VMManager::HasValidVM();
}
bool DebugInterface::isCpuPaused()

View File

@@ -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

View File

@@ -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

View File

@@ -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);

View File

@@ -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]]
@@ -4179,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;
@@ -4225,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));
@@ -4235,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)));
@@ -4305,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)
@@ -8179,7 +8185,7 @@ bool GSRendererHW::CanUseSwPrimRender(bool no_rt, bool no_ds, bool draw_sprite_t
if (start_bp < dirty_end_bp && end_bp > dirty_start_bp)
{
if (dirty_start_bp > start_bp || dirty_end_bp < end_bp)
if (dirty_start_bp <= start_bp && dirty_end_bp >= end_bp)
{
return true;
}
@@ -8975,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);
@@ -8985,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];
@@ -9001,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;
@@ -9020,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;
}

View File

@@ -228,19 +228,22 @@ bool GSTextureCache::CanTranslate(u32 bp, u32 bw, u32 spsm, GSVector4i r, u32 db
{
const GSVector2i src_page_size = GSLocalMemory::m_psm[spsm].pgs;
const GSVector2i dst_page_size = GSLocalMemory::m_psm[dpsm].pgs;
const u32 src_bw = std::max(1U, bw);
const u32 dst_bw = std::max(1U, dbw);
const bool block_layout_match = GSLocalMemory::m_psm[spsm].bpp == GSLocalMemory::m_psm[dpsm].bpp;
const bool bp_page_aligned_bp = ((bp & ~((1 << 5) - 1)) == bp) || bp == dbp || (block_layout_match && bw == dbw);
const bool bp_page_aligned_bp = ((bp & ~((1 << 5) - 1)) == bp) || bp == dbp || (block_layout_match && src_bw == dst_bw);
const GSVector4i page_mask(GSVector4i((src_page_size.x - 1), (src_page_size.y - 1)).xyxy());
const GSVector4i masked_rect(r & ~page_mask);
const int src_pixel_width = static_cast<int>(bw * 64);
const int src_pixel_width = src_bw * 64;
const int dst_pixel_width = dst_bw * 64;
// We can do this if:
// The page width matches.
// The rect width is less than the width of the destination texture and the height is less than or equal to 1 page high.
// The rect width and height is equal to the page size and it covers the width of the incoming bw, so lines are sequential.
const bool page_aligned_rect = masked_rect.xyxy().eq(r.xyxy());
const bool width_match = ((bw * 64) / src_page_size.x) == ((dbw * 64) / dst_page_size.x);
const bool width_match = (src_pixel_width / src_page_size.x) == (dst_pixel_width / dst_page_size.x);
const bool sequential_pages = page_aligned_rect && r.x == 0 && r.z == src_pixel_width;
const bool single_row = (((bw * 64) / src_page_size.x) <= ((dbw * 64) / dst_page_size.x)) && r.width() <= src_pixel_width && r.height() <= src_page_size.y;
const bool single_row = ((src_pixel_width / src_page_size.x) <= (dst_pixel_width / dst_page_size.x)) && r.width() <= src_pixel_width && r.height() <= src_page_size.y;
const bool single_page_aligned = page_aligned_rect && r.z <= src_page_size.x && r.w <= src_page_size.y;
if (block_layout_match)
{
@@ -300,7 +303,7 @@ GSVector4i GSTextureCache::TranslateAlignedRectByPage(u32 tbp, u32 tebp, u32 tbw
return GSVector4i::zero();
}
const bool block_matched_format = s_psm.bpp == t_psm.bpp && (sbw == tbw || sbw == 1);
const bool block_matched_format = s_psm.bpp == t_psm.bpp && (clamped_sbw == clamped_tbw || clamped_sbw == 1);
// If there is block offset left over, try to adjust to that.
if (block_matched_format)
{
@@ -431,6 +434,8 @@ GSVector4i GSTextureCache::TranslateAlignedRectByPage(u32 tbp, u32 tebp, u32 tbw
GSVector4i offset_rect(horizontal_dst_page_offset * t_psm.pgs.x, vertical_dst_page_offset * t_psm.pgs.y);
new_rect = in_rect + offset_rect.xyxy();
}
else
new_rect = in_rect;
if (new_rect.z > dst_bw)
{
@@ -1320,7 +1325,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const
// If the BP is offset in to a page and the format does not match, trying to match up the correct position is very difficult since we don't swizzle.
// Tomb Raider Legends does a block level BP in PSMT8 over a C16 target, which is just a nightmare to get right.
// Baldurs Gate used to have this too, but now we can translate HW moves inside targets when the format matches.
if (((bp & (BLOCKS_PER_PAGE - 1)) != (t->m_TEX0.TBP0 & (BLOCKS_PER_PAGE - 1))) && (bp & (BLOCKS_PER_PAGE - 1)) && !CanTranslate(bp, bw, psm, block_boundary_rect, t->m_TEX0.TBP0, t->m_TEX0.PSM, t->m_TEX0.TBW))
if (((bp & (BLOCKS_PER_PAGE - 1)) != (t->m_TEX0.TBP0 & (BLOCKS_PER_PAGE - 1))) && (bp & (BLOCKS_PER_PAGE - 1)))
continue;
const bool width_match = (std::max(64U, bw * 64U) >> GSLocalMemory::m_psm[psm].info.pageShiftX()) ==
@@ -2041,11 +2046,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())
{

View File

@@ -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)); }

View File

@@ -139,6 +139,7 @@ using ImGuiFullscreen::GetCachedTextureAsync;
using ImGuiFullscreen::GetPlaceholderTexture;
using ImGuiFullscreen::GetQueuedFocusResetType;
using ImGuiFullscreen::HorizontalMenuItem;
using ImGuiFullscreen::HorizontalMenuSvgItem;
using ImGuiFullscreen::IsFocusResetQueued;
using ImGuiFullscreen::IsGamepadInputSource;
using ImGuiFullscreen::LayoutScale;
@@ -271,8 +272,6 @@ namespace FullscreenUI
static std::array<std::shared_ptr<GSTexture>, static_cast<u32>(GameDatabaseSchema::Compatibility::Perfect)>
s_game_compatibility_textures;
static std::shared_ptr<GSTexture> s_banner_texture;
static std::shared_ptr<GSTexture> s_fallback_disc_texture;
static std::shared_ptr<GSTexture> s_fallback_exe_texture;
static std::vector<std::unique_ptr<GSTexture>> s_cleanup_textures;
//////////////////////////////////////////////////////////////////////////
@@ -476,9 +475,13 @@ namespace FullscreenUI
static void DrawGameListSettingsWindow();
static void SwitchToGameList();
static void PopulateGameListEntryList();
static GSTexture* GetTextureForGameListEntryType(GameList::EntryType type);
static GSTexture* GetTextureForGameListEntryType(GameList::EntryType type, const ImVec2& size, SvgScaling mode = SvgScaling::Stretch);
static GSTexture* GetGameListCover(const GameList::Entry* entry);
static GSTexture* GetCoverForCurrentGame();
static void DrawGameCover(const GameList::Entry* entry, const ImVec2& size);
static void DrawGameCover(const GameList::Entry* entry, ImDrawList* draw_list, const ImVec2& min, const ImVec2& max);
// For when we have no GameList entry
static void DrawFallbackCover(const ImVec2& size);
static void DrawFallbackCover(ImDrawList* draw_list, const ImVec2& min, const ImVec2& max);
// Lazily populated cover images.
static std::unordered_map<std::string, std::string> s_cover_image_map;
@@ -1107,9 +1110,6 @@ void FullscreenUI::ReturnToMainWindow()
bool FullscreenUI::LoadResources()
{
s_fallback_disc_texture = LoadTexture("fullscreenui/media-cdrom.png");
s_fallback_exe_texture = LoadTexture("fullscreenui/applications-system.png");
return LoadSvgResources();
}
@@ -1128,8 +1128,6 @@ bool FullscreenUI::LoadSvgResources()
void FullscreenUI::DestroyResources()
{
s_fallback_exe_texture.reset();
s_fallback_disc_texture.reset();
s_banner_texture.reset();
for (auto& tex : s_game_compatibility_textures)
tex.reset();
@@ -1457,27 +1455,26 @@ void FullscreenUI::DrawLandingWindow()
{
ResetFocusHere();
if (HorizontalMenuItem(GetCachedTexture("fullscreenui/game-list.png"), FSUI_CSTR("Game List"),
if (HorizontalMenuSvgItem("fullscreenui/game-list.svg", FSUI_CSTR("Game List"),
FSUI_CSTR("Launch a game from images scanned from your game directories.")))
{
SwitchToGameList();
}
if (HorizontalMenuItem(
GetCachedTexture("fullscreenui/media-cdrom.png"), FSUI_CSTR("Start Game"),
if (HorizontalMenuSvgItem("fullscreenui/media-cdrom.svg", FSUI_CSTR("Start Game"),
FSUI_CSTR("Launch a game from a file, disc, or starts the console without any disc inserted.")))
{
s_current_main_window = MainWindowType::StartGame;
QueueResetFocus(FocusResetType::WindowChanged);
}
if (HorizontalMenuItem(GetCachedTexture("fullscreenui/applications-system.png"), FSUI_CSTR("Settings"),
if (HorizontalMenuSvgItem("fullscreenui/applications-system.svg", FSUI_CSTR("Settings"),
FSUI_CSTR("Changes settings for the application.")))
{
SwitchToSettings();
}
if (HorizontalMenuItem(GetCachedTexture("fullscreenui/exit.png"), FSUI_CSTR("Exit"),
if (HorizontalMenuSvgItem("fullscreenui/exit.svg", FSUI_CSTR("Exit"),
FSUI_CSTR("Return to desktop mode, or exit the application.")) ||
(!AreAnyDialogsOpen() && WantsToCloseMenu()))
{
@@ -1536,26 +1533,25 @@ void FullscreenUI::DrawStartGameWindow()
{
ResetFocusHere();
if (HorizontalMenuItem(GetCachedTexture("fullscreenui/start-file.png"), FSUI_CSTR("Start File"),
if (HorizontalMenuSvgItem("fullscreenui/start-file.svg", FSUI_CSTR("Start File"),
FSUI_CSTR("Launch a game by selecting a file/disc image.")))
{
DoStartFile();
}
if (HorizontalMenuItem(GetCachedTexture("fullscreenui/drive-cdrom.png"), FSUI_CSTR("Start Disc"),
if (HorizontalMenuSvgItem("fullscreenui/drive-cdrom.svg", FSUI_CSTR("Start Disc"),
FSUI_CSTR("Start a game from a disc in your PC's DVD drive.")))
{
DoStartDisc();
}
if (HorizontalMenuItem(GetCachedTexture("fullscreenui/start-bios.png"), FSUI_CSTR("Start BIOS"),
if (HorizontalMenuSvgItem("fullscreenui/start-bios.svg", FSUI_CSTR("Start BIOS"),
FSUI_CSTR("Start the console without any disc inserted.")))
{
DoStartBIOS();
}
// https://www.iconpacks.net/free-icon/arrow-back-3783.html
if (HorizontalMenuItem(GetCachedTexture("fullscreenui/back-icon.png"), FSUI_CSTR("Back"),
if (HorizontalMenuSvgItem("fullscreenui/back-icon.svg", FSUI_CSTR("Back"),
FSUI_CSTR("Return to the previous menu.")) ||
(!AreAnyDialogsOpen() && WantsToCloseMenu()))
{
@@ -1606,8 +1602,7 @@ void FullscreenUI::DrawExitWindow()
{
ResetFocusHere();
// https://www.iconpacks.net/free-icon/arrow-back-3783.html
if (HorizontalMenuItem(GetCachedTexture("fullscreenui/back-icon.png"), FSUI_CSTR("Back"),
if (HorizontalMenuSvgItem("fullscreenui/back-icon.svg", FSUI_CSTR("Back"),
FSUI_CSTR("Return to the previous menu.")) ||
WantsToCloseMenu())
{
@@ -1615,7 +1610,7 @@ void FullscreenUI::DrawExitWindow()
QueueResetFocus(FocusResetType::WindowChanged);
}
if (HorizontalMenuItem(GetCachedTexture("fullscreenui/exit.png"), FSUI_CSTR("Exit PCSX2"),
if (HorizontalMenuSvgItem("fullscreenui/exit.svg", FSUI_CSTR("Exit PCSX2"),
FSUI_CSTR("Completely exits the application, returning you to your desktop.")))
{
DoRequestExit();
@@ -1623,8 +1618,8 @@ void FullscreenUI::DrawExitWindow()
if (!Host::InNoGUIMode())
{
if (HorizontalMenuItem(GetCachedTexture("fullscreenui/desktop-mode.png"), FSUI_CSTR("Desktop Mode"),
FSUI_CSTR("Exits Big Picture mode, returning to the desktop interface.")))
if (HorizontalMenuSvgItem("fullscreenui/desktop-mode.svg", FSUI_CSTR("Desktop Mode"),
FSUI_CSTR("Exits Big Picture mode, returning to the desktop interface.")))
{
DoDesktopMode();
}
@@ -5463,14 +5458,18 @@ void FullscreenUI::DrawPauseMenu(MainWindowType type)
}
DrawShadowedText(dl, g_medium_font, subtitle_pos, text_color, s_current_game_subtitle.c_str());
GSTexture* const cover = GetCoverForCurrentGame();
const ImVec2 image_min(display_size.x - LayoutScale(10.0f + image_width),
display_size.y - LayoutScale(LAYOUT_FOOTER_HEIGHT) - LayoutScale(10.0f + image_height) - rp_height);
const ImVec2 image_max(image_min.x + LayoutScale(image_width), image_min.y + LayoutScale(image_height) + rp_height);
const ImRect image_rect(CenterImage(
ImRect(image_min, image_max), ImVec2(static_cast<float>(cover->GetWidth()), static_cast<float>(cover->GetHeight()))));
dl->AddImage(reinterpret_cast<ImTextureID>(cover->GetNativeHandle()), image_rect.Min, image_rect.Max);
{
auto lock = GameList::GetLock();
const GameList::Entry* entry = GameList::GetEntryForPath(s_current_disc_path.c_str());
if (entry)
DrawGameCover(entry, dl, image_min, image_max);
else
DrawFallbackCover(dl, image_min, image_max);
}
}
// current time / play time
@@ -6286,7 +6285,7 @@ void FullscreenUI::PopulateGameListEntryList()
case 4: // CRC
{
if (lhs->crc != rhs->crc)
return reverse ? (lhs->crc >= rhs->crc) : (lhs->crc < rhs->crc);
return reverse ? (lhs->crc > rhs->crc) : (lhs->crc < rhs->crc);
}
break;
@@ -6458,8 +6457,6 @@ void FullscreenUI::DrawGameList(const ImVec2& heading_size)
if (!visible)
continue;
GSTexture* cover_texture = GetGameListCover(entry);
summary.clear();
if (entry->serial.empty())
fmt::format_to(std::back_inserter(summary), "{} - ", GameList::RegionToString(entry->region, true));
@@ -6469,11 +6466,7 @@ void FullscreenUI::DrawGameList(const ImVec2& heading_size)
const std::string_view filename(Path::GetFileName(entry->path));
summary.append(filename);
const ImRect image_rect(CenterImage(ImRect(bb.Min, bb.Min + image_size),
ImVec2(static_cast<float>(cover_texture->GetWidth()), static_cast<float>(cover_texture->GetHeight()))));
ImGui::GetWindowDrawList()->AddImage(reinterpret_cast<ImTextureID>(cover_texture->GetNativeHandle()),
image_rect.Min, image_rect.Max, ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), IM_COL32(255, 255, 255, 255));
DrawGameCover(entry, ImGui::GetWindowDrawList(), bb.Min, bb.Min + image_size);
const float midpoint = bb.Min.y + g_large_font->FontSize + LayoutScale(4.0f);
const float text_start_x = bb.Min.x + image_size.x + LayoutScale(15.0f);
@@ -6514,18 +6507,13 @@ void FullscreenUI::DrawGameList(const ImVec2& heading_size)
if (BeginFullscreenColumnWindow(-530.0f, 0.0f, "game_list_info", UIPrimaryDarkColor))
{
const GSTexture* cover_texture =
selected_entry ? GetGameListCover(selected_entry) : GetTextureForGameListEntryType(GameList::EntryType::Count);
if (cover_texture)
{
const ImRect image_rect(CenterImage(LayoutScale(ImVec2(275.0f, 400.0f)),
ImVec2(static_cast<float>(cover_texture->GetWidth()), static_cast<float>(cover_texture->GetHeight()))));
const ImVec2 image_size = LayoutScale(ImVec2(275.0f, 400.0f));
ImGui::SetCursorPos(LayoutScale(ImVec2(128.0f, 20.0f)));
ImGui::SetCursorPos(LayoutScale(ImVec2(128.0f, 20.0f)) + image_rect.Min);
ImGui::Image(reinterpret_cast<ImTextureID>(selected_entry ? GetGameListCover(selected_entry)->GetNativeHandle() :
GetTextureForGameListEntryType(GameList::EntryType::Count)->GetNativeHandle()),
image_rect.GetSize());
}
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;
@@ -6693,12 +6681,7 @@ void FullscreenUI::DrawGameGrid(const ImVec2& heading_size)
bb.Min += style.FramePadding;
bb.Max -= style.FramePadding;
const GSTexture* const cover_texture = GetGameListCover(entry);
const ImRect image_rect(CenterImage(ImRect(bb.Min, bb.Min + image_size),
ImVec2(static_cast<float>(cover_texture->GetWidth()), static_cast<float>(cover_texture->GetHeight()))));
ImGui::GetWindowDrawList()->AddImage(reinterpret_cast<ImTextureID>(cover_texture->GetNativeHandle()),
image_rect.Min, image_rect.Max, ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), IM_COL32(255, 255, 255, 255));
DrawGameCover(entry, ImGui::GetWindowDrawList(), bb.Min, bb.Min + image_size);
const ImRect title_bb(ImVec2(bb.Min.x, bb.Min.y + image_height + title_spacing), bb.Max);
const std::string_view title(std::string_view(entry->GetTitle(true)).substr(0, 31));
@@ -6987,33 +6970,104 @@ GSTexture* FullscreenUI::GetGameListCover(const GameList::Entry* entry)
cover_it = s_cover_image_map.emplace(entry->path, std::move(cover_path)).first;
}
GSTexture* tex = (!cover_it->second.empty()) ? GetCachedTextureAsync(cover_it->second.c_str()) : nullptr;
return tex ? tex : GetTextureForGameListEntryType(entry->type);
return (!cover_it->second.empty()) ? GetCachedTextureAsync(cover_it->second.c_str()) : nullptr;
}
GSTexture* FullscreenUI::GetTextureForGameListEntryType(GameList::EntryType type)
GSTexture* FullscreenUI::GetTextureForGameListEntryType(GameList::EntryType type, const ImVec2& size, SvgScaling mode)
{
switch (type)
{
case GameList::EntryType::ELF:
return s_fallback_exe_texture.get();
return GetCachedSvgTexture("fullscreenui/applications-system.svg", size, mode);
case GameList::EntryType::PS1Disc:
case GameList::EntryType::PS2Disc:
default:
return s_fallback_disc_texture.get();
return GetCachedSvgTexture("fullscreenui/media-cdrom.svg", size, mode);
}
}
GSTexture* FullscreenUI::GetCoverForCurrentGame()
void FullscreenUI::DrawGameCover(const GameList::Entry* entry, const ImVec2& size)
{
auto lock = GameList::GetLock();
// Used in DrawGameList (selected preview)
const GSTexture* cover_texture = GetGameListCover(entry);
const GameList::Entry* entry = GameList::GetEntryForPath(s_current_disc_path.c_str());
if (!entry)
return s_fallback_disc_texture.get();
pxAssert(ImGui::GetCurrentContext()->Style.ImageBorderSize == 0);
const ImVec2 origin = ImGui::GetCursorPos();
return GetGameListCover(entry);
if (cover_texture)
{
const ImRect image_rect(CenterImage(size,
ImVec2(static_cast<float>(cover_texture->GetWidth()), static_cast<float>(cover_texture->GetHeight()))));
ImGui::SetCursorPos(origin + image_rect.Min);
ImGui::Image(reinterpret_cast<ImTextureID>(cover_texture->GetNativeHandle()), image_rect.GetSize());
}
else
{
const float min_size = std::min(size.x, size.y);
const ImVec2 image_square(min_size, min_size);
GSTexture* const icon_texture = GetTextureForGameListEntryType(entry->type, image_square);
const ImRect image_rect(CenterImage(size, image_square));
DrawSvgTexture(icon_texture, image_square);
}
// Pretend the image we drew was the the size passed to us
ImGui::SetCursorPos(origin);
ImGui::Dummy(size);
}
void FullscreenUI::DrawGameCover(const GameList::Entry* entry, ImDrawList* draw_list, const ImVec2& min, const ImVec2& max)
{
// Used in DrawPauseMenu, DrawGameList (list item), DrawGameGrid
const GSTexture* cover_texture = GetGameListCover(entry);
if (cover_texture)
{
const ImRect image_rect(CenterImage(ImRect(min, max),
ImVec2(static_cast<float>(cover_texture->GetWidth()), static_cast<float>(cover_texture->GetHeight()))));
draw_list->AddImage(reinterpret_cast<ImTextureID>(cover_texture->GetNativeHandle()),
image_rect.Min, image_rect.Max);
}
else
{
const float min_size = std::min(max.x - min.x, max.y - min.y);
const ImVec2 image_square(min_size, min_size);
const ImRect image_rect(CenterImage(ImRect(min, max), image_square));
DrawListSvgTexture(draw_list, GetTextureForGameListEntryType(entry->type, image_square, SvgScaling::Fit),
image_rect.Min, image_rect.Max);
}
}
void FullscreenUI::DrawFallbackCover(const ImVec2& size)
{
pxAssert(ImGui::GetCurrentContext()->Style.ImageBorderSize == 0);
const ImVec2 origin = ImGui::GetCursorPos();
const float min_size = std::min(size.x, size.y);
const ImVec2 image_square(min_size, min_size);
GSTexture* const icon_texture = GetTextureForGameListEntryType(GameList::EntryType::PS2Disc, image_square);
const ImRect image_rect(CenterImage(size, image_square));
DrawSvgTexture(icon_texture, image_square);
// Pretend the image we drew was the the size passed to us
ImGui::SetCursorPos(origin);
ImGui::Dummy(size);
}
void FullscreenUI::DrawFallbackCover(ImDrawList* draw_list, const ImVec2& min, const ImVec2& max)
{
const float min_size = std::min(max.x - min.x, max.y - min.y);
const ImVec2 image_square(min_size, min_size);
const ImRect image_rect(CenterImage(ImRect(min, max), image_square));
DrawListSvgTexture(draw_list, GetTextureForGameListEntryType(GameList::EntryType::PS2Disc, image_square, SvgScaling::Fit),
image_rect.Min, image_rect.Max);
}
//////////////////////////////////////////////////////////////////////////

View File

@@ -1992,7 +1992,7 @@ void ImGuiFullscreen::EndHorizontalMenu()
EndFullscreenWindow();
}
bool ImGuiFullscreen::HorizontalMenuItem(GSTexture* icon, const char* title, const char* description)
bool ImGuiFullscreen::HorizontalMenuItem(GSTexture* icon, const ImVec2& icon_uv0, const ImVec2& icon_uv1, const char* title, const char* description)
{
ImGuiWindow* window = ImGui::GetCurrentWindow();
if (window->SkipItems)
@@ -2031,7 +2031,7 @@ bool ImGuiFullscreen::HorizontalMenuItem(GSTexture* icon, const char* title, con
const ImVec2 icon_pos = bb.Min + ImVec2((avail_width - icon_size) * 0.5f, 0.0f);
ImDrawList* dl = ImGui::GetWindowDrawList();
dl->AddImage(reinterpret_cast<ImTextureID>(icon->GetNativeHandle()), icon_pos, icon_pos + ImVec2(icon_size, icon_size));
dl->AddImage(reinterpret_cast<ImTextureID>(icon->GetNativeHandle()), icon_pos, icon_pos + ImVec2(icon_size, icon_size), icon_uv0, icon_uv1);
ImFont* title_font = g_large_font;
const ImVec2 title_size = title_font->CalcTextSizeA(title_font->FontSize, avail_width, 0.0f, title);
@@ -2056,6 +2056,22 @@ bool ImGuiFullscreen::HorizontalMenuItem(GSTexture* icon, const char* title, con
return pressed;
}
bool ImGuiFullscreen::HorizontalMenuItem(GSTexture* icon, const char* title, const char* description)
{
return HorizontalMenuItem(icon, ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), title, description);
}
bool ImGuiFullscreen::HorizontalMenuSvgItem(const char* svg_path, const char* title, const char* description, SvgScaling mode)
{
const ImVec2 icon_size = LayoutScale(150.0f, 150.0f);
GSTexture* padded_texture = GetCachedSvgTexture(svg_path, icon_size, mode);
const ImVec2 padded_size(padded_texture->GetWidth(), padded_texture->GetHeight());
const ImVec2 uv1 = icon_size / padded_size;
return HorizontalMenuItem(padded_texture, ImVec2(0.0f, 0.0f), uv1, title, description);
}
void ImGuiFullscreen::PopulateFileSelectorItems()
{
s_file_selector_items.clear();

View File

@@ -235,7 +235,9 @@ namespace ImGuiFullscreen
bool BeginHorizontalMenu(const char* name, const ImVec2& position, const ImVec2& size, u32 num_items);
void EndHorizontalMenu();
bool HorizontalMenuItem(GSTexture* icon, const ImVec2& icon_uv0, const ImVec2& icon_uv1, const char* title, const char* description);
bool HorizontalMenuItem(GSTexture* icon, const char* title, const char* description);
bool HorizontalMenuSvgItem(const char* svg_path, const char* title, const char* description, SvgScaling mode = SvgScaling::Stretch);
using FileSelectorCallback = std::function<void(const std::string& path)>;
using FileSelectorFilters = std::vector<std::string>;

View File

@@ -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)