mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-01-31 01:15:24 +01:00
Compare commits
271 Commits
gs_wrchack
...
v1.7.4230
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f9b682ad10 | ||
|
|
58959b6114 | ||
|
|
b90405a7d2 | ||
|
|
e0a1613ad9 | ||
|
|
11930ed7a2 | ||
|
|
f3ff1cec54 | ||
|
|
435e73d838 | ||
|
|
2fdea258fa | ||
|
|
b453a6a46d | ||
|
|
5b88e637d8 | ||
|
|
ac02bcbe33 | ||
|
|
9efdeae3ac | ||
|
|
54e59e2f7b | ||
|
|
2c4e02ff34 | ||
|
|
2a306cbd91 | ||
|
|
b244136179 | ||
|
|
b897f367ce | ||
|
|
6c46418f68 | ||
|
|
f0d5d21e64 | ||
|
|
93490876c9 | ||
|
|
74763d2156 | ||
|
|
b849d9862d | ||
|
|
cd575e0ed8 | ||
|
|
b5fbd88c34 | ||
|
|
6003673165 | ||
|
|
4555667554 | ||
|
|
c0db6d49f4 | ||
|
|
6630066f0b | ||
|
|
20e6a55dd1 | ||
|
|
d3f82c800f | ||
|
|
e0e525d9ae | ||
|
|
12f4d6f872 | ||
|
|
0668e9bad9 | ||
|
|
06aed8491c | ||
|
|
df2d11e70d | ||
|
|
2dde8a5e90 | ||
|
|
674b13fb3f | ||
|
|
ab17c3693f | ||
|
|
a6c372de46 | ||
|
|
62497b9300 | ||
|
|
1461a3f8d7 | ||
|
|
686b31765d | ||
|
|
05e4e98e64 | ||
|
|
e95b60d527 | ||
|
|
59aba9f757 | ||
|
|
248e94dc4c | ||
|
|
a7d574cff0 | ||
|
|
ad05193916 | ||
|
|
b24b353b2d | ||
|
|
18e4a04dba | ||
|
|
30989761e2 | ||
|
|
b219ee9049 | ||
|
|
98c611e404 | ||
|
|
7a4ef32210 | ||
|
|
c3359cea1f | ||
|
|
f73a2d571f | ||
|
|
6dfb02c826 | ||
|
|
6c093fc81e | ||
|
|
911d35e800 | ||
|
|
084fdc0a65 | ||
|
|
1382fe9c6c | ||
|
|
b33242830e | ||
|
|
8c0ee33c4c | ||
|
|
e8cf4822b1 | ||
|
|
3462f02ce2 | ||
|
|
1a67b2146a | ||
|
|
eb0d18f484 | ||
|
|
c783fc0f59 | ||
|
|
31d02c1278 | ||
|
|
85f96bb248 | ||
|
|
229cf908b7 | ||
|
|
89b18275c0 | ||
|
|
b8a86baec7 | ||
|
|
8505e9203a | ||
|
|
5d95a503bf | ||
|
|
36c7f96a1e | ||
|
|
b40b606608 | ||
|
|
03764a624f | ||
|
|
962cfa9441 | ||
|
|
b2f30ab080 | ||
|
|
24c42ae2d9 | ||
|
|
af9353298c | ||
|
|
a3ecf0b0bd | ||
|
|
58cb6ab728 | ||
|
|
f478b3959c | ||
|
|
35ce680859 | ||
|
|
7df189ced4 | ||
|
|
c35092504c | ||
|
|
0bff6f7ad9 | ||
|
|
805f985144 | ||
|
|
12e578b93c | ||
|
|
1312952305 | ||
|
|
6118b94f9e | ||
|
|
520320535e | ||
|
|
262b5f1dc0 | ||
|
|
ac36162ddc | ||
|
|
9b813f4ae3 | ||
|
|
35d05b8653 | ||
|
|
e4d6b87e5d | ||
|
|
64b38e5a4a | ||
|
|
75957c84e3 | ||
|
|
c33fb2adbd | ||
|
|
97d3baba35 | ||
|
|
e91f9925f8 | ||
|
|
b484f7aef0 | ||
|
|
9a3904103a | ||
|
|
2a2d39b392 | ||
|
|
3005ba629f | ||
|
|
795741a341 | ||
|
|
da98465d4b | ||
|
|
d28e46796f | ||
|
|
43c6e321f5 | ||
|
|
4595c2feec | ||
|
|
8b4402c517 | ||
|
|
e08ae7e8fa | ||
|
|
753efd8c4a | ||
|
|
cb786f0320 | ||
|
|
6ff64cc984 | ||
|
|
475b816280 | ||
|
|
229005942f | ||
|
|
4af25d20fe | ||
|
|
6bf5b9a8e3 | ||
|
|
be769c28fa | ||
|
|
3128c48d5b | ||
|
|
5c7161fd2f | ||
|
|
e85790b84b | ||
|
|
980e2f67fd | ||
|
|
7781907f0e | ||
|
|
1d145dd48a | ||
|
|
1a1eb30e60 | ||
|
|
a7e2b98dc7 | ||
|
|
2bf74622a5 | ||
|
|
6bcaef9325 | ||
|
|
0b3aac3d91 | ||
|
|
9a53f0f853 | ||
|
|
a97df14064 | ||
|
|
9a0cd1157f | ||
|
|
16c41255d0 | ||
|
|
c2d1e5bd18 | ||
|
|
3c85ba3eb8 | ||
|
|
f3b67b158c | ||
|
|
8dac10ae36 | ||
|
|
6b81050283 | ||
|
|
b4beacfc43 | ||
|
|
1b607a8c4d | ||
|
|
4583c64ff7 | ||
|
|
a06a07d961 | ||
|
|
520a369872 | ||
|
|
1eaec773e2 | ||
|
|
3433a42e42 | ||
|
|
e01eac615d | ||
|
|
8116646dee | ||
|
|
7f7950cd6b | ||
|
|
2eb11ded52 | ||
|
|
bd64ad510b | ||
|
|
4e9b7e61a7 | ||
|
|
37b19495a8 | ||
|
|
c12b412e87 | ||
|
|
17f137f8be | ||
|
|
fcc627c65c | ||
|
|
5bb3d8e60d | ||
|
|
264086e0aa | ||
|
|
6013d7172a | ||
|
|
a7714b2725 | ||
|
|
f9dcac8cd0 | ||
|
|
2487322e47 | ||
|
|
c7e9c9542e | ||
|
|
c1bc1af302 | ||
|
|
739f9ec758 | ||
|
|
f70a140f42 | ||
|
|
a716e69dc0 | ||
|
|
0c6e1a4d56 | ||
|
|
faf36ecba6 | ||
|
|
49f2900e1f | ||
|
|
8bd522d283 | ||
|
|
e9034a1ba1 | ||
|
|
03feacd69a | ||
|
|
0c9f44d8a4 | ||
|
|
39fb64cdcd | ||
|
|
d531a7f1af | ||
|
|
bb7ff414ae | ||
|
|
215f112521 | ||
|
|
644766d965 | ||
|
|
1e1a555d3b | ||
|
|
c64ae2684d | ||
|
|
50ed04436d | ||
|
|
2fb9beca52 | ||
|
|
cd4c1e920e | ||
|
|
e846ac367a | ||
|
|
ef31c733ee | ||
|
|
724aa657f3 | ||
|
|
0284c35f4c | ||
|
|
6ce33de287 | ||
|
|
6ccfa011d4 | ||
|
|
c9078af45e | ||
|
|
6745428d0c | ||
|
|
925e874ada | ||
|
|
03f0f2f803 | ||
|
|
857360d6b2 | ||
|
|
2dd76c3f12 | ||
|
|
666de3a874 | ||
|
|
e0e9b64db6 | ||
|
|
2f521348c6 | ||
|
|
8ac2949a1f | ||
|
|
d0d5d991ce | ||
|
|
1fc2d7de3c | ||
|
|
2598e8d9b9 | ||
|
|
01f65e98e6 | ||
|
|
c5330cf166 | ||
|
|
b78796d0c1 | ||
|
|
da1e9db2c0 | ||
|
|
6beb6aa05b | ||
|
|
6ea7777a3a | ||
|
|
f97191e241 | ||
|
|
51420dade4 | ||
|
|
cc55c01197 | ||
|
|
86ce464ee3 | ||
|
|
0fa52a75ad | ||
|
|
c91e7dc3b0 | ||
|
|
88034b176c | ||
|
|
efeaff488c | ||
|
|
5df30f5bdd | ||
|
|
cf179c42b8 | ||
|
|
a615f8bf17 | ||
|
|
b38964e814 | ||
|
|
013c9eec58 | ||
|
|
ddbd6eddf7 | ||
|
|
982fd42683 | ||
|
|
90e28e7957 | ||
|
|
f4201f3947 | ||
|
|
7844b40243 | ||
|
|
d0839a3d55 | ||
|
|
876fd9ba9e | ||
|
|
e12717c108 | ||
|
|
af0b17bb7a | ||
|
|
6f595b7d87 | ||
|
|
59cbdc79f5 | ||
|
|
50ff3649b1 | ||
|
|
9ca9db8770 | ||
|
|
fa70f0e764 | ||
|
|
3eb629f133 | ||
|
|
c9aba6bbe1 | ||
|
|
0a26adae76 | ||
|
|
f0798f6510 | ||
|
|
245b03e208 | ||
|
|
4e31e5fdc2 | ||
|
|
750a74206c | ||
|
|
7e64dc2576 | ||
|
|
8a08e2fd97 | ||
|
|
d0a933cda8 | ||
|
|
d00845f56b | ||
|
|
3350e5ebb1 | ||
|
|
aeb4445cad | ||
|
|
73abae8cb9 | ||
|
|
7ecc7b76ba | ||
|
|
71d0bbbc25 | ||
|
|
26e691ba93 | ||
|
|
c7352d9e10 | ||
|
|
7b8f9a54ec | ||
|
|
28980af858 | ||
|
|
80dce398e0 | ||
|
|
06db8eec48 | ||
|
|
9c720efe46 | ||
|
|
cbf91a8d19 | ||
|
|
f99414708d | ||
|
|
9549a6b16a | ||
|
|
3206094545 | ||
|
|
5cfae80701 | ||
|
|
b4d140c6bb | ||
|
|
c65eb3c3ee | ||
|
|
eec0984dbe |
14
.github/workflows/windows_build_matrix.yml
vendored
14
.github/workflows/windows_build_matrix.yml
vendored
@@ -38,8 +38,8 @@ jobs:
|
||||
configuration: Release AVX2
|
||||
secrets: inherit
|
||||
|
||||
build_qt_sse4_cmake:
|
||||
name: "CMake SSE4"
|
||||
build_qt_cmake:
|
||||
name: "CMake"
|
||||
uses: ./.github/workflows/windows_build_qt.yml
|
||||
with:
|
||||
jobName: Qt
|
||||
@@ -65,3 +65,13 @@ jobs:
|
||||
jobName: Qt Clang
|
||||
configuration: Release Clang AVX2
|
||||
secrets: inherit
|
||||
|
||||
build_qt_cmake_clang:
|
||||
name: "CMake"
|
||||
uses: ./.github/workflows/windows_build_qt.yml
|
||||
with:
|
||||
jobName: Qt Clang
|
||||
configuration: CMake
|
||||
buildSystem: cmake
|
||||
cmakeFlags: -DCMAKE_C_COMPILER=clang-cl -DCMAKE_CXX_COMPILER=clang-cl -DPCSX2_EXE_NAME=pcsx2-qt-clang
|
||||
secrets: inherit
|
||||
|
||||
6
.github/workflows/windows_build_qt.yml
vendored
6
.github/workflows/windows_build_qt.yml
vendored
@@ -25,6 +25,10 @@ on:
|
||||
required: false
|
||||
type: string
|
||||
default: msbuild
|
||||
cmakeFlags:
|
||||
required: false
|
||||
type: string
|
||||
default: ""
|
||||
qt_binary_url:
|
||||
required: false
|
||||
type: string
|
||||
@@ -92,7 +96,7 @@ jobs:
|
||||
shell: cmd
|
||||
run: |
|
||||
call "%ProgramFiles%\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
|
||||
cmake . -B build "-DCMAKE_PREFIX_PATH=%cd%\${{ inputs.qt_dir }}" -DQT_BUILD=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON -DDISABLE_ADVANCE_SIMD=ON -G Ninja
|
||||
cmake . -B build ${{ inputs.cmakeFlags }} "-DCMAKE_PREFIX_PATH=%cd%\${{ inputs.qt_dir }}" -DQT_BUILD=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON -DDISABLE_ADVANCE_SIMD=ON -G Ninja
|
||||
|
||||
- name: Build PCSX2
|
||||
shell: cmd
|
||||
|
||||
@@ -22,7 +22,7 @@ Installers and binaries for both stable and development builds are available fro
|
||||
|
||||
| Operating System | CPU | GPU | RAM |
|
||||
| ------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---- |
|
||||
| - Windows 10 21H2 (1809 or later) (64-bit) <br/> - Ubuntu 20.04/Debian or newer, Arch Linux, or other distro (64-bit) <br/> - macOS 10.14 | - Supports SSE4.1 <br/> - [PassMark Single Thread Performance](https://www.cpubenchmark.net/singleThread.html) rating near or greater than 1800 <br/> - Two physical cores, with hyperthreading | - Direct3D10 support <br/> - OpenGL 3.x support <br/> - Vulkan 1.1 support <br/> - Metal support <br/> - [PassMark G3D Mark](https://www.videocardbenchmark.net/high_end_gpus.html) rating around 3000 (Geforce GTX 750 Radeon RX 560 Intel Arc A380) <br/> - 2 GB Video Memory | 4 GB |
|
||||
| - Windows 10 21H2 (1809 or later) (64-bit) <br/> - Ubuntu 20.04/Debian or newer, Arch Linux, or other distro (64-bit) <br/> - macOS 10.14 | - Supports SSE4.1 <br/> - [PassMark Thread Performance](https://www.cpubenchmark.net/CPU_mega_page.html) rating near or greater than 1800<br/> - Two physical cores, with hyperthreading | - Direct3D10 support <br/> - OpenGL 3.x support <br/> - Vulkan 1.1 support <br/> - Metal support <br/> - [PassMark G3D Mark](https://www.videocardbenchmark.net/high_end_gpus.html) rating around 3000 (Geforce GTX 750, Radeon RX 560, Intel Arc A380) <br/> - 2 GB Video Memory | 4 GB |
|
||||
|
||||
_Note: Recommended Single Thread Performance is based on moderately complex games. Games that pushed the PS2 hardware to its limits will struggle on CPUs at this level. Some release titles and 2D games which underutilized the PS2 hardware may run on CPUs rated as low as 1200. A quick reference for CPU **intensive games**: [Wiki](https://wiki.pcsx2.net/Category:CPU_intensive_games), [Forum](https://forums.pcsx2.net/Thread-LIST-The-Most-CPU-Intensive-Games) and CPU **light** games: [Forum](https://forums.pcsx2.net/Thread-LIST-Games-that-don-t-need-a-strong-CPU-to-emulate)_
|
||||
|
||||
@@ -30,16 +30,16 @@ _Note: Recommended Single Thread Performance is based on moderately complex game
|
||||
|
||||
| Operating System | CPU | GPU | RAM |
|
||||
| ----------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---- |
|
||||
| - Windows 10 21H2 (1809 or later) (64-bit) <br/> - Ubuntu 22.04/Debian or newer, Arch Linux, or other distro (64-bit) <br/> - macOS 10.14 | - Supports AVX2 <br/> - [PassMark Single Thread Performance](https://www.cpubenchmark.net/singleThread.html) rating near or greater than 2600 <br/> - Four physical cores, with or without hyperthreading | - Direct3D12 support <br/> - OpenGL 4.6 support <br/> - Vulkan 1.3 support <br/> - Metal support <br/> - [PassMark G3D Mark](https://www.videocardbenchmark.net/high_end_gpus.html) rating around 6000 (GeForce GTX 1650 Radeon RX 570) <br/> - 4 GB Video Memory | 8 GB |
|
||||
| - Windows 10 21H2 (1809 or later) (64-bit) <br/> - Ubuntu 22.04/Debian or newer, Arch Linux, or other distro (64-bit) <br/> - macOS 10.14 | - Supports AVX2 <br/> - [PassMark Single Thread Performance](https://www.cpubenchmark.net/CPU_mega_page.html) rating near or greater than 2600<br/> - Four physical cores, with or without hyperthreading | - Direct3D12 support <br/> - OpenGL 4.6 support <br/> - Vulkan 1.3 support <br/> - Metal support <br/> - [PassMark G3D Mark](https://www.videocardbenchmark.net/high_end_gpus.html) rating around 6000 (GeForce GTX 1650, Radeon RX 570) <br/> - 4 GB Video Memory | 8 GB |
|
||||
|
||||
_Note: Recommended GPU is based on 3x Internal, ~1080p resolution requirements. Higher resolutions will require stronger cards; 6x Internal, ~4K resolution will require a [PassMark G3D Mark](https://www.videocardbenchmark.net/high_end_gpus.html) rating around 12000 (GeForce RTX 2060 Radeon RX 6600 Intel Arc A750). Just like CPU requirements, this is also highly game dependent. A quick reference for GPU **intensive games**: [Wiki](https://wiki.pcsx2.net/Category:GPU_intensive_games)_
|
||||
|
||||
### Technical Notes
|
||||
|
||||
- You need the [Visual C++ 2019 x64 Redistributables](https://support.microsoft.com/en-us/help/2977003/) to run PCSX2.
|
||||
- You need the [Visual C++ 2019 x64 Redistributables](https://support.microsoft.com/en-us/help/2977003/) to run PCSX2 on Windows.
|
||||
- Windows XP and Direct3D9 support was dropped after stable release 1.4.0.
|
||||
- Windows 7, Windows 8.0, and Windows 8.1 support was dropped after stable release 1.6.0.
|
||||
- 32-bit and wxwidgets support was dropped after stable release 1.6.0, with the wxwidgets code being removed completely on 25th December 2022.
|
||||
- 32-bit and wxWidgets support was dropped after stable release 1.6.0, with the wxWidgets code being removed completely on 25th December 2022.
|
||||
- Make sure to update your operating system and drivers to ensure you have the best experience possible. Having a newer GPU is also recommended so you have the latest supported drivers.
|
||||
- Because of copyright issues, and the complexity of trying to work around it, you need a BIOS dump extracted from a legitimately-owned PS2 console to use the emulator. For more information about the BIOS and how to get it from your console, visit [this page](pcsx2/Docs/PCSX2_FAQ.md#question-13-where-do-i-get-a-ps2-bios).
|
||||
- PCSX2 uses two CPU cores for emulation by default. A third core can be used via the MTVU speed hack, which is compatible with most games. This can be a significant speedup on CPUs with 3+ cores, but it may be a slowdown on GS-limited games (or on CPUs with fewer than 2 cores). Software renderers will then additionally use however many rendering threads it is set to and will need higher core counts to run efficiently.
|
||||
|
||||
189
bin/docs/PCSX2.1
189
bin/docs/PCSX2.1
@@ -1,189 +0,0 @@
|
||||
.\" Copyright 2002-2017 PCSX2 Dev Team
|
||||
.\"
|
||||
.\" This is free documentation; you can redistribute it and/or
|
||||
.\" modify it under the terms of the GNU General Public License as
|
||||
.\" published by the Free Software Foundation; either version 3 of
|
||||
.\" the License, or (at your option) any later version.
|
||||
.\"
|
||||
.\" The GNU General Public License's references to "object code"
|
||||
.\" and "executables" are to be interpreted as the output of any
|
||||
.\" document formatting or typesetting system, including
|
||||
.\" intermediate and printed output.
|
||||
.\"
|
||||
.\" This manual is distributed in the hope that it will be useful,
|
||||
.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
.\" GNU General Public License for more details.
|
||||
.\"
|
||||
.\" You should have received a copy of the GNU General Public
|
||||
.\" License along with this manual; if not, see
|
||||
.\" http://www.gnu.org/licenses.
|
||||
.Dd January 10, 2017
|
||||
.Dt PCSX2 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm PCSX2
|
||||
.Nd PlayStation(R)2 Console Emulator
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl h
|
||||
.Op Fl \-cfg Ns = Ns Ar file
|
||||
.Op Fl \-cfgpath Ns = Ns Ar path
|
||||
.Op Fl \-console
|
||||
.Op Fl \-forcewiz
|
||||
.Op Fl \-portable
|
||||
.Op Fl \-profiling
|
||||
.Op Fl \-elf Ns = Ns Ar file
|
||||
.Op Fl \-irx Ns = Ns Ar file
|
||||
.Op Fl \-nogui
|
||||
.Op Fl \-noguiprompt
|
||||
.Op Fl \-nodisc
|
||||
.Op Fl \-usecd
|
||||
.Op Fl \-fullscreen
|
||||
.Op Fl \-windowed
|
||||
.Op Fl \-nohacks
|
||||
.Op Fl \-fullboot
|
||||
.Op Fl \-gamefixes Ns = Ns Ar string
|
||||
.Op Fl \-gs Ns = Ns Ar file
|
||||
.Op Fl \-pad Ns = Ns Ar file
|
||||
.Op Fl \-spu2 Ns = Ns Ar file
|
||||
.Op Fl \-cdvd Ns = Ns Ar file
|
||||
.Op Fl \-usb Ns = Ns Ar file
|
||||
.Op Fl \-fw Ns = Ns Ar file
|
||||
.Op Fl \-dev9 Ns = Ns Ar file
|
||||
.Op Ar iso
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
is an open-source PlayStation 2 (AKA PS2) emulator.
|
||||
Its purpose is to emulate the PS2 hardware, using a combination of MIPS CPU
|
||||
interpreters, recompilers and a virtual machine that manages hardware states and
|
||||
PS2 memory.
|
||||
This allows you to play PS2 games on your PC, with many additional features and
|
||||
benefits.
|
||||
.Sh GENERAL OPTIONS
|
||||
.Bl -tag -width Ds
|
||||
.It Fl h , Fl \-help
|
||||
Displays the list of available command line options.
|
||||
.It Fl \-cfg Ns = Ns Ar file
|
||||
Uses
|
||||
.Ar file
|
||||
instead of PCSX2_vm.ini as the configuration file.
|
||||
It does not affect plugins.
|
||||
.It Fl \-cfgpath Ns = Ns Ar path
|
||||
Specifies
|
||||
.Ar path
|
||||
as the configuration file path.
|
||||
It affects both
|
||||
.Nm
|
||||
and the plugins.
|
||||
.It Fl \-console
|
||||
Forces the program log to be visible.
|
||||
.It Fl \-forcewiz
|
||||
Forces the First-Time Wizard to run.
|
||||
.It Fl \-portable
|
||||
Runs
|
||||
.Nm
|
||||
in portable mode.
|
||||
.It Fl \-profiling
|
||||
Makes it easier to use profiling tools.
|
||||
.El
|
||||
.Sh AUTO-RUN OPTIONS
|
||||
.Bl -tag -width Ds
|
||||
.It Ar iso
|
||||
Loads and runs
|
||||
.Ar iso
|
||||
at startup using the
|
||||
.Nm
|
||||
internal ISO loader.
|
||||
.It Fl \-elf Ns = Ns Ar file
|
||||
Executes
|
||||
.Ar file
|
||||
as an ELF image.
|
||||
.It Fl \-irx Ns = Ns Ar file
|
||||
Executes
|
||||
.Ar file
|
||||
as an IRX image.
|
||||
.It Fl \-nogui
|
||||
Disables display of the GUI while running games.
|
||||
.Nm
|
||||
will terminate when the game window is closed.
|
||||
.It Fl \-noguiprompt
|
||||
Prompt before exiting when
|
||||
.Fl \-nogui
|
||||
is used.
|
||||
.It Fl \-nodisc
|
||||
Boots with an empty DVD tray.
|
||||
Use this to boot into the PS2 system menu.
|
||||
.It Fl \-usecd
|
||||
Boots using the configured CDVD plugin instead of booting
|
||||
.Ar iso .
|
||||
.It Fl \-fullscreen
|
||||
Runs the game in fullscreen mode.
|
||||
.It Fl \-windowed
|
||||
Runs the game in windowed mode.
|
||||
.El
|
||||
.Sh COMPATIBILITY OPTIONS
|
||||
.Bl -tag -width Ds
|
||||
.It Fl \-nohacks
|
||||
Disables all speedhacks.
|
||||
.It Fl \-fullboot
|
||||
Disables the fast boot feature.
|
||||
.It Fl \-gamefixes= Ns Ar string
|
||||
Enable specific gamefixes for this session.
|
||||
.Ar string
|
||||
is a comma-separated list of gamefixes.
|
||||
.Pp
|
||||
Valid gamefixes: VuAddSub, VuClipFlag, FpuCompare, FpuMul, FpuNegDiv, XGKick,
|
||||
IpuWait, EETiming, SkipMpeg, OPHFlag, DMABusy,VIFFIFO, VIF1Stall, GIFFIFO,
|
||||
FMVinSoftware, GoemonTlb, ScarfaceIbit.
|
||||
.El
|
||||
.Sh PLUGIN OVERRIDES
|
||||
.Bl -tag -width Ds
|
||||
.It Fl \-gs Ns = Ns Ar file
|
||||
Uses
|
||||
.Ar file
|
||||
as the GS plugin.
|
||||
.It Fl \-pad Ns = Ns Ar file
|
||||
Uses
|
||||
.Ar file
|
||||
as the PAD plugin.
|
||||
.It Fl \-spu2 Ns = Ns Ar file
|
||||
Uses
|
||||
.Ar file
|
||||
as the SPU2 plugin.
|
||||
.It Fl \-cdvd Ns = Ns Ar file
|
||||
Uses
|
||||
.Ar file
|
||||
as the CDVD plugin.
|
||||
.It Fl \-usb Ns = Ns Ar file
|
||||
Uses
|
||||
.Ar file
|
||||
as the USB plugin.
|
||||
.It Fl \-fw Ns = Ns Ar file
|
||||
Uses
|
||||
.Ar file
|
||||
as the FW plugin.
|
||||
.It Fl \-dev9 Ns = Ns Ar file
|
||||
Uses
|
||||
.Ar file
|
||||
as the DEV9 plugin.
|
||||
.El
|
||||
.Sh FILES
|
||||
.Bl -tag -width Ds
|
||||
.It $XDG_CONFIG_DIR/PCSX2 or $HOME/PCSX2
|
||||
User configuration and data directory.
|
||||
.El
|
||||
.Sh AUTHORS
|
||||
.An PCSX2 Dev Team and many other contributors
|
||||
.Sh BUGS
|
||||
Bugs can be reported by submitting an issue at the
|
||||
.Lk https://github.com/PCSX2/pcsx2/issues "PCSX2 GitHub issue tracker" .
|
||||
.Sh PCSX2 RELATED WEBSITES
|
||||
.Bl -bullet
|
||||
.It
|
||||
.Lk http://github.com/PCSX2/pcsx2 "PCSX2 git repository"
|
||||
.It
|
||||
.Lk http://pcsx2.net "PCSX2 website"
|
||||
.It
|
||||
.Lk http://forums.pcsx2.net "PCSX2 forums"
|
||||
.El
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -66,12 +66,12 @@
|
||||
03000000c82d00000021000000000000,8BitDo SN30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
|
||||
03000000c82d00000160000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
|
||||
03000000c82d00000161000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
|
||||
03000000c82d00000121000000000000,8BitDo SN30 Pro for Android,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
|
||||
03000000c82d00000260000000000000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
|
||||
03000000c82d00000261000000000000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
|
||||
03000000c82d00001130000000000000,8BitDo Ultimate Wired,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b26,paddle1:b24,paddle2:b25,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
|
||||
03000000c82d00001230000000000000,8BitDo Ultimate Wireless,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
|
||||
03000000c82d00001330000000000000,8BitDo Ultimate Wireless,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b23,paddle2:b19,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Windows,
|
||||
03000000c82d00000121000000000000,8BitDo Xbox One SN30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
|
||||
03000000a00500003232000000000000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows,
|
||||
03000000c82d00001890000000000000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,
|
||||
03000000c82d00003032000000000000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
|
||||
@@ -302,6 +302,7 @@
|
||||
03000000242e00000b20000000000000,Hyperkin Admiral N64 Controller,+rightx:b11,+righty:b13,-rightx:b8,-righty:b12,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,platform:Windows,
|
||||
03000000242e0000ff0b000000000000,Hyperkin N64 Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b9,platform:Windows,
|
||||
03000000790000004e95000000000000,Hyperkin N64 Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a5,righty:a2,start:b9,platform:Windows,
|
||||
03000000242e00006a38000000000000,Hyperkin Trooper 2,a:b0,b:b1,back:b4,start:b5,leftshoulder:b2,rightshoulder:b3,leftx:a0,lefty:a1,platform:Windows,
|
||||
03000000d81d00000e00000000000000,iBuffalo AC02 Arcade Joystick,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b11,righttrigger:b3,rightx:a2,righty:a5,start:b8,x:b4,y:b5,platform:Windows,
|
||||
03000000d81d00000f00000000000000,iBuffalo BSGP1204 Series,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
|
||||
03000000d81d00001000000000000000,iBuffalo BSGP1204P Series,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
|
||||
@@ -446,7 +447,7 @@
|
||||
03000000120c0000f60e000000000000,P4 Gamepad,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b7,rightshoulder:b4,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000790000002201000000000000,PC Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
|
||||
030000006f0e00008501000000000000,PDP Fightpad Pro,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b0,platform:Windows,
|
||||
030000006f0e00000901000000000000,PDP Versus Fighting,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
|
||||
030000006f0e00000901000000000000,PDP PS3 Versus Fighting,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
|
||||
030000008f0e00004100000000000000,PlaySega,a:b1,b:b0,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b8,x:b4,y:b3,platform:Windows,
|
||||
03000000666600006706000000000000,PlayStation Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Windows,
|
||||
03000000e30500009605000000000000,PlayStation Adapter,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
|
||||
@@ -543,7 +544,7 @@
|
||||
030000009b2800001e00000000000000,Raphnet Vectrex Adapter,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a1,lefty:a2,x:b2,y:b3,platform:Windows,
|
||||
030000009b2800002b00000000000000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,platform:Windows,
|
||||
030000009b2800002c00000000000000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,platform:Windows,
|
||||
030000009b2800008000000000000000,Raphnet Wii Classic Adapter,a:b1,b:b4,x:b0,y:b5,back:b2,guide:b10,start:b3,leftshoulder:b6,rightshoulder:b7,dpup:b12,dpleft:b14,dpdown:b13,dpright:b15,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b8,righttrigger:b9,platform:Windows,
|
||||
030000009b2800008000000000000000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,platform:Windows,
|
||||
03000000321500000003000000000000,Razer Hydra,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
|
||||
03000000321500000204000000000000,Razer Panthera PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000321500000104000000000000,Razer Panthera PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
|
||||
@@ -850,6 +851,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
030000000d0f00003801000008010000,Hori PC Engine Mini Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,platform:Mac OS X,
|
||||
030000000d0f00009200000000010000,Hori Pokken Tournament DX Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
030000000d0f0000aa00000072050000,Hori Real Arcade Pro,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X,
|
||||
030000000d0f00000002000015010000,Hori Switch Split Pad Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
030000000d0f00006e00000000010000,Horipad 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
030000000d0f00006600000000010000,Horipad 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
030000000d0f00006600000000000000,Horipad FPS Plus 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
@@ -888,6 +890,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000790000000018000000000000,Mayflash Wii U Pro Adapter,a:b4,b:b8,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b16,leftstick:b40,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,rightstick:b44,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b12,platform:Mac OS X,
|
||||
03000000790000000018000000010000,Mayflash Wii U Pro Adapter,a:b4,b:b8,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b16,leftstick:b40,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,rightstick:b44,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b12,platform:Mac OS X,
|
||||
030000005e0400002800000002010000,Microsoft Dual Strike,a:b3,b:b2,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,rightshoulder:b7,rightx:a0,righty:a1~,start:b5,x:b1,y:b0,platform:Mac OS X,
|
||||
030000005e0400000300000006010000,Microsoft SideWinder,a:b0,b:b1,back:b9,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Mac OS X,
|
||||
030000005e0400000700000006010000,Microsoft SideWinder,a:b0,b:b1,back:b8,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Mac OS X,
|
||||
030000005e0400002700000001010000,Microsoft SideWinder Plug and Play,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b4,righttrigger:b5,x:b2,y:b3,platform:Mac OS X,
|
||||
03000000d62000007162000001000000,Moga Pro 2,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Mac OS X,
|
||||
03000000c62400002a89000000010000,MOGA XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
|
||||
@@ -904,7 +908,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
030000007e0500001720000001000000,NSO SNES Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b15,start:b9,x:b2,y:b3,platform:Mac OS X,
|
||||
03000000550900001472000025050000,NVIDIA Controller,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Mac OS X,
|
||||
030000004b120000014d000000010000,Nyko Airflo EX,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Mac OS X,
|
||||
030000006f0e00000901000002010000,PDP Versus Fighting,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
030000006f0e00000901000002010000,PDP PS3 Versus Fighting,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
030000008f0e00000300000000000000,Piranha Xtreme PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Mac OS X,
|
||||
03000000666600006706000088020000,PlayStation Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Mac OS X,
|
||||
030000004c050000da0c000000010000,PlayStation Classic Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Mac OS X,
|
||||
@@ -947,6 +951,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
030000004c0500006802000002100000,Rii RK707,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b2,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b3,righttrigger:b9,rightx:a2,righty:a3,start:b1,x:b15,y:b12,platform:Mac OS X,
|
||||
03000000c6240000fefa000000000000,Rock Candy PS3,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
|
||||
030000006f0e00008701000005010000,Rock Candy Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
03000000e804000000a000001b010000,Samsung EIGP20,a:b1,b:b3,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b11,leftx:a1,lefty:a3,rightshoulder:b12,rightx:a4,righty:a5,start:b16,x:b7,y:b9,platform:Mac OS X,
|
||||
03000000730700000401000000010000,Sanwa PlayOnline Mobile,a:b0,b:b1,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,platform:Mac OS X,
|
||||
03000000a30c00002500000006020000,Sega Genesis Mini 3B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,righttrigger:b5,start:b9,platform:Mac OS X,
|
||||
03000000811700007e05000000000000,Sega Saturn,a:b2,b:b4,dpdown:b16,dpleft:b15,dpright:b14,dpup:b17,leftshoulder:b8,lefttrigger:a5,leftx:a0,lefty:a2,rightshoulder:b9,righttrigger:a4,start:b13,x:b0,y:b6,platform:Mac OS X,
|
||||
@@ -992,6 +997,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
030000005e040000130b000011050000,Xbox One Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
|
||||
030000005e040000200b000011050000,Xbox One Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
|
||||
030000005e040000200b000013050000,Xbox One Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
|
||||
030000005e040000200b000015050000,Xbox One Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
|
||||
030000005e040000d102000000000000,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
|
||||
030000005e040000dd02000000000000,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
|
||||
030000005e040000e002000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Mac OS X,
|
||||
@@ -1067,6 +1073,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000c82d00000760000011010000,8BitDo Ultimate Wireless,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
|
||||
03000000c82d00001230000011010000,8BitDo Ultimate Wireless,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
03000000c82d00001330000011010000,8BitDo Ultimate Wireless,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b23,paddle2:b19,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
03000000c82d00000121000011010000,8BitDo Xbox One SN30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
05000000c82d00000121000000010000,8BitDo Xbox One SN30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
05000000a00500003232000001000000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux,
|
||||
05000000a00500003232000008010000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux,
|
||||
03000000c82d00001890000011010000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
|
||||
@@ -1176,6 +1184,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
030000000d0f00006a00000011010000,Hori Real Arcade Pro 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
|
||||
030000000d0f00006b00000011010000,Hori Real Arcade Pro 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
030000000d0f00001600000000010000,Hori Real Arcade Pro EXSE,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b2,y:b3,platform:Linux,
|
||||
030000000d0f00008501000015010000,Hori Switch Split Pad Pro,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000000d0f00006e00000011010000,Horipad 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
030000000d0f00006600000011010000,Horipad 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
|
||||
030000000d0f0000ee00000011010000,Horipad Mini 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
|
||||
@@ -1185,6 +1194,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000341a000005f7000010010000,HuiJia GameCube Controller Adapter,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Linux,
|
||||
05000000242e00000b20000001000000,Hyperkin Admiral N64 Controller,+rightx:b11,+righty:b13,-rightx:b8,-righty:b12,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,platform:Linux,
|
||||
03000000242e0000ff0b000011010000,Hyperkin N64 Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b9,platform:Linux,
|
||||
03000000242e00006a38000010010000,Hyperkin Trooper 2,a:b0,b:b1,back:b4,start:b5,leftshoulder:b2,rightshoulder:b3,leftx:a0,lefty:a1,platform:Linux,
|
||||
03000000242e00008816000001010000,Hyperkin X91,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
03000000f00300008d03000011010000,HyperX Clutch,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
03000000830500006020000010010000,iBuffalo SNES Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Linux,
|
||||
@@ -1251,26 +1261,28 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000b50700001203000010010000,Mega World Logic 3 Controller,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux,
|
||||
03000000780000000600000010010000,Microntek Joystick,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,
|
||||
030000005e0400002800000000010000,Microsoft Dual Strike,a:b3,b:b2,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,rightshoulder:b7,rightx:a0,righty:a1~,start:b5,x:b1,y:b0,platform:Linux,
|
||||
030000005e0400000e00000000010000,Microsoft SideWinder,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Linux,
|
||||
030000005e0400000700000000010000,Microsoft SideWinder Gamepad,a:b0,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Linux,
|
||||
030000005e0400000300000000010000,Microsoft SideWinder,a:b0,b:b1,back:b9,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Linux,
|
||||
030000005e0400000700000000010000,Microsoft SideWinder,a:b0,b:b1,back:b8,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Linux,
|
||||
030000005e0400000e00000000010000,Microsoft SideWinder Freestyle Pro,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Linux,
|
||||
030000005e0400002700000000010000,Microsoft SideWinder Plug and Play,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b4,righttrigger:b5,x:b2,y:b3,platform:Linux,
|
||||
030000005e0400008502000000010000,Microsoft Xbox,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux,
|
||||
030000005e0400008902000021010000,Microsoft Xbox,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux,
|
||||
030000005e0400008e02000001000000,Microsoft Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.1,dpleft:h0.2,dpright:h0.8,dpup:h0.4,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000005e0400008e02000004010000,Microsoft Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000005e0400008e02000056210000,Microsoft Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000005e0400008e02000062230000,Microsoft Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000005e040000120b00000b050000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000005e040000d102000001010000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000005e040000d102000003020000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
060000005e040000120b000009050000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000005e040000dd02000003020000,Microsoft Xbox One 2015,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000005e040000dd02000003020000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000005e040000ea02000008040000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
060000005e040000120b000009050000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000005e040000e302000003020000,Microsoft Xbox One Elite,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000005e040000000b000008040000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
050000005e040000050b000003090000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
030000005e040000ea02000008040000,Microsoft Xbox One S,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000005e0400008902000021010000,Microsoft Xbox pad v2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux,
|
||||
030000005e040000120b00000b050000,Microsoft Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
03000000030000000300000002000000,Miroof,a:b1,b:b0,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Linux,
|
||||
050000004d4f435554452d3035335800,Mocute 053X,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
|
||||
05000000e80400006e0400001b010000,Mocute 053X M59,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
050000004d4f435554452d3035305800,Mocute 054X,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
05000000d6200000e589000001000000,Moga 2,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux,
|
||||
05000000d6200000ad0d000001000000,Moga Pro,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux,
|
||||
@@ -1301,7 +1313,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000d620000011a7000011010000,Nintendo Switch PowerA Core Plus Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
030000007e0500000920000000026803,Nintendo Switch Pro Controller,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Linux,
|
||||
030000007e0500000920000011810000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
|
||||
050000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
|
||||
050000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
|
||||
050000007e0500000920000001800000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
|
||||
050000007e0500000720000001800000,Nintendo Switch Right Joy-Con,a:b1,b:b2,back:b9,leftshoulder:b4,leftstick:b10,leftx:a1~,lefty:a0,rightshoulder:b6,start:b8,x:b0,y:b3,platform:Linux,
|
||||
05000000010000000100000003000000,Nintendo Wii Remote,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
|
||||
@@ -1330,9 +1342,11 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
030000006f0e0000c802000012010000,PDP Kingdom Hearts Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000006f0e00008501000011010000,PDP Nintendo Switch Fightpad Pro,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
|
||||
030000006f0e00002801000011010000,PDP PS3 Rock Candy Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
030000006f0e00000901000011010000,PDP Versus Fighting,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
|
||||
030000006f0e00000901000011010000,PDP PS3 Versus Fighting,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
|
||||
03000000ad1b000004f9000000010000,PDP Xbox 360 Versus Fighting,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000006f0e0000a802000023020000,PDP Xbox One Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
|
||||
030000006f0e0000a702000023020000,PDP Xbox One Raven Black,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000006f0e0000d802000006640000,PDP Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
03000000666600006706000000010000,PlayStation Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Linux,
|
||||
030000004c050000da0c000011010000,PlayStation Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,
|
||||
03000000d9040000160f000000010000,PlayStation Controller Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux,
|
||||
@@ -1432,6 +1446,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000a30600000901000000010000,Saitek P880,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,x:b0,y:b1,platform:Linux,
|
||||
03000000a30600000b04000000010000,Saitek P990 Dual Analog,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b8,x:b0,y:b3,platform:Linux,
|
||||
03000000a306000020f6000011010000,Saitek PS2700 Rumble,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux,
|
||||
05000000e804000000a000001b010000,Samsung EIGP20,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
03000000d81d00000e00000010010000,Savior,a:b0,b:b1,back:b8,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b11,righttrigger:b3,start:b9,x:b4,y:b5,platform:Linux,
|
||||
03000000a30c00002500000011010000,Sega Genesis Mini 3B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,righttrigger:b5,start:b9,platform:Linux,
|
||||
03000000790000001100000011010000,Sega Saturn,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b4,start:b9,x:b0,y:b3,platform:Linux,
|
||||
@@ -1525,14 +1540,12 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000ffff0000ffff000000010000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux,
|
||||
0000000058626f782047616d65706100,Xbox Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000005e0400000a0b000005040000,Xbox One Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux,
|
||||
030000005e040000120b000009050000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000005e040000d102000002010000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000005e040000ea02000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000005e040000ea02000001030000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
050000005e040000e002000003090000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
050000005e040000fd02000003090000,Xbox One Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
050000005e040000fd02000030110000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
060000005e040000120b000007050000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
050000005e040000e302000002090000,Xbox One Elite,a:b0,b:b1,back:b136,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
050000005e040000220b000013050000,Xbox One Elite 2 Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
050000005e040000050b000002090000,Xbox One Elite Series 2,a:b0,b:b1,back:b136,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
@@ -1540,16 +1553,20 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
060000005e040000ea0200000d050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000005e040000120b000001050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000005e040000120b000005050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000005e040000120b000007050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000005e040000120b000009050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000005e040000120b00000d050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000005e040000120b00000f050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000005e040000130b000005050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
050000005e040000130b000001050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
050000005e040000130b000005050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
050000005e040000130b000007050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
050000005e040000130b000009050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
050000005e040000130b000011050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
050000005e040000130b000013050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
050000005e040000130b000015050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
060000005e040000120b000007050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
060000005e040000120b00000b050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000005e040000120b000007050000,Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
050000005e040000130b000007050000,Xbox Series X Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
050000005e040000130b000011050000,Xbox Series X Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
050000005e040000200b000013050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
03000000450c00002043000010010000,XEOX SL6556 BK,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
|
||||
05000000172700004431000029010000,XiaoMi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Linux,
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
#ifdef SHADER_MODEL // make safe to include in resource file to enforce dependency
|
||||
|
||||
#ifndef PS_SCALE_FACTOR
|
||||
#define PS_SCALE_FACTOR 1
|
||||
#endif
|
||||
|
||||
struct VS_INPUT
|
||||
{
|
||||
float4 p : POSITION;
|
||||
@@ -24,7 +20,6 @@ cbuffer cb0 : register(b0)
|
||||
int EMODA;
|
||||
int EMODC;
|
||||
int DOFFSET;
|
||||
int cb0_pad;
|
||||
};
|
||||
|
||||
static const float3x3 rgb2yuv =
|
||||
@@ -274,16 +269,25 @@ PS_OUTPUT ps_convert_rgba_8i(PS_INPUT input)
|
||||
uint2 subblock = pos & uint2(7u, 1u);
|
||||
uint2 coord = block | subblock;
|
||||
|
||||
// Compensate for potentially differing page pitch.
|
||||
uint SBW = uint(EMODA);
|
||||
uint DBW = uint(EMODC);
|
||||
uint2 block_xy = coord / uint2(64, 32);
|
||||
uint block_num = (block_xy.y * (DBW / 128)) + block_xy.x;
|
||||
uint2 block_offset = uint2((block_num % (SBW / 64)) * 64, (block_num / (SBW / 64)) * 32);
|
||||
coord = (coord % uint2(64, 32)) + block_offset;
|
||||
|
||||
// Apply offset to cols 1 and 2
|
||||
uint is_col23 = pos.y & 4u;
|
||||
uint is_col13 = pos.y & 2u;
|
||||
uint is_col12 = is_col23 ^ (is_col13 << 1);
|
||||
coord.x ^= is_col12; // If cols 1 or 2, flip bit 3 of x
|
||||
|
||||
if (floor(PS_SCALE_FACTOR) != PS_SCALE_FACTOR)
|
||||
coord = uint2(float2(coord) * PS_SCALE_FACTOR);
|
||||
float ScaleFactor = BGColor.x;
|
||||
if (floor(ScaleFactor) != ScaleFactor)
|
||||
coord = uint2(float2(coord) * ScaleFactor);
|
||||
else
|
||||
coord *= PS_SCALE_FACTOR;
|
||||
coord *= uint(ScaleFactor);
|
||||
|
||||
float4 pixel = Texture.Load(int3(int2(coord), 0));
|
||||
float2 sel0 = (pos.y & 2u) == 0u ? pixel.rb : pixel.ga;
|
||||
@@ -295,7 +299,7 @@ PS_OUTPUT ps_convert_rgba_8i(PS_INPUT input)
|
||||
PS_OUTPUT ps_convert_clut_4(PS_INPUT input)
|
||||
{
|
||||
// Borrowing the YUV constant buffer.
|
||||
float2 scale = BGColor.xy;
|
||||
float scale = BGColor.x;
|
||||
uint2 offset = uint2(uint(EMODA), uint(EMODC)) + uint(DOFFSET);
|
||||
|
||||
// CLUT4 is easy, just two rows of 8x8.
|
||||
@@ -310,7 +314,7 @@ PS_OUTPUT ps_convert_clut_4(PS_INPUT input)
|
||||
|
||||
PS_OUTPUT ps_convert_clut_8(PS_INPUT input)
|
||||
{
|
||||
float2 scale = BGColor.xy;
|
||||
float scale = BGColor.x;
|
||||
uint2 offset = uint2(uint(EMODA), uint(EMODC));
|
||||
uint index = min(uint(input.p.x) + uint(DOFFSET), 255u);
|
||||
|
||||
|
||||
@@ -30,7 +30,8 @@
|
||||
#define PS_ATST 1
|
||||
#define PS_FOG 0
|
||||
#define PS_IIP 0
|
||||
#define PS_CLR_HW 0
|
||||
#define PS_BLEND_HW 0
|
||||
#define PS_A_MASKED 0
|
||||
#define PS_FBA 0
|
||||
#define PS_FBMASK 0
|
||||
#define PS_LTF 1
|
||||
@@ -38,13 +39,13 @@
|
||||
#define PS_POINT_SAMPLER 0
|
||||
#define PS_SHUFFLE 0
|
||||
#define PS_READ_BA 0
|
||||
#define PS_READ16_SRC 0
|
||||
#define PS_DFMT 0
|
||||
#define PS_DEPTH_FMT 0
|
||||
#define PS_PAL_FMT 0
|
||||
#define PS_CHANNEL_FETCH 0
|
||||
#define PS_TALES_OF_ABYSS_HLE 0
|
||||
#define PS_URBAN_CHAOS_HLE 0
|
||||
#define PS_SCALE_FACTOR 1.0
|
||||
#define PS_HDR 0
|
||||
#define PS_COLCLIP 0
|
||||
#define PS_BLEND_A 0
|
||||
@@ -52,6 +53,7 @@
|
||||
#define PS_BLEND_C 0
|
||||
#define PS_BLEND_D 0
|
||||
#define PS_BLEND_MIX 0
|
||||
#define PS_ROUND_INV 0
|
||||
#define PS_FIXED_ONE_A 0
|
||||
#define PS_PABE 0
|
||||
#define PS_DITHER 0
|
||||
@@ -69,6 +71,7 @@
|
||||
|
||||
#define SW_BLEND (PS_BLEND_A || PS_BLEND_B || PS_BLEND_D)
|
||||
#define SW_BLEND_NEEDS_RT (SW_BLEND && (PS_BLEND_A == 1 || PS_BLEND_B == 1 || PS_BLEND_C == 1 || PS_BLEND_D == 1))
|
||||
#define SW_AD_TO_HW (PS_BLEND_C == 1 && PS_A_MASKED)
|
||||
|
||||
struct VS_INPUT
|
||||
{
|
||||
@@ -167,6 +170,8 @@ cbuffer cb1
|
||||
float2 TC_OffsetHack;
|
||||
float2 STScale;
|
||||
float4x4 DitherMatrix;
|
||||
float ScaledScaleFactor;
|
||||
float RcpScaleFactor;
|
||||
};
|
||||
|
||||
float4 sample_c(float2 uv, float uv_w)
|
||||
@@ -398,7 +403,7 @@ int2 clamp_wrap_uv_depth(int2 uv)
|
||||
|
||||
float4 sample_depth(float2 st, float2 pos)
|
||||
{
|
||||
float2 uv_f = (float2)clamp_wrap_uv_depth(int2(st)) * (float2)PS_SCALE_FACTOR * (float2)(1.0f / 16.0f);
|
||||
float2 uv_f = (float2)clamp_wrap_uv_depth(int2(st)) * (float2)ScaledScaleFactor;
|
||||
int2 uv = (int2)uv_f;
|
||||
|
||||
float4 t = (float4)(0.0f);
|
||||
@@ -738,9 +743,13 @@ void ps_dither(inout float3 C, float2 pos_xy)
|
||||
if (PS_DITHER == 2)
|
||||
fpos = int2(pos_xy);
|
||||
else
|
||||
fpos = int2(pos_xy / (float)PS_SCALE_FACTOR);
|
||||
fpos = int2(pos_xy * RcpScaleFactor);
|
||||
|
||||
C += DitherMatrix[fpos.x & 3][fpos.y & 3];
|
||||
float value = DitherMatrix[fpos.x & 3][fpos.y & 3];
|
||||
if (PS_ROUND_INV)
|
||||
C -= value;
|
||||
else
|
||||
C += value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -750,6 +759,9 @@ void ps_color_clamp_wrap(inout float3 C)
|
||||
// so we need to limit the color depth on dithered items
|
||||
if (SW_BLEND || PS_DITHER || PS_FBMASK)
|
||||
{
|
||||
if (PS_DFMT == FMT_16 && PS_BLEND_MIX == 0 && PS_ROUND_INV)
|
||||
C += 7.0f; // Need to round up, not down since the shader will invert
|
||||
|
||||
// Standard Clamp
|
||||
if (PS_COLCLIP == 0 && PS_HDR == 0)
|
||||
C = clamp(C, (float3)0.0f, (float3)255.0f);
|
||||
@@ -762,8 +774,10 @@ void ps_color_clamp_wrap(inout float3 C)
|
||||
}
|
||||
}
|
||||
|
||||
void ps_blend(inout float4 Color, inout float As, float2 pos_xy)
|
||||
void ps_blend(inout float4 Color, inout float4 As_rgba, float2 pos_xy)
|
||||
{
|
||||
float As = As_rgba.a;
|
||||
|
||||
if (SW_BLEND)
|
||||
{
|
||||
// PABE
|
||||
@@ -787,9 +801,9 @@ void ps_blend(inout float4 Color, inout float As, float2 pos_xy)
|
||||
float3 D = (PS_BLEND_D == 0) ? Cs : ((PS_BLEND_D == 1) ? Cd : (float3)0.0f);
|
||||
|
||||
// As/Af clamp alpha for Blend mix
|
||||
// We shouldn't clamp blend mix with clr1 as we want alpha higher
|
||||
// We shouldn't clamp blend mix with blend hw 1 as we want alpha higher
|
||||
float C_clamped = C;
|
||||
if (PS_BLEND_MIX > 0 && PS_CLR_HW != 1)
|
||||
if (PS_BLEND_MIX > 0 && PS_BLEND_HW != 1)
|
||||
C_clamped = min(C_clamped, 1.0f);
|
||||
|
||||
if (PS_BLEND_A == PS_BLEND_B)
|
||||
@@ -808,21 +822,19 @@ void ps_blend(inout float4 Color, inout float As, float2 pos_xy)
|
||||
else
|
||||
Color.rgb = trunc(((A - B) * C) + D);
|
||||
|
||||
if (PS_CLR_HW == 1)
|
||||
if (PS_BLEND_HW == 1)
|
||||
{
|
||||
// Replace Af with As so we can do proper compensation for Alpha.
|
||||
if (PS_BLEND_C == 2)
|
||||
As = Af;
|
||||
// As or Af
|
||||
As_rgba.rgb = (float3)C;
|
||||
// Subtract 1 for alpha to compensate for the changed equation,
|
||||
// if c.rgb > 255.0f then we further need to adjust alpha accordingly,
|
||||
// we pick the lowest overflow from all colors because it's the safest,
|
||||
// we divide by 255 the color because we don't know Cd value,
|
||||
// changed alpha should only be done for hw blend.
|
||||
float min_color = min(min(Color.r, Color.g), Color.b);
|
||||
float alpha_compensate = max(1.0f, min_color / 255.0f);
|
||||
As -= alpha_compensate;
|
||||
float3 alpha_compensate = max((float3)1.0f, Color.rgb / (float3)255.0f);
|
||||
As_rgba.rgb -= alpha_compensate;
|
||||
}
|
||||
else if (PS_CLR_HW == 2)
|
||||
else if (PS_BLEND_HW == 2)
|
||||
{
|
||||
// Compensate slightly for Cd*(As + 1) - Cs*As.
|
||||
// The initial factor we chose is 1 (0.00392)
|
||||
@@ -832,16 +844,26 @@ void ps_blend(inout float4 Color, inout float As, float2 pos_xy)
|
||||
float color_compensate = 1.0f * (C + 1.0f);
|
||||
Color.rgb -= (float3)color_compensate;
|
||||
}
|
||||
else if (PS_BLEND_HW == 3)
|
||||
{
|
||||
// As, Ad or Af clamped.
|
||||
As_rgba.rgb = (float3)C_clamped;
|
||||
// Cs*(Alpha + 1) might overflow, if it does then adjust alpha value
|
||||
// that is sent on second output to compensate.
|
||||
float3 overflow_check = (Color.rgb - (float3)255.0f) / 255.0f;
|
||||
float3 alpha_compensate = max((float3)0.0f, overflow_check);
|
||||
As_rgba.rgb -= alpha_compensate;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (PS_CLR_HW == 1 || PS_CLR_HW == 5)
|
||||
if (PS_BLEND_HW == 1)
|
||||
{
|
||||
// Needed for Cd * (As/Ad/F + 1) blending modes
|
||||
|
||||
Color.rgb = (float3)255.0f;
|
||||
}
|
||||
else if (PS_CLR_HW == 2 || PS_CLR_HW == 4)
|
||||
else if (PS_BLEND_HW == 2)
|
||||
{
|
||||
// Cd*As,Cd*Ad or Cd*F
|
||||
|
||||
@@ -850,12 +872,16 @@ void ps_blend(inout float4 Color, inout float As, float2 pos_xy)
|
||||
Color.rgb = max((float3)0.0f, (Alpha - (float3)1.0f));
|
||||
Color.rgb *= (float3)255.0f;
|
||||
}
|
||||
else if (PS_CLR_HW == 3)
|
||||
else if (PS_BLEND_HW == 3)
|
||||
{
|
||||
// Needed for Cs*Ad, Cs*Ad + Cd, Cd - Cs*Ad
|
||||
// Multiply Color.rgb by (255/128) to compensate for wrong Ad/255 value
|
||||
|
||||
Color.rgb *= (255.0f / 128.0f);
|
||||
// Multiply Color.rgb by (255/128) to compensate for wrong Ad/255 value when rgb are below 128.
|
||||
// When any color channel is higher than 128 then adjust the compensation automatically
|
||||
// to give us more accurate colors, otherwise they will be wrong.
|
||||
// The higher the value (>128) the lower the compensation will be.
|
||||
float max_color = max(max(Color.r, Color.g), Color.b);
|
||||
float color_compensate = 255.0f / max(128.0f, max_color);
|
||||
Color.rgb *= (float3)color_compensate;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -877,26 +903,37 @@ PS_OUTPUT ps_main(PS_INPUT input)
|
||||
{
|
||||
uint4 denorm_c = uint4(C);
|
||||
uint2 denorm_TA = uint2(float2(TA.xy) * 255.0f + 0.5f);
|
||||
|
||||
// Mask will take care of the correct destination
|
||||
if (PS_READ_BA)
|
||||
C.rb = C.bb;
|
||||
else
|
||||
C.rb = C.rr;
|
||||
|
||||
if (PS_READ_BA)
|
||||
|
||||
if (PS_READ16_SRC)
|
||||
{
|
||||
C.rb = (float2)float((denorm_c.r >> 3) | (((denorm_c.g >> 3) & 0x7u) << 5));
|
||||
if (denorm_c.a & 0x80u)
|
||||
C.ga = (float2)(float((denorm_c.a & 0x7Fu) | (denorm_TA.y & 0x80u)));
|
||||
C.ga = (float2)float((denorm_c.g >> 6) | ((denorm_c.b >> 3) << 2) | (denorm_TA.y & 0x80u));
|
||||
else
|
||||
C.ga = (float2)(float((denorm_c.a & 0x7Fu) | (denorm_TA.x & 0x80u)));
|
||||
C.ga = (float2)float((denorm_c.g >> 6) | ((denorm_c.b >> 3) << 2) | (denorm_TA.x & 0x80u));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (denorm_c.g & 0x80u)
|
||||
C.ga = (float2)(float((denorm_c.g & 0x7Fu) | (denorm_TA.y & 0x80u)));
|
||||
// Mask will take care of the correct destination
|
||||
if (PS_READ_BA)
|
||||
C.rb = C.bb;
|
||||
else
|
||||
C.ga = (float2)(float((denorm_c.g & 0x7Fu) | (denorm_TA.x & 0x80u)));
|
||||
C.rb = C.rr;
|
||||
|
||||
if (PS_READ_BA)
|
||||
{
|
||||
if (denorm_c.a & 0x80u)
|
||||
C.ga = (float2)(float((denorm_c.a & 0x7Fu) | (denorm_TA.y & 0x80u)));
|
||||
else
|
||||
C.ga = (float2)(float((denorm_c.a & 0x7Fu) | (denorm_TA.x & 0x80u)));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (denorm_c.g & 0x80u)
|
||||
C.ga = (float2)(float((denorm_c.g & 0x7Fu) | (denorm_TA.y & 0x80u)));
|
||||
else
|
||||
C.ga = (float2)(float((denorm_c.g & 0x7Fu) | (denorm_TA.x & 0x80u)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -908,15 +945,15 @@ PS_OUTPUT ps_main(PS_INPUT input)
|
||||
C.a = 128.0f;
|
||||
}
|
||||
|
||||
float alpha_blend;
|
||||
if (PS_BLEND_C == 1 && PS_CLR_HW > 3)
|
||||
float4 alpha_blend;
|
||||
if (SW_AD_TO_HW)
|
||||
{
|
||||
float4 RT = trunc(RtTexture.Load(int3(input.p.xy, 0)) * 255.0f + 0.1f);
|
||||
alpha_blend = RT.a / 128.0f;
|
||||
alpha_blend = (float4)(RT.a / 128.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
alpha_blend = C.a / 128.0f;
|
||||
alpha_blend = (float4)(C.a / 128.0f);
|
||||
}
|
||||
|
||||
// Alpha correction
|
||||
@@ -966,12 +1003,12 @@ PS_OUTPUT ps_main(PS_INPUT input)
|
||||
#if !PS_NO_COLOR
|
||||
output.c0 = PS_HDR ? float4(C.rgb / 65535.0f, C.a / 255.0f) : C / 255.0f;
|
||||
#if !PS_NO_COLOR1
|
||||
output.c1 = (float4)(alpha_blend);
|
||||
output.c1 = alpha_blend;
|
||||
#endif
|
||||
|
||||
#if PS_NO_ABLEND
|
||||
// write alpha blend factor into col0
|
||||
output.c0.a = alpha_blend;
|
||||
output.c0.a = alpha_blend.a;
|
||||
#endif
|
||||
#if PS_ONLY_ALPHA
|
||||
// rgb isn't used
|
||||
|
||||
@@ -88,6 +88,9 @@ layout(std140, binding = 0) uniform cb21
|
||||
vec2 STScale;
|
||||
|
||||
mat4 DitherMatrix;
|
||||
|
||||
float ScaledScaleFactor;
|
||||
float RcpScaleFactor;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
@@ -234,6 +234,10 @@ void ps_convert_rgb5a1_float16_biln()
|
||||
#endif
|
||||
|
||||
#ifdef ps_convert_rgba_8i
|
||||
uniform uint SBW;
|
||||
uniform uint DBW;
|
||||
uniform float ScaleFactor;
|
||||
|
||||
void ps_convert_rgba_8i()
|
||||
{
|
||||
// Convert a RGBA texture into a 8 bits packed texture
|
||||
@@ -252,16 +256,22 @@ void ps_convert_rgba_8i()
|
||||
uvec2 subblock = pos & uvec2(7u, 1u);
|
||||
uvec2 coord = block | subblock;
|
||||
|
||||
// Compensate for potentially differing page pitch.
|
||||
uvec2 block_xy = coord / uvec2(64u, 32u);
|
||||
uint block_num = (block_xy.y * (DBW / 128u)) + block_xy.x;
|
||||
uvec2 block_offset = uvec2((block_num % (SBW / 64u)) * 64u, (block_num / (SBW / 64u)) * 32u);
|
||||
coord = (coord % uvec2(64u, 32u)) + block_offset;
|
||||
|
||||
// Apply offset to cols 1 and 2
|
||||
uint is_col23 = pos.y & 4u;
|
||||
uint is_col13 = pos.y & 2u;
|
||||
uint is_col12 = is_col23 ^ (is_col13 << 1);
|
||||
coord.x ^= is_col12; // If cols 1 or 2, flip bit 3 of x
|
||||
|
||||
if (floor(PS_SCALE_FACTOR) != PS_SCALE_FACTOR)
|
||||
coord = uvec2(vec2(coord) * PS_SCALE_FACTOR);
|
||||
if (floor(ScaleFactor) != ScaleFactor)
|
||||
coord = uvec2(vec2(coord) * ScaleFactor);
|
||||
else
|
||||
coord *= uvec2(PS_SCALE_FACTOR);
|
||||
coord *= uvec2(ScaleFactor);
|
||||
|
||||
vec4 pixel = texelFetch(TextureSampler, ivec2(coord), 0);
|
||||
vec2 sel0 = (pos.y & 2u) == 0u ? pixel.rb : pixel.ga;
|
||||
@@ -316,7 +326,7 @@ void ps_hdr_resolve()
|
||||
|
||||
#ifdef ps_convert_clut_4
|
||||
uniform uvec3 offset;
|
||||
uniform vec2 scale;
|
||||
uniform float scale;
|
||||
|
||||
void ps_convert_clut_4()
|
||||
{
|
||||
@@ -324,14 +334,14 @@ void ps_convert_clut_4()
|
||||
uint index = uint(gl_FragCoord.x) + offset.z;
|
||||
uvec2 pos = uvec2(index % 8u, index / 8u);
|
||||
|
||||
ivec2 final = ivec2(floor(vec2(offset.xy + pos) * scale));
|
||||
ivec2 final = ivec2(floor(vec2(offset.xy + pos) * vec2(scale)));
|
||||
SV_Target0 = texelFetch(TextureSampler, final, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_convert_clut_8
|
||||
uniform uvec3 offset;
|
||||
uniform vec2 scale;
|
||||
uniform float scale;
|
||||
|
||||
void ps_convert_clut_8()
|
||||
{
|
||||
@@ -344,7 +354,7 @@ void ps_convert_clut_8()
|
||||
pos.x = (index % 8u) + ((subgroup >= 2u) ? 8u : 0u);
|
||||
pos.y = ((index / 32u) * 2u) + (subgroup % 2u);
|
||||
|
||||
ivec2 final = ivec2(floor(vec2(offset.xy + pos) * scale));
|
||||
ivec2 final = ivec2(floor(vec2(offset.xy + pos) * vec2(scale)));
|
||||
SV_Target0 = texelFetch(TextureSampler, final, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
#define SW_BLEND (PS_BLEND_A || PS_BLEND_B || PS_BLEND_D)
|
||||
#define SW_BLEND_NEEDS_RT (SW_BLEND && (PS_BLEND_A == 1 || PS_BLEND_B == 1 || PS_BLEND_C == 1 || PS_BLEND_D == 1))
|
||||
#define SW_AD_TO_HW (PS_BLEND_C == 1 && PS_CLR_HW > 3)
|
||||
#define SW_AD_TO_HW (PS_BLEND_C == 1 && PS_A_MASKED)
|
||||
#define PS_PRIMID_INIT (PS_DATE == 1 || PS_DATE == 2)
|
||||
#define NEEDS_RT_EARLY (PS_TEX_IS_FB == 1 || PS_DATE >= 5)
|
||||
#define NEEDS_RT (NEEDS_RT_EARLY || (!PS_PRIMID_INIT && (PS_FBMASK || SW_BLEND_NEEDS_RT || SW_AD_TO_HW)))
|
||||
@@ -328,7 +328,7 @@ ivec2 clamp_wrap_uv_depth(ivec2 uv)
|
||||
|
||||
vec4 sample_depth(vec2 st)
|
||||
{
|
||||
vec2 uv_f = vec2(clamp_wrap_uv_depth(ivec2(st))) * vec2(float(PS_SCALE_FACTOR)) * vec2(1.0f/16.0f);
|
||||
vec2 uv_f = vec2(clamp_wrap_uv_depth(ivec2(st))) * vec2(ScaledScaleFactor);
|
||||
ivec2 uv = ivec2(uv_f);
|
||||
|
||||
vec4 t = vec4(0.0f);
|
||||
@@ -652,9 +652,14 @@ void ps_dither(inout vec3 C)
|
||||
#if PS_DITHER == 2
|
||||
ivec2 fpos = ivec2(gl_FragCoord.xy);
|
||||
#else
|
||||
ivec2 fpos = ivec2(gl_FragCoord.xy / float(PS_SCALE_FACTOR));
|
||||
ivec2 fpos = ivec2(gl_FragCoord.xy * RcpScaleFactor);
|
||||
#endif
|
||||
float value = DitherMatrix[fpos.y&3][fpos.x&3];
|
||||
#if PS_ROUND_INV
|
||||
C -= value;
|
||||
#else
|
||||
C += value;
|
||||
#endif
|
||||
C += DitherMatrix[fpos.y&3][fpos.x&3];
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -664,6 +669,10 @@ void ps_color_clamp_wrap(inout vec3 C)
|
||||
// so we need to limit the color depth on dithered items
|
||||
#if SW_BLEND || PS_DITHER || PS_FBMASK
|
||||
|
||||
#if PS_DFMT == FMT_16 && PS_BLEND_MIX == 0 && PS_ROUND_INV
|
||||
C += 7.0f; // Need to round up, not down since the shader will invert
|
||||
#endif
|
||||
|
||||
// Correct the Color value based on the output format
|
||||
#if PS_COLCLIP == 0 && PS_HDR == 0
|
||||
// Standard Clamp
|
||||
@@ -686,8 +695,10 @@ void ps_color_clamp_wrap(inout vec3 C)
|
||||
#endif
|
||||
}
|
||||
|
||||
void ps_blend(inout vec4 Color, inout float As)
|
||||
void ps_blend(inout vec4 Color, inout vec4 As_rgba)
|
||||
{
|
||||
float As = As_rgba.a;
|
||||
|
||||
#if SW_BLEND
|
||||
|
||||
// PABE
|
||||
@@ -742,9 +753,9 @@ void ps_blend(inout vec4 Color, inout float As)
|
||||
#endif
|
||||
|
||||
// As/Af clamp alpha for Blend mix
|
||||
// We shouldn't clamp blend mix with clr1 as we want alpha higher
|
||||
// We shouldn't clamp blend mix with blend hw 1 as we want alpha higher
|
||||
float C_clamped = C;
|
||||
#if PS_BLEND_MIX > 0 && PS_CLR_HW != 1
|
||||
#if PS_BLEND_MIX > 0 && PS_BLEND_HW != 1
|
||||
C_clamped = min(C_clamped, 1.0f);
|
||||
#endif
|
||||
|
||||
@@ -765,20 +776,17 @@ void ps_blend(inout vec4 Color, inout float As)
|
||||
Color.rgb = trunc((A - B) * C + D);
|
||||
#endif
|
||||
|
||||
#if PS_CLR_HW == 1
|
||||
// Replace Af with As so we can do proper compensation for Alpha.
|
||||
#if PS_BLEND_C == 2
|
||||
As = Af;
|
||||
#endif
|
||||
#if PS_BLEND_HW == 1
|
||||
// As or Af
|
||||
As_rgba.rgb = vec3(C);
|
||||
// Subtract 1 for alpha to compensate for the changed equation,
|
||||
// if c.rgb > 255.0f then we further need to adjust alpha accordingly,
|
||||
// we pick the lowest overflow from all colors because it's the safest,
|
||||
// we divide by 255 the color because we don't know Cd value,
|
||||
// changed alpha should only be done for hw blend.
|
||||
float min_color = min(min(Color.r, Color.g), Color.b);
|
||||
float alpha_compensate = max(1.0f, min_color / 255.0f);
|
||||
As -= alpha_compensate;
|
||||
#elif PS_CLR_HW == 2
|
||||
vec3 alpha_compensate = max(vec3(1.0f), Color.rgb / vec3(255.0f));
|
||||
As_rgba.rgb -= alpha_compensate;
|
||||
#elif PS_BLEND_HW == 2
|
||||
// Compensate slightly for Cd*(As + 1) - Cs*As.
|
||||
// The initial factor we chose is 1 (0.00392)
|
||||
// as that is the minimum color Cd can be,
|
||||
@@ -786,13 +794,21 @@ void ps_blend(inout vec4 Color, inout float As)
|
||||
// blended value it can be.
|
||||
float color_compensate = 1.0f * (C + 1.0f);
|
||||
Color.rgb -= vec3(color_compensate);
|
||||
#elif PS_BLEND_HW == 3
|
||||
// As, Ad or Af clamped.
|
||||
As_rgba.rgb = vec3(C_clamped);
|
||||
// Cs*(Alpha + 1) might overflow, if it does then adjust alpha value
|
||||
// that is sent on second output to compensate.
|
||||
vec3 overflow_check = (Color.rgb - vec3(255.0f)) / 255.0f;
|
||||
vec3 alpha_compensate = max(vec3(0.0f), overflow_check);
|
||||
As_rgba.rgb -= alpha_compensate;
|
||||
#endif
|
||||
|
||||
#else
|
||||
// Needed for Cd * (As/Ad/F + 1) blending modes
|
||||
#if PS_CLR_HW == 1 || PS_CLR_HW == 5
|
||||
#if PS_BLEND_HW == 1
|
||||
Color.rgb = vec3(255.0f);
|
||||
#elif PS_CLR_HW == 2 || PS_CLR_HW == 4
|
||||
#elif PS_BLEND_HW == 2
|
||||
// Cd*As,Cd*Ad or Cd*F
|
||||
|
||||
#if PS_BLEND_C == 2
|
||||
@@ -803,11 +819,15 @@ void ps_blend(inout vec4 Color, inout float As)
|
||||
|
||||
Color.rgb = max(vec3(0.0f), (Alpha - vec3(1.0f)));
|
||||
Color.rgb *= vec3(255.0f);
|
||||
#elif PS_CLR_HW == 3
|
||||
#elif PS_BLEND_HW == 3
|
||||
// Needed for Cs*Ad, Cs*Ad + Cd, Cd - Cs*Ad
|
||||
// Multiply Color.rgb by (255/128) to compensate for wrong Ad/255 value
|
||||
|
||||
Color.rgb *= (255.0f / 128.0f);
|
||||
// Multiply Color.rgb by (255/128) to compensate for wrong Ad/255 value when rgb are below 128.
|
||||
// When any color channel is higher than 128 then adjust the compensation automatically
|
||||
// to give us more accurate colors, otherwise they will be wrong.
|
||||
// The higher the value (>128) the lower the compensation will be.
|
||||
float max_color = max(max(Color.r, Color.g), Color.b);
|
||||
float color_compensate = 255.0f / max(128.0f, max_color);
|
||||
Color.rgb *= vec3(color_compensate);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -871,7 +891,13 @@ void ps_main()
|
||||
#if PS_SHUFFLE
|
||||
uvec4 denorm_c = uvec4(C);
|
||||
uvec2 denorm_TA = uvec2(vec2(TA.xy) * 255.0f + 0.5f);
|
||||
|
||||
#if PS_READ16_SRC
|
||||
C.rb = vec2(float((denorm_c.r >> 3) | (((denorm_c.g >> 3) & 0x7u) << 5)));
|
||||
if (bool(denorm_c.a & 0x80u))
|
||||
C.ga = vec2(float((denorm_c.g >> 6) | ((denorm_c.b >> 3) << 2) | (denorm_TA.y & 0x80u)));
|
||||
else
|
||||
C.ga = vec2(float((denorm_c.g >> 6) | ((denorm_c.b >> 3) << 2) | (denorm_TA.x & 0x80u)));
|
||||
#else
|
||||
// Write RB part. Mask will take care of the correct destination
|
||||
#if PS_READ_BA
|
||||
C.rb = C.bb;
|
||||
@@ -907,9 +933,10 @@ void ps_main()
|
||||
// float sel = step(128.0f, c.g);
|
||||
// vec2 c_shuffle = vec2((denorm_c.gg & 0x7Fu) | (denorm_TA & 0x80u));
|
||||
// c.ga = mix(c_shuffle.xx, c_shuffle.yy, sel);
|
||||
#endif
|
||||
#endif // PS_READ_BA
|
||||
|
||||
#endif
|
||||
#endif // READ16_SRC
|
||||
#endif // PS_SHUFFLE
|
||||
|
||||
// Must be done before alpha correction
|
||||
|
||||
@@ -920,9 +947,9 @@ void ps_main()
|
||||
|
||||
#if SW_AD_TO_HW
|
||||
vec4 RT = trunc(fetch_rt() * 255.0f + 0.1f);
|
||||
float alpha_blend = RT.a / 128.0f;
|
||||
vec4 alpha_blend = vec4(RT.a / 128.0f);
|
||||
#else
|
||||
float alpha_blend = C.a / 128.0f;
|
||||
vec4 alpha_blend = vec4(C.a / 128.0f);
|
||||
#endif
|
||||
|
||||
// Correct the ALPHA value based on the output format
|
||||
@@ -962,12 +989,12 @@ void ps_main()
|
||||
SV_Target0 = C / 255.0f;
|
||||
#endif
|
||||
#if !defined(DISABLE_DUAL_SOURCE) && !PS_NO_COLOR1
|
||||
SV_Target1 = vec4(alpha_blend);
|
||||
SV_Target1 = alpha_blend;
|
||||
#endif
|
||||
|
||||
#if PS_NO_ABLEND
|
||||
// write alpha blend factor into col0
|
||||
SV_Target0.a = alpha_blend;
|
||||
SV_Target0.a = alpha_blend.a;
|
||||
#endif
|
||||
#if PS_ONLY_ALPHA
|
||||
// rgb isn't used
|
||||
|
||||
@@ -77,7 +77,7 @@ void vs_main()
|
||||
VSout.t_float.z = i_f.x; // pack for with texture
|
||||
|
||||
#if VS_POINT_SIZE
|
||||
gl_PointSize = float(VS_POINT_SIZE_VALUE);
|
||||
gl_PointSize = PointSize.x;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
#ifndef PS_SCALE_FACTOR
|
||||
#define PS_SCALE_FACTOR 1.0
|
||||
#endif
|
||||
|
||||
#ifdef VERTEX_SHADER
|
||||
|
||||
layout(location = 0) in vec4 a_pos;
|
||||
@@ -23,7 +19,17 @@ layout(location = 0) in vec2 v_tex;
|
||||
|
||||
#if defined(ps_convert_rgba8_16bits) || defined(ps_convert_float32_32bits)
|
||||
layout(location = 0) out uint o_col0;
|
||||
#else
|
||||
#elif !defined(ps_datm1) && \
|
||||
!defined(ps_datm0) && \
|
||||
!defined(ps_convert_rgba8_float32) && \
|
||||
!defined(ps_convert_rgba8_float24) && \
|
||||
!defined(ps_convert_rgba8_float16) && \
|
||||
!defined(ps_convert_rgb5a1_float16) && \
|
||||
!defined(ps_convert_rgba8_float32_biln) && \
|
||||
!defined(ps_convert_rgba8_float24_biln) && \
|
||||
!defined(ps_convert_rgba8_float16_biln) && \
|
||||
!defined(ps_convert_rgb5a1_float16_biln) && \
|
||||
!defined(ps_depth_copy)
|
||||
layout(location = 0) out vec4 o_col0;
|
||||
#endif
|
||||
|
||||
@@ -69,8 +75,6 @@ void ps_convert_rgba8_16bits()
|
||||
#ifdef ps_datm1
|
||||
void ps_datm1()
|
||||
{
|
||||
o_col0 = vec4(0, 0, 0, 0);
|
||||
|
||||
if(sample_c(v_tex).a < (127.5f / 255.0f)) // >= 0x80 pass
|
||||
discard;
|
||||
|
||||
@@ -80,8 +84,6 @@ void ps_datm1()
|
||||
#ifdef ps_datm0
|
||||
void ps_datm0()
|
||||
{
|
||||
o_col0 = vec4(0, 0, 0, 0);
|
||||
|
||||
if((127.5f / 255.0f) < sample_c(v_tex).a) // < 0x80 pass (== 0x80 should not pass)
|
||||
discard;
|
||||
}
|
||||
@@ -238,6 +240,15 @@ void ps_convert_rgb5a1_float16_biln()
|
||||
#endif
|
||||
|
||||
#ifdef ps_convert_rgba_8i
|
||||
layout(push_constant) uniform cb10
|
||||
{
|
||||
uint SBW;
|
||||
uint DBW;
|
||||
uvec2 cb_pad1;
|
||||
float ScaleFactor;
|
||||
vec3 cb_pad2;
|
||||
};
|
||||
|
||||
void ps_convert_rgba_8i()
|
||||
{
|
||||
// Convert a RGBA texture into a 8 bits packed texture
|
||||
@@ -249,37 +260,45 @@ void ps_convert_rgba_8i()
|
||||
// 1: 8 R | 8 B
|
||||
// 2: 8 G | 8 A
|
||||
// 3: 8 G | 8 A
|
||||
uvec2 pos = uvec2(gl_FragCoord.xy);
|
||||
uvec2 pos = uvec2(gl_FragCoord.xy);
|
||||
|
||||
// Collapse separate R G B A areas into their base pixel
|
||||
uvec2 block = (pos & ~uvec2(15u, 3u)) >> 1;
|
||||
uvec2 subblock = pos & uvec2(7u, 1u);
|
||||
uvec2 coord = block | subblock;
|
||||
// Collapse separate R G B A areas into their base pixel
|
||||
uvec2 block = (pos & ~uvec2(15u, 3u)) >> 1;
|
||||
uvec2 subblock = pos & uvec2(7u, 1u);
|
||||
uvec2 coord = block | subblock;
|
||||
|
||||
// Apply offset to cols 1 and 2
|
||||
uint is_col23 = pos.y & 4u;
|
||||
uint is_col13 = pos.y & 2u;
|
||||
uint is_col12 = is_col23 ^ (is_col13 << 1);
|
||||
coord.x ^= is_col12; // If cols 1 or 2, flip bit 3 of x
|
||||
// Compensate for potentially differing page pitch.
|
||||
uvec2 block_xy = coord / uvec2(64u, 32u);
|
||||
uint block_num = (block_xy.y * (DBW / 128u)) + block_xy.x;
|
||||
uvec2 block_offset = uvec2((block_num % (SBW / 64u)) * 64u, (block_num / (SBW / 64u)) * 32u);
|
||||
coord = (coord % uvec2(64u, 32u)) + block_offset;
|
||||
|
||||
if (floor(PS_SCALE_FACTOR) != PS_SCALE_FACTOR)
|
||||
coord = uvec2(vec2(coord) * PS_SCALE_FACTOR);
|
||||
else
|
||||
coord *= uvec2(PS_SCALE_FACTOR);
|
||||
// Apply offset to cols 1 and 2
|
||||
uint is_col23 = pos.y & 4u;
|
||||
uint is_col13 = pos.y & 2u;
|
||||
uint is_col12 = is_col23 ^ (is_col13 << 1);
|
||||
coord.x ^= is_col12; // If cols 1 or 2, flip bit 3 of x
|
||||
|
||||
vec4 pixel = texelFetch(samp0, ivec2(coord), 0);
|
||||
vec2 sel0 = (pos.y & 2u) == 0u ? pixel.rb : pixel.ga;
|
||||
float sel1 = (pos.x & 8u) == 0u ? sel0.x : sel0.y;
|
||||
o_col0 = vec4(sel1); // Divide by something here?
|
||||
if (floor(ScaleFactor) != ScaleFactor)
|
||||
coord = uvec2(vec2(coord) * ScaleFactor);
|
||||
else
|
||||
coord *= uvec2(ScaleFactor);
|
||||
|
||||
vec4 pixel = texelFetch(samp0, ivec2(coord), 0);
|
||||
vec2 sel0 = (pos.y & 2u) == 0u ? pixel.rb : pixel.ga;
|
||||
float sel1 = (pos.x & 8u) == 0u ? sel0.x : sel0.y;
|
||||
o_col0 = vec4(sel1); // Divide by something here?
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_convert_clut_4
|
||||
layout(push_constant) uniform cb10
|
||||
{
|
||||
vec2 scale;
|
||||
uvec2 offset;
|
||||
uint doffset;
|
||||
uint cb_pad1;
|
||||
float scale;
|
||||
vec3 cb_pad2;
|
||||
};
|
||||
|
||||
void ps_convert_clut_4()
|
||||
@@ -288,7 +307,7 @@ void ps_convert_clut_4()
|
||||
uint index = uint(gl_FragCoord.x) + doffset;
|
||||
uvec2 pos = uvec2(index % 8u, index / 8u);
|
||||
|
||||
ivec2 final = ivec2(floor(vec2(offset + pos) * scale));
|
||||
ivec2 final = ivec2(floor(vec2(offset + pos) * vec2(scale)));
|
||||
o_col0 = texelFetch(samp0, final, 0);
|
||||
}
|
||||
#endif
|
||||
@@ -296,9 +315,11 @@ void ps_convert_clut_4()
|
||||
#ifdef ps_convert_clut_8
|
||||
layout(push_constant) uniform cb10
|
||||
{
|
||||
vec2 scale;
|
||||
uvec2 offset;
|
||||
uint doffset;
|
||||
uint cb_pad1;
|
||||
float scale;
|
||||
vec3 cb_pad2;
|
||||
};
|
||||
|
||||
void ps_convert_clut_8()
|
||||
@@ -312,7 +333,7 @@ void ps_convert_clut_8()
|
||||
pos.x = (index % 8u) + ((subgroup >= 2u) ? 8u : 0u);
|
||||
pos.y = ((index / 32u) * 2u) + (subgroup % 2u);
|
||||
|
||||
ivec2 final = ivec2(floor(vec2(offset + pos) * scale));
|
||||
ivec2 final = ivec2(floor(vec2(offset + pos) * vec2(scale)));
|
||||
o_col0 = texelFetch(samp0, final, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -78,7 +78,7 @@ void main()
|
||||
#endif
|
||||
|
||||
#if VS_POINT_SIZE
|
||||
gl_PointSize = float(VS_POINT_SIZE_VALUE);
|
||||
gl_PointSize = PointSize.x;
|
||||
#endif
|
||||
|
||||
vsOut.c = a_c;
|
||||
@@ -320,7 +320,8 @@ void main()
|
||||
#define PS_TCC 1
|
||||
#define PS_ATST 1
|
||||
#define PS_FOG 0
|
||||
#define PS_CLR_HW 0
|
||||
#define PS_BLEND_HW 0
|
||||
#define PS_A_MASKED 0
|
||||
#define PS_FBA 0
|
||||
#define PS_FBMASK 0
|
||||
#define PS_LTF 1
|
||||
@@ -328,13 +329,13 @@ void main()
|
||||
#define PS_POINT_SAMPLER 0
|
||||
#define PS_SHUFFLE 0
|
||||
#define PS_READ_BA 0
|
||||
#define PS_READ16_SRC 0
|
||||
#define PS_DFMT 0
|
||||
#define PS_DEPTH_FMT 0
|
||||
#define PS_PAL_FMT 0
|
||||
#define PS_CHANNEL_FETCH 0
|
||||
#define PS_TALES_OF_ABYSS_HLE 0
|
||||
#define PS_URBAN_CHAOS_HLE 0
|
||||
#define PS_SCALE_FACTOR 1.0
|
||||
#define PS_HDR 0
|
||||
#define PS_COLCLIP 0
|
||||
#define PS_BLEND_A 0
|
||||
@@ -351,6 +352,7 @@ void main()
|
||||
|
||||
#define SW_BLEND (PS_BLEND_A || PS_BLEND_B || PS_BLEND_D)
|
||||
#define SW_BLEND_NEEDS_RT (PS_BLEND_A == 1 || PS_BLEND_B == 1 || PS_BLEND_C == 1 || PS_BLEND_D == 1)
|
||||
#define SW_AD_TO_HW (PS_BLEND_C == 1 && PS_A_MASKED)
|
||||
|
||||
#define PS_FEEDBACK_LOOP_IS_NEEDED (PS_TEX_IS_FB == 1 || PS_FBMASK || SW_BLEND_NEEDS_RT || (PS_DATE >= 5))
|
||||
|
||||
@@ -370,6 +372,8 @@ layout(std140, set = 0, binding = 1) uniform cb1
|
||||
vec2 TC_OffsetHack;
|
||||
vec2 STScale;
|
||||
mat4 DitherMatrix;
|
||||
float ScaledScaleFactor;
|
||||
float RcpScaleFactor;
|
||||
};
|
||||
|
||||
layout(location = 0) in VSOutput
|
||||
@@ -386,7 +390,7 @@ layout(location = 0) in VSOutput
|
||||
#if !defined(DISABLE_DUAL_SOURCE) && !PS_NO_COLOR1
|
||||
layout(location = 0, index = 0) out vec4 o_col0;
|
||||
layout(location = 0, index = 1) out vec4 o_col1;
|
||||
#else
|
||||
#elif !PS_NO_COLOR
|
||||
layout(location = 0) out vec4 o_col0;
|
||||
#endif
|
||||
|
||||
@@ -437,22 +441,22 @@ vec4 sample_c(vec2 uv)
|
||||
#endif
|
||||
|
||||
#if PS_AUTOMATIC_LOD == 1
|
||||
return texture(Texture, uv);
|
||||
return texture(Texture, uv);
|
||||
#elif PS_MANUAL_LOD == 1
|
||||
// FIXME add LOD: K - ( LOG2(Q) * (1 << L))
|
||||
float K = MinMax.x;
|
||||
float L = MinMax.y;
|
||||
float bias = MinMax.z;
|
||||
float max_lod = MinMax.w;
|
||||
// FIXME add LOD: K - ( LOG2(Q) * (1 << L))
|
||||
float K = MinMax.x;
|
||||
float L = MinMax.y;
|
||||
float bias = MinMax.z;
|
||||
float max_lod = MinMax.w;
|
||||
|
||||
float gs_lod = K - log2(abs(vsIn.t.w)) * L;
|
||||
// FIXME max useful ?
|
||||
//float lod = max(min(gs_lod, max_lod) - bias, 0.0f);
|
||||
float lod = min(gs_lod, max_lod) - bias;
|
||||
float gs_lod = K - log2(abs(vsIn.t.w)) * L;
|
||||
// FIXME max useful ?
|
||||
//float lod = max(min(gs_lod, max_lod) - bias, 0.0f);
|
||||
float lod = min(gs_lod, max_lod) - bias;
|
||||
|
||||
return textureLod(Texture, uv, lod);
|
||||
return textureLod(Texture, uv, lod);
|
||||
#else
|
||||
return textureLod(Texture, uv, 0); // No lod
|
||||
return textureLod(Texture, uv, 0); // No lod
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
@@ -589,7 +593,11 @@ vec4 fetch_raw_color(ivec2 xy)
|
||||
|
||||
vec4 fetch_c(ivec2 uv)
|
||||
{
|
||||
#if PS_TEX_IS_FB
|
||||
return sample_from_rt();
|
||||
#else
|
||||
return texelFetch(Texture, uv, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
@@ -638,7 +646,7 @@ ivec2 clamp_wrap_uv_depth(ivec2 uv)
|
||||
|
||||
vec4 sample_depth(vec2 st, ivec2 pos)
|
||||
{
|
||||
vec2 uv_f = vec2(clamp_wrap_uv_depth(ivec2(st))) * vec2(PS_SCALE_FACTOR) * vec2(1.0f / 16.0f);
|
||||
vec2 uv_f = vec2(clamp_wrap_uv_depth(ivec2(st))) * vec2(ScaledScaleFactor);
|
||||
ivec2 uv = ivec2(uv_f);
|
||||
|
||||
vec4 t = vec4(0.0f);
|
||||
@@ -966,108 +974,119 @@ void ps_dither(inout vec3 C)
|
||||
#if PS_DITHER == 2
|
||||
fpos = ivec2(gl_FragCoord.xy);
|
||||
#else
|
||||
fpos = ivec2(gl_FragCoord.xy / float(PS_SCALE_FACTOR));
|
||||
fpos = ivec2(gl_FragCoord.xy * RcpScaleFactor);
|
||||
#endif
|
||||
|
||||
C += DitherMatrix[fpos.y & 3][fpos.x & 3];
|
||||
float value = DitherMatrix[fpos.y & 3][fpos.x & 3];
|
||||
#if PS_ROUND_INV
|
||||
C -= value;
|
||||
#else
|
||||
C += value;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void ps_color_clamp_wrap(inout vec3 C)
|
||||
{
|
||||
// When dithering the bottom 3 bits become meaningless and cause lines in the picture
|
||||
// so we need to limit the color depth on dithered items
|
||||
// When dithering the bottom 3 bits become meaningless and cause lines in the picture
|
||||
// so we need to limit the color depth on dithered items
|
||||
#if SW_BLEND || PS_DITHER || PS_FBMASK
|
||||
|
||||
// Correct the Color value based on the output format
|
||||
#if PS_COLCLIP == 0 && PS_HDR == 0
|
||||
// Standard Clamp
|
||||
C = clamp(C, vec3(0.0f), vec3(255.0f));
|
||||
#if PS_DFMT == FMT_16 && PS_BLEND_MIX == 0 && PS_ROUND_INV
|
||||
C += 7.0f; // Need to round up, not down since the shader will invert
|
||||
#endif
|
||||
|
||||
// FIXME rouding of negative float?
|
||||
// compiler uses trunc but it might need floor
|
||||
// Correct the Color value based on the output format
|
||||
#if PS_COLCLIP == 0 && PS_HDR == 0
|
||||
// Standard Clamp
|
||||
C = clamp(C, vec3(0.0f), vec3(255.0f));
|
||||
#endif
|
||||
|
||||
// Warning: normally blending equation is mult(A, B) = A * B >> 7. GPU have the full accuracy
|
||||
// GS: Color = 1, Alpha = 255 => output 1
|
||||
// GPU: Color = 1/255, Alpha = 255/255 * 255/128 => output 1.9921875
|
||||
// FIXME rouding of negative float?
|
||||
// compiler uses trunc but it might need floor
|
||||
|
||||
// Warning: normally blending equation is mult(A, B) = A * B >> 7. GPU have the full accuracy
|
||||
// GS: Color = 1, Alpha = 255 => output 1
|
||||
// GPU: Color = 1/255, Alpha = 255/255 * 255/128 => output 1.9921875
|
||||
#if PS_DFMT == FMT_16 && PS_BLEND_MIX == 0
|
||||
// In 16 bits format, only 5 bits of colors are used. It impacts shadows computation of Castlevania
|
||||
C = vec3(ivec3(C) & ivec3(0xF8));
|
||||
// In 16 bits format, only 5 bits of colors are used. It impacts shadows computation of Castlevania
|
||||
C = vec3(ivec3(C) & ivec3(0xF8));
|
||||
#elif PS_COLCLIP == 1 || PS_HDR == 1
|
||||
C = vec3(ivec3(C) & ivec3(0xFF));
|
||||
C = vec3(ivec3(C) & ivec3(0xFF));
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
void ps_blend(inout vec4 Color, inout float As)
|
||||
void ps_blend(inout vec4 Color, inout vec4 As_rgba)
|
||||
{
|
||||
float As = As_rgba.a;
|
||||
|
||||
#if SW_BLEND
|
||||
|
||||
// PABE
|
||||
#if PS_PABE
|
||||
// No blending so early exit
|
||||
if (As < 1.0f)
|
||||
return;
|
||||
// No blending so early exit
|
||||
if (As < 1.0f)
|
||||
return;
|
||||
#endif
|
||||
|
||||
#if PS_FEEDBACK_LOOP_IS_NEEDED
|
||||
vec4 RT = trunc(sample_from_rt() * 255.0f + 0.1f);
|
||||
vec4 RT = trunc(sample_from_rt() * 255.0f + 0.1f);
|
||||
#else
|
||||
// Not used, but we define it to make the selection below simpler.
|
||||
vec4 RT = vec4(0.0f);
|
||||
// Not used, but we define it to make the selection below simpler.
|
||||
vec4 RT = vec4(0.0f);
|
||||
#endif
|
||||
|
||||
// FIXME FMT_16 case
|
||||
// FIXME Ad or Ad * 2?
|
||||
float Ad = RT.a / 128.0f;
|
||||
// FIXME FMT_16 case
|
||||
// FIXME Ad or Ad * 2?
|
||||
float Ad = RT.a / 128.0f;
|
||||
|
||||
// Let the compiler do its jobs !
|
||||
vec3 Cd = RT.rgb;
|
||||
vec3 Cs = Color.rgb;
|
||||
// Let the compiler do its jobs !
|
||||
vec3 Cd = RT.rgb;
|
||||
vec3 Cs = Color.rgb;
|
||||
|
||||
#if PS_BLEND_A == 0
|
||||
vec3 A = Cs;
|
||||
vec3 A = Cs;
|
||||
#elif PS_BLEND_A == 1
|
||||
vec3 A = Cd;
|
||||
vec3 A = Cd;
|
||||
#else
|
||||
vec3 A = vec3(0.0f);
|
||||
vec3 A = vec3(0.0f);
|
||||
#endif
|
||||
|
||||
#if PS_BLEND_B == 0
|
||||
vec3 B = Cs;
|
||||
vec3 B = Cs;
|
||||
#elif PS_BLEND_B == 1
|
||||
vec3 B = Cd;
|
||||
vec3 B = Cd;
|
||||
#else
|
||||
vec3 B = vec3(0.0f);
|
||||
vec3 B = vec3(0.0f);
|
||||
#endif
|
||||
|
||||
#if PS_BLEND_C == 0
|
||||
float C = As;
|
||||
float C = As;
|
||||
#elif PS_BLEND_C == 1
|
||||
float C = Ad;
|
||||
float C = Ad;
|
||||
#else
|
||||
float C = Af;
|
||||
float C = Af;
|
||||
#endif
|
||||
|
||||
#if PS_BLEND_D == 0
|
||||
vec3 D = Cs;
|
||||
vec3 D = Cs;
|
||||
#elif PS_BLEND_D == 1
|
||||
vec3 D = Cd;
|
||||
vec3 D = Cd;
|
||||
#else
|
||||
vec3 D = vec3(0.0f);
|
||||
vec3 D = vec3(0.0f);
|
||||
#endif
|
||||
|
||||
// As/Af clamp alpha for Blend mix
|
||||
// We shouldn't clamp blend mix with clr1 as we want alpha higher
|
||||
// We shouldn't clamp blend mix with blend hw 1 as we want alpha higher
|
||||
float C_clamped = C;
|
||||
#if PS_BLEND_MIX > 0 && PS_CLR_HW != 1
|
||||
C_clamped = min(C_clamped, 1.0f);
|
||||
#if PS_BLEND_MIX > 0 && PS_BLEND_HW != 1
|
||||
C_clamped = min(C_clamped, 1.0f);
|
||||
#endif
|
||||
|
||||
#if PS_BLEND_A == PS_BLEND_B
|
||||
Color.rgb = D;
|
||||
Color.rgb = D;
|
||||
// In blend_mix, HW adds on some alpha factor * dst.
|
||||
// Truncating here wouldn't quite get the right result because it prevents the <1 bit here from combining with a <1 bit in dst to form a ≥1 amount that pushes over the truncation.
|
||||
// Instead, apply an offset to convert HW's round to a floor.
|
||||
@@ -1083,34 +1102,39 @@ void ps_blend(inout vec4 Color, inout float As)
|
||||
Color.rgb = trunc((A - B) * C + D);
|
||||
#endif
|
||||
|
||||
#if PS_CLR_HW == 1
|
||||
// Replace Af with As so we can do proper compensation for Alpha.
|
||||
#if PS_BLEND_C == 2
|
||||
As = Af;
|
||||
#endif
|
||||
// Subtract 1 for alpha to compensate for the changed equation,
|
||||
// if c.rgb > 255.0f then we further need to adjust alpha accordingly,
|
||||
// we pick the lowest overflow from all colors because it's the safest,
|
||||
// we divide by 255 the color because we don't know Cd value,
|
||||
// changed alpha should only be done for hw blend.
|
||||
float min_color = min(min(Color.r, Color.g), Color.b);
|
||||
float alpha_compensate = max(1.0f, min_color / 255.0f);
|
||||
As -= alpha_compensate;
|
||||
#elif PS_CLR_HW == 2
|
||||
// Compensate slightly for Cd*(As + 1) - Cs*As.
|
||||
// The initial factor we chose is 1 (0.00392)
|
||||
// as that is the minimum color Cd can be,
|
||||
// then we multiply by alpha to get the minimum
|
||||
// blended value it can be.
|
||||
float color_compensate = 1.0f * (C + 1.0f);
|
||||
Color.rgb -= vec3(color_compensate);
|
||||
#if PS_BLEND_HW == 1
|
||||
// As or Af
|
||||
As_rgba.rgb = vec3(C);
|
||||
// Subtract 1 for alpha to compensate for the changed equation,
|
||||
// if c.rgb > 255.0f then we further need to adjust alpha accordingly,
|
||||
// we pick the lowest overflow from all colors because it's the safest,
|
||||
// we divide by 255 the color because we don't know Cd value,
|
||||
// changed alpha should only be done for hw blend.
|
||||
vec3 alpha_compensate = max(vec3(1.0f), Color.rgb / vec3(255.0f));
|
||||
As_rgba.rgb -= alpha_compensate;
|
||||
#elif PS_BLEND_HW == 2
|
||||
// Compensate slightly for Cd*(As + 1) - Cs*As.
|
||||
// The initial factor we chose is 1 (0.00392)
|
||||
// as that is the minimum color Cd can be,
|
||||
// then we multiply by alpha to get the minimum
|
||||
// blended value it can be.
|
||||
float color_compensate = 1.0f * (C + 1.0f);
|
||||
Color.rgb -= vec3(color_compensate);
|
||||
#elif PS_BLEND_HW == 3
|
||||
// As, Ad or Af clamped.
|
||||
As_rgba.rgb = vec3(C_clamped);
|
||||
// Cs*(Alpha + 1) might overflow, if it does then adjust alpha value
|
||||
// that is sent on second output to compensate.
|
||||
vec3 overflow_check = (Color.rgb - vec3(255.0f)) / 255.0f;
|
||||
vec3 alpha_compensate = max(vec3(0.0f), overflow_check);
|
||||
As_rgba.rgb -= alpha_compensate;
|
||||
#endif
|
||||
|
||||
#else
|
||||
#if PS_CLR_HW == 1 || PS_CLR_HW == 5
|
||||
#if PS_BLEND_HW == 1
|
||||
// Needed for Cd * (As/Ad/F + 1) blending modes
|
||||
Color.rgb = vec3(255.0f);
|
||||
#elif PS_CLR_HW == 2 || PS_CLR_HW == 4
|
||||
#elif PS_BLEND_HW == 2
|
||||
// Cd*As,Cd*Ad or Cd*F
|
||||
|
||||
#if PS_BLEND_C == 2
|
||||
@@ -1121,11 +1145,15 @@ void ps_blend(inout vec4 Color, inout float As)
|
||||
|
||||
Color.rgb = max(vec3(0.0f), (Alpha - vec3(1.0f)));
|
||||
Color.rgb *= vec3(255.0f);
|
||||
#elif PS_CLR_HW == 3
|
||||
#elif PS_BLEND_HW == 3
|
||||
// Needed for Cs*Ad, Cs*Ad + Cd, Cd - Cs*Ad
|
||||
// Multiply Color.rgb by (255/128) to compensate for wrong Ad/255 value
|
||||
|
||||
Color.rgb *= (255.0f / 128.0f);
|
||||
// Multiply Color.rgb by (255/128) to compensate for wrong Ad/255 value when rgb are below 128.
|
||||
// When any color channel is higher than 128 then adjust the compensation automatically
|
||||
// to give us more accurate colors, otherwise they will be wrong.
|
||||
// The higher the value (>128) the lower the compensation will be.
|
||||
float max_color = max(max(Color.r, Color.g), Color.b);
|
||||
float color_compensate = 255.0f / max(128.0f, max_color);
|
||||
Color.rgb *= vec3(color_compensate);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
@@ -1134,40 +1162,40 @@ void main()
|
||||
{
|
||||
#if PS_SCANMSK & 2
|
||||
// fail depth test on prohibited lines
|
||||
if ((int(gl_FragCoord.y) & 1) == (PS_SCANMSK & 1))
|
||||
if ((int(gl_FragCoord.y) & 1) == (PS_SCANMSK & 1))
|
||||
discard;
|
||||
#endif
|
||||
#if PS_DATE >= 5
|
||||
|
||||
#if PS_WRITE_RG == 1
|
||||
// Pseudo 16 bits access.
|
||||
float rt_a = sample_from_rt().g;
|
||||
// Pseudo 16 bits access.
|
||||
float rt_a = sample_from_rt().g;
|
||||
#else
|
||||
float rt_a = sample_from_rt().a;
|
||||
float rt_a = sample_from_rt().a;
|
||||
#endif
|
||||
|
||||
#if (PS_DATE & 3) == 1
|
||||
// DATM == 0: Pixel with alpha equal to 1 will failed
|
||||
bool bad = (127.5f / 255.0f) < rt_a;
|
||||
// DATM == 0: Pixel with alpha equal to 1 will failed
|
||||
bool bad = (127.5f / 255.0f) < rt_a;
|
||||
#elif (PS_DATE & 3) == 2
|
||||
// DATM == 1: Pixel with alpha equal to 0 will failed
|
||||
bool bad = rt_a < (127.5f / 255.0f);
|
||||
// DATM == 1: Pixel with alpha equal to 0 will failed
|
||||
bool bad = rt_a < (127.5f / 255.0f);
|
||||
#endif
|
||||
|
||||
if (bad) {
|
||||
discard;
|
||||
}
|
||||
if (bad) {
|
||||
discard;
|
||||
}
|
||||
|
||||
#endif // PS_DATE >= 5
|
||||
|
||||
#if PS_DATE == 3
|
||||
int stencil_ceil = int(texelFetch(PrimMinTexture, ivec2(gl_FragCoord.xy), 0).r);
|
||||
// Note gl_PrimitiveID == stencil_ceil will be the primitive that will update
|
||||
// the bad alpha value so we must keep it.
|
||||
int stencil_ceil = int(texelFetch(PrimMinTexture, ivec2(gl_FragCoord.xy), 0).r);
|
||||
// Note gl_PrimitiveID == stencil_ceil will be the primitive that will update
|
||||
// the bad alpha value so we must keep it.
|
||||
|
||||
if (gl_PrimitiveID > stencil_ceil) {
|
||||
discard;
|
||||
}
|
||||
if (gl_PrimitiveID > stencil_ceil) {
|
||||
discard;
|
||||
}
|
||||
#endif
|
||||
|
||||
vec4 C = ps_color();
|
||||
@@ -1175,98 +1203,105 @@ void main()
|
||||
#if PS_SHUFFLE
|
||||
uvec4 denorm_c = uvec4(C);
|
||||
uvec2 denorm_TA = uvec2(vec2(TA.xy) * 255.0f + 0.5f);
|
||||
|
||||
// Mask will take care of the correct destination
|
||||
#if PS_READ_BA
|
||||
C.rb = C.bb;
|
||||
#else
|
||||
C.rb = C.rr;
|
||||
#endif
|
||||
|
||||
#if PS_READ_BA
|
||||
#if PS_READ16_SRC
|
||||
C.rb = vec2(float((denorm_c.r >> 3) | (((denorm_c.g >> 3) & 0x7u) << 5)));
|
||||
if ((denorm_c.a & 0x80u) != 0u)
|
||||
C.ga = vec2(float((denorm_c.a & 0x7Fu) | (denorm_TA.y & 0x80u)));
|
||||
C.ga = vec2(float((denorm_c.g >> 6) | ((denorm_c.b >> 3) << 2) | (denorm_TA.y & 0x80u)));
|
||||
else
|
||||
C.ga = vec2(float((denorm_c.a & 0x7Fu) | (denorm_TA.x & 0x80u)));
|
||||
C.ga = vec2(float((denorm_c.g >> 6) | ((denorm_c.b >> 3) << 2) | (denorm_TA.x & 0x80u)));
|
||||
#else
|
||||
if ((denorm_c.g & 0x80u) != 0u)
|
||||
C.ga = vec2(float((denorm_c.g & 0x7Fu) | (denorm_TA.y & 0x80u)));
|
||||
else
|
||||
C.ga = vec2(float((denorm_c.g & 0x7Fu) | (denorm_TA.x & 0x80u)));
|
||||
// Mask will take care of the correct destination
|
||||
#if PS_READ_BA
|
||||
C.rb = C.bb;
|
||||
#else
|
||||
C.rb = C.rr;
|
||||
#endif
|
||||
|
||||
#if PS_READ_BA
|
||||
if ((denorm_c.a & 0x80u) != 0u)
|
||||
C.ga = vec2(float((denorm_c.a & 0x7Fu) | (denorm_TA.y & 0x80u)));
|
||||
else
|
||||
C.ga = vec2(float((denorm_c.a & 0x7Fu) | (denorm_TA.x & 0x80u)));
|
||||
#else
|
||||
if ((denorm_c.g & 0x80u) != 0u)
|
||||
C.ga = vec2(float((denorm_c.g & 0x7Fu) | (denorm_TA.y & 0x80u)));
|
||||
else
|
||||
C.ga = vec2(float((denorm_c.g & 0x7Fu) | (denorm_TA.x & 0x80u)));
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Must be done before alpha correction
|
||||
// Must be done before alpha correction
|
||||
|
||||
// AA (Fixed one) will output a coverage of 1.0 as alpha
|
||||
// AA (Fixed one) will output a coverage of 1.0 as alpha
|
||||
#if PS_FIXED_ONE_A
|
||||
C.a = 128.0f;
|
||||
C.a = 128.0f;
|
||||
#endif
|
||||
|
||||
#if (PS_BLEND_C == 1 && PS_CLR_HW > 3)
|
||||
vec4 RT = trunc(subpassLoad(RtSampler) * 255.0f + 0.1f);
|
||||
float alpha_blend = RT.a / 128.0f;
|
||||
#if (SW_AD_TO_HW)
|
||||
vec4 RT = trunc(subpassLoad(RtSampler) * 255.0f + 0.1f);
|
||||
vec4 alpha_blend = vec4(RT.a / 128.0f);
|
||||
#else
|
||||
float alpha_blend = C.a / 128.0f;
|
||||
vec4 alpha_blend = vec4(C.a / 128.0f);
|
||||
#endif
|
||||
|
||||
// Correct the ALPHA value based on the output format
|
||||
#if (PS_DFMT == FMT_16)
|
||||
float A_one = 128.0f; // alpha output will be 0x80
|
||||
C.a = (PS_FBA != 0) ? A_one : step(128.0f, C.a) * A_one;
|
||||
float A_one = 128.0f; // alpha output will be 0x80
|
||||
C.a = (PS_FBA != 0) ? A_one : step(128.0f, C.a) * A_one;
|
||||
#elif (PS_DFMT == FMT_32) && (PS_FBA != 0)
|
||||
if(C.a < 128.0f) C.a += 128.0f;
|
||||
if(C.a < 128.0f) C.a += 128.0f;
|
||||
#endif
|
||||
|
||||
// Get first primitive that will write a failling alpha value
|
||||
// Get first primitive that will write a failling alpha value
|
||||
#if PS_DATE == 1
|
||||
|
||||
// DATM == 0
|
||||
// Pixel with alpha equal to 1 will failed (128-255)
|
||||
// DATM == 0
|
||||
// Pixel with alpha equal to 1 will failed (128-255)
|
||||
o_col0 = (C.a > 127.5f) ? vec4(gl_PrimitiveID) : vec4(0x7FFFFFFF);
|
||||
|
||||
#elif PS_DATE == 2
|
||||
|
||||
// DATM == 1
|
||||
// Pixel with alpha equal to 0 will failed (0-127)
|
||||
o_col0 = (C.a < 127.5f) ? vec4(gl_PrimitiveID) : vec4(0x7FFFFFFF);
|
||||
// DATM == 1
|
||||
// Pixel with alpha equal to 0 will failed (0-127)
|
||||
o_col0 = (C.a < 127.5f) ? vec4(gl_PrimitiveID) : vec4(0x7FFFFFFF);
|
||||
|
||||
#else
|
||||
|
||||
ps_blend(C, alpha_blend);
|
||||
|
||||
ps_dither(C.rgb);
|
||||
ps_dither(C.rgb);
|
||||
|
||||
// Color clamp/wrap needs to be done after sw blending and dithering
|
||||
ps_color_clamp_wrap(C.rgb);
|
||||
// Color clamp/wrap needs to be done after sw blending and dithering
|
||||
ps_color_clamp_wrap(C.rgb);
|
||||
|
||||
ps_fbmask(C);
|
||||
ps_fbmask(C);
|
||||
|
||||
#if !PS_NO_COLOR
|
||||
#if PS_HDR == 1
|
||||
o_col0 = vec4(C.rgb / 65535.0f, C.a / 255.0f);
|
||||
#else
|
||||
o_col0 = C / 255.0f;
|
||||
#endif
|
||||
#if !defined(DISABLE_DUAL_SOURCE) && !PS_NO_COLOR1
|
||||
o_col1 = vec4(alpha_blend);
|
||||
#endif
|
||||
#if !PS_NO_COLOR
|
||||
#if PS_HDR == 1
|
||||
o_col0 = vec4(C.rgb / 65535.0f, C.a / 255.0f);
|
||||
#else
|
||||
o_col0 = C / 255.0f;
|
||||
#endif
|
||||
#if !defined(DISABLE_DUAL_SOURCE) && !PS_NO_COLOR1
|
||||
o_col1 = alpha_blend;
|
||||
#endif
|
||||
|
||||
#if PS_NO_ABLEND
|
||||
// write alpha blend factor into col0
|
||||
o_col0.a = alpha_blend;
|
||||
#endif
|
||||
#if PS_ONLY_ALPHA
|
||||
// rgb isn't used
|
||||
o_col0.rgb = vec3(0.0f);
|
||||
#endif
|
||||
#endif
|
||||
#if PS_NO_ABLEND
|
||||
// write alpha blend factor into col0
|
||||
o_col0.a = alpha_blend.a;
|
||||
#endif
|
||||
#if PS_ONLY_ALPHA
|
||||
// rgb isn't used
|
||||
o_col0.rgb = vec3(0.0f);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if PS_ZCLAMP
|
||||
gl_FragDepth = min(gl_FragCoord.z, MaxDepthPS);
|
||||
#endif
|
||||
#if PS_ZCLAMP
|
||||
gl_FragDepth = min(gl_FragCoord.z, MaxDepthPS);
|
||||
#endif
|
||||
|
||||
#endif // PS_DATE
|
||||
#endif // PS_DATE
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -46,7 +46,10 @@ endif()
|
||||
#-------------------------------------------------------------------------------
|
||||
option(USE_ASAN "Enable address sanitizer")
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
|
||||
if(MSVC AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
set(USE_CLANG_CL TRUE)
|
||||
message(STATUS "Building with Clang-CL.")
|
||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
|
||||
set(USE_CLANG TRUE)
|
||||
message(STATUS "Building with Clang/LLVM.")
|
||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
|
||||
@@ -122,6 +125,8 @@ if(${PCSX2_TARGET_ARCHITECTURES} MATCHES "x86_64")
|
||||
#set(ARCH_FLAG "-march=native -fabi-version=6")
|
||||
set(ARCH_FLAG "-march=native")
|
||||
endif()
|
||||
elseif(NOT DEFINED ARCH_FLAG AND USE_CLANG_CL)
|
||||
set(ARCH_FLAG "-msse4.1")
|
||||
endif()
|
||||
list(APPEND PCSX2_DEFS _ARCH_64=1 _M_X86=1)
|
||||
set(_ARCH_64 1)
|
||||
@@ -143,9 +148,9 @@ option(USE_PGO_OPTIMIZE "Enable PGO optimization (use profile)")
|
||||
|
||||
# Note1: Builtin strcmp/memcmp was proved to be slower on Mesa than stdlib version.
|
||||
# Note2: float operation SSE is impacted by the PCSX2 SSE configuration. In particular, flush to zero denormal.
|
||||
if(MSVC)
|
||||
if(MSVC AND NOT USE_CLANG_CL)
|
||||
add_compile_options("$<$<COMPILE_LANGUAGE:CXX>:/Zc:externConstexpr>")
|
||||
else()
|
||||
elseif(NOT MSVC)
|
||||
add_compile_options(-pipe -fvisibility=hidden -pthread -fno-builtin-strcmp -fno-builtin-memcmp -mfpmath=sse)
|
||||
|
||||
# -fno-operator-names should only be for C++ files, not C files.
|
||||
|
||||
@@ -10,8 +10,9 @@ function(detectOperatingSystem)
|
||||
if(WIN32)
|
||||
set(Windows TRUE PARENT_SCOPE)
|
||||
elseif(UNIX AND APPLE)
|
||||
# No easy way to filter out iOS.
|
||||
message(WARNING "OS X/iOS isn't supported, the build will most likely fail")
|
||||
if(IOS)
|
||||
message(WARNING "iOS isn't supported, the build will most likely fail")
|
||||
endif()
|
||||
set(MacOSX TRUE PARENT_SCOPE)
|
||||
elseif(UNIX)
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||
|
||||
@@ -79,7 +79,7 @@ wil::com_ptr_nothrow<ID3DBlob> D3D11::ShaderCompiler::CompileShader(Type type, D
|
||||
{
|
||||
Console.WriteLn("Failed to compile '%s':\n%s", target, error_string.c_str());
|
||||
|
||||
std::ofstream ofs(StringUtil::StdStringFromFormat("bad_shader_%u.txt", s_next_bad_shader_id++).c_str(),
|
||||
std::ofstream ofs(StringUtil::StdStringFromFormat("pcsx2_bad_shader_%u.txt", s_next_bad_shader_id++).c_str(),
|
||||
std::ofstream::out | std::ofstream::binary);
|
||||
if (ofs.is_open())
|
||||
{
|
||||
|
||||
@@ -445,7 +445,7 @@ ID3D12GraphicsCommandList4* Context::GetInitCommandList()
|
||||
return res.command_lists[0].get();
|
||||
}
|
||||
|
||||
void Context::ExecuteCommandList(WaitType wait_for_completion)
|
||||
bool Context::ExecuteCommandList(WaitType wait_for_completion)
|
||||
{
|
||||
CommandListResources& res = m_command_lists[m_current_command_list];
|
||||
HRESULT hr;
|
||||
@@ -463,12 +463,21 @@ void Context::ExecuteCommandList(WaitType wait_for_completion)
|
||||
if (res.init_command_list_used)
|
||||
{
|
||||
hr = res.command_lists[0]->Close();
|
||||
pxAssertRel(SUCCEEDED(hr), "Close init command list");
|
||||
if (FAILED(hr))
|
||||
{
|
||||
Console.Error("Closing init command list failed with HRESULT %08X", hr);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Close and queue command list.
|
||||
hr = res.command_lists[1]->Close();
|
||||
pxAssertRel(SUCCEEDED(hr), "Close command list");
|
||||
if (FAILED(hr))
|
||||
{
|
||||
Console.Error("Closing main command list failed with HRESULT %08X", hr);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (res.init_command_list_used)
|
||||
{
|
||||
const std::array<ID3D12CommandList*, 2> execute_lists{res.command_lists[0].get(), res.command_lists[1].get()};
|
||||
@@ -487,6 +496,8 @@ void Context::ExecuteCommandList(WaitType wait_for_completion)
|
||||
MoveToNextCommandList();
|
||||
if (wait_for_completion != WaitType::None)
|
||||
WaitForFence(res.ready_fence_value, wait_for_completion == WaitType::Spin);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Context::InvalidateSamplerGroups()
|
||||
|
||||
@@ -130,7 +130,7 @@ namespace D3D12
|
||||
};
|
||||
|
||||
/// Executes the current command list.
|
||||
void ExecuteCommandList(WaitType wait_for_completion);
|
||||
bool ExecuteCommandList(WaitType wait_for_completion);
|
||||
|
||||
/// Waits for a specific fence.
|
||||
void WaitForFence(u64 fence, bool spin);
|
||||
|
||||
@@ -119,7 +119,7 @@ namespace GL
|
||||
if (!context)
|
||||
return nullptr;
|
||||
|
||||
Console.WriteLn("Created a %s context", context->IsGLES() ? "OpenGL ES" : "OpenGL");
|
||||
Console.WriteLn("Created an %s context", context->IsGLES() ? "OpenGL ES" : "OpenGL");
|
||||
|
||||
// NOTE: Not thread-safe. But this is okay, since we're not going to be creating more than one context at a time.
|
||||
static Context* context_being_created;
|
||||
|
||||
@@ -77,7 +77,7 @@ namespace GL
|
||||
{
|
||||
Console.Error("Shader failed to compile:\n%s", info_log.c_str());
|
||||
|
||||
std::ofstream ofs(StringUtil::StdStringFromFormat("bad_shader_%u.txt", s_next_bad_shader_id++).c_str(),
|
||||
std::ofstream ofs(StringUtil::StdStringFromFormat("pcsx2_bad_shader_%u.txt", s_next_bad_shader_id++).c_str(),
|
||||
std::ofstream::out | std::ofstream::binary);
|
||||
if (ofs.is_open())
|
||||
{
|
||||
|
||||
@@ -100,6 +100,8 @@ static void SysPageFaultSignalFilter(int signal, siginfo_t* siginfo, void* ctx)
|
||||
|
||||
#if defined(__APPLE__) && defined(__x86_64__)
|
||||
void* const exception_pc = reinterpret_cast<void*>(static_cast<ucontext_t*>(ctx)->uc_mcontext->__ss.__rip);
|
||||
#elif defined(__FreeBSD__) && defined(__x86_64__)
|
||||
void* const exception_pc = reinterpret_cast<void*>(static_cast<ucontext_t*>(ctx)->uc_mcontext.mc_rip);
|
||||
#elif defined(__x86_64__)
|
||||
void* const exception_pc = reinterpret_cast<void*>(static_cast<ucontext_t*>(ctx)->uc_mcontext.gregs[REG_RIP]);
|
||||
#else
|
||||
|
||||
@@ -197,9 +197,9 @@ namespace Vulkan
|
||||
{
|
||||
u32 gpu_count = 0;
|
||||
VkResult res = vkEnumeratePhysicalDevices(instance, &gpu_count, nullptr);
|
||||
if (res != VK_SUCCESS || gpu_count == 0)
|
||||
if ((res != VK_SUCCESS && res != VK_INCOMPLETE) || gpu_count == 0)
|
||||
{
|
||||
LOG_VULKAN_ERROR(res, "vkEnumeratePhysicalDevices failed: ");
|
||||
LOG_VULKAN_ERROR(res, "vkEnumeratePhysicalDevices (1) failed: ");
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -207,12 +207,20 @@ namespace Vulkan
|
||||
gpus.resize(gpu_count);
|
||||
|
||||
res = vkEnumeratePhysicalDevices(instance, &gpu_count, gpus.data());
|
||||
if (res != VK_SUCCESS)
|
||||
if (res == VK_INCOMPLETE)
|
||||
{
|
||||
LOG_VULKAN_ERROR(res, "vkEnumeratePhysicalDevices failed: ");
|
||||
Console.Warning("First vkEnumeratePhysicalDevices() call returned %zu devices, but second returned %u", gpus.size(), gpu_count);
|
||||
}
|
||||
else if (res != VK_SUCCESS)
|
||||
{
|
||||
LOG_VULKAN_ERROR(res, "vkEnumeratePhysicalDevices (2) failed: ");
|
||||
return {};
|
||||
}
|
||||
|
||||
// Maybe we lost a GPU?
|
||||
if (gpu_count < gpus.size())
|
||||
gpus.resize(gpu_count);
|
||||
|
||||
return gpus;
|
||||
}
|
||||
|
||||
@@ -1122,9 +1130,13 @@ namespace Vulkan
|
||||
void Context::WaitForCommandBufferCompletion(u32 index)
|
||||
{
|
||||
// Wait for this command buffer to be completed.
|
||||
VkResult res = vkWaitForFences(m_device, 1, &m_frame_resources[index].fence, VK_TRUE, UINT64_MAX);
|
||||
const VkResult res = vkWaitForFences(m_device, 1, &m_frame_resources[index].fence, VK_TRUE, UINT64_MAX);
|
||||
if (res != VK_SUCCESS)
|
||||
{
|
||||
LOG_VULKAN_ERROR(res, "vkWaitForFences failed: ");
|
||||
m_last_submit_failed.store(true, std::memory_order_release);
|
||||
return;
|
||||
}
|
||||
|
||||
// Clean up any resources for command buffers between the last known completed buffer and this
|
||||
// now-completed command buffer. If we use >2 buffers, this may be more than one buffer.
|
||||
@@ -1266,11 +1278,12 @@ namespace Vulkan
|
||||
submit_info.pSignalSemaphores = &m_spin_resources[index].semaphore;
|
||||
}
|
||||
|
||||
VkResult res = vkQueueSubmit(m_graphics_queue, 1, &submit_info, resources.fence);
|
||||
const VkResult res = vkQueueSubmit(m_graphics_queue, 1, &submit_info, resources.fence);
|
||||
if (res != VK_SUCCESS)
|
||||
{
|
||||
LOG_VULKAN_ERROR(res, "vkQueueSubmit failed: ");
|
||||
pxFailRel("Failed to submit command buffer.");
|
||||
m_last_submit_failed.store(true, std::memory_order_release);
|
||||
return;
|
||||
}
|
||||
|
||||
if (spin_cycles != 0)
|
||||
@@ -1286,14 +1299,14 @@ namespace Vulkan
|
||||
|
||||
present_swap_chain->ReleaseCurrentImage();
|
||||
|
||||
VkResult res = vkQueuePresentKHR(m_present_queue, &present_info);
|
||||
const VkResult res = vkQueuePresentKHR(m_present_queue, &present_info);
|
||||
if (res != VK_SUCCESS)
|
||||
{
|
||||
// VK_ERROR_OUT_OF_DATE_KHR is not fatal, just means we need to recreate our swap chain.
|
||||
if (res != VK_ERROR_OUT_OF_DATE_KHR && res != VK_SUBOPTIMAL_KHR)
|
||||
LOG_VULKAN_ERROR(res, "vkQueuePresentKHR failed: ");
|
||||
|
||||
m_last_present_failed.store(true);
|
||||
m_last_present_failed.store(true, std::memory_order_release);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1460,6 +1473,9 @@ namespace Vulkan
|
||||
|
||||
void Context::ExecuteCommandBuffer(WaitType wait_for_completion)
|
||||
{
|
||||
if (m_last_submit_failed.load(std::memory_order_acquire))
|
||||
return;
|
||||
|
||||
// If we're waiting for completion, don't bother waking the worker thread.
|
||||
const u32 current_frame = m_current_frame;
|
||||
SubmitCommandBuffer();
|
||||
@@ -1481,9 +1497,12 @@ namespace Vulkan
|
||||
|
||||
bool Context::CheckLastPresentFail()
|
||||
{
|
||||
bool res = m_last_present_failed;
|
||||
m_last_present_failed = false;
|
||||
return res;
|
||||
return m_last_present_failed.exchange(false, std::memory_order_acq_rel);
|
||||
}
|
||||
|
||||
bool Context::CheckLastSubmitFail()
|
||||
{
|
||||
return m_last_submit_failed.load(std::memory_order_acquire);
|
||||
}
|
||||
|
||||
void Context::DeferBufferDestruction(VkBuffer object)
|
||||
@@ -1596,7 +1615,7 @@ namespace Vulkan
|
||||
VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT,
|
||||
DebugMessengerCallback, nullptr};
|
||||
|
||||
VkResult res =
|
||||
const VkResult res =
|
||||
vkCreateDebugUtilsMessengerEXT(m_instance, &messenger_info, nullptr, &m_debug_messenger_callback);
|
||||
if (res != VK_SUCCESS)
|
||||
{
|
||||
@@ -1688,7 +1707,7 @@ namespace Vulkan
|
||||
subpass_dependency_ptr};
|
||||
|
||||
VkRenderPass pass;
|
||||
VkResult res = vkCreateRenderPass(m_device, &pass_info, nullptr, &pass);
|
||||
const VkResult res = vkCreateRenderPass(m_device, &pass_info, nullptr, &pass);
|
||||
if (res != VK_SUCCESS)
|
||||
{
|
||||
LOG_VULKAN_ERROR(res, "vkCreateRenderPass failed: ");
|
||||
@@ -1894,9 +1913,14 @@ void main()
|
||||
SpinResources& resources = m_spin_resources[index];
|
||||
if (!resources.in_progress)
|
||||
return;
|
||||
VkResult res = vkWaitForFences(m_device, 1, &resources.fence, VK_TRUE, UINT64_MAX);
|
||||
|
||||
const VkResult res = vkWaitForFences(m_device, 1, &resources.fence, VK_TRUE, UINT64_MAX);
|
||||
if (res != VK_SUCCESS)
|
||||
{
|
||||
LOG_VULKAN_ERROR(res, "vkWaitForFences failed: ");
|
||||
m_last_submit_failed.store(true, std::memory_order_release);
|
||||
return;
|
||||
}
|
||||
SpinCommandCompleted(index);
|
||||
}
|
||||
|
||||
@@ -1906,7 +1930,7 @@ void main()
|
||||
resources.in_progress = false;
|
||||
const u32 timestamp_base = (index + NUM_COMMAND_BUFFERS) * 2;
|
||||
std::array<u64, 2> timestamps;
|
||||
VkResult res = vkGetQueryPoolResults(m_device, m_timestamp_query_pool, timestamp_base, static_cast<u32>(timestamps.size()),
|
||||
const VkResult res = vkGetQueryPoolResults(m_device, m_timestamp_query_pool, timestamp_base, static_cast<u32>(timestamps.size()),
|
||||
sizeof(timestamps), timestamps.data(), sizeof(u64), VK_QUERY_RESULT_64_BIT);
|
||||
if (res == VK_SUCCESS)
|
||||
{
|
||||
@@ -2014,7 +2038,7 @@ void main()
|
||||
constexpr u64 MAX_MAX_DEVIATION = 100000; // 100µs
|
||||
for (int i = 0; i < 4; i++) // 4 tries to get under MAX_MAX_DEVIATION
|
||||
{
|
||||
VkResult res = vkGetCalibratedTimestampsEXT(m_device, std::size(infos), infos, timestamps, &maxDeviation);
|
||||
const VkResult res = vkGetCalibratedTimestampsEXT(m_device, std::size(infos), infos, timestamps, &maxDeviation);
|
||||
if (res != VK_SUCCESS)
|
||||
{
|
||||
LOG_VULKAN_ERROR(res, "vkGetCalibratedTimestampsEXT failed: ");
|
||||
|
||||
@@ -209,6 +209,7 @@ namespace Vulkan
|
||||
|
||||
// Was the last present submitted to the queue a failure? If so, we must recreate our swapchain.
|
||||
bool CheckLastPresentFail();
|
||||
bool CheckLastSubmitFail();
|
||||
|
||||
// Schedule a vulkan resource for destruction later on. This will occur when the command buffer
|
||||
// is next re-used, and the GPU has finished working with the specified resource.
|
||||
@@ -373,6 +374,7 @@ namespace Vulkan
|
||||
|
||||
StreamBuffer m_texture_upload_buffer;
|
||||
|
||||
std::atomic_bool m_last_submit_failed{false};
|
||||
std::atomic_bool m_last_present_failed{false};
|
||||
std::atomic_bool m_present_done{true};
|
||||
std::mutex m_present_mutex;
|
||||
|
||||
@@ -55,7 +55,7 @@ namespace Vulkan::ShaderCompiler
|
||||
shader->setStringsWithLengths(&pass_source_code, &pass_source_code_length, 1);
|
||||
|
||||
auto DumpBadShader = [&](const char* msg) {
|
||||
std::string filename = StringUtil::StdStringFromFormat("bad_shader_%u.txt", s_next_bad_shader_id++);
|
||||
std::string filename = StringUtil::StdStringFromFormat("pcsx2_bad_shader_%u.txt", s_next_bad_shader_id++);
|
||||
Console.Error("CompileShaderToSPV: %s, writing to %s", msg, filename.c_str());
|
||||
|
||||
std::ofstream ofs(filename.c_str(), std::ofstream::out | std::ofstream::binary);
|
||||
|
||||
@@ -60,7 +60,9 @@
|
||||
|
||||
namespace GSRunner
|
||||
{
|
||||
static void InitializeConsole();
|
||||
static bool InitializeConfig();
|
||||
static bool ParseCommandLineArgs(int argc, char* argv[], VMBootParameters& params);
|
||||
|
||||
static bool CreatePlatformWindow();
|
||||
static void DestroyPlatformWindow();
|
||||
@@ -77,6 +79,7 @@ alignas(16) static SysMtgsThread s_mtgs_thread;
|
||||
static std::string s_output_prefix;
|
||||
static s32 s_loop_count = 1;
|
||||
static std::optional<bool> s_use_window;
|
||||
static bool s_no_console = false;
|
||||
|
||||
// Owned by the GS thread.
|
||||
static u32 s_dump_frame_number = 0;
|
||||
@@ -112,7 +115,7 @@ bool GSRunner::InitializeConfig()
|
||||
si.SetBoolValue("EmuCore", "EnablePerGameSettings", false);
|
||||
|
||||
// force logging
|
||||
si.SetBoolValue("Logging", "EnableSystemConsole", true);
|
||||
si.SetBoolValue("Logging", "EnableSystemConsole", !s_no_console);
|
||||
si.SetBoolValue("Logging", "EnableTimestamps", true);
|
||||
si.SetBoolValue("Logging", "EnableVerbose", true);
|
||||
|
||||
@@ -280,9 +283,9 @@ void Host::ReleaseHostDisplay(bool clear_state)
|
||||
g_host_display.reset();
|
||||
}
|
||||
|
||||
bool Host::BeginPresentFrame(bool frame_skip)
|
||||
HostDisplay::PresentResult Host::BeginPresentFrame(bool frame_skip)
|
||||
{
|
||||
if (s_loop_number == 0)
|
||||
if (s_loop_number == 0 && !s_output_prefix.empty())
|
||||
{
|
||||
// when we wrap around, don't race other files
|
||||
GSJoinSnapshotThreads();
|
||||
@@ -291,12 +294,15 @@ bool Host::BeginPresentFrame(bool frame_skip)
|
||||
std::string dump_path(fmt::format("{}_frame{}.png", s_output_prefix, s_dump_frame_number));
|
||||
GSQueueSnapshot(dump_path);
|
||||
}
|
||||
if (g_host_display->BeginPresent(frame_skip))
|
||||
return true;
|
||||
|
||||
// don't render imgui
|
||||
ImGuiManager::NewFrame();
|
||||
return false;
|
||||
const HostDisplay::PresentResult result = g_host_display->BeginPresent(frame_skip);
|
||||
if (result != HostDisplay::PresentResult::OK)
|
||||
{
|
||||
// don't render imgui
|
||||
ImGuiManager::SkipFrame();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void Host::EndPresentFrame()
|
||||
@@ -450,7 +456,15 @@ static void PrintCommandLineHelp(const char* progname)
|
||||
std::fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
static bool ParseCommandLineArgs(int argc, char* argv[], VMBootParameters& params)
|
||||
void GSRunner::InitializeConsole()
|
||||
{
|
||||
const char* var = std::getenv("PCSX2_NOCONSOLE");
|
||||
s_no_console = (var && StringUtil::FromChars<bool>(var).value_or(false));
|
||||
if (!s_no_console)
|
||||
CommonHost::InitializeEarlyConsole();
|
||||
}
|
||||
|
||||
bool GSRunner::ParseCommandLineArgs(int argc, char* argv[], VMBootParameters& params)
|
||||
{
|
||||
bool no_more_args = false;
|
||||
for (int i = 1; i < argc; i++)
|
||||
@@ -553,6 +567,19 @@ static bool ParseCommandLineArgs(int argc, char* argv[], VMBootParameters& param
|
||||
|
||||
continue;
|
||||
}
|
||||
else if (CHECK_ARG_PARAM("-upscale"))
|
||||
{
|
||||
const float upscale = StringUtil::FromChars<float>(argv[++i]).value_or(0.0f);
|
||||
if (upscale < 0.5f)
|
||||
{
|
||||
Console.WriteLn("Invalid upscale multiplier");
|
||||
return false;
|
||||
}
|
||||
|
||||
Console.WriteLn(fmt::format("Setting upscale multiplier to {}", upscale));
|
||||
s_settings_interface.SetFloatValue("EmuCore/GS", "upscale_multiplier", upscale);
|
||||
continue;
|
||||
}
|
||||
else if (CHECK_ARG_PARAM("-logfile"))
|
||||
{
|
||||
const char* logfile = argv[++i];
|
||||
@@ -570,7 +597,7 @@ static bool ParseCommandLineArgs(int argc, char* argv[], VMBootParameters& param
|
||||
else if (CHECK_ARG("-noshadercache"))
|
||||
{
|
||||
Console.WriteLn("Disabling shader cache");
|
||||
s_settings_interface.SetBoolValue("EmuCore/GS", "disable_shader_cache", false);
|
||||
s_settings_interface.SetBoolValue("EmuCore/GS", "disable_shader_cache", true);
|
||||
continue;
|
||||
}
|
||||
else if (CHECK_ARG("-window"))
|
||||
@@ -634,7 +661,7 @@ static bool ParseCommandLineArgs(int argc, char* argv[], VMBootParameters& param
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
CommonHost::InitializeEarlyConsole();
|
||||
GSRunner::InitializeConsole();
|
||||
|
||||
if (!GSRunner::InitializeConfig())
|
||||
{
|
||||
@@ -643,7 +670,7 @@ int main(int argc, char* argv[])
|
||||
}
|
||||
|
||||
VMBootParameters params;
|
||||
if (!ParseCommandLineArgs(argc, argv, params))
|
||||
if (!GSRunner::ParseCommandLineArgs(argc, argv, params))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
PerformanceMetrics::SetCPUThread(Threading::ThreadHandle::GetForCallingThread());
|
||||
@@ -653,7 +680,7 @@ int main(int argc, char* argv[])
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (s_use_window.value_or(false) && !GSRunner::CreatePlatformWindow())
|
||||
if (s_use_window.value_or(true) && !GSRunner::CreatePlatformWindow())
|
||||
{
|
||||
Console.Error("Failed to create window.");
|
||||
return EXIT_FAILURE;
|
||||
|
||||
@@ -16,7 +16,7 @@ def is_gs_path(path):
|
||||
return False
|
||||
|
||||
|
||||
def run_regression_test(runner, dumpdir, renderer, parallel, renderhacks, gspath):
|
||||
def run_regression_test(runner, dumpdir, renderer, upscale, renderhacks, parallel, gspath):
|
||||
args = [runner]
|
||||
gsname = Path(gspath).name
|
||||
while gsname.rfind('.') >= 0:
|
||||
@@ -28,6 +28,9 @@ def run_regression_test(runner, dumpdir, renderer, parallel, renderhacks, gspath
|
||||
|
||||
if renderer is not None:
|
||||
args.extend(["-renderer", renderer])
|
||||
|
||||
if upscale != 1.0:
|
||||
args.extend(["-upscale", str(upscale)])
|
||||
|
||||
if renderhacks is not None:
|
||||
args.extend(["-renderhacks", renderhacks])
|
||||
@@ -43,14 +46,21 @@ def run_regression_test(runner, dumpdir, renderer, parallel, renderhacks, gspath
|
||||
if parallel > 1:
|
||||
args.append("-noshadercache")
|
||||
|
||||
# run surfaceless, we don't want tons of windows popping up
|
||||
args.append("-surfaceless");
|
||||
|
||||
# disable output console entirely
|
||||
environ = os.environ.copy()
|
||||
environ["PCSX2_NOCONSOLE"] = "1"
|
||||
|
||||
args.append("--")
|
||||
args.append(gspath)
|
||||
|
||||
print("Running '%s'" % (" ".join(args)))
|
||||
subprocess.run(args)
|
||||
#print("Running '%s'" % (" ".join(args)))
|
||||
subprocess.run(args, env=environ, stdin=subprocess.DEVNULL, stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL)
|
||||
|
||||
|
||||
def run_regression_tests(runner, gsdir, dumpdir, renderer, renderhacks, parallel=1):
|
||||
def run_regression_tests(runner, gsdir, dumpdir, renderer, upscale, renderhacks, parallel=1):
|
||||
paths = glob.glob(gsdir + "/*.*", recursive=True)
|
||||
gamepaths = list(filter(is_gs_path, paths))
|
||||
|
||||
@@ -61,12 +71,15 @@ def run_regression_tests(runner, gsdir, dumpdir, renderer, renderhacks, parallel
|
||||
|
||||
if parallel <= 1:
|
||||
for game in gamepaths:
|
||||
run_regression_test(runner, dumpdir, renderer, parallel, renderhacks, game)
|
||||
run_regression_test(runner, dumpdir, renderer, upscale, renderhacks, parallel, game)
|
||||
else:
|
||||
print("Processing %u games on %u processors" % (len(gamepaths), parallel))
|
||||
func = partial(run_regression_test, runner, dumpdir, renderer, parallel, renderhacks)
|
||||
func = partial(run_regression_test, runner, dumpdir, renderer, upscale, renderhacks, parallel)
|
||||
pool = multiprocessing.Pool(parallel)
|
||||
pool.map(func, gamepaths)
|
||||
completed = 0
|
||||
for _ in pool.imap_unordered(func, gamepaths, chunksize=1):
|
||||
completed += 1
|
||||
print("Processed %u of %u GS dumps (%u%%)" % (completed, len(gamepaths), (completed * 100) // len(gamepaths)))
|
||||
pool.close()
|
||||
|
||||
|
||||
@@ -79,12 +92,13 @@ if __name__ == "__main__":
|
||||
parser.add_argument("-gsdir", action="store", required=True, help="Directory containing GS dumps")
|
||||
parser.add_argument("-dumpdir", action="store", required=True, help="Base directory to dump frames to")
|
||||
parser.add_argument("-renderer", action="store", required=False, help="Renderer to use")
|
||||
parser.add_argument("-upscale", action="store", type=float, default=1, help="Upscaling multiplier to use")
|
||||
parser.add_argument("-renderhacks", action="store", required=False, help="Enable HW Rendering hacks")
|
||||
parser.add_argument("-parallel", action="store", type=int, default=1, help="Number of proceeses to run")
|
||||
parser.add_argument("-renderhacks", action="store", required=False, help="Enable HW Renering hacks")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if not run_regression_tests(args.runner, os.path.realpath(args.gsdir), os.path.realpath(args.dumpdir), args.renderer, args.renderhacks, args.parallel):
|
||||
if not run_regression_tests(args.runner, os.path.realpath(args.gsdir), os.path.realpath(args.dumpdir), args.renderer, args.upscale, args.renderhacks, args.parallel):
|
||||
sys.exit(1)
|
||||
else:
|
||||
sys.exit(0)
|
||||
|
||||
@@ -385,7 +385,7 @@ void AutoUpdaterDialog::getChangesComplete(QNetworkReply* reply)
|
||||
if (update_will_break_save_states)
|
||||
{
|
||||
changes_html.prepend(tr("<h2>Save State Warning</h2><p>Installing this update will make your save states "
|
||||
"<b>incompatible</b>. Please ensure you have saved your games to memory card "
|
||||
"<b>incompatible</b>. Please ensure you have saved your games to a Memory Card "
|
||||
"before installing this update or you will lose progress.</p>"));
|
||||
}
|
||||
|
||||
@@ -495,6 +495,16 @@ void AutoUpdaterDialog::checkIfUpdateNeeded()
|
||||
|
||||
Console.WriteLn(Color_StrongRed, "Update needed.");
|
||||
|
||||
// Don't show the dialog if a game started while the update info was downloading. Some people have
|
||||
// really slow connections, apparently. If we're a manual triggered update check, then display
|
||||
// regardless. This will fall through and signal main to delete us.
|
||||
if (!m_display_messages &&
|
||||
(QtHost::IsVMValid() || (g_emu_thread->isRunningFullscreenUI() && g_emu_thread->isFullscreen())))
|
||||
{
|
||||
Console.WriteLn(Color_StrongRed, "Not showing update dialog due to active VM.");
|
||||
return;
|
||||
}
|
||||
|
||||
m_ui.currentVersion->setText(tr("Current Version: %1 (%2)").arg(getCurrentVersion()).arg(getCurrentVersionDate()));
|
||||
m_ui.newVersion->setText(tr("New Version: %1 (%2)").arg(m_latest_version).arg(m_latest_version_timestamp.toString()));
|
||||
m_ui.updateNotes->setText(tr("Loading..."));
|
||||
|
||||
@@ -58,6 +58,7 @@ target_sources(pcsx2-qt PRIVATE
|
||||
Settings/ControllerGlobalSettingsWidget.ui
|
||||
Settings/ControllerMacroEditWidget.ui
|
||||
Settings/ControllerMacroWidget.ui
|
||||
Settings/ControllerMouseSettingsDialog.ui
|
||||
Settings/ControllerSettingsDialog.cpp
|
||||
Settings/ControllerSettingsDialog.h
|
||||
Settings/ControllerSettingsDialog.ui
|
||||
|
||||
@@ -254,13 +254,17 @@ void MainWindow::setupAdditionalUi()
|
||||
m_status_vps_widget->setFixedSize(125, 16);
|
||||
m_status_vps_widget->hide();
|
||||
|
||||
m_settings_toolbar_menu = new QMenu(m_ui.toolBar);
|
||||
m_settings_toolbar_menu->addAction(m_ui.actionSettings);
|
||||
m_settings_toolbar_menu->addAction(m_ui.actionViewGameProperties);
|
||||
|
||||
for (u32 scale = 0; scale <= 10; scale++)
|
||||
{
|
||||
QAction* action = m_ui.menuWindowSize->addAction((scale == 0) ? tr("Internal Resolution") : tr("%1x Scale").arg(scale));
|
||||
connect(action, &QAction::triggered, [scale]() { g_emu_thread->requestDisplaySize(static_cast<float>(scale)); });
|
||||
}
|
||||
|
||||
updateEmulationActions(false, false);
|
||||
updateEmulationActions(false, false, false);
|
||||
updateDisplayRelatedActions(false, false, false);
|
||||
|
||||
#ifdef ENABLE_RAINTEGRATION
|
||||
@@ -316,6 +320,7 @@ void MainWindow::connectSignals()
|
||||
connect(m_ui.menuLoadState, &QMenu::aboutToShow, this, &MainWindow::onLoadStateMenuAboutToShow);
|
||||
connect(m_ui.menuSaveState, &QMenu::aboutToShow, this, &MainWindow::onSaveStateMenuAboutToShow);
|
||||
connect(m_ui.actionSettings, &QAction::triggered, [this]() { doSettings(); });
|
||||
connect(m_ui.actionSettings2, &QAction::triggered, this, &MainWindow::onSettingsTriggeredFromToolbar);
|
||||
connect(m_ui.actionInterfaceSettings, &QAction::triggered, [this]() { doSettings("Interface"); });
|
||||
connect(m_ui.actionGameListSettings, &QAction::triggered, [this]() { doSettings("Game List"); });
|
||||
connect(m_ui.actionEmulationSettings, &QAction::triggered, [this]() { doSettings("Emulation"); });
|
||||
@@ -737,6 +742,41 @@ void MainWindow::setStyleFromSettings()
|
||||
|
||||
qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }");
|
||||
}
|
||||
else if (theme == "CobaltSky")
|
||||
{
|
||||
// Custom palette by KamFretoZ, A soothing deep royal blue
|
||||
// that are meant to be easy on the eyes as the main color.
|
||||
// Alternative dark theme.
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
|
||||
const QColor gray(192, 192, 192);
|
||||
const QColor royalBlue(29, 41, 81);
|
||||
const QColor darkishBlue(17, 30, 108);
|
||||
|
||||
QPalette darkPalette;
|
||||
darkPalette.setColor(QPalette::Window, royalBlue);
|
||||
darkPalette.setColor(QPalette::WindowText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Base, royalBlue.lighter());
|
||||
darkPalette.setColor(QPalette::AlternateBase, royalBlue);
|
||||
darkPalette.setColor(QPalette::ToolTipBase, darkishBlue);
|
||||
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Text, Qt::white);
|
||||
darkPalette.setColor(QPalette::Button, royalBlue.darker());
|
||||
darkPalette.setColor(QPalette::ButtonText, Qt::white);
|
||||
darkPalette.setColor(QPalette::Link, Qt::white);
|
||||
darkPalette.setColor(QPalette::Highlight, darkishBlue.lighter());
|
||||
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
|
||||
|
||||
darkPalette.setColor(QPalette::Active, QPalette::Button, darkishBlue);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Text, gray);
|
||||
darkPalette.setColor(QPalette::Disabled, QPalette::Light, gray.darker());
|
||||
|
||||
qApp->setPalette(darkPalette);
|
||||
|
||||
qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #2a82da; border: 1px solid white; }");
|
||||
}
|
||||
else if (theme == "VioletAngelPurple")
|
||||
{
|
||||
// Custom palette by RedDevilus, Blue as main color and Purple as complimentary.
|
||||
@@ -978,32 +1018,45 @@ void MainWindow::onToolsVideoCaptureToggled(bool checked)
|
||||
g_emu_thread->beginCapture(path);
|
||||
}
|
||||
|
||||
void MainWindow::onSettingsTriggeredFromToolbar()
|
||||
{
|
||||
if (s_vm_valid)
|
||||
{
|
||||
m_settings_toolbar_menu->exec(QCursor::pos());
|
||||
}
|
||||
else
|
||||
{
|
||||
doSettings();
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::saveStateToConfig()
|
||||
{
|
||||
if (!isVisible())
|
||||
return;
|
||||
|
||||
bool changed = false;
|
||||
|
||||
const QByteArray geometry(saveGeometry());
|
||||
const QByteArray geometry_b64(geometry.toBase64());
|
||||
const std::string old_geometry_b64(Host::GetBaseStringSettingValue("UI", "MainWindowGeometry"));
|
||||
if (old_geometry_b64 != geometry_b64.constData())
|
||||
{
|
||||
const QByteArray geometry = saveGeometry();
|
||||
const QByteArray geometry_b64 = geometry.toBase64();
|
||||
const std::string old_geometry_b64 = Host::GetBaseStringSettingValue("UI", "MainWindowGeometry");
|
||||
if (old_geometry_b64 != geometry_b64.constData())
|
||||
{
|
||||
Host::SetBaseStringSettingValue("UI", "MainWindowGeometry", geometry_b64.constData());
|
||||
Host::CommitBaseSettingChanges();
|
||||
}
|
||||
Host::SetBaseStringSettingValue("UI", "MainWindowGeometry", geometry_b64.constData());
|
||||
changed = true;
|
||||
}
|
||||
|
||||
const QByteArray state(saveState());
|
||||
const QByteArray state_b64(state.toBase64());
|
||||
const std::string old_state_b64(Host::GetBaseStringSettingValue("UI", "MainWindowState"));
|
||||
if (old_state_b64 != state_b64.constData())
|
||||
{
|
||||
const QByteArray state = saveState();
|
||||
const QByteArray state_b64 = state.toBase64();
|
||||
const std::string old_state_b64 = Host::GetBaseStringSettingValue("UI", "MainWindowState");
|
||||
if (old_state_b64 != state_b64.constData())
|
||||
{
|
||||
Host::SetBaseStringSettingValue("UI", "MainWindowState", state_b64.constData());
|
||||
Host::CommitBaseSettingChanges();
|
||||
}
|
||||
Host::SetBaseStringSettingValue("UI", "MainWindowState", state_b64.constData());
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (changed)
|
||||
Host::CommitBaseSettingChanges();
|
||||
}
|
||||
|
||||
void MainWindow::restoreStateFromConfig()
|
||||
@@ -1032,13 +1085,13 @@ void MainWindow::restoreStateFromConfig()
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::updateEmulationActions(bool starting, bool running)
|
||||
void MainWindow::updateEmulationActions(bool starting, bool running, bool stopping)
|
||||
{
|
||||
const bool starting_or_running = starting || running;
|
||||
|
||||
m_ui.actionStartFile->setDisabled(starting_or_running);
|
||||
m_ui.actionStartDisc->setDisabled(starting_or_running);
|
||||
m_ui.actionStartBios->setDisabled(starting_or_running);
|
||||
m_ui.actionStartFile->setDisabled(starting_or_running || stopping);
|
||||
m_ui.actionStartDisc->setDisabled(starting_or_running || stopping);
|
||||
m_ui.actionStartBios->setDisabled(starting_or_running || stopping);
|
||||
|
||||
m_ui.actionPowerOff->setEnabled(running);
|
||||
m_ui.actionPowerOffWithoutSaving->setEnabled(running);
|
||||
@@ -1063,8 +1116,8 @@ void MainWindow::updateEmulationActions(bool starting, bool running)
|
||||
m_ui.actionPause->setChecked(false);
|
||||
|
||||
// scanning needs to be disabled while running
|
||||
m_ui.actionScanForNewGames->setDisabled(starting_or_running);
|
||||
m_ui.actionRescanAllGames->setDisabled(starting_or_running);
|
||||
m_ui.actionScanForNewGames->setDisabled(starting_or_running || stopping);
|
||||
m_ui.actionRescanAllGames->setDisabled(starting_or_running || stopping);
|
||||
}
|
||||
|
||||
void MainWindow::updateDisplayRelatedActions(bool has_surface, bool render_to_main, bool fullscreen)
|
||||
@@ -1318,6 +1371,14 @@ bool MainWindow::requestShutdown(bool allow_confirm, bool allow_save_to_state, b
|
||||
if (!isRenderingToMain() && isHidden() && !QtHost::InBatchMode() && !g_emu_thread->isRunningFullscreenUI())
|
||||
updateWindowState(true);
|
||||
|
||||
// Clear the VM valid state early. That way we can't do anything in the UI if we take a while to shut down.
|
||||
if (s_vm_valid)
|
||||
{
|
||||
s_vm_valid = false;
|
||||
updateEmulationActions(false, false, true);
|
||||
updateDisplayRelatedActions(false, false, false);
|
||||
}
|
||||
|
||||
// Now we can actually shut down the VM.
|
||||
g_emu_thread->shutdownVM(save_state);
|
||||
return true;
|
||||
@@ -1863,7 +1924,7 @@ void MainWindow::onInputRecOpenViewer()
|
||||
void MainWindow::onVMStarting()
|
||||
{
|
||||
s_vm_valid = true;
|
||||
updateEmulationActions(true, false);
|
||||
updateEmulationActions(true, false, false);
|
||||
updateWindowTitle();
|
||||
|
||||
// prevent loading state until we're fully initialized
|
||||
@@ -1874,7 +1935,7 @@ void MainWindow::onVMStarted()
|
||||
{
|
||||
s_vm_valid = true;
|
||||
m_was_disc_change_request = false;
|
||||
updateEmulationActions(true, true);
|
||||
updateEmulationActions(true, true, false);
|
||||
updateWindowTitle();
|
||||
updateStatusBarWidgetVisibility();
|
||||
updateInputRecordingActions(true);
|
||||
@@ -1923,7 +1984,7 @@ void MainWindow::onVMStopped()
|
||||
s_vm_valid = false;
|
||||
s_vm_paused = false;
|
||||
m_last_fps_status = QString();
|
||||
updateEmulationActions(false, false);
|
||||
updateEmulationActions(false, false, false);
|
||||
updateWindowTitle();
|
||||
updateWindowState();
|
||||
updateStatusBarWidgetVisibility();
|
||||
@@ -1979,6 +2040,7 @@ void MainWindow::closeEvent(QCloseEvent* event)
|
||||
// If there's no VM, we can just exit as normal.
|
||||
if (!s_vm_valid)
|
||||
{
|
||||
saveStateToConfig();
|
||||
QMainWindow::closeEvent(event);
|
||||
return;
|
||||
}
|
||||
@@ -1992,7 +2054,6 @@ void MainWindow::closeEvent(QCloseEvent* event)
|
||||
return;
|
||||
|
||||
// Application will be exited in VM stopped handler.
|
||||
saveStateToConfig();
|
||||
m_is_closing = true;
|
||||
}
|
||||
|
||||
@@ -2004,7 +2065,7 @@ static QString getFilenameFromMimeData(const QMimeData* md)
|
||||
// only one url accepted
|
||||
const QList<QUrl> urls(md->urls());
|
||||
if (urls.size() == 1)
|
||||
filename = urls.front().toLocalFile();
|
||||
filename = QDir::toNativeSeparators(urls.front().toLocalFile());
|
||||
}
|
||||
|
||||
return filename;
|
||||
@@ -2118,7 +2179,10 @@ DisplayWidget* MainWindow::createDisplay(bool fullscreen, bool render_to_main)
|
||||
|
||||
if (!g_host_display->CreateDevice(wi.value(), Host::GetEffectiveVSyncMode()))
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"), tr("Failed to create host display device context."));
|
||||
QMessageBox::critical(this, tr("Error"),
|
||||
tr("Failed to create host display device. This may be due to your GPU not supporting the chosen renderer (%1), or because your "
|
||||
"graphics drivers need to be updated.")
|
||||
.arg(QString::fromUtf8(Pcsx2Config::GSOptions::GetRendererName(EmuConfig.GS.Renderer))));
|
||||
destroyDisplayWidget(true);
|
||||
return nullptr;
|
||||
}
|
||||
@@ -2846,6 +2910,9 @@ void MainWindow::doStartFile(std::optional<CDVD_SourceType> source, const QStrin
|
||||
// we might still be saving a resume state...
|
||||
VMManager::WaitForSaveStateFlush();
|
||||
|
||||
// GetSaveStateFileName() might temporarily mount the ISO to get the serial.
|
||||
cancelGameListRefresh();
|
||||
|
||||
const std::optional<bool> resume(
|
||||
promptForResumeState(QString::fromStdString(VMManager::GetSaveStateFileName(params->filename.c_str(), -1))));
|
||||
if (!resume.has_value())
|
||||
@@ -2858,11 +2925,23 @@ void MainWindow::doStartFile(std::optional<CDVD_SourceType> source, const QStrin
|
||||
|
||||
void MainWindow::doDiscChange(CDVD_SourceType source, const QString& path)
|
||||
{
|
||||
const bool is_gs_dump = VMManager::IsGSDumpFileName(path.toStdString());
|
||||
if (is_gs_dump != GSDumpReplayer::IsReplayingDump())
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"), tr("Cannot switch from game to GS dump or vice versa."));
|
||||
return;
|
||||
}
|
||||
else if (is_gs_dump)
|
||||
{
|
||||
Host::RunOnCPUThread([path = path.toStdString()]() { GSDumpReplayer::ChangeDump(path.c_str()); });
|
||||
return;
|
||||
}
|
||||
|
||||
bool reset_system = false;
|
||||
if (!m_was_disc_change_request)
|
||||
{
|
||||
QMessageBox message(QMessageBox::Question, tr("Confirm Disc Change"),
|
||||
tr("Do you want to swap discs or boot the new image (via system reset)?"));
|
||||
tr("Do you want to swap discs or boot the new image (via system reset)?"), QMessageBox::NoButton, this);
|
||||
message.addButton(tr("Swap Disc"), QMessageBox::ActionRole);
|
||||
QPushButton* reset_button = message.addButton(tr("Reset"), QMessageBox::ActionRole);
|
||||
QPushButton* cancel_button = message.addButton(QMessageBox::Cancel);
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include <QtWidgets/QLabel>
|
||||
#include <QtWidgets/QMainWindow>
|
||||
#include <QtWidgets/QMenu>
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
|
||||
@@ -170,6 +171,7 @@ private Q_SLOTS:
|
||||
void onBlockDumpActionToggled(bool checked);
|
||||
void onShowAdvancedSettingsToggled(bool checked);
|
||||
void onToolsVideoCaptureToggled(bool checked);
|
||||
void onSettingsTriggeredFromToolbar();
|
||||
|
||||
// Input Recording
|
||||
void onInputRecNewActionTriggered();
|
||||
@@ -211,7 +213,7 @@ private:
|
||||
void saveStateToConfig();
|
||||
void restoreStateFromConfig();
|
||||
|
||||
void updateEmulationActions(bool starting, bool running);
|
||||
void updateEmulationActions(bool starting, bool running, bool stopping);
|
||||
void updateDisplayRelatedActions(bool has_surface, bool render_to_main, bool fullscreen);
|
||||
void updateStatusBarWidgetVisibility();
|
||||
void updateWindowTitle();
|
||||
@@ -283,6 +285,8 @@ private:
|
||||
QLabel* m_status_vps_widget = nullptr;
|
||||
QLabel* m_status_resolution_widget = nullptr;
|
||||
|
||||
QMenu* m_settings_toolbar_menu = nullptr;
|
||||
|
||||
QString m_current_disc_path;
|
||||
QString m_current_elf_override;
|
||||
QString m_current_game_serial;
|
||||
|
||||
@@ -79,13 +79,15 @@
|
||||
<addaction name="menuLoadState"/>
|
||||
<addaction name="menuSaveState"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionSettings"/>
|
||||
<addaction name="actionSettings"/> <!-- Please consult with macOS users before removing -->
|
||||
<addaction name="actionExit"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuSettings">
|
||||
<property name="title">
|
||||
<string>S&ettings</string>
|
||||
</property>
|
||||
<addaction name="actionViewGameProperties"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionInterfaceSettings"/>
|
||||
<addaction name="actionGameListSettings"/>
|
||||
<addaction name="actionBIOSSettings"/>
|
||||
@@ -156,7 +158,6 @@
|
||||
<addaction name="actionViewGameList"/>
|
||||
<addaction name="actionViewGameGrid"/>
|
||||
<addaction name="actionViewSystemDisplay"/>
|
||||
<addaction name="actionViewGameProperties"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionFullscreen"/>
|
||||
<addaction name="menuWindowSize"/>
|
||||
@@ -245,7 +246,7 @@
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionFullscreen"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionSettings"/>
|
||||
<addaction name="actionSettings2"/>
|
||||
<addaction name="actionControllerSettings"/>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusBar"/>
|
||||
@@ -522,7 +523,19 @@
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Settings...</string>
|
||||
<string>&Settings</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::PreferencesRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSettings2">
|
||||
<property name="icon">
|
||||
<iconset theme="settings-3-line">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Settings</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::PreferencesRole</enum>
|
||||
|
||||
@@ -795,17 +795,22 @@ void EmuThread::onDisplayWindowResized(int width, int height, float scale)
|
||||
void EmuThread::onApplicationStateChanged(Qt::ApplicationState state)
|
||||
{
|
||||
// NOTE: This is executed on the emu thread, not UI thread.
|
||||
if (!m_pause_on_focus_loss || !VMManager::HasValidVM())
|
||||
if (!VMManager::HasValidVM())
|
||||
return;
|
||||
|
||||
const bool focus_loss = (state != Qt::ApplicationActive);
|
||||
if (focus_loss)
|
||||
{
|
||||
if (!m_was_paused_by_focus_loss && VMManager::GetState() == VMState::Running)
|
||||
if (m_pause_on_focus_loss && !m_was_paused_by_focus_loss && VMManager::GetState() == VMState::Running)
|
||||
{
|
||||
m_was_paused_by_focus_loss = true;
|
||||
VMManager::SetPaused(true);
|
||||
}
|
||||
|
||||
// Clear the state of all keyboard binds.
|
||||
// That way, if we had a key held down, and lost focus, the bind won't be stuck enabled because we never
|
||||
// got the key release message, because it happened in another window which "stole" the event.
|
||||
InputManager::ClearBindStateFromSource(InputManager::MakeHostKeyboardKey(0));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -967,17 +972,17 @@ void Host::ReleaseHostDisplay(bool clear_state)
|
||||
g_emu_thread->releaseHostDisplay(clear_state);
|
||||
}
|
||||
|
||||
bool Host::BeginPresentFrame(bool frame_skip)
|
||||
HostDisplay::PresentResult Host::BeginPresentFrame(bool frame_skip)
|
||||
{
|
||||
if (!g_host_display->BeginPresent(frame_skip))
|
||||
const HostDisplay::PresentResult result = g_host_display->BeginPresent(frame_skip);
|
||||
if (result != HostDisplay::PresentResult::OK)
|
||||
{
|
||||
// if we're skipping a frame, we need to reset imgui's state, since
|
||||
// we won't be calling EndPresentFrame().
|
||||
ImGuiManager::NewFrame();
|
||||
return false;
|
||||
ImGuiManager::SkipFrame();
|
||||
}
|
||||
|
||||
return true;
|
||||
return result;
|
||||
}
|
||||
|
||||
void Host::EndPresentFrame()
|
||||
|
||||
@@ -56,8 +56,8 @@ AchievementSettingsWidget::AchievementSettingsWidget(SettingsDialog* dialog, QWi
|
||||
dialog->registerWidgetHelp(m_ui.unofficialTestMode, tr("Test Unofficial Achievements"), tr("Unchecked"),
|
||||
tr("When enabled, PCSX2 will list achievements from unofficial sets. Please note that these achievements are "
|
||||
"not tracked by RetroAchievements, so they unlock every time."));
|
||||
dialog->registerWidgetHelp(m_ui.richPresence, tr("Enable Rich Presence"), tr("Unchecked"),
|
||||
tr("When enabled, rich presence information will be collected and sent to the server where supported."));
|
||||
dialog->registerWidgetHelp(m_ui.richPresence, tr("Enable RA's Rich Presence"), tr("Unchecked"),
|
||||
tr("When enabled, rich presence information will be collected and sent to the RetroAchievements servers where supported."));
|
||||
dialog->registerWidgetHelp(m_ui.challengeMode, tr("Enable Hardcore Mode"), tr("Unchecked"),
|
||||
tr("\"Challenge\" mode for achievements, including leaderboard tracking. Disables save state, cheats, and slowdown functions."));
|
||||
dialog->registerWidgetHelp(m_ui.leaderboards, tr("Enable Leaderboards"), tr("Checked"),
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="richPresence">
|
||||
<property name="text">
|
||||
<string>Enable Rich Presence</string>
|
||||
<string>Enable RA's Rich Presence</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -72,7 +72,7 @@ AdvancedSettingsWidget::AdvancedSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
dialog->registerWidgetHelp(m_ui.eeClampMode, tr("Clamping Mode"), tr("Normal (Default)"), tr(""));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.eeRecompiler, tr("Enable Recompiler"), tr("Checked"),
|
||||
tr("Performs just - in - time binary translation of 64 - bit MIPS - IV machine code to x86."));
|
||||
tr("Performs just-in-time binary translation of 64-bit MIPS-IV machine code to x86."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.eeWaitLoopDetection, tr("Wait Loop Detection"), tr("Checked"),
|
||||
tr("Moderate speedup for some games, with no known side effects."));
|
||||
@@ -86,15 +86,15 @@ AdvancedSettingsWidget::AdvancedSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
tr("Uses backpatching to avoid register flushing on every memory access."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.pauseOnTLBMiss, tr("Pause On TLB Miss"), tr("Unchecked"),
|
||||
tr("Pauses the virtual machine when a TLB miss occurs, instead of ignoring it and continuing. Note the the VM will pause after the "
|
||||
tr("Pauses the virtual machine when a TLB miss occurs, instead of ignoring it and continuing. Note that the VM will pause after the "
|
||||
"end of the block, not on the instruction which caused the exception. Refer to the console to see the address where the invalid "
|
||||
"access occurred."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.vu0RoundingMode, tr("Rounding Mode"), tr("Chop / Zero (Default)"), tr(""));
|
||||
dialog->registerWidgetHelp(m_ui.vu1RoundingMode, tr("Rounding Mode"), tr("Chop / Zero (Default)"), tr(""));
|
||||
dialog->registerWidgetHelp(m_ui.vu0RoundingMode, tr("VU0 Rounding Mode"), tr("Chop / Zero (Default)"), tr(""));
|
||||
dialog->registerWidgetHelp(m_ui.vu1RoundingMode, tr("VU1 Rounding Mode"), tr("Chop / Zero (Default)"), tr(""));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.vu0ClampMode, tr("Clamping Mode"), tr("Normal (Default)"), tr(""));
|
||||
dialog->registerWidgetHelp(m_ui.vu1ClampMode, tr("Clamping Mode"), tr("Normal (Default)"), tr(""));
|
||||
dialog->registerWidgetHelp(m_ui.vu0ClampMode, tr("VU0 Clamping Mode"), tr("Normal (Default)"), tr(""));
|
||||
dialog->registerWidgetHelp(m_ui.vu1ClampMode, tr("VU1 Clamping Mode"), tr("Normal (Default)"), tr(""));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.vu0Recompiler, tr("Enable VU0 Recompiler (Micro Mode)"), tr("Checked"), tr("Enables VU0 Recompiler."));
|
||||
|
||||
@@ -107,7 +107,7 @@ AdvancedSettingsWidget::AdvancedSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
tr("Performs just-in-time binary translation of 32-bit MIPS-I machine code to x86."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.gameFixes, tr("Enable Game Fixes"), tr("Checked"),
|
||||
tr("Automatically loads and applies gamefixes to known problematic games on game start."));
|
||||
tr("Automatically loads and applies fixes to known problematic games on game start."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.patches, tr("Enable Compatibility Patches"), tr("Checked"),
|
||||
tr("Automatically loads and applies compatibility patches to known problematic games."));
|
||||
|
||||
@@ -109,7 +109,7 @@ AudioSettingsWidget::AudioSettingsWidget(SettingsDialog* dialog, QWidget* parent
|
||||
updateLatencyLabels();
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.syncMode, tr("Synchronization"), tr("TimeStretch (Recommended)"),
|
||||
tr("When running outside of 100% speed, adjusts the tempo on audio instead of dropping frames. Produces much nicer fast forward/slowdown audio."));
|
||||
tr("When running outside of 100% speed, adjusts the tempo on audio instead of dropping frames. Produces much nicer fast-forward/slowdown audio."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.expansionMode, tr("Expansion"), tr("Stereo (None, Default)"), tr(""));
|
||||
|
||||
@@ -126,7 +126,7 @@ AudioSettingsWidget::AudioSettingsWidget(SettingsDialog* dialog, QWidget* parent
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.sequenceLength, tr("Sequence Length"), tr("30 ms"), tr(""));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.seekWindowSize, tr("Seekwindow Size"), tr("20 ms"), tr(""));
|
||||
dialog->registerWidgetHelp(m_ui.seekWindowSize, tr("Seek Window Size"), tr("20 ms"), tr(""));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.overlap, tr("Overlap"), tr("10 ms"), tr(""));
|
||||
|
||||
|
||||
@@ -345,6 +345,11 @@ ControllerMacroEditWidget::ControllerMacroEditWidget(ControllerMacroWidget* pare
|
||||
m_ui.bindList->addItem(item);
|
||||
}
|
||||
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileNormalized(
|
||||
dialog->getProfileSettingsInterface(), m_ui.pressure, section, fmt::format("Macro{}Pressure", index + 1u), 100.0f, 1.0f);
|
||||
connect(m_ui.pressure, &QSlider::valueChanged, this, &ControllerMacroEditWidget::onPressureChanged);
|
||||
onPressureChanged();
|
||||
|
||||
m_frequency = dialog->getIntValue(section.c_str(), fmt::format("Macro{}Frequency", index + 1u).c_str(), 0);
|
||||
updateFrequencyText();
|
||||
|
||||
@@ -371,6 +376,11 @@ QString ControllerMacroEditWidget::getSummary() const
|
||||
return str.isEmpty() ? tr("Not Configured") : str;
|
||||
}
|
||||
|
||||
void ControllerMacroEditWidget::onPressureChanged()
|
||||
{
|
||||
m_ui.pressureValue->setText(tr("%1%").arg(m_ui.pressure->value()));
|
||||
}
|
||||
|
||||
void ControllerMacroEditWidget::onSetFrequencyClicked()
|
||||
{
|
||||
bool okay;
|
||||
|
||||
@@ -113,6 +113,7 @@ public:
|
||||
QString getSummary() const;
|
||||
|
||||
private Q_SLOTS:
|
||||
void onPressureChanged();
|
||||
void onSetFrequencyClicked();
|
||||
void updateBinds();
|
||||
|
||||
|
||||
@@ -45,10 +45,10 @@ ControllerGlobalSettingsWidget::ControllerGlobalSettingsWidget(QWidget* parent,
|
||||
#endif
|
||||
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableMouseMapping, "UI", "EnableMouseMapping", false);
|
||||
connect(m_ui.mouseSettings, &QToolButton::clicked, this, &ControllerGlobalSettingsWidget::mouseSettingsClicked);
|
||||
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, m_ui.multitapPort1, "Pad", "MultitapPort1", false);
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, m_ui.multitapPort2, "Pad", "MultitapPort2", false);
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileFloat(sif, m_ui.pointerXScale, "Pad", "PointerXScale", 8.0f);
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileFloat(sif, m_ui.pointerYScale, "Pad", "PointerYScale", 8.0f);
|
||||
|
||||
#ifdef _WIN32
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableXInputSource, "InputSources", "XInput", false);
|
||||
@@ -81,13 +81,6 @@ ControllerGlobalSettingsWidget::ControllerGlobalSettingsWidget(QWidget* parent,
|
||||
for (QCheckBox* cb : {m_ui.multitapPort1, m_ui.multitapPort2})
|
||||
connect(cb, &QCheckBox::stateChanged, this, [this]() { emit bindingSetupChanged(); });
|
||||
|
||||
connect(m_ui.pointerXScale, &QSlider::valueChanged, this,
|
||||
[this](int value) { m_ui.pointerXScaleLabel->setText(QStringLiteral("%1").arg(value)); });
|
||||
connect(m_ui.pointerYScale, &QSlider::valueChanged, this,
|
||||
[this](int value) { m_ui.pointerYScaleLabel->setText(QStringLiteral("%1").arg(value)); });
|
||||
m_ui.pointerXScaleLabel->setText(QStringLiteral("%1").arg(m_ui.pointerXScale->value()));
|
||||
m_ui.pointerYScaleLabel->setText(QStringLiteral("%1").arg(m_ui.pointerYScale->value()));
|
||||
|
||||
updateSDLOptionsEnabled();
|
||||
}
|
||||
|
||||
@@ -128,6 +121,12 @@ void ControllerGlobalSettingsWidget::ledSettingsClicked()
|
||||
dialog.exec();
|
||||
}
|
||||
|
||||
void ControllerGlobalSettingsWidget::mouseSettingsClicked()
|
||||
{
|
||||
ControllerMouseSettingsDialog dialog(this, m_dialog);
|
||||
dialog.exec();
|
||||
}
|
||||
|
||||
ControllerLEDSettingsDialog::ControllerLEDSettingsDialog(QWidget* parent, ControllerSettingsDialog* dialog)
|
||||
: QDialog(parent)
|
||||
, m_dialog(dialog)
|
||||
@@ -156,3 +155,35 @@ void ControllerLEDSettingsDialog::linkButton(ColorPickerButton* button, u32 play
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
ControllerMouseSettingsDialog::ControllerMouseSettingsDialog(QWidget* parent, ControllerSettingsDialog* dialog)
|
||||
: QDialog(parent)
|
||||
{
|
||||
m_ui.setupUi(this);
|
||||
|
||||
SettingsInterface* sif = dialog->getProfileSettingsInterface();
|
||||
|
||||
m_ui.icon->setPixmap(QIcon::fromTheme(QStringLiteral("mouse-line")).pixmap(32, 32));
|
||||
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileFloat(sif, m_ui.pointerXSpeedSlider, "Pad", "PointerXSpeed", 40.0f);
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileFloat(sif, m_ui.pointerYSpeedSlider, "Pad", "PointerYSpeed", 40.0f);
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileFloat(sif, m_ui.pointerXDeadZoneSlider, "Pad", "PointerXDeadZone", 20.0f);
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileFloat(sif, m_ui.pointerYDeadZoneSlider, "Pad", "PointerYDeadZone", 20.0f);
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileFloat(sif, m_ui.pointerInertiaSlider, "Pad", "PointerInertia", 10.0f);
|
||||
|
||||
connect(m_ui.pointerXSpeedSlider, &QSlider::valueChanged, this, [this](int value) { m_ui.pointerXSpeedVal->setText(QStringLiteral("%1").arg(value)); });
|
||||
connect(m_ui.pointerYSpeedSlider, &QSlider::valueChanged, this, [this](int value) { m_ui.pointerYSpeedVal->setText(QStringLiteral("%1").arg(value)); });
|
||||
connect(m_ui.pointerXDeadZoneSlider, &QSlider::valueChanged, this, [this](int value) { m_ui.pointerXDeadZoneVal->setText(QStringLiteral("%1").arg(value)); });
|
||||
connect(m_ui.pointerYDeadZoneSlider, &QSlider::valueChanged, this, [this](int value) { m_ui.pointerYDeadZoneVal->setText(QStringLiteral("%1").arg(value)); });
|
||||
connect(m_ui.pointerInertiaSlider, &QSlider::valueChanged, this, [this](int value) { m_ui.pointerInertiaVal->setText(QStringLiteral("%1").arg(value)); });
|
||||
|
||||
m_ui.pointerXSpeedVal->setText(QStringLiteral("%1").arg(m_ui.pointerXSpeedSlider->value()));
|
||||
m_ui.pointerYSpeedVal->setText(QStringLiteral("%1").arg(m_ui.pointerYSpeedSlider->value()));
|
||||
m_ui.pointerXDeadZoneVal->setText(QStringLiteral("%1").arg(m_ui.pointerXDeadZoneSlider->value()));
|
||||
m_ui.pointerYDeadZoneVal->setText(QStringLiteral("%1").arg(m_ui.pointerYDeadZoneSlider->value()));
|
||||
m_ui.pointerInertiaVal->setText(QStringLiteral("%1").arg(m_ui.pointerInertiaSlider->value()));
|
||||
|
||||
connect(m_ui.buttonBox->button(QDialogButtonBox::Close), &QPushButton::clicked, this, &QDialog::accept);
|
||||
}
|
||||
|
||||
ControllerMouseSettingsDialog::~ControllerMouseSettingsDialog() = default;
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
#include "ui_ControllerGlobalSettingsWidget.h"
|
||||
#include "ui_ControllerLEDSettingsDialog.h"
|
||||
#include "ui_ControllerMouseSettingsDialog.h"
|
||||
|
||||
class ControllerSettingsDialog;
|
||||
|
||||
@@ -44,6 +45,7 @@ Q_SIGNALS:
|
||||
private Q_SLOTS:
|
||||
void updateSDLOptionsEnabled();
|
||||
void ledSettingsClicked();
|
||||
void mouseSettingsClicked();
|
||||
|
||||
private:
|
||||
Ui::ControllerGlobalSettingsWidget m_ui;
|
||||
@@ -64,3 +66,15 @@ private:
|
||||
Ui::ControllerLEDSettingsDialog m_ui;
|
||||
ControllerSettingsDialog* m_dialog;
|
||||
};
|
||||
|
||||
class ControllerMouseSettingsDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ControllerMouseSettingsDialog(QWidget* parent, ControllerSettingsDialog* dialog);
|
||||
~ControllerMouseSettingsDialog();
|
||||
|
||||
private:
|
||||
Ui::ControllerMouseSettingsDialog m_ui;
|
||||
};
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>902</width>
|
||||
<height>677</height>
|
||||
<height>583</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@@ -26,6 +26,32 @@
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="5" column="0">
|
||||
<widget class="QGroupBox" name="profileSettings">
|
||||
<property name="title">
|
||||
<string>Profile Settings</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_5">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>When this option is enabled, hotkeys can be set in this input profile, and will be used instead of the global hotkeys. By default, hotkeys are always shared between all profiles.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="useProfileHotkeyBindings">
|
||||
<property name="text">
|
||||
<string>Use Per-Profile Hotkeys</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QGroupBox" name="sdlGroup">
|
||||
<property name="title">
|
||||
@@ -65,8 +91,7 @@
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="lightbulb-line">
|
||||
<normaloff>.</normaloff>.
|
||||
</iconset>
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -75,58 +100,6 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QGroupBox" name="xinputGroup">
|
||||
<property name="title">
|
||||
<string>XInput Source</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>The XInput source provides support for XBox 360 / XBox One / XBox Series controllers, and third party controllers which implement the XInput protocol.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="enableXInputSource">
|
||||
<property name="text">
|
||||
<string>Enable XInput Input Source</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QGroupBox" name="dinputGroup">
|
||||
<property name="title">
|
||||
<string>DInput Source</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_6">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string>The DInput source provides support for legacy controllers which do not support XInput. Accessing these controllers via SDL instead is recommended, but DirectInput can be used if they are not compatible with SDL.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="enableDInputSource">
|
||||
<property name="text">
|
||||
<string>Enable DInput Input Source</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
@@ -140,16 +113,16 @@
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QGroupBox" name="profileSettings">
|
||||
<item row="1" column="0">
|
||||
<widget class="QGroupBox" name="xinputGroup">
|
||||
<property name="title">
|
||||
<string>Profile Settings</string>
|
||||
<string>XInput Source</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_5">
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>When this option is enabled, hotkeys can be set in this input profile, and will be used instead of the global hotkeys. By default, hotkeys are always shared between all profiles.</string>
|
||||
<string>The XInput source provides support for Xbox 360 / Xbox One / Xbox Series controllers, and third party controllers which implement the XInput protocol.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
@@ -157,9 +130,9 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="useProfileHotkeyBindings">
|
||||
<widget class="QCheckBox" name="enableXInputSource">
|
||||
<property name="text">
|
||||
<string>Use Per-Profile Hotkeys</string>
|
||||
<string>Enable XInput Input Source</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -199,146 +172,6 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QGroupBox" name="mouseGroup">
|
||||
<property name="title">
|
||||
<string>Mouse/Pointer Source</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Using raw input improves precision when you bind controller sticks to the mouse pointer. Also enables multiple mice to be used.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Horizontal Sensitivity:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QSlider" name="pointerXScale">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>150</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>30</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="pointerXScaleLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>10</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Vertical Sensitivity:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QSlider" name="pointerYScale">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>150</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>30</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="pointerYScaleLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>10</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="enableMouseMapping">
|
||||
<property name="text">
|
||||
<string>Enable Mouse Mapping</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" rowspan="7">
|
||||
<widget class="QGroupBox" name="groupBox_3">
|
||||
<property name="title">
|
||||
@@ -364,6 +197,72 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QGroupBox" name="dinputGroup">
|
||||
<property name="title">
|
||||
<string>DInput Source</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_6">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string>The DInput source provides support for legacy controllers which do not support XInput. Accessing these controllers via SDL instead is recommended, but DirectInput can be used if they are not compatible with SDL.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="enableDInputSource">
|
||||
<property name="text">
|
||||
<string>Enable DInput Input Source</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QGroupBox" name="mouseGroup">
|
||||
<property name="title">
|
||||
<string>Mouse/Pointer Source</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>PCSX2 allows you to use your mouse to simulate analog stick movement.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3" stretch="1,0">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="enableMouseMapping">
|
||||
<property name="text">
|
||||
<string>Enable Mouse Mapping</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="mouseSettings">
|
||||
<property name="toolTip">
|
||||
<string>Controller LED Settings</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Settings...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>595</width>
|
||||
<height>473</height>
|
||||
<width>691</width>
|
||||
<height>547</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@@ -32,6 +32,9 @@
|
||||
<string>Binds/Buttons</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="1" column="0">
|
||||
<widget class="QListWidget" name="bindList"/>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
@@ -42,8 +45,54 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QListWidget" name="bindList"/>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_4">
|
||||
<property name="title">
|
||||
<string>Pressure</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>For buttons which are pressure sensitive, this slider controls how much force will be simulated when the macro is active.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="pressureLayout">
|
||||
<item>
|
||||
<widget class="QSlider" name="pressure">
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="tickPosition">
|
||||
<enum>QSlider::TicksBelow</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="pressureValue">
|
||||
<property name="text">
|
||||
<string>100%</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
|
||||
417
pcsx2-qt/Settings/ControllerMouseSettingsDialog.ui
Normal file
417
pcsx2-qt/Settings/ControllerMouseSettingsDialog.ui
Normal file
@@ -0,0 +1,417 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ControllerMouseSettingsDialog</class>
|
||||
<widget class="QDialog" name="ControllerMouseSettingsDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>654</width>
|
||||
<height>169</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Mouse Mapping Settings</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="5" column="1">
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Close</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<layout class="QHBoxLayout" name="pointerYSpeed">
|
||||
<item>
|
||||
<widget class="QLabel" name="pointerYSpeedLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>70</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Y Speed</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSlider" name="pointerYSpeedSlider">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="pointerYSpeedVal">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>30</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>10</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<layout class="QHBoxLayout" name="pointerXSpeed">
|
||||
<item>
|
||||
<widget class="QLabel" name="pointerXSpeedLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>70</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>X Speed</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSlider" name="pointerXSpeedSlider">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="pointerXSpeedVal">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>30</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>10</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<property name="bottomMargin">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="icon">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>32</width>
|
||||
<height>32</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>32</width>
|
||||
<height>32</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p><span style=" font-weight:700;">Mouse Mapping Settings</span><br/>These settings fine-tune the behavior when mapping a mouse to the emulated controller.</p></body></html></string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::RichText</enum>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="4" column="0" colspan="2">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<layout class="QHBoxLayout" name="pointerInertia">
|
||||
<item>
|
||||
<widget class="QLabel" name="pointerInertiaLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>70</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Inertia</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSlider" name="pointerInertiaSlider">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="pointerInertiaVal">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>30</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>10</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<layout class="QHBoxLayout" name="pointerXDeadZone">
|
||||
<item>
|
||||
<widget class="QLabel" name="pointerXDeadZoneLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>70</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>X Dead Zone</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSlider" name="pointerXDeadZoneSlider">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="pointerXDeadZoneVal">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>30</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>10</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<layout class="QHBoxLayout" name="pointerYDeadZone">
|
||||
<item>
|
||||
<widget class="QLabel" name="pointerYDeadZoneLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>70</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Y Dead Zone</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSlider" name="pointerYDeadZoneSlider">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="pointerYDeadZoneVal">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>30</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>10</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="../resources/resources.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -68,7 +68,7 @@
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Profile:</string>
|
||||
<string>Editing Profile:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -122,14 +122,14 @@ void CreateMemoryCardDialog::createCard()
|
||||
if (FileMcd_GetCardInfo(nameStr).has_value())
|
||||
{
|
||||
QMessageBox::critical(this, tr("Create Memory Card"),
|
||||
tr("Failed to create the memory card, because another card with the name '%1' already exists.").arg(name));
|
||||
tr("Failed to create the Memory Card, because another card with the name '%1' already exists.").arg(name));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!FileMcd_CreateNewCard(nameStr, m_type, m_fileType))
|
||||
{
|
||||
QMessageBox::critical(this, tr("Create Memory Card"),
|
||||
tr("Failed to create the memory card, the log may contain more information."));
|
||||
tr("Failed to create the Memory Card, the log may contain more information."));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -141,6 +141,6 @@ void CreateMemoryCardDialog::createCard()
|
||||
}
|
||||
#endif
|
||||
|
||||
QMessageBox::information(this, tr("Create Memory Card"), tr("Memory card '%1' created.").arg(name));
|
||||
QMessageBox::information(this, tr("Create Memory Card"), tr("Memory Card '%1' created.").arg(name));
|
||||
accept();
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p><span style=" font-weight:700;">Create Memory Card</span><br />Enter the name of the memory card you wish to create, and choose a size. We recommend either using 8MB memory cards, or folder memory cards for best compatibility.</p></body></html></string>
|
||||
<string><html><head/><body><p><span style=" font-weight:700;">Create Memory Card</span><br />Enter the name of the Memory Card you wish to create, and choose a size. We recommend either using 8MB Memory Cards, or folder Memory Cards for best compatibility.</p></body></html></string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::RichText</enum>
|
||||
@@ -112,7 +112,7 @@
|
||||
<item>
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>A typical size for third-party memory cards which should work with most games.</string>
|
||||
<string>A typical size for third-party Memory Cards which should work with most games.</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
@@ -136,7 +136,7 @@
|
||||
<item>
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>A typical size for third-party memory cards which should work with most games.</string>
|
||||
<string>A typical size for third-party Memory Cards which should work with most games.</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
@@ -184,7 +184,7 @@
|
||||
<item>
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>Store memory card contents in the host filesystem instead of a file.</string>
|
||||
<string>Store Memory Card contents in the host filesystem instead of a file.</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
@@ -208,7 +208,7 @@
|
||||
<item>
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string>This is the standard Sony-provisioned size PS1 memory card, and only compatible with PS1 games.</string>
|
||||
<string>This is the standard Sony-provisioned size PS1 Memory Card, and only compatible with PS1 games.</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||
@@ -235,7 +235,7 @@
|
||||
<item>
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>NTFS compression is built-in, fast, and completely reliable. Typically compresses memory cards (highly recommended).</string>
|
||||
<string>NTFS compression is built-in, fast, and completely reliable. Typically compresses Memory Cards (highly recommended).</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Network DNS Hosts Inport/Export</string>
|
||||
<string>Network DNS Hosts Import/Export</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
|
||||
@@ -90,26 +90,26 @@ EmulationSettingsWidget::EmulationSettingsWidget(SettingsDialog* dialog, QWidget
|
||||
dialog->registerWidgetHelp(m_ui.normalSpeed, tr("Normal Speed"), "100%",
|
||||
tr("Sets the target emulation speed. It is not guaranteed that this speed will be reached, "
|
||||
"and if not, the emulator will run as fast as it can manage."));
|
||||
dialog->registerWidgetHelp(m_ui.fastForwardSpeed, tr("Fast Forward Speed"), tr("User Preference"),
|
||||
tr("Sets the fast forward speed. This speed will be used when the fast forward hotkey is pressed/toggled."));
|
||||
dialog->registerWidgetHelp(m_ui.slowMotionSpeed, tr("Slow Motion Speed"), tr("User Preference"),
|
||||
tr("Sets the slow motion speed. This speed will be used when the slow motion hotkey is pressed/toggled."));
|
||||
dialog->registerWidgetHelp(m_ui.fastForwardSpeed, tr("Fast-Forward Speed"), tr("User Preference"),
|
||||
tr("Sets the fast-forward speed. This speed will be used when the fast-forward hotkey is pressed/toggled."));
|
||||
dialog->registerWidgetHelp(m_ui.slowMotionSpeed, tr("Slow-Motion Speed"), tr("User Preference"),
|
||||
tr("Sets the slow-motion speed. This speed will be used when the slow-motion hotkey is pressed/toggled."));
|
||||
dialog->registerWidgetHelp(m_ui.speedLimiter, tr("Speed Limiter"), tr("Checked"),
|
||||
tr("Limits the emulation to the appropriate framerate for the currently running game."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.eeCycleRate, tr("Cycle Rate"), tr("100% (Normal Speed)"),
|
||||
dialog->registerWidgetHelp(m_ui.eeCycleRate, tr("EE Cycle Rate"), tr("100% (Normal Speed)"),
|
||||
tr("Higher values may increase internal framerate in games, but will increase CPU requirements substantially. "
|
||||
"Lower values will reduce the CPU load allowing lightweight games to run full speed on weaker CPUs."));
|
||||
dialog->registerWidgetHelp(m_ui.eeCycleSkipping, tr("Cycle Skip"), tr("Disabled"),
|
||||
dialog->registerWidgetHelp(m_ui.eeCycleSkipping, tr("EE Cycle Skip"), tr("Disabled"),
|
||||
tr("Makes the emulated Emotion Engine skip cycles. "
|
||||
"Helps a small subset of games like SOTC. Most of the time it's harmful to performance."));
|
||||
dialog->registerWidgetHelp(m_ui.affinityControl, tr("Affinity Control"), tr("Disabled"),
|
||||
tr("Sets the priority for specific threads in a specific order ignoring the system scheduler. "
|
||||
"May help CPUs with big (P) and little (E) cores (e.g. Intel 12th or newer generation CPUs from Intel or other vendors such as AMD)"));
|
||||
dialog->registerWidgetHelp(m_ui.MTVU, tr("MTVU (Multi-threaded VU1)"), tr("Checked"),
|
||||
"May help CPUs with big (P) and little (E) cores (e.g. Intel 12th or newer generation CPUs from Intel or other vendors such as AMD)."));
|
||||
dialog->registerWidgetHelp(m_ui.MTVU, tr("Enable Multithreaded VU1 (MTVU1)"), tr("Checked"),
|
||||
tr("Generally a speedup on CPUs with 3 or more threads. "
|
||||
"Safe for most games, but a few are incompatible and may hang."));
|
||||
dialog->registerWidgetHelp(m_ui.instantVU1, tr("Instant VU1"), tr("Checked"),
|
||||
dialog->registerWidgetHelp(m_ui.instantVU1, tr("Enable Instant VU1"), tr("Checked"),
|
||||
tr("Runs VU1 instantly. Provides a modest speed improvement in most games. "
|
||||
"Safe for most games, but a few games may exhibit graphical errors."));
|
||||
dialog->registerWidgetHelp(m_ui.fastCDVD, tr("Enable Fast CDVD"), tr("Unchecked"),
|
||||
@@ -120,8 +120,8 @@ EmulationSettingsWidget::EmulationSettingsWidget(SettingsDialog* dialog, QWidget
|
||||
tr("Allows games and homebrew to access files / folders directly on the host computer."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.optimalFramePacing, tr("Optimal Frame Pacing"), tr("Unchecked"),
|
||||
tr("Sets the vsync queue size to 0, making every frame be completed and presented by the GS before input is polled, and the next frame begins. "
|
||||
"Using this setting can reduce input lag, at the cost of measurably higher CPU and GPU requirements."));
|
||||
tr("Sets the VSync queue size to 0, making every frame be completed and presented by the GS before input is polled and the next frame begins. "
|
||||
"Using this setting can reduce input lag at the cost of measurably higher CPU and GPU requirements."));
|
||||
dialog->registerWidgetHelp(m_ui.maxFrameLatency, tr("Maximum Frame Latency"), tr("2 Frames"),
|
||||
tr("Sets the maximum number of frames that can be queued up to the GS, before the CPU thread will wait for one of them to complete before continuing. "
|
||||
"Higher values can assist with smoothing out irregular frame times, but add additional input lag."));
|
||||
|
||||
@@ -51,14 +51,14 @@
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Slow Motion Speed:</string>
|
||||
<string>Slow-Motion Speed:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Fast Forward Speed:</string>
|
||||
<string>Fast-Forward Speed:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -97,7 +97,7 @@
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="MTVU">
|
||||
<property name="text">
|
||||
<string>Enable Multi-Threaded VU1 (MTVU)</string>
|
||||
<string>Enable Multithreaded VU1 (MTVU)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -80,6 +80,15 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
|
||||
m_ui.setupUi(this);
|
||||
|
||||
#ifndef PCSX2_DEVBUILD
|
||||
if (!m_dialog->isPerGameSettings())
|
||||
{
|
||||
// We removed hardware fixes from global settings, but people in the past did set this stuff globally.
|
||||
// So, just reset it all. We can remove this code at some point in the future.
|
||||
resetManualHardwareFixes();
|
||||
}
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Global Settings
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -166,11 +175,8 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.dithering, "EmuCore/GS", "dithering_ps2", 2);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(
|
||||
sif, m_ui.mipmapping, "EmuCore/GS", "mipmap_hw", static_cast<int>(HWMipmapLevel::Automatic), -1);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(
|
||||
sif, m_ui.crcFixLevel, "EmuCore/GS", "crc_hack_level", static_cast<int>(CRCHackLevel::Automatic), -1);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(
|
||||
sif, m_ui.blending, "EmuCore/GS", "accurate_blending_unit", static_cast<int>(AccBlendLevel::Basic));
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.gpuPaletteConversion, "EmuCore/GS", "paltex", false);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(
|
||||
sif, m_ui.texturePreloading, "EmuCore/GS", "texture_preloading", static_cast<int>(TexturePreloadingLevel::Off));
|
||||
|
||||
@@ -178,12 +184,16 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
&GraphicsSettingsWidget::onTrilinearFilteringChanged);
|
||||
connect(m_ui.gpuPaletteConversion, QOverload<int>::of(&QCheckBox::stateChanged), this,
|
||||
&GraphicsSettingsWidget::onGpuPaletteConversionChanged);
|
||||
connect(m_ui.textureInsideRt, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
||||
&GraphicsSettingsWidget::onTextureInsideRtChanged);
|
||||
onTrilinearFilteringChanged();
|
||||
onGpuPaletteConversionChanged(m_ui.gpuPaletteConversion->checkState());
|
||||
onTextureInsideRtChanged();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// HW Renderer Fixes
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.crcFixLevel, "EmuCore/GS", "crc_hack_level", static_cast<int>(CRCHackLevel::Automatic), -1);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.halfScreenFix, "EmuCore/GS", "UserHacks_Half_Bottom_Override", -1, -1);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.cpuSpriteRenderBW, "EmuCore/GS", "UserHacks_CPUSpriteRenderBW", 0);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.cpuCLUTRender, "EmuCore/GS", "UserHacks_CPUCLUTRender", 0);
|
||||
@@ -197,7 +207,12 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.preloadFrameData, "EmuCore/GS", "preload_frame_with_gs_data", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(
|
||||
sif, m_ui.disablePartialInvalidation, "EmuCore/GS", "UserHacks_DisablePartialInvalidation", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.textureInsideRt, "EmuCore/GS", "UserHacks_TextureInsideRt", false);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(
|
||||
sif, m_ui.textureInsideRt, "EmuCore/GS", "UserHacks_TextureInsideRt", static_cast<int>(GSTextureInRtMode::Disabled));
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.readTCOnClose, "EmuCore/GS", "UserHacks_ReadTCOnClose", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.targetPartialInvalidation, "EmuCore/GS", "UserHacks_TargetPartialInvalidation", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.estimateTextureRegion, "EmuCore/GS", "UserHacks_EstimateTextureRegion", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.gpuPaletteConversion, "EmuCore/GS", "paltex", false);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// HW Upscaling Fixes
|
||||
@@ -289,13 +304,11 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
m_ui.advancedOptionsFormLayout->removeRow(0);
|
||||
m_ui.gsDownloadMode = nullptr;
|
||||
|
||||
// Remove texture offset and skipdraw range for global settings.
|
||||
m_ui.upscalingFixesLayout->removeRow(2);
|
||||
m_ui.hardwareFixesLayout->removeRow(3);
|
||||
m_ui.skipDrawStart = nullptr;
|
||||
m_ui.skipDrawEnd = nullptr;
|
||||
m_ui.textureOffsetX = nullptr;
|
||||
m_ui.textureOffsetY = nullptr;
|
||||
// Don't allow setting hardware fixes globally.
|
||||
// Too many stupid youtube "best settings" guides, that break other games.
|
||||
m_ui.hardwareRenderingOptionsLayout->removeWidget(m_ui.enableHWFixes);
|
||||
delete m_ui.enableHWFixes;
|
||||
m_ui.enableHWFixes = nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -372,7 +385,8 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
dialog->registerWidgetHelp(m_ui.PCRTCOverscan, tr("Show Overscan"), tr("Unchecked"),
|
||||
tr("Enables the option to show the overscan area on games which draw more than the safe area of the screen."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.fmvAspectRatio, tr("FMV Aspect Ratio"), tr("Off (Default)"), tr("Overrides the FMV aspect ratio."));
|
||||
dialog->registerWidgetHelp(m_ui.fmvAspectRatio, tr("FMV Aspect Ratio"), tr("Off (Default)"),
|
||||
tr("Overrides the full-motion video (FMV) aspect ratio."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.PCRTCAntiBlur, tr("Anti-Blur"), tr("Checked"),
|
||||
tr("Enables internal Anti-Blur hacks. Less accurate to PS2 rendering but will make a lot of games look less blurry."));
|
||||
@@ -402,24 +416,33 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
tr("Selects the quality at which screenshots will be compressed. Higher values preserve more detail for JPEG, and reduce file "
|
||||
"size for PNG."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.stretchY, tr("Stretch Height"), tr("100%"), tr(""));
|
||||
dialog->registerWidgetHelp(m_ui.stretchY, tr("Vertical Stretch"), tr("100%"),
|
||||
// Characters </> need to be converted into entities in order to be shown correctly.
|
||||
tr("Stretches (< 100%) or squashes (> 100%) the vertical component of the display."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.fullscreenModes, tr("Fullscreen Mode"), tr("Borderless Fullscreen"),
|
||||
tr("Chooses the fullscreen resolution and frequency."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.cropLeft, tr("Left"), tr("0px"), tr(""));
|
||||
dialog->registerWidgetHelp(m_ui.cropLeft, tr("Left"), tr("0px"),
|
||||
tr("Changes the number of pixels cropped from the left side of the display."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.cropTop, tr("Top"), tr("0px"), tr(""));
|
||||
dialog->registerWidgetHelp(m_ui.cropTop, tr("Top"), tr("0px"),
|
||||
tr("Changes the number of pixels cropped from the top of the display."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.cropRight, tr("Right"), tr("0px"), tr(""));
|
||||
dialog->registerWidgetHelp(m_ui.cropRight, tr("Right"), tr("0px"),
|
||||
tr("Changes the number of pixels cropped from the right side of the display."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.cropBottom, tr("Bottom"), tr("0px"), tr(""));
|
||||
dialog->registerWidgetHelp(m_ui.cropBottom, tr("Bottom"), tr("0px"),
|
||||
tr("Changes the number of pixels cropped from the bottom of the display."));
|
||||
}
|
||||
|
||||
// Rendering tab
|
||||
{
|
||||
// Hardware
|
||||
dialog->registerWidgetHelp(m_ui.upscaleMultiplier, tr("Internal Resolution"), tr("Native (PS2) (Default)"), tr(""));
|
||||
dialog->registerWidgetHelp(m_ui.upscaleMultiplier, tr("Internal Resolution"), tr("Native (PS2) (Default)"),
|
||||
tr("Control the resolution at which games are rendered. High resolutions can impact performance on"
|
||||
"older or lower-end GPUs.<br>Non-native resolution may cause minor graphical issues in some games.<br>"
|
||||
"FMV resolution will remain unchanged, as the video files are pre-rendered."));
|
||||
|
||||
dialog->registerWidgetHelp(
|
||||
m_ui.mipmapping, tr("Mipmapping"), tr("Automatic (Default)"), tr("Control the accuracy level of the mipmapping emulation."));
|
||||
@@ -428,7 +451,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
m_ui.textureFiltering, tr("Texture Filtering"), tr("Bilinear (PS2)"), tr("Control the texture filtering of the emulation."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.trilinearFiltering, tr("Trilinear Filtering"), tr("Automatic (Default)"),
|
||||
tr("Control the texture tri-filtering of the emulation."));
|
||||
tr("Control the texture's trilinear filtering of the emulation."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.anisotropicFiltering, tr("Anisotropic Filtering"), tr("Off (Default)"),
|
||||
tr("Reduces texture aliasing at extreme viewing angles."));
|
||||
@@ -446,7 +469,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
tr("Control the accuracy level of the GS blending unit emulation.<br> "
|
||||
"The higher the setting, the more blending is emulated in the shader accurately, and the higher the speed penalty will "
|
||||
"be.<br> "
|
||||
"Do note that Direct3D's blending is reduced in capability compared to OpenGL/Vulkan"));
|
||||
"Do note that Direct3D's blending is reduced in capability compared to OpenGL/Vulkan."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.texturePreloading, tr("Texture Preloading"), tr("Full (Hash Cache)"),
|
||||
tr("Uploads entire textures at once instead of small pieces, avoiding redundant uploads when possible. "
|
||||
@@ -491,7 +514,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.cpuSpriteRenderBW, tr("CPU Sprite Renderer Size"), tr("0 (Disabled)"), tr(""));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.cpuCLUTRender, tr("Software Clut Render"), tr("0 (Disabled)"), tr(""));
|
||||
dialog->registerWidgetHelp(m_ui.cpuCLUTRender, tr("Software CLUT Render"), tr("0 (Disabled)"), tr(""));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.skipDrawStart, tr("Skipdraw Range Start"), tr("0"),
|
||||
tr("Completely skips drawing surfaces from the surface in the left box up to the surface specified in the box on the right."));
|
||||
@@ -513,21 +536,31 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
"Disables accurate GS Memory Clearing to be done on the CPU, and let the GPU handle it, which can help Kingdom Hearts "
|
||||
"games."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.disablePartialInvalidation, tr("Disable Partial Invalidation"), tr("Unchecked"),
|
||||
dialog->registerWidgetHelp(m_ui.disablePartialInvalidation, tr("Disable Partial Source Invalidation"), tr("Unchecked"),
|
||||
tr("By default, the texture cache handles partial invalidations. Unfortunately it is very costly to compute CPU wise. "
|
||||
"This hack replaces the partial invalidation with a complete deletion of the texture to reduce the CPU load. "
|
||||
"It helps snowblind engine games."));
|
||||
dialog->registerWidgetHelp(m_ui.frameBufferConversion, tr("Frame Buffer Conversion"), tr("Unchecked"),
|
||||
tr("Convert 4-bit and 8-bit frame buffer on the CPU instead of the GPU. "
|
||||
"It helps with the Snowblind engine games."));
|
||||
dialog->registerWidgetHelp(m_ui.frameBufferConversion, tr("Framebuffer Conversion"), tr("Unchecked"),
|
||||
tr("Convert 4-bit and 8-bit framebuffer on the CPU instead of the GPU. "
|
||||
"Helps Harry Potter and Stuntman games. It has a big impact on performance."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.preloadFrameData, tr("Preload Frame Data"), tr("Unchecked"),
|
||||
tr("Uploads GS data when rendering a new frame to reproduce some effects accurately. "
|
||||
"Fixes black screen issues in games like Armored Core: Last Raven."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.textureInsideRt, tr("Texture Inside RT"), tr("Unchecked"),
|
||||
tr("Allows the texture cache to reuse as an input texture the inner portion of a previous framebuffer. "
|
||||
"In some selected games this is enabled by default regardless of this setting."));
|
||||
dialog->registerWidgetHelp(m_ui.textureInsideRt, tr("Texture Inside RT"), tr("Disabled"),
|
||||
tr("Allows the texture cache to reuse as an input texture the inner portion of a previous framebuffer."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.readTCOnClose, tr("Read Targets When Closing"), tr("Unchecked"),
|
||||
tr("Flushes all targets in the texture cache back to local memory when shutting down. Can prevent lost visuals when saving "
|
||||
"state or switching renderers, but can also cause graphical corruption."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.targetPartialInvalidation, tr("Target Partial Invalidation"), tr("Unchecked"),
|
||||
tr("Allows partial invalidation of render targets, which can fix graphical errors in some games. Texture Inside Render Target "
|
||||
"automatically enables this option."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.estimateTextureRegion, tr("Estimate Texture Region"), tr("Unchecked"),
|
||||
tr("Attempts to reduce the texture size when games do not set it themselves (e.g. Snowblind games)."));
|
||||
}
|
||||
|
||||
// Upscaling Fixes tab
|
||||
@@ -549,7 +582,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
"too."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.alignSprite, tr("Align Sprite"), tr("Unchecked"),
|
||||
tr("Fixes issues with upscaling(vertical lines) in Namco games like Ace Combat, Tekken, Soul Calibur, etc."));
|
||||
tr("Fixes issues with upscaling (vertical lines) in Namco games like Ace Combat, Tekken, Soul Calibur, etc."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.wildHack, tr("Wild Arms Hack"), tr("Unchecked"),
|
||||
tr("Lowers the GS precision to avoid gaps between pixels when upscaling. Fixes the text on Wild Arms games."));
|
||||
@@ -592,22 +625,23 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.shadeBoostSaturation, tr("Saturation"), tr("50"), tr(""));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.tvShader, tr("TV Shader"), tr("None (Default)"), tr(""));
|
||||
dialog->registerWidgetHelp(m_ui.tvShader, tr("TV Shader"), tr("None (Default)"),
|
||||
tr("Applies a shader which replicates the visual effects of different styles of television set."));
|
||||
}
|
||||
|
||||
// OSD tab
|
||||
{
|
||||
dialog->registerWidgetHelp(
|
||||
m_ui.osdScale, tr("OSD Scale"), tr("100%"), tr("Scales the size of the onscreen OSD from 100% to 500%."));
|
||||
m_ui.osdScale, tr("OSD Scale"), tr("100%"), tr("Scales the size of the onscreen OSD from 50% to 500%."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.osdShowMessages, tr("Show OSD Messages"), tr("Checked"),
|
||||
tr("Shows on-screen-display messages when events occur such as save states being "
|
||||
"created/loaded, screenshots being taken, etc."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.osdShowFPS, tr("Show Game Frame Rate"), tr("Unchecked"),
|
||||
dialog->registerWidgetHelp(m_ui.osdShowFPS, tr("Show FPS"), tr("Unchecked"),
|
||||
tr("Shows the internal frame rate of the game in the top-right corner of the display."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.osdShowSpeed, tr("Show Emulation Speed"), tr("Unchecked"),
|
||||
dialog->registerWidgetHelp(m_ui.osdShowSpeed, tr("Show Speed Percentages"), tr("Unchecked"),
|
||||
tr("Shows the current emulation speed of the system in the top-right corner of the display as a percentage."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.osdShowResolution, tr("Show Resolution"), tr("Unchecked"),
|
||||
@@ -621,7 +655,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
tr("Shows counters for internal graphical utilization, useful for debugging."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.osdShowIndicators, tr("Show Indicators"), tr("Unchecked"),
|
||||
tr("Shows OSD icon indicators for emulation states such as Pausing, Turbo, Fast Forward, and Slow Motion."));
|
||||
tr("Shows OSD icon indicators for emulation states such as Pausing, Turbo, Fast-Forward, and Slow-Motion."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.osdShowSettings, tr("Show Settings"), tr("Unchecked"),
|
||||
tr("Displays various settings and the current values of those settings, useful for debugging."));
|
||||
@@ -654,7 +688,8 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
tr("Allows the GPU instead of just the CPU to transform lines into sprites. "
|
||||
"This reduces CPU load and bandwidth requirement, but it is heavier on the GPU."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.gsDumpCompression, tr("GS Dump Compression"), tr("Zstandard (zst)"), tr(""));
|
||||
dialog->registerWidgetHelp(m_ui.gsDumpCompression, tr("GS Dump Compression"), tr("Zstandard (zst)"),
|
||||
tr("Change the compression algorithm used when creating a GS dump."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.useBlitSwapChain, tr("Use Blit Swap Chain"), tr("Unchecked"),
|
||||
tr("Uses a blit presentation model instead of flipping when using the Direct3D 11 "
|
||||
@@ -665,7 +700,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.disableDualSource, tr("Disable Dual Source Blending"), tr("Unchecked"), tr(""));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.disableFramebufferFetch, tr("Disable Frame Buffer Fetch"), tr("Unchecked"), tr(""));
|
||||
dialog->registerWidgetHelp(m_ui.disableFramebufferFetch, tr("Disable Framebuffer Fetch"), tr("Unchecked"), tr(""));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.skipPresentingDuplicateFrames, tr("Skip Presenting Duplicate Frames"), tr("Unchecked"),
|
||||
tr("Detects when idle frames are being presented in 25/30fps games, and skips presenting those frames. The frame is still "
|
||||
@@ -828,9 +863,18 @@ void GraphicsSettingsWidget::onEnableAudioCaptureArgumentsChanged()
|
||||
|
||||
void GraphicsSettingsWidget::onGpuPaletteConversionChanged(int state)
|
||||
{
|
||||
const bool enabled = state == Qt::CheckState::PartiallyChecked ? Host::GetBaseBoolSettingValue("EmuCore/GS", "paltex", false) : state;
|
||||
const bool disabled =
|
||||
state == Qt::CheckState::PartiallyChecked ? Host::GetBaseBoolSettingValue("EmuCore/GS", "paltex", false) : (state != 0);
|
||||
|
||||
m_ui.anisotropicFiltering->setEnabled(!enabled);
|
||||
m_ui.anisotropicFiltering->setDisabled(disabled);
|
||||
}
|
||||
|
||||
void GraphicsSettingsWidget::onTextureInsideRtChanged()
|
||||
{
|
||||
const bool disabled = static_cast<GSTextureInRtMode>(m_dialog->getEffectiveIntValue("EmuCore/GS", "UserHacks_TextureInsideRt",
|
||||
static_cast<int>(GSTextureInRtMode::Disabled))) >= GSTextureInRtMode::InsideTargets;
|
||||
|
||||
m_ui.targetPartialInvalidation->setDisabled(disabled);
|
||||
}
|
||||
|
||||
GSRendererType GraphicsSettingsWidget::getEffectiveRenderer() const
|
||||
@@ -855,7 +899,7 @@ void GraphicsSettingsWidget::updateRendererDependentOptions()
|
||||
const bool is_hardware = (type == GSRendererType::DX11 || type == GSRendererType::DX12 || type == GSRendererType::OGL ||
|
||||
type == GSRendererType::VK || type == GSRendererType::Metal);
|
||||
const bool is_software = (type == GSRendererType::SW);
|
||||
const bool hw_fixes = (is_hardware && m_ui.enableHWFixes->checkState() == Qt::Checked);
|
||||
const bool hw_fixes = (is_hardware && m_ui.enableHWFixes && m_ui.enableHWFixes->checkState() == Qt::Checked);
|
||||
const int prev_tab = m_ui.tabs->currentIndex();
|
||||
|
||||
// hw rendering
|
||||
@@ -884,10 +928,12 @@ void GraphicsSettingsWidget::updateRendererDependentOptions()
|
||||
else if (is_hardware && prev_tab == 2)
|
||||
m_ui.tabs->setCurrentIndex(1);
|
||||
|
||||
m_ui.useBlitSwapChain->setEnabled(is_dx11);
|
||||
|
||||
m_ui.overrideTextureBarriers->setDisabled(is_sw_dx);
|
||||
m_ui.overrideGeometryShader->setDisabled(is_sw_dx);
|
||||
|
||||
m_ui.useBlitSwapChain->setEnabled(is_dx11);
|
||||
m_ui.disableFramebufferFetch->setDisabled(is_sw_dx);
|
||||
|
||||
// populate adapters
|
||||
HostDisplay::AdapterAndModeList modes;
|
||||
@@ -980,3 +1026,58 @@ void GraphicsSettingsWidget::updateRendererDependentOptions()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GraphicsSettingsWidget::resetManualHardwareFixes()
|
||||
{
|
||||
bool changed = false;
|
||||
{
|
||||
auto lock = Host::GetSettingsLock();
|
||||
SettingsInterface* const si = Host::Internal::GetBaseSettingsLayer();
|
||||
|
||||
auto check_bool = [&](const char* section, const char* key, bool expected) {
|
||||
if (si->GetBoolValue(section, key, expected) != expected)
|
||||
{
|
||||
si->SetBoolValue(section, key, expected);
|
||||
changed = true;
|
||||
}
|
||||
};
|
||||
auto check_int = [&](const char* section, const char* key, s32 expected) {
|
||||
if (si->GetIntValue(section, key, expected) != expected)
|
||||
{
|
||||
si->SetIntValue(section, key, expected);
|
||||
changed = true;
|
||||
}
|
||||
};
|
||||
|
||||
check_bool("EmuCore/GS", "UserHacks", false);
|
||||
|
||||
check_int("EmuCore/GS", "crc_hack_level", static_cast<int>(CRCHackLevel::Automatic));
|
||||
check_int("EmuCore/GS", "UserHacks_Half_Bottom_Override", -1);
|
||||
check_int("EmuCore/GS", "UserHacks_CPUSpriteRenderBW", 0);
|
||||
check_int("EmuCore/GS", "UserHacks_CPUCLUTRender", 0);
|
||||
check_int("EmuCore/GS", "UserHacks_GPUTargetCLUTMode", 0);
|
||||
check_int("EmuCore/GS", "UserHacks_SkipDraw_Start", 0);
|
||||
check_int("EmuCore/GS", "UserHacks_SkipDraw_End", 0);
|
||||
check_bool("EmuCore/GS", "UserHacks_AutoFlush", false);
|
||||
check_bool("EmuCore/GS", "UserHacks_CPU_FB_Conversion", false);
|
||||
check_bool("EmuCore/GS", "UserHacks_DisableDepthSupport", false);
|
||||
check_bool("EmuCore/GS", "UserHacks_Disable_Safe_Features", false);
|
||||
check_bool("EmuCore/GS", "preload_frame_with_gs_data", false);
|
||||
check_bool("EmuCore/GS", "UserHacks_DisablePartialInvalidation", false);
|
||||
check_int("EmuCore/GS", "UserHacks_TextureInsideRt", static_cast<int>(GSTextureInRtMode::Disabled));
|
||||
check_bool("EmuCore/GS", "UserHacks_ReadTCOnClose", false);
|
||||
check_bool("EmuCore/GS", "UserHacks_TargetPartialInvalidation", false);
|
||||
check_bool("EmuCore/GS", "UserHacks_EstimateTextureRegion", false);
|
||||
check_bool("EmuCore/GS", "paltex", false);
|
||||
check_int("EmuCore/GS", "UserHacks_HalfPixelOffset", 0);
|
||||
check_int("EmuCore/GS", "UserHacks_round_sprite_offset", 0);
|
||||
check_int("EmuCore/GS", "UserHacks_TCOffsetX", 0);
|
||||
check_int("EmuCore/GS", "UserHacks_TCOffsetY", 0);
|
||||
check_bool("EmuCore/GS", "UserHacks_align_sprite_X", false);
|
||||
check_bool("EmuCore/GS", "UserHacks_merge_pp_sprite", false);
|
||||
check_bool("EmuCore/GS", "UserHacks_WildHack", false);
|
||||
}
|
||||
|
||||
if (changed)
|
||||
Host::CommitBaseSettingChanges();
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ private Q_SLOTS:
|
||||
void onAdapterChanged(int index);
|
||||
void onTrilinearFilteringChanged();
|
||||
void onGpuPaletteConversionChanged(int state);
|
||||
void onTextureInsideRtChanged();
|
||||
void onFullscreenModeChanged(int index);
|
||||
void onShadeBoostChanged();
|
||||
void onCaptureContainerChanged();
|
||||
@@ -53,6 +54,7 @@ private Q_SLOTS:
|
||||
private:
|
||||
GSRendererType getEffectiveRenderer() const;
|
||||
void updateRendererDependentOptions();
|
||||
void resetManualHardwareFixes();
|
||||
|
||||
SettingsDialog* m_dialog;
|
||||
|
||||
|
||||
@@ -143,7 +143,7 @@
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_23">
|
||||
<property name="text">
|
||||
<string>De-interlacing:</string>
|
||||
<string>Deinterlacing:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -338,7 +338,7 @@
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="integerScaling">
|
||||
<property name="text">
|
||||
<string>Integer Upscaling</string>
|
||||
<string>Integer Scaling</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -600,54 +600,13 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>CRC Fix Level:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QComboBox" name="crcFixLevel">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Automatic (Default)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>None (Debug)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Minimum (Debug)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Partial (OpenGL)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Full (Direct3D)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Aggressive</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>Blending Accuracy:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<item row="6" column="1">
|
||||
<widget class="QComboBox" name="blending">
|
||||
<item>
|
||||
<property name="text">
|
||||
@@ -681,14 +640,14 @@
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0">
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="label_20">
|
||||
<property name="text">
|
||||
<string>Texture Preloading:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1">
|
||||
<item row="7" column="1">
|
||||
<widget class="QComboBox" name="texturePreloading">
|
||||
<item>
|
||||
<property name="text">
|
||||
@@ -707,30 +666,23 @@
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="0" colspan="2">
|
||||
<layout class="QGridLayout" name="basicCheckboxGridLayout">
|
||||
<item row="8" column="0" colspan="2">
|
||||
<layout class="QGridLayout" name="hardwareRenderingOptionsLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="gpuPaletteConversion">
|
||||
<property name="text">
|
||||
<string>GPU Palette Conversion</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="enableHWFixes">
|
||||
<property name="text">
|
||||
<string>Manual Hardware Renderer Fixes</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="spinGPUDuringReadbacks">
|
||||
<property name="text">
|
||||
<string>Spin GPU During Readbacks</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="enableHWFixes">
|
||||
<property name="text">
|
||||
<string>Manual Hardware Renderer Fixes</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="spinCPUDuringReadbacks">
|
||||
<property name="text">
|
||||
<string>Spin CPU During Readbacks</string>
|
||||
@@ -828,14 +780,14 @@
|
||||
<string>Hardware Fixes</string>
|
||||
</attribute>
|
||||
<layout class="QFormLayout" name="hardwareFixesLayout">
|
||||
<item row="0" column="0">
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>Half Screen Fix:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="halfScreenFix">
|
||||
<item>
|
||||
<property name="text">
|
||||
@@ -854,14 +806,14 @@
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_36">
|
||||
<property name="text">
|
||||
<string>CPU Sprite Render Size:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<item row="2" column="1">
|
||||
<widget class="QComboBox" name="cpuSpriteRenderBW">
|
||||
<item>
|
||||
<property name="text">
|
||||
@@ -920,85 +872,14 @@
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_12">
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_16">
|
||||
<property name="text">
|
||||
<string>Skipdraw Range:</string>
|
||||
<string>Software CLUT Render:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QSpinBox" name="skipDrawStart">
|
||||
<property name="maximum">
|
||||
<number>10000</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="skipDrawEnd">
|
||||
<property name="maximum">
|
||||
<number>10000</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="5" column="0" colspan="2">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="hwAutoFlush">
|
||||
<property name="text">
|
||||
<string>Auto Flush</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="frameBufferConversion">
|
||||
<property name="text">
|
||||
<string>Frame Buffer Conversion</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="disableDepthEmulation">
|
||||
<property name="text">
|
||||
<string>Disable Depth Emulation</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QCheckBox" name="disableSafeFeatures">
|
||||
<property name="text">
|
||||
<string>Disable Safe Features</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QCheckBox" name="disablePartialInvalidation">
|
||||
<property name="text">
|
||||
<string>Disable Partial Invalidation</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="preloadFrameData">
|
||||
<property name="text">
|
||||
<string>Preload Frame Data</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QCheckBox" name="textureInsideRt">
|
||||
<property name="text">
|
||||
<string>Texture Inside RT</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<item row="3" column="1">
|
||||
<widget class="QComboBox" name="cpuCLUTRender">
|
||||
<property name="currentText">
|
||||
<string extracomment="0 (Disabled)">0 (Disabled)</string>
|
||||
@@ -1023,21 +904,14 @@
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_16">
|
||||
<property name="text">
|
||||
<string>Software CLUT Render:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_47">
|
||||
<property name="text">
|
||||
<string>GPU Target CLUT:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<item row="4" column="1">
|
||||
<widget class="QComboBox" name="gpuTargetCLUTMode">
|
||||
<item>
|
||||
<property name="text">
|
||||
@@ -1056,6 +930,172 @@
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_45">
|
||||
<property name="text">
|
||||
<string>Texture Inside RT:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QComboBox" name="textureInsideRt">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Disabled (Default)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Inside Target</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Merge Targets</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_12">
|
||||
<property name="text">
|
||||
<string>Skipdraw Range:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QSpinBox" name="skipDrawStart">
|
||||
<property name="maximum">
|
||||
<number>10000</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="skipDrawEnd">
|
||||
<property name="maximum">
|
||||
<number>10000</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="7" column="0" colspan="2">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="hwAutoFlush">
|
||||
<property name="text">
|
||||
<string>Auto Flush</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QCheckBox" name="disableSafeFeatures">
|
||||
<property name="text">
|
||||
<string>Disable Safe Features</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="disableDepthEmulation">
|
||||
<property name="text">
|
||||
<string>Disable Depth Emulation</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="frameBufferConversion">
|
||||
<property name="text">
|
||||
<string>Frame Buffer Conversion</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QCheckBox" name="readTCOnClose">
|
||||
<property name="text">
|
||||
<string>Read Targets When Closing</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QCheckBox" name="disablePartialInvalidation">
|
||||
<property name="text">
|
||||
<string>Disable Partial Source Invalidation</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QCheckBox" name="targetPartialInvalidation">
|
||||
<property name="text">
|
||||
<string>Target Partial Invalidation</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="preloadFrameData">
|
||||
<property name="text">
|
||||
<string>Preload Frame Data</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QCheckBox" name="estimateTextureRegion">
|
||||
<property name="text">
|
||||
<string>Estimate Texture Region</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QCheckBox" name="gpuPaletteConversion">
|
||||
<property name="text">
|
||||
<string>GPU Palette Conversion</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>CRC Fix Level:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="crcFixLevel">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Automatic (Default)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>None (Debug)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Minimum (Debug)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Partial (OpenGL)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Full (Direct3D)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Aggressive</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QGroupBox" name="upscalingFixesTab">
|
||||
@@ -1536,7 +1576,7 @@
|
||||
<string>%</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>100</number>
|
||||
<number>50</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>500</number>
|
||||
@@ -1590,7 +1630,7 @@
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="osdShowMessages">
|
||||
<property name="text">
|
||||
<string>Show Notifications</string>
|
||||
<string>Show OSD Messages</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -1611,7 +1651,7 @@
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="osdShowSpeed">
|
||||
<property name="text">
|
||||
<string>Show Speed</string>
|
||||
<string>Show Speed Percentages</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -67,6 +67,8 @@ InputBindingDialog::InputBindingDialog(SettingsInterface* sif, InputBindingInfo:
|
||||
else
|
||||
{
|
||||
m_ui.verticalLayout->removeWidget(m_ui.sensitivityWidget);
|
||||
delete m_ui.sensitivityWidget;
|
||||
m_ui.sensitivityWidget = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ static const char* THEME_NAMES[] = {
|
||||
QT_TRANSLATE_NOOP("InterfaceSettingsWidget", "PCSX2 (White/Blue) [Light]"),
|
||||
QT_TRANSLATE_NOOP("InterfaceSettingsWidget", "Scarlet Devil (Red/Purple) [Dark]"),
|
||||
QT_TRANSLATE_NOOP("InterfaceSettingsWidget", "Violet Angel (Blue/Purple) [Dark]"),
|
||||
QT_TRANSLATE_NOOP("InterfaceSettingsWidget", "Cobalt Sky (Royal Blue) [Dark]"),
|
||||
QT_TRANSLATE_NOOP("InterfaceSettingsWidget", "Ruby (Black/Red) [Dark]"),
|
||||
QT_TRANSLATE_NOOP("InterfaceSettingsWidget", "Sapphire (Black/Blue) [Dark]"),
|
||||
QT_TRANSLATE_NOOP("InterfaceSettingsWidget", "Custom.qss [Drop in PCSX2 Folder]"),
|
||||
@@ -46,6 +47,7 @@ static const char* THEME_VALUES[] = {
|
||||
"PCSX2Blue",
|
||||
"ScarletDevilRed",
|
||||
"VioletAngelPurple",
|
||||
"CobaltSky",
|
||||
"Ruby",
|
||||
"Sapphire",
|
||||
"Custom",
|
||||
@@ -129,7 +131,7 @@ InterfaceSettingsWidget::InterfaceSettingsWidget(SettingsDialog* dialog, QWidget
|
||||
m_ui.confirmShutdown, tr("Confirm Shutdown"), tr("Checked"),
|
||||
tr("Determines whether a prompt will be displayed to confirm shutting down the virtual machine "
|
||||
"when the hotkey is pressed."));
|
||||
dialog->registerWidgetHelp(m_ui.saveStateOnShutdown, tr("Save State On Shutdown"), tr("Checked"),
|
||||
dialog->registerWidgetHelp(m_ui.saveStateOnShutdown, tr("Save State On Shutdown"), tr("Unchecked"),
|
||||
tr("Automatically saves the emulator state when powering down or exiting. You can then "
|
||||
"resume directly from where you left off next time."));
|
||||
dialog->registerWidgetHelp(m_ui.pauseOnStart, tr("Pause On Start"), tr("Unchecked"),
|
||||
@@ -150,7 +152,7 @@ InterfaceSettingsWidget::InterfaceSettingsWidget(SettingsDialog* dialog, QWidget
|
||||
m_ui.hideMainWindow, tr("Hide Main Window When Running"), tr("Unchecked"),
|
||||
tr("Hides the main window (with the game list) when a game is running, requires Render To Separate Window to be enabled."));
|
||||
dialog->registerWidgetHelp(m_ui.perGameSettings, tr("Enable Per-Game Settings"), tr("Checked"),
|
||||
tr("When enabled, custom per-game settings will be appled. Disable to always use the global configuration."));
|
||||
tr("When enabled, custom per-game settings will be applied. Disable to always use the global configuration."));
|
||||
dialog->registerWidgetHelp(
|
||||
m_ui.discordPresence, tr("Enable Discord Presence"), tr("Unchecked"),
|
||||
tr("Shows the game you are currently playing as part of your profile in Discord."));
|
||||
|
||||
@@ -49,22 +49,22 @@ MemoryCardConvertDialog::MemoryCardConvertDialog(QWidget* parent, QString select
|
||||
switch (m_srcCardInfo.type)
|
||||
{
|
||||
case MemoryCardType::File:
|
||||
SetType(MemoryCardType::Folder, MemoryCardFileType::Unknown, "Uses a folder on your PC filesystem, instead of a file. Infinite capacity, while keeping the same compatibility as an 8 MB memory card.");
|
||||
SetType(MemoryCardType::Folder, MemoryCardFileType::Unknown, "Uses a folder on your PC filesystem, instead of a file. Infinite capacity, while keeping the same compatibility as an 8 MB Memory Card.");
|
||||
break;
|
||||
case MemoryCardType::Folder:
|
||||
switch (m_ui.conversionTypeSelect->currentData().toInt())
|
||||
{
|
||||
case 8:
|
||||
SetType(MemoryCardType::File, MemoryCardFileType::PS2_8MB, "A standard, 8 MB memory card. Most compatible, but smallest capacity.");
|
||||
SetType(MemoryCardType::File, MemoryCardFileType::PS2_8MB, "A standard, 8 MB Memory Card. Most compatible, but smallest capacity.");
|
||||
break;
|
||||
case 16:
|
||||
SetType(MemoryCardType::File, MemoryCardFileType::PS2_16MB, "2x larger as a standard memory card. May have some compatibility issues.");
|
||||
SetType(MemoryCardType::File, MemoryCardFileType::PS2_16MB, "2x larger than a standard Memory Card. May have some compatibility issues.");
|
||||
break;
|
||||
case 32:
|
||||
SetType(MemoryCardType::File, MemoryCardFileType::PS2_32MB, "4x larger than a standard memory card. Likely to have compatibility issues.");
|
||||
SetType(MemoryCardType::File, MemoryCardFileType::PS2_32MB, "4x larger than a standard Memory Card. Likely to have compatibility issues.");
|
||||
break;
|
||||
case 64:
|
||||
SetType(MemoryCardType::File, MemoryCardFileType::PS2_64MB, "8x larger than a standard memory card. Likely to have compatibility issues.");
|
||||
SetType(MemoryCardType::File, MemoryCardFileType::PS2_64MB, "8x larger than a standard Memory Card. Likely to have compatibility issues.");
|
||||
break;
|
||||
default:
|
||||
QMessageBox::critical(this, tr("Convert Memory Card Failed"), tr("Invalid MemoryCardType"));
|
||||
@@ -104,7 +104,7 @@ void MemoryCardConvertDialog::onProgressUpdated(int value, int range)
|
||||
|
||||
void MemoryCardConvertDialog::onThreadFinished()
|
||||
{
|
||||
QMessageBox::information(this, tr("Conversion Complete"), tr("Memory card \"%1\" converted to \"%2\"").arg(m_selectedCard).arg(m_destCardName));
|
||||
QMessageBox::information(this, tr("Conversion Complete"), tr("Memory Card \"%1\" converted to \"%2\"").arg(m_selectedCard).arg(m_destCardName));
|
||||
accept();
|
||||
}
|
||||
|
||||
@@ -151,7 +151,7 @@ bool MemoryCardConvertDialog::SetupPicklist()
|
||||
{
|
||||
case MemoryCardType::File:
|
||||
m_ui.conversionTypeSelect->addItems({"Folder"});
|
||||
SetType(MemoryCardType::Folder, MemoryCardFileType::Unknown, "Uses a folder on your PC filesystem, instead of a file. Infinite capacity, while keeping the same compatibility as an 8 MB memory card.");
|
||||
SetType(MemoryCardType::Folder, MemoryCardFileType::Unknown, "Uses a folder on your PC filesystem, instead of a file. Infinite capacity, while keeping the same compatibility as an 8 MB Memory Card.");
|
||||
break;
|
||||
case MemoryCardType::Folder:
|
||||
// Compute which file types should be allowed.
|
||||
@@ -225,7 +225,7 @@ bool MemoryCardConvertDialog::SetupPicklist()
|
||||
|
||||
if (!typeSet)
|
||||
{
|
||||
QMessageBox::critical(this, tr("Cannot Convert Memory Card"), tr("Your folder memory card has too much data inside it to be converted to a file memory card. The largest supported file memory card has a capacity of 64 MB. To convert your folder memory card, you must remove game folders until its size is 64 MB or less."));
|
||||
QMessageBox::critical(this, tr("Cannot Convert Memory Card"), tr("Your folder Memory Card has too much data inside it to be converted to a file Memory Card. The largest supported file Memory Card has a capacity of 64 MB. To convert your folder Memory Card, you must remove game folders until its size is 64 MB or less."));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -286,25 +286,25 @@ void MemoryCardConvertDialog::SetType(MemoryCardType type, MemoryCardFileType fi
|
||||
|
||||
void MemoryCardConvertDialog::SetType_8()
|
||||
{
|
||||
SetType(MemoryCardType::File, MemoryCardFileType::PS2_8MB, "A standard, 8 MB memory card. Most compatible, but smallest capacity.");
|
||||
SetType(MemoryCardType::File, MemoryCardFileType::PS2_8MB, "A standard, 8 MB Memory Card. Most compatible, but smallest capacity.");
|
||||
}
|
||||
|
||||
void MemoryCardConvertDialog::SetType_16()
|
||||
{
|
||||
SetType(MemoryCardType::File, MemoryCardFileType::PS2_16MB, "2x larger as a standard memory card. May have some compatibility issues.");
|
||||
SetType(MemoryCardType::File, MemoryCardFileType::PS2_16MB, "2x larger as a standard Memory Card. May have some compatibility issues.");
|
||||
}
|
||||
|
||||
void MemoryCardConvertDialog::SetType_32()
|
||||
{
|
||||
SetType(MemoryCardType::File, MemoryCardFileType::PS2_32MB, "4x larger than a standard memory card. Likely to have compatibility issues.");
|
||||
SetType(MemoryCardType::File, MemoryCardFileType::PS2_32MB, "4x larger than a standard Memory Card. Likely to have compatibility issues.");
|
||||
}
|
||||
|
||||
void MemoryCardConvertDialog::SetType_64()
|
||||
{
|
||||
SetType(MemoryCardType::File, MemoryCardFileType::PS2_64MB, "8x larger than a standard memory card. Likely to have compatibility issues.");
|
||||
SetType(MemoryCardType::File, MemoryCardFileType::PS2_64MB, "8x larger than a standard Memory Card. Likely to have compatibility issues.");
|
||||
}
|
||||
|
||||
void MemoryCardConvertDialog::SetType_Folder()
|
||||
{
|
||||
SetType(MemoryCardType::Folder, MemoryCardFileType::Unknown, "Uses a folder on your PC filesystem, instead of a file. Infinite capacity, while keeping the same compatibility as an 8 MB memory card.");
|
||||
SetType(MemoryCardType::Folder, MemoryCardFileType::Unknown, "Uses a folder on your PC filesystem, instead of a file. Infinite capacity, while keeping the same compatibility as an 8 MB Memory Card.");
|
||||
}
|
||||
|
||||
@@ -109,7 +109,7 @@
|
||||
p, li { white-space: pre-wrap; }
|
||||
hr { height: 1px; border-width: 0; }
|
||||
</style></head><body style=" font-family:'Segoe UI'; font-size:9pt; font-weight:400; font-style:normal;">
|
||||
<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Note: Converting a memory card creates a COPY of your existing memory card. It does NOT delete, modify, or replace your existing memory card.</p></body></html></string>
|
||||
<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Note: Converting a Memory Card creates a COPY of your existing Memory Card. It does NOT delete, modify, or replace your existing Memory Card.</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QTextBrowser" name="conversionTypeDescription">
|
||||
|
||||
@@ -84,7 +84,7 @@ bool MemoryCardConvertWorker::ConvertToFile(const std::string& srcFolderName, co
|
||||
|
||||
if (!writeResult)
|
||||
{
|
||||
Console.Error("%s(%s, %s, %d) Failed to write memory card contents to file", __FUNCTION__, srcPath.c_str(), destPath.c_str(), type);
|
||||
Console.Error("%s(%s, %s, %d) Failed to write Memory Card contents to file", __FUNCTION__, srcPath.c_str(), destPath.c_str(), type);
|
||||
return false;
|
||||
}
|
||||
#ifdef _WIN32
|
||||
@@ -112,7 +112,7 @@ bool MemoryCardConvertWorker::ConvertToFolder(const std::string& srcFileName, co
|
||||
|
||||
if (!sourceBufferOpt.has_value())
|
||||
{
|
||||
Console.Error("%s(%s, %s, %d) Failed to open file memory card!", __FUNCTION__, srcFileName.c_str(), destFolderName.c_str(), type);
|
||||
Console.Error("%s(%s, %s, %d) Failed to open file Memory Card!", __FUNCTION__, srcFileName.c_str(), destFolderName.c_str(), type);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -147,8 +147,8 @@ bool MemoryCardConvertWorker::ConvertToFolder(const std::string& srcFileName, co
|
||||
|
||||
targetFolderMemoryCard.Close();
|
||||
|
||||
// If the source file memory card was larger than 8 MB, the raw copy will have also made the superblock of
|
||||
// the destination folder memory card larger than 8 MB. For compatibility, we always want folder memory cards
|
||||
// If the source file Memory Card was larger than 8 MB, the raw copy will have also made the superblock of
|
||||
// the destination folder Memory Card larger than 8 MB. For compatibility, we always want folder Memory Cards
|
||||
// to report 8 MB, so we'll override that here. Don't do this on the simulated run, only the actual.
|
||||
if (!simulateWrites && sourceBuffer.size() != FolderMemoryCard::TotalSizeRaw)
|
||||
{
|
||||
|
||||
@@ -71,8 +71,8 @@ MemoryCardSettingsWidget::MemoryCardSettingsWidget(SettingsDialog* dialog, QWidg
|
||||
|
||||
refresh();
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.autoEject, tr("Auto-eject memory cards when loading save states"), tr("Checked"),
|
||||
tr("Avoids broken memory card saves. May not work with some games such as Guitar Hero."));
|
||||
dialog->registerWidgetHelp(m_ui.autoEject, tr("Auto-eject Memory Cards when loading save states"), tr("Checked"),
|
||||
tr("Avoids broken Memory Card saves. May not work with some games such as Guitar Hero."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.automaticManagement, tr("Automatically manage saves based on running game"), tr("Checked"),
|
||||
tr("(Folder type only / Card size: Auto) Loads only the relevant booted game saves, ignoring others. Avoids running out of space for saves."));
|
||||
@@ -99,7 +99,7 @@ void MemoryCardSettingsWidget::setupAdditionalUi()
|
||||
for (u32 i = 0; i < static_cast<u32>(m_slots.size()); i++)
|
||||
createSlotWidgets(&m_slots[i], i);
|
||||
|
||||
// button to swap memory cards
|
||||
// button to swap Memory Cards
|
||||
QToolButton* swap_button = new QToolButton(m_ui.portGroupBox);
|
||||
swap_button->setIcon(QIcon::fromTheme("arrow-left-right-line"));
|
||||
swap_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
|
||||
@@ -156,7 +156,7 @@ void MemoryCardSettingsWidget::tryInsertCard(u32 slot, const QString& newCard)
|
||||
const std::vector<AvailableMcdInfo> mcds(FileMcd_GetAvailableCards(true));
|
||||
if (std::none_of(mcds.begin(), mcds.end(), [&newCardStr](const AvailableMcdInfo& mcd) { return mcd.name == newCardStr; }))
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"), tr("This memory card is unknown."));
|
||||
QMessageBox::critical(this, tr("Error"), tr("This Memory Card is unknown."));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -218,7 +218,7 @@ void MemoryCardSettingsWidget::deleteCard()
|
||||
return;
|
||||
|
||||
if (QMessageBox::question(QtUtils::GetRootWidget(this), tr("Delete Memory Card"),
|
||||
tr("Are you sure you wish to delete the memory card '%1'?\n\n"
|
||||
tr("Are you sure you wish to delete the Memory Card '%1'?\n\n"
|
||||
"This action cannot be reversed, and you will lose any saves on the card.")
|
||||
.arg(selectedCard)) != QMessageBox::Yes)
|
||||
{
|
||||
@@ -228,7 +228,7 @@ void MemoryCardSettingsWidget::deleteCard()
|
||||
if (!FileMcd_DeleteCard(selectedCard.toStdString()))
|
||||
{
|
||||
QMessageBox::critical(QtUtils::GetRootWidget(this), tr("Delete Memory Card"),
|
||||
tr("Failed to delete the memory card. The log may have more information."));
|
||||
tr("Failed to delete the Memory Card. The log may have more information."));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -264,7 +264,7 @@ void MemoryCardSettingsWidget::renameCard()
|
||||
if (!FileMcd_RenameCard(selectedCard.toStdString(), newNameStr))
|
||||
{
|
||||
QMessageBox::critical(QtUtils::GetRootWidget(this), tr("Rename Memory Card"),
|
||||
tr("Failed to rename memory card. The log may contain more information."));
|
||||
tr("Failed to rename Memory Card. The log may contain more information."));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -198,7 +198,7 @@
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="autoEject">
|
||||
<property name="text">
|
||||
<string>Auto-eject memory cards when loading save states</string>
|
||||
<string>Auto-eject Memory Cards when loading save states</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -113,9 +113,9 @@ void SettingsDialog::setupUi(const GameList::Entry* game)
|
||||
// Only show the game fixes for per-game settings, there's really no reason to be setting them globally.
|
||||
if (show_advanced_settings && isPerGameSettings())
|
||||
{
|
||||
addWidget(m_game_fix_settings_widget = new GameFixSettingsWidget(this, m_ui.settingsContainer), tr("Game Fix"),
|
||||
addWidget(m_game_fix_settings_widget = new GameFixSettingsWidget(this, m_ui.settingsContainer), tr("Game Fixes"),
|
||||
QStringLiteral("close-line"),
|
||||
tr("<strong>Game Fix Settings</strong><hr>Gamefixes can work around incorrect emulation in some titles<br>however they can "
|
||||
tr("<strong>Game Fixes Settings</strong><hr>Game Fixes can work around incorrect emulation in some titles.<br>However, they can "
|
||||
"also cause problems in games if used incorrectly.<br>It is best to leave them all disabled unless advised otherwise."));
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ void SettingsDialog::setupUi(const GameList::Entry* game)
|
||||
tr("<strong>Audio Settings</strong><hr>These options control the audio output of the console.<br><br>Mouse over an option for "
|
||||
"additional information."));
|
||||
|
||||
// for now, memory cards aren't settable per-game
|
||||
// for now, Memory Cards aren't settable per-game
|
||||
if (!isPerGameSettings())
|
||||
{
|
||||
addWidget(m_memory_card_settings = new MemoryCardSettingsWidget(this, m_ui.settingsContainer), tr("Memory Cards"),
|
||||
|
||||
@@ -423,6 +423,9 @@
|
||||
<QtUi Include="Settings\ControllerLEDSettingsDialog.ui">
|
||||
<FileType>Document</FileType>
|
||||
</QtUi>
|
||||
<QtUi Include="Settings\ControllerMouseSettingsDialog.ui">
|
||||
<FileType>Document</FileType>
|
||||
</QtUi>
|
||||
<None Include="Settings\USBBindingWidget_DrivingForce.ui" />
|
||||
<None Include="Settings\USBBindingWidget_GTForce.ui" />
|
||||
<QtUi Include="Settings\USBDeviceWidget.ui">
|
||||
@@ -439,4 +442,4 @@
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<Import Project="$(SolutionDir)common\vsprops\QtCompile.targets" />
|
||||
<ImportGroup Label="ExtensionTargets" />
|
||||
</Project>
|
||||
</Project>
|
||||
@@ -583,6 +583,9 @@
|
||||
<QtUi Include="Settings\ControllerLEDSettingsDialog.ui">
|
||||
<Filter>Settings</Filter>
|
||||
</QtUi>
|
||||
<QtUi Include="Settings\ControllerMouseSettingsDialog.ui">
|
||||
<Filter>Settings</Filter>
|
||||
</QtUi>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Settings\FolderSettingsWidget.ui">
|
||||
|
||||
1
pcsx2-qt/resources/icons/black/svg/mouse-line.svg
Normal file
1
pcsx2-qt/resources/icons/black/svg/mouse-line.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M11.141 4c-1.582 0-2.387.169-3.128.565a3.453 3.453 0 0 0-1.448 1.448C6.169 6.753 6 7.559 6 9.14v5.718c0 1.582.169 2.387.565 3.128.337.63.818 1.111 1.448 1.448.74.396 1.546.565 3.128.565h1.718c1.582 0 2.387-.169 3.128-.565a3.453 3.453 0 0 0 1.448-1.448c.396-.74.565-1.546.565-3.128V9.14c0-1.582-.169-2.387-.565-3.128a3.453 3.453 0 0 0-1.448-1.448C15.247 4.169 14.441 4 12.86 4H11.14zm0-2h1.718c2.014 0 3.094.278 4.072.801a5.452 5.452 0 0 1 2.268 2.268c.523.978.801 2.058.801 4.072v5.718c0 2.014-.278 3.094-.801 4.072a5.452 5.452 0 0 1-2.268 2.268c-.978.523-2.058.801-4.072.801H11.14c-2.014 0-3.094-.278-4.072-.801a5.452 5.452 0 0 1-2.268-2.268C4.278 17.953 4 16.873 4 14.859V9.14c0-2.014.278-3.094.801-4.072A5.452 5.452 0 0 1 7.07 2.801C8.047 2.278 9.127 2 11.141 2zM11 6h2v5h-2V6z"/></svg>
|
||||
|
After Width: | Height: | Size: 918 B |
1
pcsx2-qt/resources/icons/white/svg/mouse-line.svg
Normal file
1
pcsx2-qt/resources/icons/white/svg/mouse-line.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M11.141 4c-1.582 0-2.387.169-3.128.565a3.453 3.453 0 0 0-1.448 1.448C6.169 6.753 6 7.559 6 9.14v5.718c0 1.582.169 2.387.565 3.128.337.63.818 1.111 1.448 1.448.74.396 1.546.565 3.128.565h1.718c1.582 0 2.387-.169 3.128-.565a3.453 3.453 0 0 0 1.448-1.448c.396-.74.565-1.546.565-3.128V9.14c0-1.582-.169-2.387-.565-3.128a3.453 3.453 0 0 0-1.448-1.448C15.247 4.169 14.441 4 12.86 4H11.14zm0-2h1.718c2.014 0 3.094.278 4.072.801a5.452 5.452 0 0 1 2.268 2.268c.523.978.801 2.058.801 4.072v5.718c0 2.014-.278 3.094-.801 4.072a5.452 5.452 0 0 1-2.268 2.268c-.978.523-2.058.801-4.072.801H11.14c-2.014 0-3.094-.278-4.072-.801a5.452 5.452 0 0 1-2.268-2.268C4.278 17.953 4 16.873 4 14.859V9.14c0-2.014.278-3.094.801-4.072A5.452 5.452 0 0 1 7.07 2.801C8.047 2.278 9.127 2 11.141 2zM11 6h2v5h-2V6z" fill="#ffffff"/></svg>
|
||||
|
After Width: | Height: | Size: 933 B |
@@ -40,6 +40,7 @@
|
||||
<file>icons/black/svg/lightbulb-line.svg</file>
|
||||
<file>icons/black/svg/list-check.svg</file>
|
||||
<file>icons/black/svg/login-box-line.svg</file>
|
||||
<file>icons/black/svg/mouse-line.svg</file>
|
||||
<file>icons/black/svg/pause-line.svg</file>
|
||||
<file>icons/black/svg/play-line.svg</file>
|
||||
<file>icons/black/svg/price-tag-3-line.svg</file>
|
||||
@@ -100,6 +101,7 @@
|
||||
<file>icons/white/svg/lightbulb-line.svg</file>
|
||||
<file>icons/white/svg/list-check.svg</file>
|
||||
<file>icons/white/svg/login-box-line.svg</file>
|
||||
<file>icons/white/svg/mouse-line.svg</file>
|
||||
<file>icons/white/svg/pause-line.svg</file>
|
||||
<file>icons/white/svg/play-line.svg</file>
|
||||
<file>icons/white/svg/price-tag-3-line.svg</file>
|
||||
|
||||
@@ -66,6 +66,7 @@ bool IOCtlSrc::Reopen()
|
||||
|
||||
void IOCtlSrc::SetSpindleSpeed(bool restore_defaults) const
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
u16 speed = restore_defaults ? 0xFFFF : m_media_type >= 0 ? 5540 :
|
||||
3600;
|
||||
int ioctl_code = m_media_type >= 0 ? DKIOCDVDSETSPEED : DKIOCCDSETSPEED;
|
||||
@@ -77,6 +78,10 @@ void IOCtlSrc::SetSpindleSpeed(bool restore_defaults) const
|
||||
{
|
||||
DevCon.WriteLn("CDVD: Spindle speed set to %d", speed);
|
||||
}
|
||||
#else
|
||||
// FIXME: FreeBSD equivalent for DKIOCDVDSETSPEED DKIOCCDSETSPEED.
|
||||
DevCon.Warning("CDVD: Setting spindle speed not supported!");
|
||||
#endif
|
||||
}
|
||||
|
||||
u32 IOCtlSrc::GetSectorCount() const
|
||||
|
||||
@@ -21,7 +21,7 @@ if(NOT TOP_CMAKE_WAS_SOURCED)
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
if (MSVC_VERSION GREATER_EQUAL 1930)
|
||||
if (NOT USE_CLANG_CL AND MSVC_VERSION GREATER_EQUAL 1930)
|
||||
target_compile_options(PCSX2_FLAGS INTERFACE /fp:contract)
|
||||
endif()
|
||||
target_compile_options(PCSX2_FLAGS INTERFACE /GS-)
|
||||
@@ -1288,7 +1288,7 @@ function(setup_main_executable target)
|
||||
install(FILES $<TARGET_PDB_FILE:${target}> DESTINATION ${CMAKE_SOURCE_DIR}/bin)
|
||||
endif()
|
||||
find_program(WINDEPLOYQT_EXE windeployqt HINTS "${QT_BINARY_DIRECTORY}")
|
||||
install(CODE "execute_process(COMMAND \"${WINDEPLOYQT_EXE}\" \"${CMAKE_SOURCE_DIR}/bin/pcsx2-qt.exe\" --plugindir ${CMAKE_SOURCE_DIR}/bin/QtPlugins --no-compiler-runtime --no-system-d3d-compiler)")
|
||||
install(CODE "execute_process(COMMAND \"${WINDEPLOYQT_EXE}\" \"${CMAKE_SOURCE_DIR}/bin/$<TARGET_FILE_NAME:${target}>\" --plugindir ${CMAKE_SOURCE_DIR}/bin/QtPlugins --no-compiler-runtime --no-system-d3d-compiler)")
|
||||
install(CODE "file(WRITE \"${CMAKE_SOURCE_DIR}/bin/qt.conf\" \"[Paths]\\nPlugins = ./QtPlugins\")")
|
||||
endif()
|
||||
|
||||
@@ -1365,6 +1365,10 @@ function(setup_main_executable target)
|
||||
COMMAND bash -c "set +x\; echo 'Elevating to enable networking capability on $<TARGET_FILE:${target}>...'\; sudo setcap 'CAP_NET_RAW+eip CAP_NET_ADMIN+eip' '$<TARGET_FILE:${target}>'"
|
||||
)
|
||||
endif()
|
||||
|
||||
if(PCSX2_EXE_NAME)
|
||||
set_target_properties(${target} PROPERTIES OUTPUT_NAME ${PCSX2_EXE_NAME})
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
source_groups_from_vcxproj_filters(pcsx2core.vcxproj.filters)
|
||||
|
||||
@@ -357,6 +357,13 @@ enum class GSGPUTargetCLUTMode : u8
|
||||
InsideTarget,
|
||||
};
|
||||
|
||||
enum class GSTextureInRtMode : u8
|
||||
{
|
||||
Disabled,
|
||||
InsideTargets,
|
||||
MergeTargets,
|
||||
};
|
||||
|
||||
// Template function for casting enumerations to their underlying type
|
||||
template <typename Enumeration>
|
||||
typename std::underlying_type<Enumeration>::type enum_cast(Enumeration E)
|
||||
@@ -607,6 +614,7 @@ struct Pcsx2Config
|
||||
{
|
||||
static const char* AspectRatioNames[];
|
||||
static const char* FMVAspectRatioSwitchNames[];
|
||||
static const char* BlendingLevelNames[];
|
||||
static const char* CaptureContainers[];
|
||||
|
||||
static const char* GetRendererName(GSRendererType type);
|
||||
@@ -658,18 +666,19 @@ struct Pcsx2Config
|
||||
GPUPaletteConversion : 1,
|
||||
AutoFlushSW : 1,
|
||||
PreloadFrameWithGSData : 1,
|
||||
WrapGSMem : 1,
|
||||
Mipmap : 1,
|
||||
ManualUserHacks : 1,
|
||||
UserHacks_AlignSpriteX : 1,
|
||||
UserHacks_AutoFlush : 1,
|
||||
UserHacks_CPUFBConversion : 1,
|
||||
UserHacks_ReadTCOnClose : 1,
|
||||
UserHacks_DisableDepthSupport : 1,
|
||||
UserHacks_DisablePartialInvalidation : 1,
|
||||
UserHacks_DisableSafeFeatures : 1,
|
||||
UserHacks_MergePPSprite : 1,
|
||||
UserHacks_WildHack : 1,
|
||||
UserHacks_TextureInsideRt : 1,
|
||||
UserHacks_TargetPartialInvalidation : 1,
|
||||
UserHacks_EstimateTextureRegion : 1,
|
||||
FXAA : 1,
|
||||
ShadeBoost : 1,
|
||||
DumpGSData : 1,
|
||||
@@ -745,6 +754,7 @@ struct Pcsx2Config
|
||||
int UserHacks_CPUSpriteRenderBW{0};
|
||||
int UserHacks_CPUCLUTRender{ 0 };
|
||||
GSGPUTargetCLUTMode UserHacks_GPUTargetCLUTMode{GSGPUTargetCLUTMode::Disabled};
|
||||
GSTextureInRtMode UserHacks_TextureInsideRt{GSTextureInRtMode::Disabled};
|
||||
TriFiltering TriFilter{TriFiltering::Automatic};
|
||||
int OverrideTextureBarriers{-1};
|
||||
int OverrideGeometryShaders{-1};
|
||||
|
||||
@@ -543,12 +543,16 @@ static __fi void DoFMVSwitch()
|
||||
RendererSwitched = false;
|
||||
}
|
||||
|
||||
// Convenience function to update UI thread and set patches.
|
||||
static __fi void frameLimitUpdateCore()
|
||||
// Convenience function to update UI thread and set patches.
|
||||
static __fi void VSyncUpdateCore()
|
||||
{
|
||||
DoFMVSwitch();
|
||||
|
||||
VMManager::Internal::VSyncOnCPUThread();
|
||||
}
|
||||
|
||||
static __fi void VSyncCheckExit()
|
||||
{
|
||||
if (VMManager::Internal::IsExecutionInterrupted())
|
||||
Cpu->ExitExecution();
|
||||
}
|
||||
@@ -559,10 +563,7 @@ static __fi void frameLimit()
|
||||
{
|
||||
// Framelimiter off in settings? Framelimiter go brrr.
|
||||
if (EmuConfig.GS.LimitScalar == 0.0f || s_use_vsync_for_timing)
|
||||
{
|
||||
frameLimitUpdateCore();
|
||||
return;
|
||||
}
|
||||
|
||||
const u64 uExpectedEnd = m_iStart + m_iTicks; // Compute when we would expect this frame to end, assuming everything goes perfectly perfect.
|
||||
const u64 iEnd = GetCPUTicks(); // The current tick we actually stopped on.
|
||||
@@ -573,7 +574,6 @@ static __fi void frameLimit()
|
||||
{
|
||||
// ... Fudge the next frame start over a bit. Prevents fast forward zoomies.
|
||||
m_iStart += (sDeltaTime / m_iTicks) * m_iTicks;
|
||||
frameLimitUpdateCore();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -597,16 +597,17 @@ static __fi void frameLimit()
|
||||
|
||||
// Finally, set our next frame start to when this one ends
|
||||
m_iStart = uExpectedEnd;
|
||||
frameLimitUpdateCore();
|
||||
}
|
||||
|
||||
static __fi void VSyncStart(u32 sCycle)
|
||||
{
|
||||
// Update vibration at the end of a frame.
|
||||
VSyncUpdateCore();
|
||||
PAD::Update();
|
||||
|
||||
frameLimit(); // limit FPS
|
||||
gsPostVsyncStart(); // MUST be after framelimit; doing so before causes funk with frame times!
|
||||
VSyncCheckExit();
|
||||
|
||||
if(EmuConfig.Trace.Enabled && EmuConfig.Trace.EE.m_EnableAll)
|
||||
SysTrace.EE.Counters.Write( " ================ EE COUNTER VSYNC START (frame: %d) ================", g_FrameCount );
|
||||
|
||||
@@ -169,8 +169,8 @@ The clamp modes are also numerically based.
|
||||
* alignSprite [`0` or `1`] {Off or On} Default: Off (`0`)
|
||||
* mergeSprite [`0` or `1`] {Off or On} Default: Off (`0`)
|
||||
* wildArmsHack [`0` or `1`] {Off or On} Default: Off (`0`)
|
||||
* skipDrawStart [Value between `0` to `100000`] {0-100000} Default: Off (`0`)
|
||||
* skipDrawEnd [Value between `0` to `100000`] {0-100000} Default: Off (`0`)
|
||||
* skipDrawStart [Value between `0` to `10000`] {0-10000} Default: Off (`0`)
|
||||
* skipDrawEnd [Value between `0` to `10000`] {0-10000} Default: Off (`0`)
|
||||
* halfPixelOffset [`0` or `1` or `2` or `3`] {Off, Normal Vertex, Special Texture or Special Texture Aggressive} Default: Off (`0`)
|
||||
* roundSprite [`0` or `1` or `2`] {Off, Half or Full} Default: Off (`0`)
|
||||
|
||||
|
||||
@@ -126,12 +126,12 @@
|
||||
"minimum": 0,
|
||||
"maximum": 1
|
||||
},
|
||||
"disableDepthSupport": {
|
||||
"readTCOnClose": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 1
|
||||
},
|
||||
"wrapGSMem": {
|
||||
"disableDepthSupport": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 1
|
||||
@@ -146,11 +146,16 @@
|
||||
"minimum": 0,
|
||||
"maximum": 1
|
||||
},
|
||||
"textureInsideRT": {
|
||||
"partialTargetInvalidation": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 1
|
||||
},
|
||||
"textureInsideRT": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 2
|
||||
},
|
||||
"alignSprite": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
@@ -166,6 +171,21 @@
|
||||
"minimum": 0,
|
||||
"maximum": 1
|
||||
},
|
||||
"estimateTextureRegion": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 1
|
||||
},
|
||||
"PCRTCOffsets": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 1
|
||||
},
|
||||
"PCRTCOverscan": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 1
|
||||
},
|
||||
"mipmap": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
@@ -231,6 +251,21 @@
|
||||
"minimum": 0,
|
||||
"maximum": 2
|
||||
},
|
||||
"minimumBlendingLevel": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 5
|
||||
},
|
||||
"maximumBlendingLevel": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 5
|
||||
},
|
||||
"recommendedBlendingLevel": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 5
|
||||
},
|
||||
"getSkipCount": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
@@ -160,7 +160,7 @@ void CommonHost::SetDataDirectory()
|
||||
EmuFolders::DataRoot = Path::Combine(StringUtil::WideStringToUTF8String(documents_directory), "PCSX2");
|
||||
CoTaskMemFree(documents_directory);
|
||||
}
|
||||
#elif defined(__linux__)
|
||||
#elif defined(__linux__) || defined(__FreeBSD__)
|
||||
// Use $XDG_CONFIG_HOME/PCSX2 if it exists.
|
||||
const char* xdg_config_home = getenv("XDG_CONFIG_HOME");
|
||||
if (xdg_config_home && Path::IsAbsolute(xdg_config_home))
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include "Frontend/D3D11HostDisplay.h"
|
||||
#include "GS/Renderers/DX11/D3D.h"
|
||||
|
||||
#include "imgui.h"
|
||||
#include "imgui_impl_dx11.h"
|
||||
@@ -439,49 +440,6 @@ void D3D11HostDisplay::DestroySurface()
|
||||
m_swap_chain.reset();
|
||||
}
|
||||
|
||||
static std::string GetDriverVersionFromLUID(const LUID& luid)
|
||||
{
|
||||
std::string ret;
|
||||
|
||||
HKEY hKey;
|
||||
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\DirectX", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
|
||||
{
|
||||
DWORD max_key_len = 0, adapter_count = 0;
|
||||
if (RegQueryInfoKeyW(hKey, nullptr, nullptr, nullptr, &adapter_count, &max_key_len,
|
||||
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr) == ERROR_SUCCESS)
|
||||
{
|
||||
std::vector<TCHAR> current_name(max_key_len + 1);
|
||||
for (DWORD i = 0; i < adapter_count; ++i)
|
||||
{
|
||||
DWORD subKeyLength = static_cast<DWORD>(current_name.size());
|
||||
if (RegEnumKeyExW(hKey, i, current_name.data(), &subKeyLength, nullptr, nullptr, nullptr, nullptr) == ERROR_SUCCESS)
|
||||
{
|
||||
LUID current_luid = {};
|
||||
DWORD current_luid_size = sizeof(uint64_t);
|
||||
if (RegGetValueW(hKey, current_name.data(), L"AdapterLuid", RRF_RT_QWORD, nullptr, ¤t_luid, ¤t_luid_size) == ERROR_SUCCESS &&
|
||||
current_luid.HighPart == luid.HighPart && current_luid.LowPart == luid.LowPart)
|
||||
{
|
||||
LARGE_INTEGER driver_version = {};
|
||||
DWORD driver_version_size = sizeof(driver_version);
|
||||
if (RegGetValueW(hKey, current_name.data(), L"DriverVersion", RRF_RT_QWORD, nullptr, &driver_version, &driver_version_size) == ERROR_SUCCESS)
|
||||
{
|
||||
WORD nProduct = HIWORD(driver_version.HighPart);
|
||||
WORD nVersion = LOWORD(driver_version.HighPart);
|
||||
WORD nSubVersion = HIWORD(driver_version.LowPart);
|
||||
WORD nBuild = LOWORD(driver_version.LowPart);
|
||||
ret = StringUtil::StdStringFromFormat("%u.%u.%u.%u", nProduct, nVersion, nSubVersion, nBuild);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string D3D11HostDisplay::GetDriverInfo() const
|
||||
{
|
||||
std::string ret = "Unknown Feature Level";
|
||||
@@ -518,7 +476,7 @@ std::string D3D11HostDisplay::GetDriverInfo() const
|
||||
ret += StringUtil::WideStringToUTF8String(desc.Description);
|
||||
ret += "\n";
|
||||
|
||||
const std::string driver_version(GetDriverVersionFromLUID(desc.AdapterLuid));
|
||||
const std::string driver_version(D3D::GetDriverVersionFromLUID(desc.AdapterLuid));
|
||||
if (!driver_version.empty())
|
||||
{
|
||||
ret += "Driver Version: ";
|
||||
@@ -641,13 +599,10 @@ bool D3D11HostDisplay::UpdateImGuiFontTexture()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool D3D11HostDisplay::BeginPresent(bool frame_skip)
|
||||
HostDisplay::PresentResult D3D11HostDisplay::BeginPresent(bool frame_skip)
|
||||
{
|
||||
if (frame_skip || !m_swap_chain)
|
||||
{
|
||||
ImGui::EndFrame();
|
||||
return false;
|
||||
}
|
||||
return PresentResult::FrameSkipped;
|
||||
|
||||
// When using vsync, the time here seems to include the time for the buffer to become available.
|
||||
// This blows our our GPU usage number considerably, so read the timestamp before the final blit
|
||||
@@ -664,7 +619,7 @@ bool D3D11HostDisplay::BeginPresent(bool frame_skip)
|
||||
const CD3D11_RECT scissor(0, 0, m_window_info.surface_width, m_window_info.surface_height);
|
||||
m_context->RSSetViewports(1, &vp);
|
||||
m_context->RSSetScissorRects(1, &scissor);
|
||||
return true;
|
||||
return PresentResult::OK;
|
||||
}
|
||||
|
||||
void D3D11HostDisplay::EndPresent()
|
||||
|
||||
@@ -65,7 +65,7 @@ public:
|
||||
|
||||
void SetVSync(VsyncMode mode) override;
|
||||
|
||||
bool BeginPresent(bool frame_skip) override;
|
||||
PresentResult BeginPresent(bool frame_skip) override;
|
||||
void EndPresent() override;
|
||||
|
||||
bool SetGPUTimingEnabled(bool enabled) override;
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include "Frontend/D3D12HostDisplay.h"
|
||||
#include "GS/Renderers/DX11/D3D.h"
|
||||
|
||||
#include "common/Assertions.h"
|
||||
#include "common/Console.h"
|
||||
#include "common/D3D12/Context.h"
|
||||
@@ -343,49 +345,6 @@ void D3D12HostDisplay::DestroySurface()
|
||||
m_swap_chain.reset();
|
||||
}
|
||||
|
||||
static std::string GetDriverVersionFromLUID(const LUID& luid)
|
||||
{
|
||||
std::string ret;
|
||||
|
||||
HKEY hKey;
|
||||
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\DirectX", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
|
||||
{
|
||||
DWORD max_key_len = 0, adapter_count = 0;
|
||||
if (RegQueryInfoKey(hKey, nullptr, nullptr, nullptr, &adapter_count, &max_key_len,
|
||||
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr) == ERROR_SUCCESS)
|
||||
{
|
||||
std::vector<TCHAR> current_name(max_key_len + 1);
|
||||
for (DWORD i = 0; i < adapter_count; ++i)
|
||||
{
|
||||
DWORD subKeyLength = static_cast<DWORD>(current_name.size());
|
||||
if (RegEnumKeyExW(hKey, i, current_name.data(), &subKeyLength, nullptr, nullptr, nullptr, nullptr) == ERROR_SUCCESS)
|
||||
{
|
||||
LUID current_luid = {};
|
||||
DWORD current_luid_size = sizeof(uint64_t);
|
||||
if (RegGetValueW(hKey, current_name.data(), L"AdapterLuid", RRF_RT_QWORD, nullptr, ¤t_luid, ¤t_luid_size) == ERROR_SUCCESS &&
|
||||
current_luid.HighPart == luid.HighPart && current_luid.LowPart == luid.LowPart)
|
||||
{
|
||||
LARGE_INTEGER driver_version = {};
|
||||
DWORD driver_version_size = sizeof(driver_version);
|
||||
if (RegGetValueW(hKey, current_name.data(), L"DriverVersion", RRF_RT_QWORD, nullptr, &driver_version, &driver_version_size) == ERROR_SUCCESS)
|
||||
{
|
||||
WORD nProduct = HIWORD(driver_version.HighPart);
|
||||
WORD nVersion = LOWORD(driver_version.HighPart);
|
||||
WORD nSubVersion = HIWORD(driver_version.LowPart);
|
||||
WORD nBuild = LOWORD(driver_version.LowPart);
|
||||
ret = StringUtil::StdStringFromFormat("%u.%u.%u.%u", nProduct, nVersion, nSubVersion, nBuild);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string D3D12HostDisplay::GetDriverInfo() const
|
||||
{
|
||||
std::string ret = "Unknown Feature Level";
|
||||
@@ -417,7 +376,7 @@ std::string D3D12HostDisplay::GetDriverInfo() const
|
||||
ret += StringUtil::WideStringToUTF8String(desc.Description);
|
||||
ret += "\n";
|
||||
|
||||
const std::string driver_version(GetDriverVersionFromLUID(desc.AdapterLuid));
|
||||
const std::string driver_version(D3D::GetDriverVersionFromLUID(desc.AdapterLuid));
|
||||
if (!driver_version.empty())
|
||||
{
|
||||
ret += "Driver Version: ";
|
||||
@@ -554,13 +513,13 @@ bool D3D12HostDisplay::UpdateImGuiFontTexture()
|
||||
return ImGui_ImplDX12_CreateFontsTexture();
|
||||
}
|
||||
|
||||
bool D3D12HostDisplay::BeginPresent(bool frame_skip)
|
||||
HostDisplay::PresentResult D3D12HostDisplay::BeginPresent(bool frame_skip)
|
||||
{
|
||||
if (m_device_lost)
|
||||
return HostDisplay::PresentResult::DeviceLost;
|
||||
|
||||
if (frame_skip || !m_swap_chain)
|
||||
{
|
||||
ImGui::EndFrame();
|
||||
return false;
|
||||
}
|
||||
return PresentResult::FrameSkipped;
|
||||
|
||||
static constexpr std::array<float, 4> clear_color = {};
|
||||
D3D12::Texture& swap_chain_buf = m_swap_chain_buffers[m_current_swap_chain_buffer];
|
||||
@@ -574,7 +533,7 @@ bool D3D12HostDisplay::BeginPresent(bool frame_skip)
|
||||
const D3D12_RECT scissor{0, 0, static_cast<LONG>(m_window_info.surface_width), static_cast<LONG>(m_window_info.surface_height)};
|
||||
cmdlist->RSSetViewports(1, &vp);
|
||||
cmdlist->RSSetScissorRects(1, &scissor);
|
||||
return true;
|
||||
return PresentResult::OK;
|
||||
}
|
||||
|
||||
void D3D12HostDisplay::EndPresent()
|
||||
@@ -586,7 +545,11 @@ void D3D12HostDisplay::EndPresent()
|
||||
m_current_swap_chain_buffer = ((m_current_swap_chain_buffer + 1) % static_cast<u32>(m_swap_chain_buffers.size()));
|
||||
|
||||
swap_chain_buf.TransitionToState(g_d3d12_context->GetCommandList(), D3D12_RESOURCE_STATE_PRESENT);
|
||||
g_d3d12_context->ExecuteCommandList(D3D12::Context::WaitType::None);
|
||||
if (!g_d3d12_context->ExecuteCommandList(D3D12::Context::WaitType::None))
|
||||
{
|
||||
m_device_lost = true;
|
||||
return;
|
||||
}
|
||||
|
||||
const bool vsync = static_cast<UINT>(m_vsync_mode != VsyncMode::Off);
|
||||
if (!vsync && m_using_allow_tearing)
|
||||
|
||||
@@ -71,7 +71,7 @@ public:
|
||||
|
||||
void SetVSync(VsyncMode mode) override;
|
||||
|
||||
bool BeginPresent(bool frame_skip) override;
|
||||
PresentResult BeginPresent(bool frame_skip) override;
|
||||
void EndPresent() override;
|
||||
|
||||
bool SetGPUTimingEnabled(bool enabled) override;
|
||||
@@ -97,4 +97,5 @@ protected:
|
||||
|
||||
bool m_allow_tearing_supported = false;
|
||||
bool m_using_allow_tearing = false;
|
||||
bool m_device_lost = false;
|
||||
};
|
||||
|
||||
@@ -3071,6 +3071,12 @@ void FullscreenUI::DrawGraphicsSettingsPage()
|
||||
renderer == GSRendererType::OGL || renderer == GSRendererType::VK || renderer == GSRendererType::Metal);
|
||||
//const bool is_software = (renderer == GSRendererType::SW);
|
||||
|
||||
#ifndef PCSX2_DEVBUILD
|
||||
const bool hw_fixes_visible = is_hardware && IsEditingGameSettings(bsi);
|
||||
#else
|
||||
const bool hw_fixes_visible = is_hardware;
|
||||
#endif
|
||||
|
||||
BeginMenuButtons();
|
||||
|
||||
MenuHeading("Renderer");
|
||||
@@ -3134,8 +3140,6 @@ void FullscreenUI::DrawGraphicsSettingsPage()
|
||||
std::size(s_anisotropic_filtering_entries));
|
||||
DrawIntListSetting(bsi, "Dithering", "Selects the type of dithering applies when the game requests it.", "EmuCore/GS",
|
||||
"dithering_ps2", 2, s_dithering_options, std::size(s_dithering_options));
|
||||
DrawIntListSetting(bsi, "CRC Fix Level", "Applies manual fixes to difficult-to-emulate effects in the hardware renderers.",
|
||||
"EmuCore/GS", "crc_hack_level", static_cast<int>(CRCHackLevel::Automatic), s_crc_fix_options, std::size(s_crc_fix_options), -1);
|
||||
DrawIntListSetting(bsi, "Blending Accuracy",
|
||||
"Determines the level of accuracy when emulating blend modes not supported by the host graphics API.", "EmuCore/GS",
|
||||
"accurate_blending_unit", static_cast<int>(AccBlendLevel::Basic), s_blending_options, std::size(s_blending_options));
|
||||
@@ -3143,17 +3147,18 @@ void FullscreenUI::DrawGraphicsSettingsPage()
|
||||
"Uploads full textures to the GPU on use, rather than only the utilized regions. Can improve performance in some games.",
|
||||
"EmuCore/GS", "texture_preloading", static_cast<int>(TexturePreloadingLevel::Off), s_preloading_options,
|
||||
std::size(s_preloading_options));
|
||||
DrawIntListSetting(bsi, "Hardware Download Mode", "Changes synchronization behavior for GS downloads.", "EmuCore/GS",
|
||||
"HWDownloadMode", static_cast<int>(GSHardwareDownloadMode::Enabled), s_hw_download, std::size(s_hw_download));
|
||||
DrawToggleSetting(bsi, "GPU Palette Conversion",
|
||||
"Applies palettes to textures on the GPU instead of the CPU. Can result in speed improvements in some games.", "EmuCore/GS",
|
||||
"paltex", false);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawIntRangeSetting(bsi, "Software Rendering Threads",
|
||||
"Number of threads to use in addition to the main GS thread for rasterization.", "EmuCore/GS", "extrathreads", 2, 0, 10);
|
||||
DrawToggleSetting(bsi, "Auto Flush (Software)", "Force a primitive flush when a framebuffer is also an input texture.",
|
||||
"EmuCore/GS", "autoflush_sw", true);
|
||||
DrawToggleSetting(bsi, "Edge AA (AA1)", "Enables emulation of the GS's edge anti-aliasing (AA1).", "EmuCore/GS", "aa1", true);
|
||||
DrawToggleSetting(bsi, "Mipmapping", "Enables emulation of the GS's texture mipmapping.", "EmuCore/GS", "mipmap", true);
|
||||
}
|
||||
|
||||
if (is_hardware)
|
||||
if (hw_fixes_visible)
|
||||
{
|
||||
MenuHeading("Hardware Fixes");
|
||||
DrawToggleSetting(bsi, "Manual Hardware Fixes", "Disables automatic hardware fixes, allowing you to set fixes manually.",
|
||||
@@ -3166,10 +3171,13 @@ void FullscreenUI::DrawGraphicsSettingsPage()
|
||||
"3 (192 Max Width)", "4 (256 Max Width)", "5 (320 Max Width)", "6 (384 Max Width)", "7 (448 Max Width)",
|
||||
"8 (512 Max Width)", "9 (576 Max Width)", "10 (640 Max Width)"};
|
||||
static constexpr const char* s_cpu_clut_render_options[] = {"0 (Disabled)", "1 (Normal)", "2 (Aggressive)"};
|
||||
static constexpr const char* s_texture_inside_rt_options[] = {"Disabled", "Inside Target", "Merge Targets"};
|
||||
static constexpr const char* s_half_pixel_offset_options[] = {
|
||||
"Off (Default)", "Normal (Vertex)", "Special (Texture)", "Special (Texture - Aggressive)"};
|
||||
static constexpr const char* s_round_sprite_options[] = {"Off (Default)", "Half", "Full"};
|
||||
|
||||
DrawIntListSetting(bsi, "CRC Fix Level", "Applies manual fixes to difficult-to-emulate effects in the hardware renderers.",
|
||||
"EmuCore/GS", "crc_hack_level", static_cast<int>(CRCHackLevel::Automatic), s_crc_fix_options, std::size(s_crc_fix_options), -1);
|
||||
DrawIntListSetting(bsi, "Half-Bottom Override", "Control the half-screen fix detection on texture shuffling.", "EmuCore/GS",
|
||||
"UserHacks_Half_Bottom_Override", -1, s_generic_options, std::size(s_generic_options), -1);
|
||||
DrawIntListSetting(bsi, "CPU Sprite Render Size", "Uses software renderer to draw texture decompression-like sprites.",
|
||||
@@ -3193,9 +3201,22 @@ void FullscreenUI::DrawGraphicsSettingsPage()
|
||||
DrawToggleSetting(bsi, "Disable Partial Invalidation",
|
||||
"Removes texture cache entries when there is any intersection, rather than only the intersected areas.", "EmuCore/GS",
|
||||
"UserHacks_DisablePartialInvalidation", false, manual_hw_fixes);
|
||||
DrawToggleSetting(bsi, "Texture Inside Render Target",
|
||||
DrawIntListSetting(bsi, "Texture Inside Render Target",
|
||||
"Allows the texture cache to reuse as an input texture the inner portion of a previous framebuffer.", "EmuCore/GS",
|
||||
"UserHacks_TextureInsideRt", false, manual_hw_fixes);
|
||||
"UserHacks_TextureInsideRt", 0, s_texture_inside_rt_options, std::size(s_texture_inside_rt_options), 0, manual_hw_fixes);
|
||||
DrawToggleSetting(bsi, "Target Partial Invalidation",
|
||||
"Allows partial invalidation of render targets, which can fix graphical errors in some games.", "EmuCore/GS",
|
||||
"UserHacks_TargetPartialInvalidation", false,
|
||||
!GetEffectiveBoolSetting(bsi, "EmuCore/GS", "UserHacks_TextureInsideRt", false));
|
||||
DrawToggleSetting(bsi, "Read Targets When Closing",
|
||||
"Flushes all targets in the texture cache back to local memory when shutting down.", "EmuCore/GS",
|
||||
"UserHacks_ReadTCOnClose", false, manual_hw_fixes);
|
||||
DrawToggleSetting(bsi, "Estimate Texture Region",
|
||||
"Attempts to reduce the texture size when games do not set it themselves (e.g. Snowblind games).", "EmuCore/GS",
|
||||
"UserHacks_EstimateTextureRegion", false, manual_hw_fixes);
|
||||
DrawToggleSetting(bsi, "GPU Palette Conversion",
|
||||
"Applies palettes to textures on the GPU instead of the CPU. Can result in speed improvements in some games.", "EmuCore/GS",
|
||||
"paltex", false);
|
||||
|
||||
MenuHeading("Upscaling Fixes");
|
||||
DrawIntListSetting(bsi, "Half-Pixel Offset", "Adjusts vertices relative to upscaling.", "EmuCore/GS",
|
||||
@@ -3215,16 +3236,6 @@ void FullscreenUI::DrawGraphicsSettingsPage()
|
||||
"UserHacks_WildHack", false, manual_hw_fixes);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// extrathreads
|
||||
DrawIntRangeSetting(bsi, "Software Rendering Threads",
|
||||
"Number of threads to use in addition to the main GS thread for rasterization.", "EmuCore/GS", "extrathreads", 2, 0, 10);
|
||||
DrawToggleSetting(bsi, "Auto Flush (Software)", "Force a primitive flush when a framebuffer is also an input texture.",
|
||||
"EmuCore/GS", "autoflush_sw", true);
|
||||
DrawToggleSetting(bsi, "Edge AA (AA1)", "Enables emulation of the GS's edge anti-aliasing (AA1).", "EmuCore/GS", "aa1", true);
|
||||
DrawToggleSetting(bsi, "Mipmapping", "Enables emulation of the GS's texture mipmapping.", "EmuCore/GS", "mipmap", true);
|
||||
}
|
||||
|
||||
if (is_hardware)
|
||||
{
|
||||
@@ -3291,6 +3302,11 @@ void FullscreenUI::DrawGraphicsSettingsPage()
|
||||
DrawToggleSetting(bsi, "Disable Threaded Presentation",
|
||||
"Presents frames on a worker thread, instead of on the GS thread. Can improve frame times on some systems, at the cost of "
|
||||
"potentially worse frame pacing.", "EmuCore/GS", "DisableThreadedPresentation", false);
|
||||
if (hw_fixes_visible)
|
||||
{
|
||||
DrawIntListSetting(bsi, "Hardware Download Mode", "Changes synchronization behavior for GS downloads.", "EmuCore/GS",
|
||||
"HWDownloadMode", static_cast<int>(GSHardwareDownloadMode::Enabled), s_hw_download, std::size(s_hw_download));
|
||||
}
|
||||
DrawIntListSetting(bsi, "Override Texture Barriers", "Forces texture barrier functionality to the specified value.", "EmuCore/GS",
|
||||
"OverrideTextureBarriers", -1, s_generic_options, std::size(s_generic_options), -1);
|
||||
DrawIntListSetting(bsi, "Override Geometry Shaders", "Forces geometry shader functionality to the specified value.", "EmuCore/GS",
|
||||
@@ -3881,6 +3897,10 @@ void FullscreenUI::DrawControllerSettingsPage()
|
||||
if (MenuButton(ICON_FA_LIGHTBULB " Frequency", freq_summary.c_str()))
|
||||
ImGui::OpenPopup(freq_key.c_str());
|
||||
|
||||
const std::string pressure_key(fmt::format("Macro{}Pressure", macro_index + 1));
|
||||
DrawFloatSpinBoxSetting(bsi, ICON_FA_ARROW_DOWN " Pressure", "Determines how much pressure is simulated when macro is active.",
|
||||
section, pressure_key.c_str(), 1.0f, 0.01f, 1.0f, 0.01f, 100.0f, "%.0f%%");
|
||||
|
||||
ImGui::SetNextWindowSize(LayoutScale(500.0f, 180.0f));
|
||||
ImGui::SetNextWindowPos(ImGui::GetIO().DisplaySize * 0.5f, ImGuiCond_Always, ImVec2(0.5f, 0.5f));
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ bool ImGuiManager::Initialize()
|
||||
return false;
|
||||
}
|
||||
|
||||
s_global_scale = std::max(1.0f, g_host_display->GetWindowScale() * (EmuConfig.GS.OsdScale / 100.0f));
|
||||
s_global_scale = std::max(0.5f, g_host_display->GetWindowScale() * (EmuConfig.GS.OsdScale / 100.0f));
|
||||
|
||||
ImGui::CreateContext();
|
||||
|
||||
@@ -185,7 +185,7 @@ void ImGuiManager::WindowResized()
|
||||
void ImGuiManager::UpdateScale()
|
||||
{
|
||||
const float window_scale = g_host_display ? g_host_display->GetWindowScale() : 1.0f;
|
||||
const float scale = std::max(window_scale * (EmuConfig.GS.OsdScale / 100.0f), 1.0f);
|
||||
const float scale = std::max(window_scale * (EmuConfig.GS.OsdScale / 100.0f), 0.5f);
|
||||
|
||||
if (scale == s_global_scale && (!HasFullscreenFonts() || !ImGuiFullscreen::UpdateLayoutScale()))
|
||||
return;
|
||||
@@ -229,6 +229,12 @@ void ImGuiManager::NewFrame()
|
||||
}
|
||||
}
|
||||
|
||||
void ImGuiManager::SkipFrame()
|
||||
{
|
||||
ImGui::EndFrame();
|
||||
NewFrame();
|
||||
}
|
||||
|
||||
void ImGuiManager::SetStyle()
|
||||
{
|
||||
ImGuiStyle& style = ImGui::GetStyle();
|
||||
@@ -411,7 +417,7 @@ ImFont* ImGuiManager::AddFixedFont(float size)
|
||||
bool ImGuiManager::AddIconFonts(float size)
|
||||
{
|
||||
// clang-format off
|
||||
static constexpr ImWchar range_fa[] = { 0xf001,0xf002,0xf005,0xf005,0xf007,0xf007,0xf00c,0xf00e,0xf011,0xf011,0xf013,0xf013,0xf017,0xf017,0xf019,0xf019,0xf01c,0xf01c,0xf021,0xf021,0xf023,0xf023,0xf025,0xf025,0xf027,0xf028,0xf02d,0xf02e,0xf030,0xf030,0xf03a,0xf03a,0xf03d,0xf03d,0xf04a,0xf04c,0xf04e,0xf04e,0xf050,0xf050,0xf052,0xf052,0xf059,0xf059,0xf05e,0xf05e,0xf065,0xf065,0xf067,0xf067,0xf06a,0xf06a,0xf071,0xf071,0xf077,0xf078,0xf07b,0xf07c,0xf084,0xf085,0xf091,0xf091,0xf0ac,0xf0ad,0xf0b0,0xf0b0,0xf0c5,0xf0c5,0xf0c7,0xf0c9,0xf0cb,0xf0cb,0xf0d0,0xf0d0,0xf0dc,0xf0dc,0xf0e2,0xf0e2,0xf0eb,0xf0eb,0xf0f1,0xf0f1,0xf0f3,0xf0f3,0xf0fe,0xf0fe,0xf110,0xf110,0xf119,0xf119,0xf11b,0xf11c,0xf121,0xf121,0xf133,0xf133,0xf140,0xf140,0xf144,0xf144,0xf14a,0xf14a,0xf15b,0xf15b,0xf15d,0xf15d,0xf188,0xf188,0xf191,0xf192,0xf1c9,0xf1c9,0xf1dd,0xf1de,0xf1e6,0xf1e6,0xf1ea,0xf1eb,0xf1f8,0xf1f8,0xf1fc,0xf1fc,0xf242,0xf242,0xf245,0xf245,0xf26c,0xf26c,0xf279,0xf279,0xf2d0,0xf2d0,0xf2db,0xf2db,0xf2f2,0xf2f2,0xf2f5,0xf2f5,0xf302,0xf302,0xf3c1,0xf3c1,0xf3fd,0xf3fd,0xf410,0xf410,0xf466,0xf466,0xf479,0xf479,0xf500,0xf500,0xf517,0xf517,0xf51f,0xf51f,0xf543,0xf543,0xf545,0xf545,0xf547,0xf548,0xf552,0xf552,0xf5a2,0xf5a2,0xf65d,0xf65e,0xf6a9,0xf6a9,0xf756,0xf756,0xf7c2,0xf7c2,0xf807,0xf807,0xf815,0xf815,0xf818,0xf818,0xf84c,0xf84c,0xf8cc,0xf8cc,0xf8d9,0xf8d9,0x0,0x0 };
|
||||
static constexpr ImWchar range_fa[] = { 0xf002,0xf002,0xf005,0xf005,0xf007,0xf007,0xf00c,0xf00e,0xf011,0xf011,0xf013,0xf013,0xf017,0xf017,0xf019,0xf019,0xf01c,0xf01c,0xf021,0xf021,0xf023,0xf023,0xf025,0xf025,0xf027,0xf028,0xf02d,0xf02e,0xf030,0xf030,0xf03a,0xf03a,0xf03d,0xf03d,0xf04a,0xf04c,0xf04e,0xf04e,0xf050,0xf050,0xf052,0xf052,0xf059,0xf059,0xf05e,0xf05e,0xf063,0xf063,0xf065,0xf065,0xf067,0xf067,0xf06a,0xf06a,0xf071,0xf071,0xf077,0xf078,0xf07b,0xf07c,0xf084,0xf085,0xf091,0xf091,0xf0ac,0xf0ad,0xf0b0,0xf0b0,0xf0c5,0xf0c5,0xf0c7,0xf0c9,0xf0cb,0xf0cb,0xf0d0,0xf0d0,0xf0dc,0xf0dc,0xf0e2,0xf0e2,0xf0eb,0xf0eb,0xf0f1,0xf0f1,0xf0f3,0xf0f3,0xf0fe,0xf0fe,0xf110,0xf110,0xf119,0xf119,0xf11b,0xf11c,0xf121,0xf121,0xf133,0xf133,0xf140,0xf140,0xf144,0xf144,0xf14a,0xf14a,0xf15b,0xf15b,0xf15d,0xf15d,0xf188,0xf188,0xf191,0xf192,0xf1c9,0xf1c9,0xf1dd,0xf1de,0xf1e6,0xf1e6,0xf1ea,0xf1eb,0xf1f8,0xf1f8,0xf1fc,0xf1fc,0xf242,0xf242,0xf245,0xf245,0xf26c,0xf26c,0xf279,0xf279,0xf2d0,0xf2d0,0xf2db,0xf2db,0xf2f2,0xf2f2,0xf2f5,0xf2f5,0xf302,0xf302,0xf3c1,0xf3c1,0xf3fd,0xf3fd,0xf410,0xf410,0xf466,0xf466,0xf479,0xf479,0xf500,0xf500,0xf517,0xf517,0xf51f,0xf51f,0xf543,0xf543,0xf545,0xf545,0xf547,0xf548,0xf552,0xf552,0xf5a2,0xf5a2,0xf65d,0xf65e,0xf6a9,0xf6a9,0xf756,0xf756,0xf7c2,0xf7c2,0xf807,0xf807,0xf815,0xf815,0xf818,0xf818,0xf84c,0xf84c,0xf8cc,0xf8cc,0xf8d9,0xf8d9,0x0,0x0 };
|
||||
// clang-format on
|
||||
|
||||
ImFontConfig cfg;
|
||||
|
||||
@@ -40,6 +40,9 @@ namespace ImGuiManager
|
||||
/// Call at the beginning of the frame to set up ImGui state.
|
||||
void NewFrame();
|
||||
|
||||
/// Call when skipping rendering a frame, to update internal state.
|
||||
void SkipFrame();
|
||||
|
||||
/// Renders any on-screen display elements.
|
||||
void RenderOSD();
|
||||
|
||||
|
||||
@@ -406,11 +406,13 @@ void ImGuiManager::DrawSettingsOverlay()
|
||||
if (GSConfig.UserHacks_CPUSpriteRenderBW != 0)
|
||||
APPEND("CSBW={} ", GSConfig.UserHacks_CPUSpriteRenderBW);
|
||||
if (GSConfig.UserHacks_CPUCLUTRender != 0)
|
||||
APPEND("CCD={} ", GSConfig.UserHacks_CPUCLUTRender);
|
||||
APPEND("CCLUT={} ", GSConfig.UserHacks_CPUCLUTRender);
|
||||
if (GSConfig.UserHacks_GPUTargetCLUTMode != GSGPUTargetCLUTMode::Disabled)
|
||||
APPEND("GCLUT={} ", static_cast<int>(GSConfig.UserHacks_GPUTargetCLUTMode));
|
||||
if (GSConfig.SkipDrawStart != 0 || GSConfig.SkipDrawEnd != 0)
|
||||
APPEND("SD={}/{} ", GSConfig.SkipDrawStart, GSConfig.SkipDrawEnd);
|
||||
if (GSConfig.UserHacks_TextureInsideRt)
|
||||
APPEND("TexRT ");
|
||||
if (GSConfig.UserHacks_TextureInsideRt != GSTextureInRtMode::Disabled)
|
||||
APPEND("TexRT={} ", static_cast<int>(GSConfig.UserHacks_TextureInsideRt));
|
||||
if (GSConfig.UserHacks_WildHack)
|
||||
APPEND("WA ");
|
||||
if (GSConfig.UserHacks_MergePPSprite)
|
||||
@@ -421,16 +423,20 @@ void ImGuiManager::DrawSettingsOverlay()
|
||||
APPEND("AF ");
|
||||
if (GSConfig.UserHacks_CPUFBConversion)
|
||||
APPEND("FBC ");
|
||||
if (GSConfig.UserHacks_ReadTCOnClose)
|
||||
APPEND("FTC ");
|
||||
if(GSConfig.UserHacks_DisableDepthSupport)
|
||||
APPEND("DDE ");
|
||||
if (GSConfig.UserHacks_DisablePartialInvalidation)
|
||||
APPEND("DPIV ");
|
||||
if (GSConfig.UserHacks_TargetPartialInvalidation)
|
||||
APPEND("TPV ");
|
||||
if (GSConfig.UserHacks_DisableSafeFeatures)
|
||||
APPEND("DSF ");
|
||||
if (GSConfig.WrapGSMem)
|
||||
APPEND("WGSM ");
|
||||
if (GSConfig.PreloadFrameWithGSData)
|
||||
APPEND("PLFD ");
|
||||
if (GSConfig.UserHacks_EstimateTextureRegion)
|
||||
APPEND("ETR ");
|
||||
}
|
||||
|
||||
#undef APPEND
|
||||
|
||||
@@ -160,7 +160,11 @@ struct PointerAxisState
|
||||
static std::array<std::array<float, static_cast<u8>(InputPointerAxis::Count)>, InputManager::MAX_POINTER_DEVICES> s_host_pointer_positions;
|
||||
static std::array<std::array<PointerAxisState, static_cast<u8>(InputPointerAxis::Count)>, InputManager::MAX_POINTER_DEVICES>
|
||||
s_pointer_state;
|
||||
static std::array<float, static_cast<u8>(InputPointerAxis::Count)> s_pointer_axis_scale;
|
||||
static std::array<float, 2> s_pointer_axis_speed;
|
||||
static std::array<float, 2> s_pointer_axis_dead_zone;
|
||||
static std::array<float, 2> s_pointer_axis_range;
|
||||
static std::array<float, 2> s_pointer_pos = {0.0f, 0.0f};
|
||||
static float s_pointer_inertia = 0.0f;
|
||||
|
||||
using PointerMoveCallback = std::function<void(InputBindingKey key, float value)>;
|
||||
using KeyboardEventCallback = std::function<void(InputBindingKey key, float value)>;
|
||||
@@ -662,8 +666,7 @@ void InputManager::AddPadBindings(SettingsInterface& si, u32 pad_index, const ch
|
||||
|
||||
for (u32 macro_button_index = 0; macro_button_index < PAD::NUM_MACRO_BUTTONS_PER_CONTROLLER; macro_button_index++)
|
||||
{
|
||||
const std::vector<std::string> bindings(
|
||||
si.GetStringList(section.c_str(), StringUtil::StdStringFromFormat("Macro%u", macro_button_index + 1).c_str()));
|
||||
const std::vector<std::string> bindings(si.GetStringList(section.c_str(), fmt::format("Macro{}", macro_button_index + 1).c_str()));
|
||||
if (!bindings.empty())
|
||||
{
|
||||
AddBindings(bindings, InputButtonEventHandler{[pad_index, macro_button_index](bool state) {
|
||||
@@ -919,6 +922,71 @@ bool InputManager::ProcessEvent(InputBindingKey key, float value, bool skip_butt
|
||||
return true;
|
||||
}
|
||||
|
||||
void InputManager::ClearBindStateFromSource(InputBindingKey key)
|
||||
{
|
||||
// Why are we doing it this way? Because any of the bindings could cause a reload and invalidate our iterators :(.
|
||||
// Axis handlers should be fine, so we'll do those as a first pass.
|
||||
for (const auto& [match_key, binding] : s_binding_map)
|
||||
{
|
||||
if (key.source_type != match_key.source_type || key.source_subtype != match_key.source_subtype ||
|
||||
key.source_index != match_key.source_index || !IsAxisHandler(binding->handler))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < binding->num_keys; i++)
|
||||
{
|
||||
if (binding->keys[i].MaskDirection() != match_key)
|
||||
continue;
|
||||
|
||||
std::get<InputAxisEventHandler>(binding->handler)(0.0f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Now go through the button handlers, and pick them off.
|
||||
bool matched;
|
||||
do
|
||||
{
|
||||
matched = false;
|
||||
|
||||
for (const auto& [match_key, binding] : s_binding_map)
|
||||
{
|
||||
if (key.source_type != match_key.source_type || key.source_subtype != match_key.source_subtype ||
|
||||
key.source_index != match_key.source_index || IsAxisHandler(binding->handler))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < binding->num_keys; i++)
|
||||
{
|
||||
if (binding->keys[i].MaskDirection() != match_key)
|
||||
continue;
|
||||
|
||||
// Skip if we weren't pressed.
|
||||
const u8 bit = static_cast<u8>(1) << i;
|
||||
if ((binding->current_mask & bit) == 0)
|
||||
continue;
|
||||
|
||||
// Only fire handler if we're changing from active state.
|
||||
const u8 current_mask = binding->current_mask;
|
||||
binding->current_mask &= ~bit;
|
||||
|
||||
if (current_mask == binding->full_mask)
|
||||
{
|
||||
std::get<InputButtonEventHandler>(binding->handler)(0.0f);
|
||||
matched = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Need to start again, might've reloaded.
|
||||
if (matched)
|
||||
break;
|
||||
}
|
||||
} while (matched);
|
||||
}
|
||||
|
||||
bool InputManager::PreprocessEvent(InputBindingKey key, float value, GenericInputBinding generic_key)
|
||||
{
|
||||
// does imgui want the event?
|
||||
@@ -950,15 +1018,34 @@ void InputManager::GenerateRelativeMouseEvents()
|
||||
{
|
||||
for (u32 axis = 0; axis < static_cast<u32>(static_cast<u8>(InputPointerAxis::Count)); axis++)
|
||||
{
|
||||
const InputBindingKey key(MakePointerAxisKey(device, static_cast<InputPointerAxis>(axis)));
|
||||
|
||||
PointerAxisState& state = s_pointer_state[device][axis];
|
||||
const float delta = static_cast<float>(state.delta.exchange(0, std::memory_order_acquire)) / 65536.0f;
|
||||
const float unclamped_value = delta * s_pointer_axis_scale[axis];
|
||||
float value = 0.0f;
|
||||
|
||||
const InputBindingKey key(MakePointerAxisKey(device, static_cast<InputPointerAxis>(axis)));
|
||||
if (axis >= static_cast<u32>(InputPointerAxis::WheelX) && ImGuiManager::ProcessPointerAxisEvent(key, unclamped_value))
|
||||
continue;
|
||||
if (axis <= static_cast<u32>(InputPointerAxis::Y))
|
||||
{
|
||||
s_pointer_pos[axis] += delta * s_pointer_axis_speed[axis];
|
||||
value = std::clamp(s_pointer_pos[axis], -1.0f, 1.0f);
|
||||
s_pointer_pos[axis] -= value;
|
||||
s_pointer_pos[axis] *= s_pointer_inertia;
|
||||
|
||||
value *= s_pointer_axis_range[axis];
|
||||
if (value > 0.0f)
|
||||
value += s_pointer_axis_dead_zone[axis];
|
||||
else if (value < 0.0f)
|
||||
value -= s_pointer_axis_dead_zone[axis];
|
||||
}
|
||||
else
|
||||
{
|
||||
// ImGui can consume mouse wheel events when the mouse is over a UI element.
|
||||
if (delta != 0.0f && ImGuiManager::ProcessPointerAxisEvent(key, delta))
|
||||
continue;
|
||||
|
||||
value = std::clamp(delta, -1.0f, 1.0f);
|
||||
}
|
||||
|
||||
const float value = std::clamp(unclamped_value, -1.0f, 1.0f);
|
||||
if (value != state.last_value)
|
||||
{
|
||||
state.last_value = value;
|
||||
@@ -1203,14 +1290,18 @@ void InputManager::ReloadBindings(SettingsInterface& si, SettingsInterface& bind
|
||||
for (u32 pad = 0; pad < PAD::NUM_CONTROLLER_PORTS; pad++)
|
||||
AddPadBindings(binding_si, pad, PAD::GetDefaultPadType(pad));
|
||||
|
||||
for (u32 axis = 0; axis < static_cast<u32>(InputPointerAxis::Count); axis++)
|
||||
constexpr float ui_ctrl_range = 100.0f;
|
||||
constexpr float pointer_sensitivity = 0.05f;
|
||||
for (u32 axis = 0; axis <= static_cast<u32>(InputPointerAxis::Y); axis++)
|
||||
{
|
||||
// From lilypad: 1 mouse pixel = 1/8th way down.
|
||||
const float default_scale = (axis <= static_cast<u32>(InputPointerAxis::Y)) ? 8.0f : 1.0f;
|
||||
s_pointer_axis_scale[axis] =
|
||||
1.0f /
|
||||
std::max(si.GetFloatValue("Pad", fmt::format("Pointer{}Scale", s_pointer_axis_names[axis]).c_str(), default_scale), 1.0f);
|
||||
s_pointer_axis_speed[axis] = si.GetFloatValue("Pad", fmt::format("Pointer{}Speed", s_pointer_axis_names[axis]).c_str(), 40.0f) /
|
||||
ui_ctrl_range * pointer_sensitivity;
|
||||
s_pointer_axis_dead_zone[axis] = std::min(
|
||||
si.GetFloatValue("Pad", fmt::format("Pointer{}DeadZone", s_pointer_axis_names[axis]).c_str(), 20.0f) / ui_ctrl_range, 1.0f);
|
||||
s_pointer_axis_range[axis] = 1.0f - s_pointer_axis_dead_zone[axis];
|
||||
}
|
||||
s_pointer_inertia = si.GetFloatValue("Pad", "PointerInertia", 10.0f) / ui_ctrl_range;
|
||||
s_pointer_pos = {};
|
||||
|
||||
for (u32 port = 0; port < USB::NUM_PORTS; port++)
|
||||
AddUSBBindings(binding_si, port);
|
||||
|
||||
@@ -257,6 +257,9 @@ namespace InputManager
|
||||
/// Returns true if anything was bound to this key, otherwise false.
|
||||
bool InvokeEvents(InputBindingKey key, float value, GenericInputBinding generic_key = GenericInputBinding::Unknown);
|
||||
|
||||
/// Clears internal state for any binds with a matching source/index.
|
||||
void ClearBindStateFromSource(InputBindingKey key);
|
||||
|
||||
/// Sets a hook which can be used to intercept events before they're processed by the normal bindings.
|
||||
/// This is typically used when binding new controls to detect what gets pressed.
|
||||
void SetHook(InputInterceptHook::Callback callback);
|
||||
|
||||
@@ -81,7 +81,7 @@ public:
|
||||
std::unique_ptr<HostDisplayTexture> CreateTexture(u32 width, u32 height, const void* data, u32 data_stride, bool dynamic = false) override;
|
||||
void UpdateTexture(id<MTLTexture> texture, u32 x, u32 y, u32 width, u32 height, const void* data, u32 data_stride);
|
||||
void UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* data, u32 data_stride) override;
|
||||
bool BeginPresent(bool frame_skip) override;
|
||||
PresentResult BeginPresent(bool frame_skip) override;
|
||||
void EndPresent() override;
|
||||
void SetVSync(VsyncMode mode) override;
|
||||
|
||||
|
||||
@@ -265,7 +265,7 @@ void MetalHostDisplay::UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y,
|
||||
|
||||
static bool s_capture_next = false;
|
||||
|
||||
bool MetalHostDisplay::BeginPresent(bool frame_skip)
|
||||
HostDisplay::PresentResult MetalHostDisplay::BeginPresent(bool frame_skip)
|
||||
{ @autoreleasepool {
|
||||
GSDeviceMTL* dev = static_cast<GSDeviceMTL*>(g_gs_device.get());
|
||||
if (dev && m_capture_start_frame && dev->FrameNo() == m_capture_start_frame)
|
||||
@@ -273,7 +273,7 @@ bool MetalHostDisplay::BeginPresent(bool frame_skip)
|
||||
if (frame_skip || m_window_info.type == WindowInfo::Type::Surfaceless || !g_gs_device)
|
||||
{
|
||||
ImGui::EndFrame();
|
||||
return false;
|
||||
return PresentResult::FrameSkipped;
|
||||
}
|
||||
id<MTLCommandBuffer> buf = dev->GetRenderCmdBuf();
|
||||
m_current_drawable = MRCRetain([m_layer nextDrawable]);
|
||||
@@ -284,13 +284,13 @@ bool MetalHostDisplay::BeginPresent(bool frame_skip)
|
||||
[buf popDebugGroup];
|
||||
dev->FlushEncoders();
|
||||
ImGui::EndFrame();
|
||||
return false;
|
||||
return PresentResult::FrameSkipped;
|
||||
}
|
||||
[m_pass_desc colorAttachments][0].texture = [m_current_drawable texture];
|
||||
id<MTLRenderCommandEncoder> enc = [buf renderCommandEncoderWithDescriptor:m_pass_desc];
|
||||
[enc setLabel:@"Present"];
|
||||
dev->m_current_render.encoder = MRCRetain(enc);
|
||||
return true;
|
||||
return PresentResult::OK;
|
||||
}}
|
||||
|
||||
void MetalHostDisplay::EndPresent()
|
||||
|
||||
@@ -335,13 +335,10 @@ bool OpenGLHostDisplay::UpdateImGuiFontTexture()
|
||||
return ImGui_ImplOpenGL3_CreateFontsTexture();
|
||||
}
|
||||
|
||||
bool OpenGLHostDisplay::BeginPresent(bool frame_skip)
|
||||
HostDisplay::PresentResult OpenGLHostDisplay::BeginPresent(bool frame_skip)
|
||||
{
|
||||
if (frame_skip || m_window_info.type == WindowInfo::Type::Surfaceless)
|
||||
{
|
||||
ImGui::EndFrame();
|
||||
return false;
|
||||
}
|
||||
return PresentResult::FrameSkipped;
|
||||
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
@@ -350,7 +347,7 @@ bool OpenGLHostDisplay::BeginPresent(bool frame_skip)
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
glViewport(0, 0, m_window_info.surface_width, m_window_info.surface_height);
|
||||
|
||||
return true;
|
||||
return PresentResult::OK;
|
||||
}
|
||||
|
||||
void OpenGLHostDisplay::EndPresent()
|
||||
|
||||
@@ -58,7 +58,7 @@ public:
|
||||
|
||||
void SetVSync(VsyncMode mode) override;
|
||||
|
||||
bool BeginPresent(bool frame_skip) override;
|
||||
PresentResult BeginPresent(bool frame_skip) override;
|
||||
void EndPresent() override;
|
||||
|
||||
bool SetGPUTimingEnabled(bool enabled) override;
|
||||
|
||||
@@ -294,7 +294,8 @@ bool VulkanHostDisplay::CreateDevice(const WindowInfo& wi, VsyncMode vsync)
|
||||
|
||||
bool VulkanHostDisplay::SetupDevice()
|
||||
{
|
||||
Vulkan::ShaderCache::Create(EmuFolders::Cache, SHADER_CACHE_VERSION, EmuConfig.GS.UseDebugDevice);
|
||||
Vulkan::ShaderCache::Create(EmuConfig.GS.DisableShaderCache ? std::string_view() : std::string_view(EmuFolders::Cache),
|
||||
SHADER_CACHE_VERSION, EmuConfig.GS.UseDebugDevice);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -339,17 +340,18 @@ bool VulkanHostDisplay::DoneCurrent()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VulkanHostDisplay::BeginPresent(bool frame_skip)
|
||||
HostDisplay::PresentResult VulkanHostDisplay::BeginPresent(bool frame_skip)
|
||||
{
|
||||
if (frame_skip || !m_swap_chain)
|
||||
{
|
||||
ImGui::EndFrame();
|
||||
return false;
|
||||
}
|
||||
return PresentResult::FrameSkipped;
|
||||
|
||||
// Previous frame needs to be presented before we can acquire the swap chain.
|
||||
g_vulkan_context->WaitForPresentComplete();
|
||||
|
||||
// Check if the device was lost.
|
||||
if (g_vulkan_context->CheckLastSubmitFail())
|
||||
return PresentResult::DeviceLost;
|
||||
|
||||
VkResult res = m_swap_chain->AcquireNextImage();
|
||||
if (res != VK_SUCCESS)
|
||||
{
|
||||
@@ -367,7 +369,7 @@ bool VulkanHostDisplay::BeginPresent(bool frame_skip)
|
||||
{
|
||||
Console.Error("Failed to recreate surface after loss");
|
||||
g_vulkan_context->ExecuteCommandBuffer(Vulkan::Context::WaitType::None);
|
||||
return false;
|
||||
return PresentResult::FrameSkipped;
|
||||
}
|
||||
|
||||
res = m_swap_chain->AcquireNextImage();
|
||||
@@ -380,7 +382,7 @@ bool VulkanHostDisplay::BeginPresent(bool frame_skip)
|
||||
// Still submit the command buffer, otherwise we'll end up with several frames waiting.
|
||||
LOG_VULKAN_ERROR(res, "vkAcquireNextImageKHR() failed: ");
|
||||
g_vulkan_context->ExecuteCommandBuffer(Vulkan::Context::WaitType::None);
|
||||
return false;
|
||||
return PresentResult::FrameSkipped;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -401,7 +403,7 @@ bool VulkanHostDisplay::BeginPresent(bool frame_skip)
|
||||
const VkRect2D scissor{{0, 0}, {static_cast<u32>(swap_chain_texture.GetWidth()), static_cast<u32>(swap_chain_texture.GetHeight())}};
|
||||
vkCmdSetViewport(g_vulkan_context->GetCurrentCommandBuffer(), 0, 1, &vp);
|
||||
vkCmdSetScissor(g_vulkan_context->GetCurrentCommandBuffer(), 0, 1, &scissor);
|
||||
return true;
|
||||
return PresentResult::OK;
|
||||
}
|
||||
|
||||
void VulkanHostDisplay::EndPresent()
|
||||
|
||||
@@ -47,7 +47,7 @@ public:
|
||||
|
||||
void SetVSync(VsyncMode mode) override;
|
||||
|
||||
bool BeginPresent(bool frame_skip) override;
|
||||
PresentResult BeginPresent(bool frame_skip) override;
|
||||
void EndPresent() override;
|
||||
|
||||
bool SetGPUTimingEnabled(bool enabled) override;
|
||||
|
||||
@@ -209,15 +209,15 @@ static bool DoGSOpen(GSRendererType renderer, u8* basemem)
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
if (!g_gs_device->Create())
|
||||
{
|
||||
if (!g_gs_device->Create())
|
||||
{
|
||||
g_gs_device->Destroy();
|
||||
g_gs_device.reset();
|
||||
return false;
|
||||
}
|
||||
g_gs_device->Destroy();
|
||||
g_gs_device.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!g_gs_renderer)
|
||||
{
|
||||
if (renderer == GSRendererType::Null)
|
||||
{
|
||||
g_gs_renderer = std::make_unique<GSRendererNull>();
|
||||
@@ -230,55 +230,71 @@ static bool DoGSOpen(GSRendererType renderer, u8* basemem)
|
||||
{
|
||||
g_gs_renderer = std::unique_ptr<GSRenderer>(MULTI_ISA_SELECT(makeGSRendererSW)(GSConfig.SWExtraThreads));
|
||||
}
|
||||
|
||||
g_gs_renderer->SetRegsMem(basemem);
|
||||
g_gs_renderer->ResetPCRTC();
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
else
|
||||
{
|
||||
Host::ReportFormattedErrorAsync("GS", "GS error: Exception caught in GSopen: %s", ex.what());
|
||||
g_gs_renderer.reset();
|
||||
g_gs_device->Destroy();
|
||||
g_gs_device.reset();
|
||||
return false;
|
||||
Console.Warning("(DoGSOpen) Using existing renderer.");
|
||||
}
|
||||
|
||||
GSConfig.OsdShowGPU = EmuConfig.GS.OsdShowGPU && g_host_display->SetGPUTimingEnabled(true);
|
||||
|
||||
g_gs_renderer->SetRegsMem(basemem);
|
||||
g_perfmon.Reset();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GSreopen(bool recreate_display, const Pcsx2Config::GSOptions& old_config)
|
||||
bool GSreopen(bool recreate_display, bool recreate_renderer, const Pcsx2Config::GSOptions& old_config)
|
||||
{
|
||||
Console.WriteLn("Reopening GS with %s display", recreate_display ? "new" : "existing");
|
||||
|
||||
g_gs_renderer->Flush(GSState::GSFlushReason::GSREOPEN);
|
||||
if (recreate_renderer)
|
||||
g_gs_renderer->Flush(GSState::GSFlushReason::GSREOPEN);
|
||||
|
||||
if (GSConfig.UserHacks_ReadTCOnClose)
|
||||
g_gs_renderer->ReadbackTextureCache();
|
||||
|
||||
freezeData fd = {};
|
||||
if (g_gs_renderer->Freeze(&fd, true) != 0)
|
||||
std::unique_ptr<u8[]> fd_data;
|
||||
if (recreate_renderer)
|
||||
{
|
||||
Console.Error("(GSreopen) Failed to get GS freeze size");
|
||||
return false;
|
||||
}
|
||||
if (g_gs_renderer->Freeze(&fd, true) != 0)
|
||||
{
|
||||
Console.Error("(GSreopen) Failed to get GS freeze size");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unique_ptr<u8[]> fd_data = std::make_unique<u8[]>(fd.size);
|
||||
fd.data = fd_data.get();
|
||||
if (g_gs_renderer->Freeze(&fd, false) != 0)
|
||||
fd_data = std::make_unique<u8[]>(fd.size);
|
||||
fd.data = fd_data.get();
|
||||
if (g_gs_renderer->Freeze(&fd, false) != 0)
|
||||
{
|
||||
Console.Error("(GSreopen) Failed to freeze GS");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Error("(GSreopen) Failed to freeze GS");
|
||||
return false;
|
||||
// Make sure nothing is left over.
|
||||
g_gs_renderer->PurgeTextureCache();
|
||||
g_gs_renderer->PurgePool();
|
||||
}
|
||||
|
||||
if (recreate_display)
|
||||
{
|
||||
g_gs_device->ResetAPIState();
|
||||
if (Host::BeginPresentFrame(true))
|
||||
if (Host::BeginPresentFrame(false) == HostDisplay::PresentResult::OK)
|
||||
Host::EndPresentFrame();
|
||||
}
|
||||
|
||||
u8* basemem = g_gs_renderer->GetRegsMem();
|
||||
const u32 gamecrc = g_gs_renderer->GetGameCRC();
|
||||
g_gs_renderer->Destroy();
|
||||
g_gs_renderer.reset();
|
||||
if (recreate_renderer)
|
||||
{
|
||||
g_gs_renderer->Destroy();
|
||||
g_gs_renderer.reset();
|
||||
}
|
||||
|
||||
g_gs_device->Destroy();
|
||||
g_gs_device.reset();
|
||||
|
||||
@@ -327,13 +343,17 @@ bool GSreopen(bool recreate_display, const Pcsx2Config::GSOptions& old_config)
|
||||
}
|
||||
}
|
||||
|
||||
if (g_gs_renderer->Defrost(&fd) != 0)
|
||||
if (recreate_renderer)
|
||||
{
|
||||
Console.Error("(GSreopen) Failed to defrost");
|
||||
return false;
|
||||
if (g_gs_renderer->Defrost(&fd) != 0)
|
||||
{
|
||||
Console.Error("(GSreopen) Failed to defrost");
|
||||
return false;
|
||||
}
|
||||
|
||||
g_gs_renderer->SetGameCRC(gamecrc);
|
||||
}
|
||||
|
||||
g_gs_renderer->SetGameCRC(gamecrc);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -698,18 +718,17 @@ void GSUpdateConfig(const Pcsx2Config::GSOptions& new_config)
|
||||
GSConfig.DisableShaderCache != old_config.DisableShaderCache ||
|
||||
GSConfig.DisableThreadedPresentation != old_config.DisableThreadedPresentation
|
||||
);
|
||||
if (!GSreopen(do_full_restart, old_config))
|
||||
if (!GSreopen(do_full_restart, true, old_config))
|
||||
pxFailRel("Failed to do full GS reopen");
|
||||
return;
|
||||
}
|
||||
|
||||
// Options which aren't using the global struct yet, so we need to recreate all GS objects.
|
||||
if (
|
||||
GSConfig.UpscaleMultiplier != old_config.UpscaleMultiplier ||
|
||||
GSConfig.SWExtraThreads != old_config.SWExtraThreads ||
|
||||
GSConfig.SWExtraThreadsHeight != old_config.SWExtraThreadsHeight)
|
||||
{
|
||||
if (!GSreopen(false, old_config))
|
||||
if (!GSreopen(false, true, old_config))
|
||||
pxFailRel("Failed to do quick GS reopen");
|
||||
|
||||
return;
|
||||
@@ -736,7 +755,6 @@ void GSUpdateConfig(const Pcsx2Config::GSOptions& new_config)
|
||||
GSConfig.TriFilter != old_config.TriFilter ||
|
||||
GSConfig.GPUPaletteConversion != old_config.GPUPaletteConversion ||
|
||||
GSConfig.PreloadFrameWithGSData != old_config.PreloadFrameWithGSData ||
|
||||
GSConfig.WrapGSMem != old_config.WrapGSMem ||
|
||||
GSConfig.UserHacks_CPUFBConversion != old_config.UserHacks_CPUFBConversion ||
|
||||
GSConfig.UserHacks_DisableDepthSupport != old_config.UserHacks_DisableDepthSupport ||
|
||||
GSConfig.UserHacks_DisablePartialInvalidation != old_config.UserHacks_DisablePartialInvalidation ||
|
||||
@@ -745,6 +763,8 @@ void GSUpdateConfig(const Pcsx2Config::GSOptions& new_config)
|
||||
GSConfig.UserHacks_CPUCLUTRender != old_config.UserHacks_CPUCLUTRender ||
|
||||
GSConfig.UserHacks_GPUTargetCLUTMode != old_config.UserHacks_GPUTargetCLUTMode)
|
||||
{
|
||||
if (GSConfig.UserHacks_ReadTCOnClose)
|
||||
g_gs_renderer->ReadbackTextureCache();
|
||||
g_gs_renderer->PurgeTextureCache();
|
||||
g_gs_renderer->PurgePool();
|
||||
}
|
||||
@@ -787,7 +807,7 @@ void GSSwitchRenderer(GSRendererType new_renderer)
|
||||
const bool recreate_display = (!is_software_switch && existing_api != GetAPIForRenderer(new_renderer));
|
||||
const Pcsx2Config::GSOptions old_config(GSConfig);
|
||||
GSConfig.Renderer = new_renderer;
|
||||
if (!GSreopen(recreate_display, old_config))
|
||||
if (!GSreopen(recreate_display, true, old_config))
|
||||
pxFailRel("Failed to reopen GS for renderer switch.");
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ s16 GSLookupBeforeDrawFunctionId(const std::string_view& name);
|
||||
int GSinit();
|
||||
void GSshutdown();
|
||||
bool GSopen(const Pcsx2Config::GSOptions& config, GSRendererType renderer, u8* basemem);
|
||||
bool GSreopen(bool recreate_display, const Pcsx2Config::GSOptions& old_config);
|
||||
bool GSreopen(bool recreate_display, bool recreate_renderer, const Pcsx2Config::GSOptions& old_config);
|
||||
void GSreset(bool hardware_reset);
|
||||
void GSclose();
|
||||
void GSgifSoftReset(u32 mask);
|
||||
|
||||
@@ -406,6 +406,7 @@ void GSClut::Read32(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA)
|
||||
u32 CBW;
|
||||
GSVector2i offset;
|
||||
GSVector2i size;
|
||||
float scale;
|
||||
if (!TEX0.CSM)
|
||||
{
|
||||
CBW = 0; // don't care
|
||||
@@ -422,7 +423,7 @@ void GSClut::Read32(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA)
|
||||
size.y = 1;
|
||||
}
|
||||
|
||||
GSTexture* src = g_gs_renderer->LookupPaletteSource(TEX0.CBP, TEX0.CPSM, CBW, offset, size);
|
||||
GSTexture* src = g_gs_renderer->LookupPaletteSource(TEX0.CBP, TEX0.CPSM, CBW, offset, &scale, size);
|
||||
if (src)
|
||||
{
|
||||
GSTexture* dst = is_4bit ? m_gpu_clut4 : m_gpu_clut8;
|
||||
@@ -438,7 +439,7 @@ void GSClut::Read32(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA)
|
||||
{
|
||||
GL_PUSH("Update GPU CLUT [CBP=%04X, CPSM=%s, CBW=%u, CSA=%u, Offset=(%d,%d)]",
|
||||
TEX0.CBP, psm_str(TEX0.CPSM), CBW, TEX0.CSA, offset.x, offset.y);
|
||||
g_gs_device->UpdateCLUTTexture(src, offset.x, offset.y, dst, dOffset, dst_size);
|
||||
g_gs_device->UpdateCLUTTexture(src, scale, offset.x, offset.y, dst, dOffset, dst_size);
|
||||
m_current_gpu_clut = dst;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,15 +24,6 @@ const CRC::Game CRC::m_games[] =
|
||||
{
|
||||
// Note: IDs 0x7ACF7E03, 0x7D4EA48F, 0x37C53760 - shouldn't be added as it's from the multiloaders when packing games.
|
||||
{0x00000000, NoTitle /* NoRegion */},
|
||||
{0x9AAC5309, FFX2 /* EU */},
|
||||
{0x9AAC530C, FFX2 /* FR */},
|
||||
{0x9AAC530A, FFX2 /* ES */},
|
||||
{0x9AAC530D, FFX2 /* DE */},
|
||||
{0x9AAC530B, FFX2 /* IT */},
|
||||
{0x48FE0C71, FFX2 /* US */},
|
||||
{0x8A6D7F14, FFX2 /* JP */},
|
||||
{0xE1FD9A2D, FFX2 /* JP */}, // int.
|
||||
{0x11624CD6, FFX2 /* KO */},
|
||||
{0x08C1ED4D, HauntingGround /* EU */},
|
||||
{0x2CD5794C, HauntingGround /* EU */},
|
||||
{0x867BB945, HauntingGround /* JP */},
|
||||
|
||||
@@ -23,7 +23,6 @@ public:
|
||||
enum Title : u32
|
||||
{
|
||||
NoTitle,
|
||||
FFX2,
|
||||
GetawayGames,
|
||||
HauntingGround,
|
||||
ICO,
|
||||
|
||||
@@ -180,6 +180,12 @@ public:
|
||||
return BNHelper(*this, x, y).value();
|
||||
}
|
||||
|
||||
/// Get the block number of the given pixel, without wrapping to MAX_BLOCKS
|
||||
u32 bnNoWrap(int x, int y) const
|
||||
{
|
||||
return BNHelper(*this, x, y).valueNoWrap();
|
||||
}
|
||||
|
||||
/// Get a helper class for efficiently calculating multiple block numbers
|
||||
BNHelper bnMulti(int x, int y) const
|
||||
{
|
||||
@@ -481,7 +487,7 @@ public:
|
||||
static psm_t m_psm[64];
|
||||
static readImage m_readImageX;
|
||||
|
||||
static const int m_vmsize = 1024 * 1024 * 4;
|
||||
static constexpr int m_vmsize = 1024 * 1024 * 4;
|
||||
|
||||
u8* m_vm8;
|
||||
|
||||
@@ -981,10 +987,15 @@ public:
|
||||
off.loopPixels(r, vm32(), (u32*)src, pitch, [&](u32* dst, u32* src) { *dst = *src; });
|
||||
}
|
||||
|
||||
void WritePixel32(u8* RESTRICT src, u32 pitch, const GSOffset& off, const GSVector4i& r, u32 write_mask)
|
||||
{
|
||||
off.loopPixels(r, vm32(), (u32*)src, pitch, [&](u32* dst, u32* src) { *dst = (*dst & ~write_mask) | (*src & write_mask); });
|
||||
}
|
||||
|
||||
void WritePixel24(u8* RESTRICT src, u32 pitch, const GSOffset& off, const GSVector4i& r)
|
||||
{
|
||||
off.loopPixels(r, vm32(), (u32*)src, pitch,
|
||||
[&](u32* dst, u32* src)
|
||||
[&](u32* dst, u32* src)
|
||||
{
|
||||
*dst = (*dst & 0xff000000) | (*src & 0x00ffffff);
|
||||
});
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#define PAGE_SIZE 8192u
|
||||
#define BLOCK_SIZE 256u
|
||||
#define COLUMN_SIZE 64u
|
||||
#define BLOCKS_PER_PAGE (PAGE_SIZE / BLOCK_SIZE)
|
||||
|
||||
#define MAX_PAGES (VM_SIZE / PAGE_SIZE)
|
||||
#define MAX_BLOCKS (VM_SIZE / BLOCK_SIZE)
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <iomanip> // Dump Verticles
|
||||
|
||||
int GSState::s_n = 0;
|
||||
int GSState::s_transfer_n = 0;
|
||||
|
||||
static __fi bool IsAutoFlushEnabled()
|
||||
{
|
||||
@@ -37,14 +38,61 @@ static __fi bool IsFirstProvokingVertex()
|
||||
return (GSConfig.Renderer != GSRendererType::SW && !g_gs_device->Features().provoking_vertex_last);
|
||||
}
|
||||
|
||||
constexpr int GSState::GetSaveStateSize()
|
||||
{
|
||||
int size = 0;
|
||||
|
||||
size += sizeof(STATE_VERSION);
|
||||
size += sizeof(m_env.PRIM);
|
||||
size += sizeof(m_env.PRMODECONT);
|
||||
size += sizeof(m_env.TEXCLUT);
|
||||
size += sizeof(m_env.SCANMSK);
|
||||
size += sizeof(m_env.TEXA);
|
||||
size += sizeof(m_env.FOGCOL);
|
||||
size += sizeof(m_env.DIMX);
|
||||
size += sizeof(m_env.DTHE);
|
||||
size += sizeof(m_env.COLCLAMP);
|
||||
size += sizeof(m_env.PABE);
|
||||
size += sizeof(m_env.BITBLTBUF);
|
||||
size += sizeof(m_env.TRXDIR);
|
||||
size += sizeof(m_env.TRXPOS);
|
||||
size += sizeof(m_env.TRXREG);
|
||||
size += sizeof(m_env.TRXREG); // obsolete
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
size += sizeof(m_env.CTXT[i].XYOFFSET);
|
||||
size += sizeof(m_env.CTXT[i].TEX0);
|
||||
size += sizeof(m_env.CTXT[i].TEX1);
|
||||
size += sizeof(m_env.CTXT[i].CLAMP);
|
||||
size += sizeof(m_env.CTXT[i].MIPTBP1);
|
||||
size += sizeof(m_env.CTXT[i].MIPTBP2);
|
||||
size += sizeof(m_env.CTXT[i].SCISSOR);
|
||||
size += sizeof(m_env.CTXT[i].ALPHA);
|
||||
size += sizeof(m_env.CTXT[i].TEST);
|
||||
size += sizeof(m_env.CTXT[i].FBA);
|
||||
size += sizeof(m_env.CTXT[i].FRAME);
|
||||
size += sizeof(m_env.CTXT[i].ZBUF);
|
||||
}
|
||||
|
||||
size += sizeof(m_v.RGBAQ);
|
||||
size += sizeof(m_v.ST);
|
||||
size += sizeof(m_v.UV);
|
||||
size += sizeof(m_v.FOG);
|
||||
size += sizeof(m_v.XYZ);
|
||||
size += sizeof(GIFReg); // obsolete
|
||||
|
||||
size += sizeof(m_tr.x);
|
||||
size += sizeof(m_tr.y);
|
||||
size += GSLocalMemory::m_vmsize;
|
||||
size += (sizeof(GIFPath::tag) + sizeof(GIFPath::reg)) * 4 /* std::size(GSState::m_path) */; // std::size won't work without an instance.
|
||||
size += sizeof(m_q);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
GSState::GSState()
|
||||
: m_version(STATE_VERSION)
|
||||
, m_q(1.0f)
|
||||
, m_scanmask_used(0)
|
||||
, tex_flushed(true)
|
||||
, m_vt(this, IsFirstProvokingVertex())
|
||||
, m_regs(NULL)
|
||||
, m_crc(0)
|
||||
: m_vt(this, IsFirstProvokingVertex())
|
||||
{
|
||||
// m_nativeres seems to be a hack. Unfortunately it impacts draw call number which make debug painful in the replayer.
|
||||
// Let's keep it disabled to ease debug.
|
||||
@@ -52,6 +100,7 @@ GSState::GSState()
|
||||
m_mipmap = GSConfig.Mipmap;
|
||||
|
||||
s_n = 0;
|
||||
s_transfer_n = 0;
|
||||
|
||||
memset(&m_v, 0, sizeof(m_v));
|
||||
memset(&m_vertex, 0, sizeof(m_vertex));
|
||||
@@ -63,54 +112,6 @@ GSState::GSState()
|
||||
|
||||
m_draw_transfers.clear();
|
||||
|
||||
m_sssize = 0;
|
||||
|
||||
m_sssize += sizeof(m_version);
|
||||
m_sssize += sizeof(m_env.PRIM);
|
||||
m_sssize += sizeof(m_env.PRMODECONT);
|
||||
m_sssize += sizeof(m_env.TEXCLUT);
|
||||
m_sssize += sizeof(m_env.SCANMSK);
|
||||
m_sssize += sizeof(m_env.TEXA);
|
||||
m_sssize += sizeof(m_env.FOGCOL);
|
||||
m_sssize += sizeof(m_env.DIMX);
|
||||
m_sssize += sizeof(m_env.DTHE);
|
||||
m_sssize += sizeof(m_env.COLCLAMP);
|
||||
m_sssize += sizeof(m_env.PABE);
|
||||
m_sssize += sizeof(m_env.BITBLTBUF);
|
||||
m_sssize += sizeof(m_env.TRXDIR);
|
||||
m_sssize += sizeof(m_env.TRXPOS);
|
||||
m_sssize += sizeof(m_env.TRXREG);
|
||||
m_sssize += sizeof(m_env.TRXREG); // obsolete
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
m_sssize += sizeof(m_env.CTXT[i].XYOFFSET);
|
||||
m_sssize += sizeof(m_env.CTXT[i].TEX0);
|
||||
m_sssize += sizeof(m_env.CTXT[i].TEX1);
|
||||
m_sssize += sizeof(m_env.CTXT[i].CLAMP);
|
||||
m_sssize += sizeof(m_env.CTXT[i].MIPTBP1);
|
||||
m_sssize += sizeof(m_env.CTXT[i].MIPTBP2);
|
||||
m_sssize += sizeof(m_env.CTXT[i].SCISSOR);
|
||||
m_sssize += sizeof(m_env.CTXT[i].ALPHA);
|
||||
m_sssize += sizeof(m_env.CTXT[i].TEST);
|
||||
m_sssize += sizeof(m_env.CTXT[i].FBA);
|
||||
m_sssize += sizeof(m_env.CTXT[i].FRAME);
|
||||
m_sssize += sizeof(m_env.CTXT[i].ZBUF);
|
||||
}
|
||||
|
||||
m_sssize += sizeof(m_v.RGBAQ);
|
||||
m_sssize += sizeof(m_v.ST);
|
||||
m_sssize += sizeof(m_v.UV);
|
||||
m_sssize += sizeof(m_v.FOG);
|
||||
m_sssize += sizeof(m_v.XYZ);
|
||||
m_sssize += sizeof(GIFReg); // obsolete
|
||||
|
||||
m_sssize += sizeof(m_tr.x);
|
||||
m_sssize += sizeof(m_tr.y);
|
||||
m_sssize += m_mem.m_vmsize;
|
||||
m_sssize += (sizeof(m_path[0].tag) + sizeof(m_path[0].reg)) * std::size(m_path);
|
||||
m_sssize += sizeof(m_q);
|
||||
|
||||
PRIM = &m_env.PRIM;
|
||||
//CSR->rREV = 0x20;
|
||||
m_env.PRMODECONT.AC = 1;
|
||||
@@ -285,6 +286,14 @@ void GSState::ResetHandlers()
|
||||
m_fpGIFRegHandlers[GIF_A_D_REG_LABEL] = &GSState::GIFRegHandlerNull;
|
||||
}
|
||||
|
||||
void GSState::ResetPCRTC()
|
||||
{
|
||||
PCRTCDisplays.SetVideoMode(GetVideoMode());
|
||||
PCRTCDisplays.EnableDisplays(m_regs->PMODE, m_regs->SMODE2, isReallyInterlaced());
|
||||
PCRTCDisplays.SetRects(0, m_regs->DISP[0].DISPLAY, m_regs->DISP[0].DISPFB);
|
||||
PCRTCDisplays.SetRects(1, m_regs->DISP[1].DISPLAY, m_regs->DISP[1].DISPFB);
|
||||
}
|
||||
|
||||
void GSState::UpdateSettings(const Pcsx2Config::GSOptions& old_config)
|
||||
{
|
||||
m_mipmap = GSConfig.Mipmap;
|
||||
@@ -340,264 +349,6 @@ GSVideoMode GSState::GetVideoMode()
|
||||
__assume(0); // unreachable
|
||||
}
|
||||
|
||||
bool GSState::IsAnalogue()
|
||||
{
|
||||
return GetVideoMode() == GSVideoMode::NTSC || GetVideoMode() == GSVideoMode::PAL || GetVideoMode() == GSVideoMode::HDTV_1080I;
|
||||
}
|
||||
|
||||
GSVector4i GSState::GetFrameMagnifiedRect(int i)
|
||||
{
|
||||
GSVector4i rectangle = { 0, 0, 0, 0 };
|
||||
|
||||
if (!IsEnabled(i))
|
||||
return rectangle;
|
||||
|
||||
const int videomode = static_cast<int>(GetVideoMode()) - 1;
|
||||
const auto& DISP = m_regs->DISP[i].DISPLAY;
|
||||
const bool ignore_offset = !GSConfig.PCRTCOffsets;
|
||||
|
||||
const u32 DW = DISP.DW + 1;
|
||||
const u32 DH = DISP.DH + 1;
|
||||
;
|
||||
// The number of sub pixels to draw are given in DH and DW, the MAGH/V relates to the size of the original square in the FB
|
||||
// but the size it's drawn to uses the default size of the display mode (for PAL/NTSC this is a MAGH of 3)
|
||||
// so for example a game will have a DW of 2559 and a MAGH of 4 to make it 512 (from the FB), but because it's drawing 2560 subpixels
|
||||
// it will cover the entire 640 wide of the screen (2560 / (3+1)).
|
||||
int width;
|
||||
int height;
|
||||
if (ignore_offset)
|
||||
{
|
||||
width = (DW / (DISP.MAGH + 1));
|
||||
height = (DH / (DISP.MAGV + 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
width = (DW / (VideoModeDividers[videomode].x + 1));
|
||||
height = (DH / (VideoModeDividers[videomode].y + 1));
|
||||
}
|
||||
|
||||
int res_multi = 1;
|
||||
|
||||
if (isinterlaced() && m_regs->SMODE2.FFMD && height > 1)
|
||||
res_multi = 2;
|
||||
|
||||
// Set up the display rectangle based on the values obtained from DISPLAY registers
|
||||
rectangle.right = width;
|
||||
rectangle.bottom = height / res_multi;
|
||||
|
||||
return rectangle;
|
||||
}
|
||||
|
||||
int GSState::GetDisplayHMagnification()
|
||||
{
|
||||
// Pick one of the DISPLAY's and hope that they are both the same. Favour DISPLAY[1]
|
||||
for (int i = 1; i >= 0; i--)
|
||||
{
|
||||
if (IsEnabled(i))
|
||||
return m_regs->DISP[i].DISPLAY.MAGH + 1;
|
||||
}
|
||||
|
||||
// If neither DISPLAY is enabled, fallback to resolution offset (should never happen)
|
||||
const int videomode = static_cast<int>(GetVideoMode()) - 1;
|
||||
return VideoModeDividers[videomode].x + 1;
|
||||
}
|
||||
|
||||
GSVector4i GSState::GetDisplayRect(int i)
|
||||
{
|
||||
GSVector4i rectangle = { 0, 0, 0, 0 };
|
||||
|
||||
if (i == -1)
|
||||
{
|
||||
return GetDisplayRect(0).runion(GetDisplayRect(1));
|
||||
}
|
||||
|
||||
if (!IsEnabled(i))
|
||||
return rectangle;
|
||||
|
||||
const auto& DISP = m_regs->DISP[i].DISPLAY;
|
||||
|
||||
const u32 DW = DISP.DW + 1;
|
||||
const u32 DH = DISP.DH + 1;
|
||||
const u32 MAGH = DISP.MAGH + 1;
|
||||
const u32 MAGV = DISP.MAGV + 1;
|
||||
|
||||
const GSVector2i magnification(MAGH, MAGV);
|
||||
|
||||
const int width = DW / magnification.x;
|
||||
const int height = DH / magnification.y;
|
||||
|
||||
const GSVector2i offsets = GetResolutionOffset(i);
|
||||
|
||||
// Set up the display rectangle based on the values obtained from DISPLAY registers
|
||||
rectangle.left = offsets.x;
|
||||
rectangle.top = offsets.y;
|
||||
|
||||
rectangle.right = rectangle.left + width;
|
||||
rectangle.bottom = rectangle.top + height;
|
||||
|
||||
return rectangle;
|
||||
}
|
||||
|
||||
GSVector2i GSState::GetResolutionOffset(int i)
|
||||
{
|
||||
GSVector2i offset = { 0, 0 };
|
||||
|
||||
if (!IsEnabled(i))
|
||||
return offset;
|
||||
|
||||
const int videomode = static_cast<int>(GetVideoMode()) - 1;
|
||||
const auto& DISP = m_regs->DISP[i].DISPLAY;
|
||||
|
||||
const auto& SMODE2 = m_regs->SMODE2;
|
||||
const int res_multi = (SMODE2.INT + 1);
|
||||
const GSVector4i offsets = !GSConfig.PCRTCOverscan ? VideoModeOffsets[videomode] : VideoModeOffsetsOverscan[videomode];
|
||||
|
||||
offset.x = (static_cast<int>(DISP.DX) - offsets.z) / (VideoModeDividers[videomode].x + 1);
|
||||
offset.y = (static_cast<int>(DISP.DY) - (offsets.w * ((IsAnalogue() && res_multi) ? res_multi : 1))) / (VideoModeDividers[videomode].y + 1);
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
GSVector2i GSState::GetResolution()
|
||||
{
|
||||
const int videomode = static_cast<int>(GetVideoMode()) - 1;
|
||||
const bool ignore_offset = !GSConfig.PCRTCOffsets;
|
||||
|
||||
const GSVector4i offsets = !GSConfig.PCRTCOverscan ? VideoModeOffsets[videomode] : VideoModeOffsetsOverscan[videomode];
|
||||
|
||||
GSVector2i resolution(offsets.x, offsets.y);
|
||||
|
||||
// The resolution of the framebuffer is double when in FRAME mode and interlaced.
|
||||
// Also we need a special check because no-interlace patches like to render in the original height, but in non-interlaced mode
|
||||
// which means it would normally go off the bottom of the screen. Advantages of emulation, i guess... Limited to Ignore Offsets + Deinterlacing = Off.
|
||||
if ((isinterlaced() && !m_regs->SMODE2.FFMD) || (GSConfig.InterlaceMode == GSInterlaceMode::Off && !GSConfig.PCRTCOffsets && !isinterlaced()))
|
||||
resolution.y *= 2;
|
||||
|
||||
if (ignore_offset)
|
||||
{
|
||||
// Ideally we'd just cut the width at the resolution, but of course we have to hack the hack...
|
||||
// Some games (Mortal Kombat Armageddon) render the image at 834 pixels then shrink it to 624 pixels
|
||||
// which does fit, but when we ignore offsets we go on framebuffer size and some other games
|
||||
// such as Johnny Mosleys Mad Trix and Transformers render too much but design it to go off the screen.
|
||||
int magnified_width = (VideoModeDividers[videomode].z + 1) / GetDisplayHMagnification();
|
||||
|
||||
// When viewing overscan allow up to the overscan size
|
||||
if (GSConfig.PCRTCOverscan)
|
||||
magnified_width = std::max(magnified_width, offsets.x);
|
||||
|
||||
GSVector4i total_rect = GetDisplayRect(0).runion(GetDisplayRect(1));
|
||||
total_rect.z = total_rect.z - total_rect.x;
|
||||
total_rect.w = total_rect.w - total_rect.y;
|
||||
total_rect.z = std::min(total_rect.z, magnified_width);
|
||||
total_rect.w = std::min(total_rect.w, resolution.y);
|
||||
resolution.x = total_rect.z;
|
||||
resolution.y = total_rect.w;
|
||||
}
|
||||
|
||||
return resolution;
|
||||
}
|
||||
|
||||
GSVector4i GSState::GetFrameRect(int i, bool ignore_off)
|
||||
{
|
||||
// If no specific context is requested then pass the merged rectangle as return value
|
||||
if (i == -1)
|
||||
return GetFrameRect(0, ignore_off).runion(GetFrameRect(1, ignore_off));
|
||||
|
||||
GSVector4i rectangle = { 0, 0, 0, 0 };
|
||||
|
||||
if (!IsEnabled(i))
|
||||
return rectangle;
|
||||
|
||||
const auto& DISP = m_regs->DISP[i].DISPLAY;
|
||||
|
||||
const u32 DW = DISP.DW + 1;
|
||||
const u32 DH = DISP.DH + 1;
|
||||
const GSVector2i magnification(DISP.MAGH+1, DISP.MAGV + 1);
|
||||
|
||||
const u32 DBX = m_regs->DISP[i].DISPFB.DBX;
|
||||
int DBY = m_regs->DISP[i].DISPFB.DBY;
|
||||
|
||||
|
||||
const int w = DW / magnification.x;
|
||||
const int h = DH / magnification.y;
|
||||
|
||||
// If the combined height overflows 2048, it's likely adding a bit of extra data before the picture for offsetting the interlace
|
||||
// only game known to do this is NASCAR '08
|
||||
if (!ignore_off && (DBY + h) >= 2048)
|
||||
DBY = DBY - 2048;
|
||||
|
||||
rectangle.left = (ignore_off) ? 0 : DBX;
|
||||
rectangle.top = (ignore_off) ? 0 : DBY;
|
||||
|
||||
rectangle.right = rectangle.left + w;
|
||||
rectangle.bottom = rectangle.top + h;
|
||||
|
||||
if (isinterlaced() && m_regs->SMODE2.FFMD && h > 1)
|
||||
{
|
||||
rectangle.bottom += 1;
|
||||
rectangle.bottom >>= 1;
|
||||
}
|
||||
|
||||
return rectangle;
|
||||
}
|
||||
|
||||
int GSState::GetFramebufferHeight()
|
||||
{
|
||||
// Framebuffer height is 11 bits max
|
||||
constexpr int height_limit = (1 << 11);
|
||||
|
||||
const GSVector4i disp1_rect = GetFrameRect(0, true);
|
||||
const GSVector4i disp2_rect = GetFrameRect(1, true);
|
||||
const GSVector4i combined = disp1_rect.runion(disp2_rect);
|
||||
|
||||
// DBY isn't an offset to the frame memory but rather an offset to read output circuit inside
|
||||
// the frame memory, hence the top offset should also be calculated for the total height of the
|
||||
// frame memory. Also we need to wrap the value only when we're dealing with values with range of the
|
||||
// frame memory (offset + read output circuit height, IOW bottom of merged_output)
|
||||
const int max_height = std::max(disp1_rect.height(), disp2_rect.height());
|
||||
const int frame_memory_height = std::max(max_height, combined.bottom % height_limit);
|
||||
|
||||
if (frame_memory_height > 1024)
|
||||
GL_PERF("Massive framebuffer height detected! (height:%d)", frame_memory_height);
|
||||
|
||||
return frame_memory_height;
|
||||
}
|
||||
|
||||
int GSState::GetFramebufferBitDepth()
|
||||
{
|
||||
if (IsEnabled(0))
|
||||
return GSLocalMemory::m_psm[m_regs->DISP[0].DISPFB.PSM].bpp;
|
||||
else if (IsEnabled(1))
|
||||
return GSLocalMemory::m_psm[m_regs->DISP[1].DISPFB.PSM].bpp;
|
||||
|
||||
return 32;
|
||||
}
|
||||
|
||||
int GSState::GetFramebufferWidth()
|
||||
{
|
||||
const GSVector4i disp1_rect = GetFrameRect(0, true);
|
||||
const GSVector4i disp2_rect = GetFrameRect(1, true);
|
||||
|
||||
const int max_width = std::max(disp1_rect.width(), disp2_rect.width());
|
||||
|
||||
return max_width;
|
||||
}
|
||||
|
||||
bool GSState::IsEnabled(int i)
|
||||
{
|
||||
ASSERT(i >= 0 && i < 2);
|
||||
|
||||
const auto& DISP = m_regs->DISP[i].DISPLAY;
|
||||
|
||||
const bool disp1_enabled = m_regs->PMODE.EN1;
|
||||
const bool disp2_enabled = m_regs->PMODE.EN2;
|
||||
|
||||
if ((i == 0 && disp1_enabled) || (i == 1 && disp2_enabled))
|
||||
return DISP.DW && DISP.DH;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
float GSState::GetTvRefreshRate()
|
||||
{
|
||||
const GSVideoMode videomode = GetVideoMode();
|
||||
@@ -1771,6 +1522,7 @@ void GSState::FlushWrite()
|
||||
m_tr.start += len;
|
||||
|
||||
g_perfmon.Put(GSPerfMon::Swizzle, len);
|
||||
s_transfer_n++;
|
||||
}
|
||||
|
||||
// This function decides if the context has changed in a way which warrants flushing the draw.
|
||||
@@ -2007,17 +1759,29 @@ void GSState::Write(const u8* mem, int len)
|
||||
// Invalid the CLUT if it crosses paths.
|
||||
m_mem.m_clut.InvalidateRange(write_start_bp, write_end_bp);
|
||||
|
||||
if (GSConfig.PreloadFrameWithGSData)
|
||||
GSVector4i r;
|
||||
|
||||
r.left = m_env.TRXPOS.DSAX;
|
||||
r.top = m_env.TRXPOS.DSAY;
|
||||
r.right = r.left + m_env.TRXREG.RRW;
|
||||
r.bottom = r.top + m_env.TRXREG.RRH;
|
||||
|
||||
// Store the transfer for preloading new RT's.
|
||||
if ((m_draw_transfers.size() > 0 && blit.DBP == m_draw_transfers.back().blit.DBP))
|
||||
{
|
||||
// Store the transfer for preloading new RT's.
|
||||
if (m_draw_transfers.size() == 0 || (m_draw_transfers.size() > 0 && blit.DBP != m_draw_transfers.back().blit.DBP))
|
||||
{
|
||||
GSUploadQueue new_transfer = { blit, s_n };
|
||||
m_draw_transfers.push_back(new_transfer);
|
||||
}
|
||||
// Same BP, let's update the rect.
|
||||
GSUploadQueue transfer = m_draw_transfers.back();
|
||||
m_draw_transfers.pop_back();
|
||||
transfer.rect = transfer.rect.runion(r);
|
||||
m_draw_transfers.push_back(transfer);
|
||||
}
|
||||
else
|
||||
{
|
||||
GSUploadQueue new_transfer = { blit, r, s_n };
|
||||
m_draw_transfers.push_back(new_transfer);
|
||||
}
|
||||
|
||||
GL_CACHE("Write! ... => 0x%x W:%d F:%s (DIR %d%d), dPos(%d %d) size(%d %d)",
|
||||
GL_CACHE("Write! %u ... => 0x%x W:%d F:%s (DIR %d%d), dPos(%d %d) size(%d %d)", s_transfer_n,
|
||||
blit.DBP, blit.DBW, psm_str(blit.DPSM),
|
||||
m_env.TRXPOS.DIRX, m_env.TRXPOS.DIRY,
|
||||
m_env.TRXPOS.DSAX, m_env.TRXPOS.DSAY, w, h);
|
||||
@@ -2025,12 +1789,6 @@ void GSState::Write(const u8* mem, int len)
|
||||
if (m_tr.end == 0 && len >= m_tr.total)
|
||||
{
|
||||
// received all data in one piece, no need to buffer it
|
||||
GSVector4i r;
|
||||
|
||||
r.left = m_env.TRXPOS.DSAX;
|
||||
r.top = m_env.TRXPOS.DSAY;
|
||||
r.right = r.left + m_env.TRXREG.RRW;
|
||||
r.bottom = r.top + m_env.TRXREG.RRH;
|
||||
ExpandTarget(m_env.BITBLTBUF, r);
|
||||
InvalidateVideoMem(blit, r, true);
|
||||
|
||||
@@ -2039,6 +1797,7 @@ void GSState::Write(const u8* mem, int len)
|
||||
m_tr.start = m_tr.end = m_tr.total;
|
||||
|
||||
g_perfmon.Put(GSPerfMon::Swizzle, len);
|
||||
s_transfer_n++;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2105,6 +1864,7 @@ void GSState::Move()
|
||||
{
|
||||
// ffxii uses this to move the top/bottom of the scrolling menus offscreen and then blends them back over the text to create a shading effect
|
||||
// guitar hero copies the far end of the board to do a similar blend too
|
||||
s_transfer_n++;
|
||||
|
||||
int sx = m_env.TRXPOS.SSAX;
|
||||
int sy = m_env.TRXPOS.SSAY;
|
||||
@@ -2164,15 +1924,26 @@ void GSState::Move()
|
||||
Flush(GSFlushReason::LOCALTOLOCALMOVE);
|
||||
}
|
||||
|
||||
if (GSConfig.PreloadFrameWithGSData)
|
||||
GSVector4i r;
|
||||
r.left = m_env.TRXPOS.DSAX;
|
||||
r.top = m_env.TRXPOS.DSAY;
|
||||
r.right = r.left + m_env.TRXREG.RRW;
|
||||
r.bottom = r.top + m_env.TRXREG.RRH;
|
||||
// Store the transfer for preloading new RT's.
|
||||
if ((m_draw_transfers.size() > 0 && m_env.BITBLTBUF.DBP == m_draw_transfers.back().blit.DBP))
|
||||
{
|
||||
// Store the transfer for preloading new RT's.
|
||||
if (m_draw_transfers.size() == 0 || (m_draw_transfers.size() > 0 && dbp != m_draw_transfers.back().blit.DBP))
|
||||
{
|
||||
GSUploadQueue new_transfer = { m_env.BITBLTBUF, s_n };
|
||||
m_draw_transfers.push_back(new_transfer);
|
||||
}
|
||||
// Same BP, let's update the rect.
|
||||
GSUploadQueue transfer = m_draw_transfers.back();
|
||||
m_draw_transfers.pop_back();
|
||||
transfer.rect = transfer.rect.runion(r);
|
||||
m_draw_transfers.push_back(transfer);
|
||||
}
|
||||
else
|
||||
{
|
||||
GSUploadQueue new_transfer = { m_env.BITBLTBUF, r, s_n };
|
||||
m_draw_transfers.push_back(new_transfer);
|
||||
}
|
||||
|
||||
// Invalid the CLUT if it crosses paths.
|
||||
m_mem.m_clut.InvalidateRange(write_start_bp, write_end_bp);
|
||||
|
||||
@@ -2370,6 +2141,19 @@ void GSState::ReadLocalMemoryUnsync(u8* mem, int qwc, GIFRegBITBLTBUF BITBLTBUF,
|
||||
m_mem.ReadImageX(tb.x, tb.y, mem, len, BITBLTBUF, TRXPOS, TRXREG);
|
||||
}
|
||||
|
||||
void GSState::PurgePool()
|
||||
{
|
||||
g_gs_device->PurgePool();
|
||||
}
|
||||
|
||||
void GSState::PurgeTextureCache()
|
||||
{
|
||||
}
|
||||
|
||||
void GSState::ReadbackTextureCache()
|
||||
{
|
||||
}
|
||||
|
||||
template void GSState::Transfer<0>(const u8* mem, u32 size);
|
||||
template void GSState::Transfer<1>(const u8* mem, u32 size);
|
||||
template void GSState::Transfer<2>(const u8* mem, u32 size);
|
||||
@@ -2580,18 +2364,22 @@ int GSState::Freeze(freezeData* fd, bool sizeonly)
|
||||
{
|
||||
if (sizeonly)
|
||||
{
|
||||
fd->size = m_sssize;
|
||||
fd->size = GetSaveStateSize();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!fd->data || fd->size < m_sssize)
|
||||
if (!fd->data || fd->size < GetSaveStateSize())
|
||||
return -1;
|
||||
|
||||
Flush(GSFlushReason::SAVESTATE);
|
||||
|
||||
u8* data = fd->data;
|
||||
if (GSConfig.UserHacks_ReadTCOnClose)
|
||||
ReadbackTextureCache();
|
||||
|
||||
WriteState(data, &m_version);
|
||||
u8* data = fd->data;
|
||||
const u32 version = STATE_VERSION;
|
||||
|
||||
WriteState(data, &version);
|
||||
WriteState(data, &m_env.PRIM);
|
||||
WriteState(data, &m_env.PRMODECONT);
|
||||
WriteState(data, &m_env.TEXCLUT);
|
||||
@@ -2659,7 +2447,7 @@ int GSState::Defrost(const freezeData* fd)
|
||||
if (!fd || !fd->data || fd->size == 0)
|
||||
return -1;
|
||||
|
||||
if (fd->size < m_sssize)
|
||||
if (fd->size < GetSaveStateSize())
|
||||
return -1;
|
||||
|
||||
u8* data = fd->data;
|
||||
@@ -2668,7 +2456,7 @@ int GSState::Defrost(const freezeData* fd)
|
||||
|
||||
ReadState(&version, data);
|
||||
|
||||
if (version > m_version)
|
||||
if (version > STATE_VERSION)
|
||||
{
|
||||
Console.Error("GS: Savestate version is incompatible. Load aborted.");
|
||||
return -1;
|
||||
@@ -2775,6 +2563,8 @@ int GSState::Defrost(const freezeData* fd)
|
||||
|
||||
g_perfmon.SetFrame(5000);
|
||||
|
||||
ResetPCRTC();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -3164,7 +2954,7 @@ __forceinline void GSState::HandleAutoFlush()
|
||||
|
||||
const GSVector2i offset = GSVector2i(m_context->XYOFFSET.OFX, m_context->XYOFFSET.OFY);
|
||||
const GSVector4i scissor = GSVector4i(m_context->scissor.in);
|
||||
GSVector4i old_tex_rect = GSVector4i(0, 0, 0, 0);
|
||||
GSVector4i old_tex_rect = GSVector4i::zero();
|
||||
int current_draw_end = m_index.tail;
|
||||
|
||||
while (current_draw_end >= n)
|
||||
@@ -3334,8 +3124,8 @@ __forceinline void GSState::VertexKick(u32 skip)
|
||||
case GS_TRIANGLESTRIP:
|
||||
case GS_TRIANGLEFAN:
|
||||
case GS_SPRITE:
|
||||
// FIXME: GREG I don't understand the purpose of the m_nativeres check
|
||||
// It impacts badly the number of draw call in the HW renderer.
|
||||
// Discard degenerate triangles. For native resolution, we can ignore the subpixel bits,
|
||||
// because at the boundaries, they're irrelevant.
|
||||
test |= m_nativeres ? pmin.eq16(pmax).zwzwl() : pmin.eq16(pmax);
|
||||
break;
|
||||
default:
|
||||
@@ -4098,9 +3888,6 @@ GIFRegTEX0 GSState::GetTex0Layer(u32 lod)
|
||||
|
||||
GSState::GSTransferBuffer::GSTransferBuffer()
|
||||
{
|
||||
x = y = 0;
|
||||
start = end = total = 0;
|
||||
|
||||
constexpr size_t alloc_size = 1024 * 1024 * 4;
|
||||
buff = reinterpret_cast<u8*>(_aligned_malloc(alloc_size, 32));
|
||||
}
|
||||
|
||||
@@ -35,13 +35,15 @@ public:
|
||||
GSState();
|
||||
virtual ~GSState();
|
||||
|
||||
static constexpr int GetSaveStateSize();
|
||||
|
||||
private:
|
||||
// RESTRICT prevents multiple loads of the same part of the register when accessing its bitfields (the compiler is happy to know that memory writes in-between will not go there)
|
||||
|
||||
typedef void (GSState::*GIFPackedRegHandler)(const GIFPackedReg* RESTRICT r);
|
||||
|
||||
GIFPackedRegHandler m_fpGIFPackedRegHandlers[16];
|
||||
GIFPackedRegHandler m_fpGIFPackedRegHandlerXYZ[8][4];
|
||||
GIFPackedRegHandler m_fpGIFPackedRegHandlers[16] = {};
|
||||
GIFPackedRegHandler m_fpGIFPackedRegHandlerXYZ[8][4] = {};
|
||||
|
||||
void CheckFlushes();
|
||||
|
||||
@@ -58,14 +60,14 @@ private:
|
||||
|
||||
typedef void (GSState::*GIFRegHandler)(const GIFReg* RESTRICT r);
|
||||
|
||||
GIFRegHandler m_fpGIFRegHandlers[256];
|
||||
GIFRegHandler m_fpGIFRegHandlerXYZ[8][4];
|
||||
GIFRegHandler m_fpGIFRegHandlers[256] = {};
|
||||
GIFRegHandler m_fpGIFRegHandlerXYZ[8][4] = {};
|
||||
|
||||
typedef void (GSState::*GIFPackedRegHandlerC)(const GIFPackedReg* RESTRICT r, u32 size);
|
||||
|
||||
GIFPackedRegHandlerC m_fpGIFPackedRegHandlersC[2];
|
||||
GIFPackedRegHandlerC m_fpGIFPackedRegHandlerSTQRGBAXYZF2[8];
|
||||
GIFPackedRegHandlerC m_fpGIFPackedRegHandlerSTQRGBAXYZ2[8];
|
||||
GIFPackedRegHandlerC m_fpGIFPackedRegHandlersC[2] = {};
|
||||
GIFPackedRegHandlerC m_fpGIFPackedRegHandlerSTQRGBAXYZF2[8] = {};
|
||||
GIFPackedRegHandlerC m_fpGIFPackedRegHandlerSTQRGBAXYZ2[8] = {};
|
||||
|
||||
template<u32 prim, bool auto_flush, bool index_swap> void GIFPackedRegHandlerSTQRGBAXYZF2(const GIFPackedReg* RESTRICT r, u32 size);
|
||||
template<u32 prim, bool auto_flush, bool index_swap> void GIFPackedRegHandlerSTQRGBAXYZ2(const GIFPackedReg* RESTRICT r, u32 size);
|
||||
@@ -117,15 +119,12 @@ private:
|
||||
template<bool auto_flush, bool index_swap>
|
||||
void SetPrimHandlers();
|
||||
|
||||
u32 m_version;
|
||||
int m_sssize;
|
||||
|
||||
struct GSTransferBuffer
|
||||
{
|
||||
int x, y;
|
||||
int start, end, total;
|
||||
u8* buff;
|
||||
GIFRegBITBLTBUF m_blit;
|
||||
int x = 0, y = 0;
|
||||
int start = 0, end = 0, total = 0;
|
||||
u8* buff = nullptr;
|
||||
GIFRegBITBLTBUF m_blit = {};
|
||||
|
||||
GSTransferBuffer();
|
||||
virtual ~GSTransferBuffer();
|
||||
@@ -139,14 +138,14 @@ private:
|
||||
void CalcAlphaMinMax();
|
||||
|
||||
protected:
|
||||
GSVertex m_v;
|
||||
float m_q;
|
||||
GSVector4i m_scissor;
|
||||
GSVector4i m_ofxy;
|
||||
GSVertex m_v = {};
|
||||
float m_q = 1.0f;
|
||||
GSVector4i m_scissor = {};
|
||||
GSVector4i m_ofxy = {};
|
||||
|
||||
u8 m_scanmask_used;
|
||||
bool tex_flushed;
|
||||
bool m_isPackedUV_HackFlag;
|
||||
u8 m_scanmask_used = 0;
|
||||
bool tex_flushed = true;
|
||||
bool m_isPackedUV_HackFlag = false;
|
||||
|
||||
struct
|
||||
{
|
||||
@@ -154,13 +153,13 @@ protected:
|
||||
u32 head, tail, next, maxcount; // head: first vertex, tail: last vertex + 1, next: last indexed + 1
|
||||
u32 xy_tail;
|
||||
u64 xy[4];
|
||||
} m_vertex;
|
||||
} m_vertex = {};
|
||||
|
||||
struct
|
||||
{
|
||||
u32* buff;
|
||||
u32 tail;
|
||||
} m_index;
|
||||
} m_index = {};
|
||||
|
||||
void UpdateContext();
|
||||
void UpdateScissor();
|
||||
@@ -210,29 +209,31 @@ public:
|
||||
struct GSUploadQueue
|
||||
{
|
||||
GIFRegBITBLTBUF blit;
|
||||
GSVector4i rect;
|
||||
int draw;
|
||||
};
|
||||
|
||||
GIFPath m_path[4];
|
||||
GIFRegPRIM* PRIM;
|
||||
GSPrivRegSet* m_regs;
|
||||
GIFPath m_path[4] = {};
|
||||
GIFRegPRIM* PRIM = nullptr;
|
||||
GSPrivRegSet* m_regs = nullptr;
|
||||
GSLocalMemory m_mem;
|
||||
GSDrawingEnvironment m_env;
|
||||
GSDrawingEnvironment m_backup_env;
|
||||
GSDrawingEnvironment m_prev_env;
|
||||
GSVector4i temp_draw_rect;
|
||||
GSDrawingContext* m_context;
|
||||
u32 m_crc;
|
||||
CRC::Game m_game;
|
||||
GSDrawingEnvironment m_env = {};
|
||||
GSDrawingEnvironment m_backup_env = {};
|
||||
GSDrawingEnvironment m_prev_env = {};
|
||||
GSVector4i temp_draw_rect = {};
|
||||
GSDrawingContext* m_context = nullptr;
|
||||
u32 m_crc = 0;
|
||||
CRC::Game m_game = {};
|
||||
std::unique_ptr<GSDumpBase> m_dump;
|
||||
bool m_nativeres;
|
||||
bool m_mipmap;
|
||||
u32 m_dirty_gs_regs;
|
||||
int m_backed_up_ctx;
|
||||
bool m_nativeres = false;
|
||||
bool m_mipmap = false;
|
||||
u8 m_force_preload = 0;
|
||||
u32 m_dirty_gs_regs = 0;
|
||||
int m_backed_up_ctx = 0;
|
||||
std::vector<GSUploadQueue> m_draw_transfers;
|
||||
bool m_force_preload;
|
||||
|
||||
static int s_n;
|
||||
static int s_transfer_n;
|
||||
|
||||
static constexpr u32 STATE_VERSION = 8;
|
||||
|
||||
@@ -278,7 +279,7 @@ public:
|
||||
GSREOPEN = 1 << 13,
|
||||
};
|
||||
|
||||
GSFlushReason m_state_flush_reason;
|
||||
GSFlushReason m_state_flush_reason = UNKNOWN;
|
||||
|
||||
enum PRIM_OVERLAP
|
||||
{
|
||||
@@ -287,62 +288,592 @@ public:
|
||||
PRIM_OVERLAP_NO
|
||||
};
|
||||
|
||||
PRIM_OVERLAP m_prim_overlap;
|
||||
PRIM_OVERLAP m_prim_overlap = PRIM_OVERLAP_UNKNOW;
|
||||
std::vector<size_t> m_drawlist;
|
||||
|
||||
// The horizontal offset values (under z) for PAL and NTSC have been tweaked
|
||||
// they should be apparently 632 and 652 respectively, but that causes a thick black line on the left
|
||||
// these values leave a small black line on the right in a bunch of games, but it's not so bad.
|
||||
// The only conclusion I can come to is there is horizontal overscan expected so there would normally
|
||||
// be black borders either side anyway, or both sides slightly covered.
|
||||
const GSVector4i VideoModeOffsets[6] = {
|
||||
GSVector4i(640, 224, 642, 25),
|
||||
GSVector4i(640, 256, 676, 36),
|
||||
GSVector4i(640, 480, 276, 34),
|
||||
GSVector4i(720, 480, 232, 35),
|
||||
GSVector4i(1280, 720, 302, 24),
|
||||
GSVector4i(1920, 540, 238, 40)
|
||||
};
|
||||
struct GSPCRTCRegs
|
||||
{
|
||||
// The horizontal offset values (under z) for PAL and NTSC have been tweaked
|
||||
// they should be apparently 632 and 652 respectively, but that causes a thick black line on the left
|
||||
// these values leave a small black line on the right in a bunch of games, but it's not so bad.
|
||||
// The only conclusion I can come to is there is horizontal overscan expected so there would normally
|
||||
// be black borders either side anyway, or both sides slightly covered.
|
||||
static inline constexpr GSVector4i VideoModeOffsets[6] = {
|
||||
GSVector4i::cxpr(640, 224, 642, 25),
|
||||
GSVector4i::cxpr(640, 256, 676, 36),
|
||||
GSVector4i::cxpr(640, 480, 276, 34),
|
||||
GSVector4i::cxpr(720, 480, 232, 35),
|
||||
GSVector4i::cxpr(1280, 720, 302, 24),
|
||||
GSVector4i::cxpr(1920, 540, 238, 40)
|
||||
};
|
||||
|
||||
const GSVector4i VideoModeOffsetsOverscan[6] = {
|
||||
GSVector4i(711, 243, 498, 12),
|
||||
GSVector4i(702, 288, 532, 18),
|
||||
GSVector4i(640, 480, 276, 34),
|
||||
GSVector4i(720, 480, 232, 35),
|
||||
GSVector4i(1280, 720, 302, 24),
|
||||
GSVector4i(1920, 540, 238, 40)
|
||||
};
|
||||
static inline constexpr GSVector4i VideoModeOffsetsOverscan[6] = {
|
||||
GSVector4i::cxpr(711, 243, 498, 12),
|
||||
GSVector4i::cxpr(702, 288, 532, 18),
|
||||
GSVector4i::cxpr(640, 480, 276, 34),
|
||||
GSVector4i::cxpr(720, 480, 232, 35),
|
||||
GSVector4i::cxpr(1280, 720, 302, 24),
|
||||
GSVector4i::cxpr(1920, 540, 238, 40)
|
||||
};
|
||||
|
||||
const GSVector4i VideoModeDividers[6] = {
|
||||
GSVector4i(3, 0, 2559, 239),
|
||||
GSVector4i(3, 0, 2559, 287),
|
||||
GSVector4i(1, 0, 1279, 479),
|
||||
GSVector4i(1, 0, 1439, 479),
|
||||
GSVector4i(0, 0, 1279, 719),
|
||||
GSVector4i(0, 0, 1919, 1079)
|
||||
};
|
||||
static inline constexpr GSVector4i VideoModeDividers[6] = {
|
||||
GSVector4i::cxpr(3, 0, 2559, 239),
|
||||
GSVector4i::cxpr(3, 0, 2559, 287),
|
||||
GSVector4i::cxpr(1, 0, 1279, 479),
|
||||
GSVector4i::cxpr(1, 0, 1439, 479),
|
||||
GSVector4i::cxpr(0, 0, 1279, 719),
|
||||
GSVector4i::cxpr(0, 0, 1919, 1079)
|
||||
};
|
||||
|
||||
struct PCRTCDisplay
|
||||
{
|
||||
bool enabled;
|
||||
int FBP;
|
||||
int FBW;
|
||||
int PSM;
|
||||
GSRegDISPFB prevFramebufferReg;
|
||||
GSVector2i prevDisplayOffset;
|
||||
GSVector2i displayOffset;
|
||||
GSVector4i displayRect;
|
||||
GSVector2i magnification;
|
||||
GSVector2i prevFramebufferOffsets;
|
||||
GSVector2i framebufferOffsets;
|
||||
GSVector4i framebufferRect;
|
||||
|
||||
int Block()
|
||||
{
|
||||
return FBP << 5;
|
||||
}
|
||||
};
|
||||
|
||||
int videomode = 0;
|
||||
int interlaced = 0;
|
||||
int FFMD = 0;
|
||||
bool PCRTCSameSrc = false;
|
||||
bool toggling_field = false;
|
||||
PCRTCDisplay PCRTCDisplays[2] = {};
|
||||
|
||||
bool IsAnalogue()
|
||||
{
|
||||
const GSVideoMode video = static_cast<GSVideoMode>(videomode + 1);
|
||||
return video == GSVideoMode::NTSC || video == GSVideoMode::PAL || video == GSVideoMode::HDTV_1080I;
|
||||
}
|
||||
|
||||
// Calculates which display is closest to matching zero offsets in either direction.
|
||||
GSVector2i NearestToZeroOffset()
|
||||
{
|
||||
GSVector2i returnValue = { 1, 1 };
|
||||
|
||||
if (!PCRTCDisplays[0].enabled && !PCRTCDisplays[1].enabled)
|
||||
return returnValue;
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
if (!PCRTCDisplays[i].enabled)
|
||||
{
|
||||
returnValue.x = 1 - i;
|
||||
returnValue.y = 1 - i;
|
||||
return returnValue;
|
||||
}
|
||||
}
|
||||
|
||||
if (abs(PCRTCDisplays[0].displayOffset.x - VideoModeOffsets[videomode].z) <
|
||||
abs(PCRTCDisplays[1].displayOffset.x - VideoModeOffsets[videomode].z))
|
||||
returnValue.x = 0;
|
||||
|
||||
// When interlaced, the vertical base offset is doubled
|
||||
const int verticalOffset = VideoModeOffsets[videomode].w * (1 << interlaced);
|
||||
|
||||
if (abs(PCRTCDisplays[0].displayOffset.y - verticalOffset) <
|
||||
abs(PCRTCDisplays[1].displayOffset.y - verticalOffset))
|
||||
returnValue.y = 0;
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
void SetVideoMode(GSVideoMode videoModeIn)
|
||||
{
|
||||
videomode = static_cast<int>(videoModeIn) - 1;
|
||||
}
|
||||
|
||||
// Enable each of the displays.
|
||||
void EnableDisplays(GSRegPMODE pmode, GSRegSMODE2 smode2, bool smodetoggle)
|
||||
{
|
||||
PCRTCDisplays[0].enabled = pmode.EN1;
|
||||
PCRTCDisplays[1].enabled = pmode.EN2;
|
||||
|
||||
interlaced = smode2.INT && IsAnalogue();
|
||||
FFMD = smode2.FFMD;
|
||||
toggling_field = smodetoggle && IsAnalogue();
|
||||
}
|
||||
|
||||
void CheckSameSource()
|
||||
{
|
||||
if (PCRTCDisplays[0].enabled != PCRTCDisplays[1].enabled || (PCRTCDisplays[0].enabled | PCRTCDisplays[1].enabled) == false)
|
||||
{
|
||||
PCRTCSameSrc = false;
|
||||
return;
|
||||
}
|
||||
|
||||
PCRTCSameSrc = PCRTCDisplays[0].FBP == PCRTCDisplays[1].FBP &&
|
||||
PCRTCDisplays[0].FBW == PCRTCDisplays[1].FBW &&
|
||||
GSUtil::HasCompatibleBits(PCRTCDisplays[0].PSM, PCRTCDisplays[1].PSM);
|
||||
}
|
||||
|
||||
bool FrameWrap()
|
||||
{
|
||||
const GSVector4i combined_rect = GSVector4i(PCRTCDisplays[0].framebufferRect.runion(PCRTCDisplays[1].framebufferRect));
|
||||
return combined_rect.w >= 2048 || combined_rect.z >= 2048;
|
||||
}
|
||||
|
||||
// If the start point of both frames match, we can do a single read
|
||||
bool FrameRectMatch()
|
||||
{
|
||||
return PCRTCSameSrc;
|
||||
}
|
||||
|
||||
GSVector2i GetResolution()
|
||||
{
|
||||
GSVector2i resolution;
|
||||
|
||||
const GSVector4i offsets = !GSConfig.PCRTCOverscan ? VideoModeOffsets[videomode] : VideoModeOffsetsOverscan[videomode];
|
||||
const bool is_full_height = interlaced || (toggling_field && GSConfig.InterlaceMode != GSInterlaceMode::Off) || GSConfig.InterlaceMode == GSInterlaceMode::Off;
|
||||
|
||||
if (!GSConfig.PCRTCOffsets)
|
||||
{
|
||||
if (PCRTCDisplays[0].enabled && PCRTCDisplays[1].enabled)
|
||||
{
|
||||
const GSVector4i combined_size = PCRTCDisplays[0].displayRect.runion(PCRTCDisplays[1].displayRect);
|
||||
resolution = { combined_size.width(), combined_size.height() };
|
||||
}
|
||||
else if (PCRTCDisplays[0].enabled)
|
||||
{
|
||||
resolution = { PCRTCDisplays[0].displayRect.width(), PCRTCDisplays[0].displayRect.height() };
|
||||
}
|
||||
else
|
||||
{
|
||||
resolution = { PCRTCDisplays[1].displayRect.width(), PCRTCDisplays[1].displayRect.height() };
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const int shift = is_full_height ? 1 : 0;
|
||||
resolution = { offsets.x, offsets.y << shift };
|
||||
}
|
||||
|
||||
resolution.x = std::min(resolution.x, offsets.x);
|
||||
resolution.y = std::min(resolution.y, is_full_height ? offsets.y << 1 : offsets.y);
|
||||
|
||||
return resolution;
|
||||
}
|
||||
|
||||
GSVector4i GetFramebufferRect(int display)
|
||||
{
|
||||
if (display == -1)
|
||||
{
|
||||
return GSVector4i(PCRTCDisplays[0].framebufferRect.runion(PCRTCDisplays[1].framebufferRect));
|
||||
}
|
||||
else
|
||||
{
|
||||
return PCRTCDisplays[display].framebufferRect;
|
||||
}
|
||||
}
|
||||
|
||||
int GetFramebufferBitDepth()
|
||||
{
|
||||
if (PCRTCDisplays[0].enabled)
|
||||
return GSLocalMemory::m_psm[PCRTCDisplays[0].PSM].bpp;
|
||||
else if (PCRTCDisplays[1].enabled)
|
||||
return GSLocalMemory::m_psm[PCRTCDisplays[1].PSM].bpp;
|
||||
|
||||
return 32;
|
||||
}
|
||||
|
||||
GSVector2i GetFramebufferSize(int display)
|
||||
{
|
||||
int max_height = !GSConfig.PCRTCOverscan ? VideoModeOffsets[videomode].y : VideoModeOffsetsOverscan[videomode].y;
|
||||
|
||||
if (!(FFMD && interlaced))
|
||||
{
|
||||
max_height *= 2;
|
||||
}
|
||||
|
||||
if (display == -1)
|
||||
{
|
||||
GSVector4i combined_rect = PCRTCDisplays[0].framebufferRect.runion(PCRTCDisplays[1].framebufferRect);
|
||||
|
||||
if (combined_rect.z >= 2048)
|
||||
{
|
||||
const int high_x = (PCRTCDisplays[0].framebufferRect.x > PCRTCDisplays[1].framebufferRect.x) ? PCRTCDisplays[0].framebufferRect.x : PCRTCDisplays[1].framebufferRect.x;
|
||||
combined_rect.z -= GSConfig.UseHardwareRenderer() ? 2048 : high_x;
|
||||
combined_rect.x = 0;
|
||||
}
|
||||
|
||||
if (combined_rect.w >= 2048)
|
||||
{
|
||||
const int high_y = (PCRTCDisplays[0].framebufferRect.y > PCRTCDisplays[1].framebufferRect.y) ? PCRTCDisplays[0].framebufferRect.y : PCRTCDisplays[1].framebufferRect.y;
|
||||
combined_rect.w -= GSConfig.UseHardwareRenderer() ? 2048 : high_y;
|
||||
combined_rect.y = 0;
|
||||
}
|
||||
|
||||
// Cap the framebuffer read to the maximum display height, otherwise the hardware renderer gets messy.
|
||||
const int min_mag = std::max(1, std::min(PCRTCDisplays[0].magnification.y, PCRTCDisplays[1].magnification.y));
|
||||
int offset = PCRTCDisplays[0].displayRect.runion(PCRTCDisplays[1].displayRect).y;
|
||||
|
||||
if (FFMD && interlaced)
|
||||
{
|
||||
offset = (offset - 1) / 2;
|
||||
}
|
||||
|
||||
// Hardware mode needs a wider framebuffer as it can't offset the read.
|
||||
if (GSConfig.UseHardwareRenderer())
|
||||
{
|
||||
combined_rect.z += std::max(PCRTCDisplays[0].framebufferOffsets.x, PCRTCDisplays[1].framebufferOffsets.x);
|
||||
combined_rect.w += std::max(PCRTCDisplays[0].framebufferOffsets.y, PCRTCDisplays[1].framebufferOffsets.y);
|
||||
}
|
||||
offset = (max_height / min_mag) - offset;
|
||||
combined_rect.w = std::min(combined_rect.w, offset);
|
||||
return GSVector2i(combined_rect.z, combined_rect.w);
|
||||
}
|
||||
else
|
||||
{
|
||||
GSVector4i out_rect = PCRTCDisplays[display].framebufferRect;
|
||||
|
||||
if (out_rect.z >= 2048)
|
||||
{
|
||||
out_rect.z -= GSConfig.UseHardwareRenderer() ? 2048 : out_rect.x;
|
||||
out_rect.x = 0;
|
||||
}
|
||||
|
||||
if (out_rect.w >= 2048)
|
||||
{
|
||||
out_rect.w -= GSConfig.UseHardwareRenderer() ? 2048 : out_rect.y;
|
||||
out_rect.y = 0;
|
||||
}
|
||||
|
||||
// Cap the framebuffer read to the maximum display height, otherwise the hardware renderer gets messy.
|
||||
const int min_mag = std::max(1, PCRTCDisplays[display].magnification.y);
|
||||
int offset = PCRTCDisplays[display].displayRect.y;
|
||||
|
||||
if (FFMD && interlaced)
|
||||
{
|
||||
offset = (offset - 1) / 2;
|
||||
}
|
||||
|
||||
offset = (max_height / min_mag) - offset;
|
||||
out_rect.w = std::min(out_rect.w, offset);
|
||||
|
||||
// Hardware mode needs a wider framebuffer as it can't offset the read.
|
||||
if (GSConfig.UseHardwareRenderer())
|
||||
{
|
||||
out_rect.z += PCRTCDisplays[display].framebufferOffsets.x;
|
||||
out_rect.w += PCRTCDisplays[display].framebufferOffsets.y;
|
||||
}
|
||||
return GSVector2i(out_rect.z, out_rect.w);
|
||||
}
|
||||
}
|
||||
|
||||
// Sets up the rectangles for both the framebuffer read and the displays for the merge circuit.
|
||||
void SetRects(int display, GSRegDISPLAY displayReg, GSRegDISPFB framebufferReg)
|
||||
{
|
||||
// Save framebuffer information first, while we're here.
|
||||
PCRTCDisplays[display].FBP = framebufferReg.FBP;
|
||||
PCRTCDisplays[display].FBW = framebufferReg.FBW;
|
||||
PCRTCDisplays[display].PSM = framebufferReg.PSM;
|
||||
PCRTCDisplays[display].prevFramebufferReg = framebufferReg;
|
||||
// Probably not really enabled but will cause a mess.
|
||||
// Q-Ball Billiards enables both circuits but doesn't set one of them up.
|
||||
if (PCRTCDisplays[display].FBW == 0 && displayReg.DW == 0 && displayReg.DH == 0 && displayReg.MAGH == 0)
|
||||
{
|
||||
PCRTCDisplays[display].enabled = false;
|
||||
return;
|
||||
}
|
||||
PCRTCDisplays[display].magnification = GSVector2i(displayReg.MAGH + 1, displayReg.MAGV + 1);
|
||||
const u32 DW = displayReg.DW + 1;
|
||||
const u32 DH = displayReg.DH + 1;
|
||||
|
||||
const int renderWidth = DW / PCRTCDisplays[display].magnification.x;
|
||||
const int renderHeight = DH / PCRTCDisplays[display].magnification.y;
|
||||
|
||||
u32 finalDisplayWidth = renderWidth;
|
||||
u32 finalDisplayHeight = renderHeight;
|
||||
// When using screen offsets the screen gets squashed/resized in to the actual screen size.
|
||||
if (GSConfig.PCRTCOffsets)
|
||||
{
|
||||
finalDisplayWidth = DW / (VideoModeDividers[videomode].x + 1);
|
||||
finalDisplayHeight = DH / (VideoModeDividers[videomode].y + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
finalDisplayWidth = std::min(finalDisplayWidth ,DW / (VideoModeDividers[videomode].x + 1));
|
||||
finalDisplayHeight = std::min(finalDisplayHeight, DH / (VideoModeDividers[videomode].y + 1));
|
||||
}
|
||||
|
||||
// Framebuffer size and offsets.
|
||||
PCRTCDisplays[display].prevFramebufferOffsets = PCRTCDisplays[display].framebufferOffsets;
|
||||
PCRTCDisplays[display].framebufferRect.x = 0;
|
||||
PCRTCDisplays[display].framebufferRect.y = 0;
|
||||
PCRTCDisplays[display].framebufferRect.z = renderWidth;
|
||||
|
||||
if(FFMD && interlaced) // Round up the height as if it's an odd value, this will cause havok with the merge circuit.
|
||||
PCRTCDisplays[display].framebufferRect.w = (renderHeight + 1) >> (FFMD * interlaced); // Half height read if FFMD + INT enabled.
|
||||
else
|
||||
PCRTCDisplays[display].framebufferRect.w = renderHeight;
|
||||
PCRTCDisplays[display].framebufferOffsets.x = framebufferReg.DBX;
|
||||
PCRTCDisplays[display].framebufferOffsets.y = framebufferReg.DBY;
|
||||
|
||||
const bool is_interlaced_resolution = interlaced || (toggling_field && GSConfig.InterlaceMode != GSInterlaceMode::Off);
|
||||
|
||||
// If the interlace flag isn't set, but it's still interlacing, the height is likely reported wrong.
|
||||
// Q-Ball Billiards.
|
||||
if (is_interlaced_resolution && !interlaced)
|
||||
finalDisplayHeight *= 2;
|
||||
|
||||
// Display size and offsets.
|
||||
PCRTCDisplays[display].displayRect.x = 0;
|
||||
PCRTCDisplays[display].displayRect.y = 0;
|
||||
PCRTCDisplays[display].displayRect.z = finalDisplayWidth;
|
||||
PCRTCDisplays[display].displayRect.w = finalDisplayHeight;
|
||||
PCRTCDisplays[display].prevDisplayOffset = PCRTCDisplays[display].displayOffset;
|
||||
PCRTCDisplays[display].displayOffset.x = displayReg.DX;
|
||||
PCRTCDisplays[display].displayOffset.y = displayReg.DY;
|
||||
}
|
||||
|
||||
// Calculate framebuffer read offsets, should be considered if only one circuit is enabled, or difference is more than 1 line.
|
||||
// Only considered if "Anti-blur" is enabled.
|
||||
void CalculateFramebufferOffset()
|
||||
{
|
||||
if (GSConfig.PCRTCAntiBlur && PCRTCSameSrc)
|
||||
{
|
||||
if (abs(PCRTCDisplays[1].framebufferOffsets.y - PCRTCDisplays[0].framebufferOffsets.y) == 1
|
||||
&& PCRTCDisplays[0].displayRect.y == PCRTCDisplays[1].displayRect.y)
|
||||
{
|
||||
if (PCRTCDisplays[1].framebufferOffsets.y < PCRTCDisplays[0].framebufferOffsets.y)
|
||||
PCRTCDisplays[0].framebufferOffsets.y = PCRTCDisplays[1].framebufferOffsets.y;
|
||||
else
|
||||
PCRTCDisplays[1].framebufferOffsets.y = PCRTCDisplays[0].framebufferOffsets.y;
|
||||
}
|
||||
if (abs(PCRTCDisplays[1].framebufferOffsets.x - PCRTCDisplays[0].framebufferOffsets.x) == 1
|
||||
&& PCRTCDisplays[0].displayRect.x == PCRTCDisplays[1].displayRect.x)
|
||||
{
|
||||
if (PCRTCDisplays[1].framebufferOffsets.x < PCRTCDisplays[0].framebufferOffsets.x)
|
||||
PCRTCDisplays[0].framebufferOffsets.x = PCRTCDisplays[1].framebufferOffsets.x;
|
||||
else
|
||||
PCRTCDisplays[1].framebufferOffsets.x = PCRTCDisplays[0].framebufferOffsets.x;
|
||||
}
|
||||
}
|
||||
PCRTCDisplays[0].framebufferRect.x += PCRTCDisplays[0].framebufferOffsets.x;
|
||||
PCRTCDisplays[0].framebufferRect.z += PCRTCDisplays[0].framebufferOffsets.x;
|
||||
PCRTCDisplays[0].framebufferRect.y += PCRTCDisplays[0].framebufferOffsets.y;
|
||||
PCRTCDisplays[0].framebufferRect.w += PCRTCDisplays[0].framebufferOffsets.y;
|
||||
|
||||
PCRTCDisplays[1].framebufferRect.x += PCRTCDisplays[1].framebufferOffsets.x;
|
||||
PCRTCDisplays[1].framebufferRect.z += PCRTCDisplays[1].framebufferOffsets.x;
|
||||
PCRTCDisplays[1].framebufferRect.y += PCRTCDisplays[1].framebufferOffsets.y;
|
||||
PCRTCDisplays[1].framebufferRect.w += PCRTCDisplays[1].framebufferOffsets.y;
|
||||
}
|
||||
|
||||
// Used in software mode to align the buffer when reading. Offset is accounted for (block aligned) by GetOutput.
|
||||
void RemoveFramebufferOffset(int display)
|
||||
{
|
||||
if (display >= 0)
|
||||
{
|
||||
// Hardware needs nothing but handling for wrapped framebuffers.
|
||||
if (GSConfig.UseHardwareRenderer())
|
||||
{
|
||||
if (PCRTCDisplays[display].framebufferRect.z >= 2048)
|
||||
{
|
||||
PCRTCDisplays[display].framebufferRect.x = 0;
|
||||
PCRTCDisplays[display].framebufferRect.z -= 2048;
|
||||
}
|
||||
if (PCRTCDisplays[display].framebufferRect.w >= 2048)
|
||||
{
|
||||
PCRTCDisplays[display].framebufferRect.y = 0;
|
||||
PCRTCDisplays[display].framebufferRect.w -= 2048;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const GSLocalMemory::psm_t& psm = GSLocalMemory::m_psm[PCRTCDisplays[display].PSM];
|
||||
|
||||
// Software mode - See note below.
|
||||
GSVector4i r = PCRTCDisplays[display].framebufferRect;
|
||||
r = r.ralign<Align_Outside>(psm.bs);
|
||||
|
||||
PCRTCDisplays[display].framebufferRect.z -= r.x;
|
||||
PCRTCDisplays[display].framebufferRect.w -= r.y;
|
||||
PCRTCDisplays[display].framebufferRect.x -= r.x;
|
||||
PCRTCDisplays[display].framebufferRect.y -= r.y;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Software Mode Note:
|
||||
// This code is to read the framebuffer nicely block aligned in software, then leave the remaining offset in to the block.
|
||||
// In hardware mode this doesn't happen, it reads the whole framebuffer, so we need to keep the offset.
|
||||
if (!GSConfig.UseHardwareRenderer())
|
||||
{
|
||||
const GSLocalMemory::psm_t& psm = GSLocalMemory::m_psm[PCRTCDisplays[1].PSM];
|
||||
|
||||
GSVector4i r = PCRTCDisplays[0].framebufferRect.runion(PCRTCDisplays[1].framebufferRect);
|
||||
r = r.ralign<Align_Outside>(psm.bs);
|
||||
|
||||
PCRTCDisplays[0].framebufferRect.x -= r.x;
|
||||
PCRTCDisplays[0].framebufferRect.y -= r.y;
|
||||
PCRTCDisplays[0].framebufferRect.z -= r.x;
|
||||
PCRTCDisplays[0].framebufferRect.w -= r.y;
|
||||
PCRTCDisplays[1].framebufferRect.x -= r.x;
|
||||
PCRTCDisplays[1].framebufferRect.y -= r.y;
|
||||
PCRTCDisplays[1].framebufferRect.z -= r.x;
|
||||
PCRTCDisplays[1].framebufferRect.w -= r.y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the two displays are offset from each other, move them to the correct offsets.
|
||||
// If using screen offsets, calculate the positions here.
|
||||
void CalculateDisplayOffset(bool scanmask)
|
||||
{
|
||||
const bool both_enabled = PCRTCDisplays[0].enabled && PCRTCDisplays[1].enabled;
|
||||
// Offsets are generally ignored, the "hacky" way of doing the displays, but direct to framebuffers.
|
||||
if (!GSConfig.PCRTCOffsets)
|
||||
{
|
||||
const GSVector4i offsets = !GSConfig.PCRTCOverscan ? VideoModeOffsets[videomode] : VideoModeOffsetsOverscan[videomode];
|
||||
int int_off[2] = { 0, 0 };
|
||||
GSVector2i zeroDisplay = NearestToZeroOffset();
|
||||
GSVector2i baseOffset = PCRTCDisplays[zeroDisplay.y].displayOffset;
|
||||
|
||||
if (both_enabled)
|
||||
{
|
||||
int blurOffset = abs(PCRTCDisplays[1].displayOffset.y - PCRTCDisplays[0].displayOffset.y);
|
||||
if (GSConfig.PCRTCAntiBlur && !scanmask && blurOffset < 4)
|
||||
{
|
||||
if (PCRTCDisplays[1].displayOffset.y > PCRTCDisplays[0].displayOffset.y)
|
||||
PCRTCDisplays[1].displayOffset.y -= blurOffset;
|
||||
else
|
||||
PCRTCDisplays[0].displayOffset.y -= blurOffset;
|
||||
}
|
||||
}
|
||||
|
||||
// If there's a single pixel offset, account for it else it can throw interlacing out.
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
if (!PCRTCDisplays[i].enabled)
|
||||
continue;
|
||||
|
||||
// Should this be MAGV/H in the DISPLAY register rather than the "default" magnification?
|
||||
const int offset = (PCRTCDisplays[i].displayOffset.y - (offsets.w * (interlaced + 1))) / (VideoModeDividers[videomode].y + 1);
|
||||
|
||||
if (offset > 4)
|
||||
continue;
|
||||
|
||||
int_off[i] = offset & 1;
|
||||
if (offset < 0)
|
||||
int_off[i] = -int_off[i];
|
||||
|
||||
PCRTCDisplays[i].displayRect.y += int_off[i];
|
||||
PCRTCDisplays[i].displayRect.w += int_off[i];
|
||||
}
|
||||
|
||||
// Handle difference in offset between the two displays, used in games like DmC and Time Crisis 2 (for split screen).
|
||||
// Offset is not screen based, but relative to each other.
|
||||
if (both_enabled)
|
||||
{
|
||||
GSVector2i offset;
|
||||
|
||||
offset.x = (PCRTCDisplays[1 - zeroDisplay.x].displayOffset.x - PCRTCDisplays[zeroDisplay.x].displayOffset.x) / (VideoModeDividers[videomode].x + 1);
|
||||
offset.y = (PCRTCDisplays[1 - zeroDisplay.y].displayOffset.y - PCRTCDisplays[zeroDisplay.y].displayOffset.y) / (VideoModeDividers[videomode].y + 1);
|
||||
|
||||
if (offset.x >= 4 || !GSConfig.PCRTCAntiBlur)
|
||||
{
|
||||
PCRTCDisplays[1 - zeroDisplay.x].displayRect.x += offset.x;
|
||||
PCRTCDisplays[1 - zeroDisplay.x].displayRect.z += offset.x;
|
||||
}
|
||||
if (offset.y >= 4 || !GSConfig.PCRTCAntiBlur)
|
||||
{
|
||||
PCRTCDisplays[1 - zeroDisplay.y].displayRect.y += offset.y - int_off[1 - zeroDisplay.y];
|
||||
PCRTCDisplays[1 - zeroDisplay.y].displayRect.w += offset.y - int_off[1 - zeroDisplay.y];
|
||||
}
|
||||
|
||||
baseOffset = PCRTCDisplays[zeroDisplay.y].displayOffset;
|
||||
}
|
||||
|
||||
// Handle any large vertical offset from the zero position on the screen.
|
||||
// Example: Hokuto no Ken, does a rougly -14 offset to bring the screen up.
|
||||
// Ignore the lowest bit, we've already accounted for this
|
||||
int vOffset = ((static_cast<int>(baseOffset.y) - (offsets.w * (interlaced + 1))) / (VideoModeDividers[videomode].y + 1));
|
||||
|
||||
if(vOffset <= 4 && vOffset != 0)
|
||||
{
|
||||
PCRTCDisplays[0].displayRect.y += vOffset - int_off[0];
|
||||
PCRTCDisplays[0].displayRect.w += vOffset - int_off[0];
|
||||
PCRTCDisplays[1].displayRect.y += vOffset - int_off[1];
|
||||
PCRTCDisplays[1].displayRect.w += vOffset - int_off[1];
|
||||
}
|
||||
}
|
||||
else // We're using screen offsets, so just calculate the entire offset.
|
||||
{
|
||||
const GSVector4i offsets = !GSConfig.PCRTCOverscan ? VideoModeOffsets[videomode] : VideoModeOffsetsOverscan[videomode];
|
||||
GSVector2i offset = { 0, 0 };
|
||||
GSVector2i zeroDisplay = NearestToZeroOffset();
|
||||
|
||||
if (both_enabled)
|
||||
{
|
||||
int blurOffset = abs(PCRTCDisplays[1].displayOffset.y - PCRTCDisplays[0].displayOffset.y);
|
||||
if (GSConfig.PCRTCAntiBlur && !scanmask && blurOffset < 4)
|
||||
{
|
||||
if (PCRTCDisplays[1].displayOffset.y > PCRTCDisplays[0].displayOffset.y)
|
||||
PCRTCDisplays[1].displayOffset.y -= blurOffset;
|
||||
else
|
||||
PCRTCDisplays[0].displayOffset.y -= blurOffset;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
// Should this be MAGV/H in the DISPLAY register rather than the "default" magnification?
|
||||
offset.x = (static_cast<int>(PCRTCDisplays[i].displayOffset.x) - offsets.z) / (VideoModeDividers[videomode].x + 1);
|
||||
offset.y = (static_cast<int>(PCRTCDisplays[i].displayOffset.y) - (offsets.w * (interlaced + 1))) / (VideoModeDividers[videomode].y + 1);
|
||||
|
||||
PCRTCDisplays[i].displayRect.x += offset.x;
|
||||
PCRTCDisplays[i].displayRect.z += offset.x;
|
||||
PCRTCDisplays[i].displayRect.y += offset.y;
|
||||
PCRTCDisplays[i].displayRect.w += offset.y;
|
||||
}
|
||||
|
||||
if (both_enabled)
|
||||
{
|
||||
GSVector2i offset;
|
||||
|
||||
offset.x = (PCRTCDisplays[1 - zeroDisplay.x].displayRect.x - PCRTCDisplays[zeroDisplay.x].displayRect.x);
|
||||
offset.y = (PCRTCDisplays[1 - zeroDisplay.y].displayRect.y - PCRTCDisplays[zeroDisplay.y].displayRect.y);
|
||||
|
||||
if (offset.x > 0 && offset.x < 4 && GSConfig.PCRTCAntiBlur)
|
||||
{
|
||||
PCRTCDisplays[1 - zeroDisplay.x].displayRect.x -= offset.x;
|
||||
PCRTCDisplays[1 - zeroDisplay.x].displayRect.z -= offset.x;
|
||||
}
|
||||
if (offset.y > 0 && offset.y < 4 && GSConfig.PCRTCAntiBlur)
|
||||
{
|
||||
PCRTCDisplays[1 - zeroDisplay.y].displayRect.y -= offset.y;
|
||||
PCRTCDisplays[1 - zeroDisplay.y].displayRect.w -= offset.y;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} PCRTCDisplays;
|
||||
|
||||
public:
|
||||
/// Returns the appropriate directory for draw dumping.
|
||||
static std::string GetDrawDumpPath(const char* format, ...);
|
||||
|
||||
void ResetHandlers();
|
||||
void ResetPCRTC();
|
||||
|
||||
int GetFramebufferHeight();
|
||||
int GetFramebufferWidth();
|
||||
int GetFramebufferBitDepth();
|
||||
int GetDisplayHMagnification();
|
||||
GSVector4i GetDisplayRect(int i = -1);
|
||||
GSVector4i GetFrameMagnifiedRect(int i = -1);
|
||||
GSVector2i GetResolutionOffset(int i = -1);
|
||||
GSVector2i GetResolution();
|
||||
GSVector4i GetFrameRect(int i = -1, bool ignore_off = false);
|
||||
GSVideoMode GetVideoMode();
|
||||
|
||||
bool IsEnabled(int i);
|
||||
bool isinterlaced();
|
||||
bool isReallyInterlaced();
|
||||
bool IsAnalogue();
|
||||
|
||||
float GetTvRefreshRate();
|
||||
|
||||
@@ -355,7 +886,9 @@ public:
|
||||
bool TestDrawChanged();
|
||||
void FlushWrite();
|
||||
virtual void Draw() = 0;
|
||||
virtual void PurgePool() = 0;
|
||||
virtual void PurgePool();
|
||||
virtual void PurgeTextureCache();
|
||||
virtual void ReadbackTextureCache();
|
||||
virtual void InvalidateVideoMem(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r, bool eewrite = false) {}
|
||||
virtual void InvalidateLocalMem(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r, bool clut = false) {}
|
||||
virtual void ExpandTarget(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r) {}
|
||||
|
||||
@@ -130,21 +130,44 @@ bool GSUtil::HasSharedBits(u32 spsm, const u32* RESTRICT ptr)
|
||||
return (ptr[spsm >> 5] & (1 << (spsm & 0x1f))) == 0;
|
||||
}
|
||||
|
||||
// Pixels can NOT coexist in the same 32bits of space.
|
||||
// Example: Using PSMT8H or PSMT4HL/HH with CT24 would fail this check.
|
||||
bool GSUtil::HasSharedBits(u32 spsm, u32 dpsm)
|
||||
{
|
||||
return (s_maps.SharedBitsField[dpsm][spsm >> 5] & (1 << (spsm & 0x1f))) == 0;
|
||||
}
|
||||
|
||||
// Pixels can NOT coexist in the same 32bits of space.
|
||||
// Example: Using PSMT8H or PSMT4HL/HH with CT24 would fail this check.
|
||||
// SBP and DBO must match.
|
||||
bool GSUtil::HasSharedBits(u32 sbp, u32 spsm, u32 dbp, u32 dpsm)
|
||||
{
|
||||
return ((sbp ^ dbp) | (s_maps.SharedBitsField[dpsm][spsm >> 5] & (1 << (spsm & 0x1f)))) == 0;
|
||||
}
|
||||
|
||||
// Shares bit depths, only detects 16/24/32 bit formats.
|
||||
// 24/32bit cross compatible, 16bit compatbile with 16bit.
|
||||
bool GSUtil::HasCompatibleBits(u32 spsm, u32 dpsm)
|
||||
{
|
||||
return (s_maps.CompatibleBitsField[spsm][dpsm >> 5] & (1 << (dpsm & 0x1f))) != 0;
|
||||
}
|
||||
|
||||
u32 GSUtil::GetChannelMask(u32 spsm)
|
||||
{
|
||||
switch (spsm)
|
||||
{
|
||||
case PSM_PSMCT24:
|
||||
case PSM_PSMZ24:
|
||||
return 0x7;
|
||||
case PSM_PSMT8H:
|
||||
case PSM_PSMT4HH: // This sucks, I'm sorry, but we don't have a way to do half channels
|
||||
case PSM_PSMT4HL: // So uuhh TODO I guess.
|
||||
return 0x8;
|
||||
default:
|
||||
return 0xf;
|
||||
}
|
||||
}
|
||||
|
||||
CRCHackLevel GSUtil::GetRecommendedCRCHackLevel(GSRendererType type)
|
||||
{
|
||||
return (type == GSRendererType::DX11 || type == GSRendererType::DX12) ? CRCHackLevel::Full : CRCHackLevel::Partial;
|
||||
@@ -156,14 +179,19 @@ GSRendererType GSUtil::GetPreferredRenderer()
|
||||
// Mac: Prefer Metal hardware.
|
||||
return GSRendererType::Metal;
|
||||
#elif defined(_WIN32)
|
||||
if (D3D::ShouldPreferRenderer() == D3D::Renderer::Vulkan)
|
||||
const u8 preferred = D3D::ShouldPreferRenderer();
|
||||
#if defined(ENABLE_VULKAN)
|
||||
if (preferred == D3D::Renderer::Vulkan)
|
||||
return GSRendererType::VK;
|
||||
#endif
|
||||
#if defined(ENABLE_OPENGL)
|
||||
else if (D3D::ShouldPreferRenderer() == D3D::Renderer::OpenGL)
|
||||
if (preferred == D3D::Renderer::OpenGL)
|
||||
return GSRendererType::OGL;
|
||||
#endif
|
||||
else
|
||||
return GSRendererType::DX11;
|
||||
if (preferred == D3D::Renderer::Direct3D12)
|
||||
return GSRendererType::DX12;
|
||||
|
||||
return GSRendererType::DX11;
|
||||
#else
|
||||
// Linux: Prefer GL/Vulkan, whatever is available.
|
||||
#if defined(ENABLE_OPENGL)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user