Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cbe20c0eed | ||
|
|
ec288ffa62 | ||
|
|
7e18c02c7e | ||
|
|
4a505cc239 | ||
|
|
35c81106c6 | ||
|
|
1094222d3f | ||
|
|
065d0db4c9 | ||
|
|
bc51537080 | ||
|
|
b7dfcb282b | ||
|
|
78a9411766 | ||
|
|
4724f67596 | ||
|
|
e0851bb86f | ||
|
|
08e68d9563 | ||
|
|
0b6dccae51 | ||
|
|
60adfd5046 | ||
|
|
3e782d355d | ||
|
|
22a7324b69 | ||
|
|
f3b4c50909 | ||
|
|
a45f27e6e9 | ||
|
|
2f84bf0cca | ||
|
|
3e2c3e5075 | ||
|
|
154259d0a6 | ||
|
|
7d2d05ff59 |
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
@@ -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>
|
||||
|
||||
|
Before Width: | Height: | Size: 38 KiB |
41
bin/resources/fullscreenui/applications-system.svg
Normal 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 |
|
Before Width: | Height: | Size: 8.5 KiB |
7
bin/resources/fullscreenui/back-icon.svg
Normal 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 |
|
Before Width: | Height: | Size: 13 KiB |
7
bin/resources/fullscreenui/desktop-mode.svg
Normal 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 |
|
Before Width: | Height: | Size: 19 KiB |
7
bin/resources/fullscreenui/drive-cdrom.svg
Normal 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 |
|
Before Width: | Height: | Size: 27 KiB |
7
bin/resources/fullscreenui/exit.svg
Normal 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 |
|
Before Width: | Height: | Size: 48 KiB |
7
bin/resources/fullscreenui/game-list.svg
Normal 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 |
|
Before Width: | Height: | Size: 100 KiB |
7
bin/resources/fullscreenui/media-cdrom.svg
Normal 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 |
|
Before Width: | Height: | Size: 14 KiB |
9
bin/resources/fullscreenui/start-bios.svg
Normal 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 |
|
Before Width: | Height: | Size: 22 KiB |
7
bin/resources/fullscreenui/start-file.svg
Normal 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 |
@@ -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>
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -617,72 +617,71 @@ void GSRenderer::VSync(u32 field, bool registers_written, bool idle_frame)
|
||||
EndPresentFrame();
|
||||
|
||||
PerformanceMetrics::Update(registers_written, fb_sprite_frame, skip_frame);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!idle_frame)
|
||||
g_gs_device->AgePool();
|
||||
|
||||
|
||||
g_perfmon.EndFrame(idle_frame);
|
||||
|
||||
if ((g_perfmon.GetFrame() & 0x1f) == 0)
|
||||
g_perfmon.Update();
|
||||
|
||||
// Little bit ugly, but we can't do CAS inside the render pass.
|
||||
GSVector4i src_rect;
|
||||
GSVector4 src_uv, draw_rect;
|
||||
GSTexture* current = g_gs_device->GetCurrent();
|
||||
if (current && !blank_frame)
|
||||
else
|
||||
{
|
||||
src_rect = CalculateDrawSrcRect(current, m_real_size);
|
||||
src_uv = GSVector4(src_rect) / GSVector4(current->GetSize()).xyxy();
|
||||
draw_rect = CalculateDrawDstRect(g_gs_device->GetWindowWidth(), g_gs_device->GetWindowHeight(),
|
||||
src_rect, current->GetSize(), s_display_alignment, g_gs_device->UsesLowerLeftOrigin(),
|
||||
GetVideoMode() == GSVideoMode::SDTV_480P);
|
||||
s_last_draw_rect = draw_rect;
|
||||
if (!idle_frame)
|
||||
g_gs_device->AgePool();
|
||||
|
||||
if (GSConfig.CASMode != GSCASMode::Disabled)
|
||||
{
|
||||
static bool cas_log_once = false;
|
||||
if (g_gs_device->Features().cas_sharpening)
|
||||
{
|
||||
// sharpen only if the IR is higher than the display resolution
|
||||
const bool sharpen_only = (GSConfig.CASMode == GSCASMode::SharpenOnly ||
|
||||
(current->GetWidth() > g_gs_device->GetWindowWidth() &&
|
||||
current->GetHeight() > g_gs_device->GetWindowHeight()));
|
||||
g_gs_device->CAS(current, src_rect, src_uv, draw_rect, sharpen_only);
|
||||
}
|
||||
else if (!cas_log_once)
|
||||
{
|
||||
Host::AddIconOSDMessage("CASUnsupported", ICON_FA_EXCLAMATION_TRIANGLE,
|
||||
TRANSLATE_SV("GS",
|
||||
"CAS is not available, your graphics driver does not support the required functionality."),
|
||||
10.0f);
|
||||
cas_log_once = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
g_perfmon.EndFrame(idle_frame);
|
||||
|
||||
if (BeginPresentFrame(false))
|
||||
{
|
||||
if ((g_perfmon.GetFrame() & 0x1f) == 0)
|
||||
g_perfmon.Update();
|
||||
|
||||
// Little bit ugly, but we can't do CAS inside the render pass.
|
||||
GSVector4i src_rect;
|
||||
GSVector4 src_uv, draw_rect;
|
||||
GSTexture* current = g_gs_device->GetCurrent();
|
||||
if (current && !blank_frame)
|
||||
{
|
||||
const u64 current_time = Common::Timer::GetCurrentValue();
|
||||
const float shader_time = static_cast<float>(Common::Timer::ConvertValueToSeconds(current_time - m_shader_time_start));
|
||||
src_rect = CalculateDrawSrcRect(current, m_real_size);
|
||||
src_uv = GSVector4(src_rect) / GSVector4(current->GetSize()).xyxy();
|
||||
draw_rect = CalculateDrawDstRect(g_gs_device->GetWindowWidth(), g_gs_device->GetWindowHeight(),
|
||||
src_rect, current->GetSize(), s_display_alignment, g_gs_device->UsesLowerLeftOrigin(),
|
||||
GetVideoMode() == GSVideoMode::SDTV_480P);
|
||||
s_last_draw_rect = draw_rect;
|
||||
|
||||
g_gs_device->PresentRect(current, src_uv, nullptr, draw_rect,
|
||||
s_tv_shader_indices[GSConfig.TVShader], shader_time, GSConfig.LinearPresent != GSPostBilinearMode::Off);
|
||||
if (GSConfig.CASMode != GSCASMode::Disabled)
|
||||
{
|
||||
static bool cas_log_once = false;
|
||||
if (g_gs_device->Features().cas_sharpening)
|
||||
{
|
||||
// sharpen only if the IR is higher than the display resolution
|
||||
const bool sharpen_only = (GSConfig.CASMode == GSCASMode::SharpenOnly ||
|
||||
(current->GetWidth() > g_gs_device->GetWindowWidth() &&
|
||||
current->GetHeight() > g_gs_device->GetWindowHeight()));
|
||||
g_gs_device->CAS(current, src_rect, src_uv, draw_rect, sharpen_only);
|
||||
}
|
||||
else if (!cas_log_once)
|
||||
{
|
||||
Host::AddIconOSDMessage("CASUnsupported", ICON_FA_EXCLAMATION_TRIANGLE,
|
||||
TRANSLATE_SV("GS", "CAS is not available, your graphics driver does not support the required functionality."),
|
||||
10.0f);
|
||||
cas_log_once = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EndPresentFrame();
|
||||
if (BeginPresentFrame(false))
|
||||
{
|
||||
if (current && !blank_frame)
|
||||
{
|
||||
const u64 current_time = Common::Timer::GetCurrentValue();
|
||||
const float shader_time = static_cast<float>(Common::Timer::ConvertValueToSeconds(current_time - m_shader_time_start));
|
||||
|
||||
if (GSConfig.OsdShowGPU)
|
||||
PerformanceMetrics::OnGPUPresent(g_gs_device->GetAndResetAccumulatedGPUTime());
|
||||
g_gs_device->PresentRect(current, src_uv, nullptr, draw_rect,
|
||||
s_tv_shader_indices[GSConfig.TVShader], shader_time, GSConfig.LinearPresent != GSPostBilinearMode::Off);
|
||||
}
|
||||
|
||||
EndPresentFrame();
|
||||
|
||||
if (GSConfig.OsdShowGPU)
|
||||
PerformanceMetrics::OnGPUPresent(g_gs_device->GetAndResetAccumulatedGPUTime());
|
||||
}
|
||||
|
||||
PerformanceMetrics::Update(registers_written, fb_sprite_frame, false);
|
||||
}
|
||||
|
||||
PerformanceMetrics::Update(registers_written, fb_sprite_frame, false);
|
||||
|
||||
// snapshot
|
||||
if (!m_snapshot.empty())
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
@@ -8178,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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
@@ -424,13 +427,15 @@ 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;
|
||||
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()) ==
|
||||
@@ -1626,14 +1631,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 +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())
|
||||
{
|
||||
|
||||
@@ -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)); }
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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;
|
||||
|
||||