mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-01-31 01:15:24 +01:00
Compare commits
261 Commits
v1.7.3879
...
gs_wrchack
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d2202a4e33 | ||
|
|
9b1163f959 | ||
|
|
5b5edc506d | ||
|
|
b30b4375e7 | ||
|
|
1b0c03d892 | ||
|
|
bca49184e7 | ||
|
|
26d6c33163 | ||
|
|
9420615317 | ||
|
|
7198c6b8c6 | ||
|
|
9513864851 | ||
|
|
f9b8aa1862 | ||
|
|
34371c070c | ||
|
|
d6099dd263 | ||
|
|
a1bc39141e | ||
|
|
13ed41d077 | ||
|
|
8a0a8f718f | ||
|
|
7d08a54ad9 | ||
|
|
b9b47e3ec7 | ||
|
|
16989f2122 | ||
|
|
892d3a370d | ||
|
|
6af7ca9867 | ||
|
|
c3c354f794 | ||
|
|
43572a1560 | ||
|
|
79daed63ee | ||
|
|
21d3ad86d4 | ||
|
|
31ebe842e8 | ||
|
|
88487de72f | ||
|
|
616da8c99d | ||
|
|
ec8712cceb | ||
|
|
3d6923b2a1 | ||
|
|
f04337becf | ||
|
|
9a5dd4c19d | ||
|
|
643e0b1039 | ||
|
|
330061a6e7 | ||
|
|
0a292715cf | ||
|
|
52f034a513 | ||
|
|
25e05388ba | ||
|
|
7ad9a1af03 | ||
|
|
9346c69343 | ||
|
|
4a3f0ccf96 | ||
|
|
52a1396e29 | ||
|
|
f556dd2584 | ||
|
|
aea5c09825 | ||
|
|
8c3c9a1219 | ||
|
|
a4f1f383a7 | ||
|
|
ee73c5c1b5 | ||
|
|
c2904a4633 | ||
|
|
6faa2249f9 | ||
|
|
119c3acfe7 | ||
|
|
138a2683f2 | ||
|
|
463637fa10 | ||
|
|
d5aab926bf | ||
|
|
37ba04b770 | ||
|
|
3d0b7dee71 | ||
|
|
a287c2caac | ||
|
|
1b673d9dd0 | ||
|
|
d10621c201 | ||
|
|
e1d6dfc324 | ||
|
|
130ea2a7ca | ||
|
|
c8d53253d2 | ||
|
|
5c67438925 | ||
|
|
1012dba8d7 | ||
|
|
e8d43f53d9 | ||
|
|
a0e8ce4b13 | ||
|
|
0e35b3edcb | ||
|
|
25bb5851ec | ||
|
|
80b0bc0869 | ||
|
|
c05743b7b9 | ||
|
|
7c2a1f0f37 | ||
|
|
0b8b9e75d1 | ||
|
|
d65c343e91 | ||
|
|
cd8e7cc947 | ||
|
|
0df5cf2e91 | ||
|
|
412275e40d | ||
|
|
4c7ad66bd7 | ||
|
|
8ac21357c3 | ||
|
|
2fd88b901b | ||
|
|
5697759d9e | ||
|
|
ee0042c768 | ||
|
|
a6212f1388 | ||
|
|
7bfea60b35 | ||
|
|
beee740dc8 | ||
|
|
e31387b8bc | ||
|
|
3586a12c46 | ||
|
|
bf21254b13 | ||
|
|
dc9f61e70a | ||
|
|
3028998a43 | ||
|
|
42511ce8d8 | ||
|
|
c245d2134f | ||
|
|
f01884537d | ||
|
|
b48fb0d4da | ||
|
|
7a6470a19d | ||
|
|
bfd8fc771a | ||
|
|
f96ca4ac1f | ||
|
|
937bfce68e | ||
|
|
5869d35d85 | ||
|
|
8d3325e6cd | ||
|
|
4badb5b975 | ||
|
|
7e4ff233ec | ||
|
|
0e3397239d | ||
|
|
08bae3da2e | ||
|
|
4b49c8bd6e | ||
|
|
c1bd1fcbd4 | ||
|
|
1c3379f082 | ||
|
|
86c97a8ba3 | ||
|
|
8e6c18d3f4 | ||
|
|
f1e80c466d | ||
|
|
9a542bcb20 | ||
|
|
290c8ec420 | ||
|
|
517ccd5e40 | ||
|
|
bb7bbe0a60 | ||
|
|
ca25a31d79 | ||
|
|
e804e99013 | ||
|
|
f447aded57 | ||
|
|
c596a51593 | ||
|
|
ed26368a3a | ||
|
|
1b40e4aaca | ||
|
|
84d7fe550b | ||
|
|
e68d507659 | ||
|
|
2db1e8fb81 | ||
|
|
df674d4056 | ||
|
|
21dcda147c | ||
|
|
201d5ba219 | ||
|
|
2728462d77 | ||
|
|
f73b497b67 | ||
|
|
d2bdb85dc8 | ||
|
|
3572b4752e | ||
|
|
20de162a55 | ||
|
|
64a8e66bac | ||
|
|
ccc1874a4b | ||
|
|
4fec896378 | ||
|
|
d485fcb3ee | ||
|
|
c9498c3cec | ||
|
|
62fffaf56f | ||
|
|
553a5cc455 | ||
|
|
957ec1d3d3 | ||
|
|
00c158387b | ||
|
|
d12fa690c0 | ||
|
|
94226e83ba | ||
|
|
4cf041f6cb | ||
|
|
1b86a6e6f8 | ||
|
|
6e907ae618 | ||
|
|
39dde85d03 | ||
|
|
8bb9170865 | ||
|
|
2cd5ce6aea | ||
|
|
64fbaff82b | ||
|
|
15a38f5f9d | ||
|
|
4c1d93a322 | ||
|
|
6a40959f3a | ||
|
|
c4bf297f42 | ||
|
|
da1b408f97 | ||
|
|
91c3e3b684 | ||
|
|
609a44aaf2 | ||
|
|
3d84443bcf | ||
|
|
56046d4db8 | ||
|
|
90fc037833 | ||
|
|
ee4eadf7a6 | ||
|
|
3292121e67 | ||
|
|
c8416b820b | ||
|
|
c9d229e336 | ||
|
|
bfbcd7a949 | ||
|
|
bf2ba3c4d1 | ||
|
|
9d50d44c99 | ||
|
|
e76afee12d | ||
|
|
06ef51db2e | ||
|
|
a85a2a3cc5 | ||
|
|
8fbecbcdd7 | ||
|
|
b386f78d68 | ||
|
|
095757044a | ||
|
|
9b3b8aa4de | ||
|
|
4932834441 | ||
|
|
8773ebf64b | ||
|
|
f628795b3f | ||
|
|
0c78bda328 | ||
|
|
d9f4bc70fb | ||
|
|
ddd2ea5f4d | ||
|
|
a326303956 | ||
|
|
ba1eba98ea | ||
|
|
8282ebce40 | ||
|
|
4c3b7c45cf | ||
|
|
668251274a | ||
|
|
e79fc72950 | ||
|
|
bcda41120e | ||
|
|
80fc00bb05 | ||
|
|
f71ccab811 | ||
|
|
795951a2e8 | ||
|
|
d62999ed16 | ||
|
|
9b1699a5a4 | ||
|
|
88c1f00b62 | ||
|
|
6834367a3e | ||
|
|
dedcf21a37 | ||
|
|
a747a5f9fa | ||
|
|
fcfb9865df | ||
|
|
aa1e9cc9fa | ||
|
|
9b7d21891d | ||
|
|
df19baed37 | ||
|
|
7848f6a1c5 | ||
|
|
14e128337d | ||
|
|
cb314f0a0b | ||
|
|
ddb313fd2b | ||
|
|
8f183955a0 | ||
|
|
536a4162c4 | ||
|
|
41a47f99f7 | ||
|
|
31fa1ea21e | ||
|
|
fb49c71118 | ||
|
|
0b87cfc7d4 | ||
|
|
76fa37019e | ||
|
|
d94e861a78 | ||
|
|
d9b537d334 | ||
|
|
93c2081d3f | ||
|
|
5ad8ed43fd | ||
|
|
1f4416a77a | ||
|
|
e9d4dba64b | ||
|
|
3a2307a5c6 | ||
|
|
d6c1af1a0c | ||
|
|
f6cb7ca01d | ||
|
|
bc0fdc49e0 | ||
|
|
43ccb63eb5 | ||
|
|
a0000a8547 | ||
|
|
a37ff0c4f2 | ||
|
|
e449ad7472 | ||
|
|
a718a785b3 | ||
|
|
ea7cc08832 | ||
|
|
a342f4c7e9 | ||
|
|
0af2657bbc | ||
|
|
451c2a244f | ||
|
|
a603aed7db | ||
|
|
f6bbf410f1 | ||
|
|
018692edd0 | ||
|
|
2740785df5 | ||
|
|
613a9964a1 | ||
|
|
2ef2f5db1d | ||
|
|
577e15a949 | ||
|
|
58ff3e6c0d | ||
|
|
80c471a939 | ||
|
|
b78fca7b91 | ||
|
|
be76092195 | ||
|
|
771d3c3c9d | ||
|
|
8c21765c0f | ||
|
|
a2e3522862 | ||
|
|
e20c2210f5 | ||
|
|
11f3fecd11 | ||
|
|
1a5d7c1c5d | ||
|
|
0bca1aab74 | ||
|
|
95fa15f902 | ||
|
|
d586582489 | ||
|
|
7ef46eaa29 | ||
|
|
38957625ad | ||
|
|
d30e076dbd | ||
|
|
0619555232 | ||
|
|
3ffa5eb613 | ||
|
|
c60583c6bb | ||
|
|
4cf7a1086d | ||
|
|
fa75006ca9 | ||
|
|
d28b2fa057 | ||
|
|
0a90765ed0 | ||
|
|
2892f629f0 | ||
|
|
5be05853c6 | ||
|
|
0f569ac5cb | ||
|
|
b725c1e8e0 | ||
|
|
4d418d1bb5 |
24
.github/labeler.yml
vendored
24
.github/labeler.yml
vendored
@@ -32,6 +32,8 @@
|
||||
- '**/GameIndex.*'
|
||||
'Installer | Package':
|
||||
- 'build.sh'
|
||||
'Translations':
|
||||
- 'pcsx2-qt/Translations/*'
|
||||
|
||||
# Tools / Features
|
||||
'Debugger':
|
||||
@@ -45,6 +47,9 @@
|
||||
'TAS Functionality':
|
||||
- 'pcsx2/Recording/*'
|
||||
- 'pcsx2/Recording/**/*'
|
||||
'RetroAchievements':
|
||||
- 'pcsx2/Frontend/Achievements.*'
|
||||
- 'pcsx2/Achievements.*'
|
||||
|
||||
# Emulation Components
|
||||
'Counters':
|
||||
@@ -64,21 +69,31 @@
|
||||
'GS':
|
||||
- 'pcsx2/GS/*'
|
||||
- 'pcsx2/GS/**/*'
|
||||
- 'bin/resources/shaders/*'
|
||||
- 'bin/resources/shaders/**/*'
|
||||
'GS: Direct3D 11':
|
||||
- 'pcsx2/GS/Renderers/DX11/*'
|
||||
- 'pcsx2/GS/Renderers/DX11/**/*'
|
||||
- 'bin/resources/shaders/dx11/*'
|
||||
- 'bin/resources/shaders/dx11/**/*'
|
||||
'GS: Direct3D 12':
|
||||
- 'pcsx2/GS/Renderers/DX12/*'
|
||||
- 'pcsx2/GS/Renderers/DX12/**/*'
|
||||
- 'bin/resources/shaders/dx11/*'
|
||||
- 'bin/resources/shaders/dx11/**/*'
|
||||
'GS: Hardware':
|
||||
- 'pcsx2/GS/Renderers/HW/*'
|
||||
- 'pcsx2/GS/Renderers/HW/**/*'
|
||||
'GS: OpenGL':
|
||||
- 'pcsx2/GS/Renderers/OpenGL/*'
|
||||
- 'pcsx2/GS/Renderers/OpenGL/**/*'
|
||||
- 'bin/resources/shaders/opengl/*'
|
||||
- 'bin/resources/shaders/opengl/**/*'
|
||||
'GS: Vulkan':
|
||||
- 'pcsx2/GS/Renderers/Vulkan/*'
|
||||
- 'pcsx2/GS/Renderers/Vulkan/**/*'
|
||||
- 'bin/resources/shaders/vulkan/*'
|
||||
- 'bin/resources/shaders/vulkan/**/*'
|
||||
'GS: Metal':
|
||||
- 'pcsx2/GS/Renderers/Metal/*'
|
||||
- 'pcsx2/GS/Renderers/Metal/**/*'
|
||||
@@ -102,12 +117,9 @@
|
||||
'Memory Card':
|
||||
- 'pcsx2/gui/MemoryCard*'
|
||||
- 'pcsx2/gui/**/MemoryCard*'
|
||||
'PAD: Linux/Mac':
|
||||
- 'pcsx2/PAD/Linux/*'
|
||||
- 'pcsx2/PAD/Linux/**/*'
|
||||
'PAD: Windows':
|
||||
- 'pcsx2/PAD/Windows/*'
|
||||
- 'pcsx2/PAD/Windows/**/*'
|
||||
'PAD':
|
||||
- 'pcsx2/PAD/*'
|
||||
- 'pcsx2/PAD/**/*'
|
||||
'SPU2':
|
||||
- 'pcsx2/SPU2/*'
|
||||
- 'pcsx2/SPU2/**/*'
|
||||
|
||||
17
.github/workflows/linux_build_matrix.yml
vendored
17
.github/workflows/linux_build_matrix.yml
vendored
@@ -9,25 +9,12 @@ on:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
build_linux_qt_sse4:
|
||||
build_linux_qt:
|
||||
name: "AppImage"
|
||||
uses: ./.github/workflows/linux_build_qt.yml
|
||||
with:
|
||||
jobName: "Qt SSE4"
|
||||
jobName: "Qt"
|
||||
compiler: clang
|
||||
cmakeflags: ""
|
||||
simd: "SSE4"
|
||||
buildAppImage: true
|
||||
secrets: inherit
|
||||
|
||||
build_linux_qt_avx2:
|
||||
name: "AppImage"
|
||||
uses: ./.github/workflows/linux_build_qt.yml
|
||||
with:
|
||||
jobName: "Qt AVX2"
|
||||
detail: ""
|
||||
compiler: clang
|
||||
cmakeflags: "-DARCH_FLAG=-march=haswell"
|
||||
simd: "AVX2"
|
||||
buildAppImage: true
|
||||
secrets: inherit
|
||||
|
||||
9
.github/workflows/linux_build_qt.yml
vendored
9
.github/workflows/linux_build_qt.yml
vendored
@@ -28,10 +28,6 @@ on:
|
||||
required: false
|
||||
type: string
|
||||
default: ""
|
||||
simd:
|
||||
required: false
|
||||
type: string
|
||||
default: ""
|
||||
cheats_url:
|
||||
required: false
|
||||
type: string
|
||||
@@ -63,7 +59,6 @@ jobs:
|
||||
OS: linux
|
||||
GUI_FRAMEWORK: QT
|
||||
ARCH: ${{ inputs.platform }}
|
||||
SIMD: ${{ inputs.simd }}
|
||||
EVENT_NAME: ${{ github.event_name }}
|
||||
PR_TITLE: ${{ github.event.pull_request.title }}
|
||||
PR_NUM: ${{ github.event.pull_request.number }}
|
||||
@@ -79,8 +74,8 @@ jobs:
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: .ccache
|
||||
key: ${{ inputs.os }} ${{ inputs.platform }} ${{ inputs.compiler }} ${{ inputs.simd }} ${{ inputs.detail }} ccache ${{ steps.ccache_cache_timestamp.outputs.timestamp }}
|
||||
restore-keys: ${{ inputs.os }} ${{ inputs.platform }} ${{ inputs.compiler }} ${{ inputs.simd }} ${{ inputs.detail }} ccache
|
||||
key: ${{ inputs.os }} ${{ inputs.platform }} ${{ inputs.compiler }} ${{ inputs.detail }} ccache ${{ steps.ccache_cache_timestamp.outputs.timestamp }}
|
||||
restore-keys: ${{ inputs.os }} ${{ inputs.platform }} ${{ inputs.compiler }} ${{ inputs.detail }} ccache
|
||||
|
||||
- name: Install Packages
|
||||
env:
|
||||
|
||||
1
.github/workflows/macos_build.yml
vendored
1
.github/workflows/macos_build.yml
vendored
@@ -49,7 +49,6 @@ jobs:
|
||||
OS: macos
|
||||
GUI_FRAMEWORK: ${{ inputs.gui }}
|
||||
ARCH: ${{ inputs.platform }}
|
||||
SIMD: ''
|
||||
EVENT_NAME: ${{ github.event_name }}
|
||||
PR_TITLE: ${{ github.event.pull_request.title }}
|
||||
PR_NUM: ${{ github.event.pull_request.number }}
|
||||
|
||||
32
.github/workflows/release_pipeline.yml
vendored
32
.github/workflows/release_pipeline.yml
vendored
@@ -8,32 +8,28 @@ on:
|
||||
jobs:
|
||||
# Build Everything
|
||||
# Linux
|
||||
build_linux_qt_sse4:
|
||||
build_linux_qt:
|
||||
if: github.repository == 'PCSX2/pcsx2'
|
||||
name: "Linux - AppImage SSE4"
|
||||
name: "Linux"
|
||||
uses: ./.github/workflows/linux_build_qt.yml
|
||||
with:
|
||||
jobName: "Qt"
|
||||
compiler: clang
|
||||
cmakeflags: ""
|
||||
simd: "SSE4"
|
||||
buildAppImage: true
|
||||
secrets: inherit
|
||||
|
||||
build_linux_qt_avx2:
|
||||
if: github.repository == 'PCSX2/pcsx2'
|
||||
name: "Linux - AppImage AVX2"
|
||||
uses: ./.github/workflows/linux_build_qt.yml
|
||||
with:
|
||||
jobName: "Qt"
|
||||
detail: ""
|
||||
compiler: clang
|
||||
cmakeflags: "-DARCH_FLAG=-march=haswell"
|
||||
simd: "AVX2"
|
||||
buildAppImage: true
|
||||
secrets: inherit
|
||||
|
||||
# Windows
|
||||
build_windows_qt:
|
||||
if: github.repository == 'PCSX2/pcsx2'
|
||||
name: "Windows"
|
||||
uses: ./.github/workflows/windows_build_qt.yml
|
||||
with:
|
||||
jobName: Qt
|
||||
configuration: CMake
|
||||
buildSystem: cmake
|
||||
secrets: inherit
|
||||
|
||||
build_qt_sse4:
|
||||
if: github.repository == 'PCSX2/pcsx2'
|
||||
name: "Windows - SSE4"
|
||||
@@ -67,8 +63,8 @@ jobs:
|
||||
upload_artifacts:
|
||||
if: github.repository == 'PCSX2/pcsx2'
|
||||
needs:
|
||||
- build_linux_qt_sse4
|
||||
- build_linux_qt_avx2
|
||||
- build_linux_qt
|
||||
- build_windows_qt
|
||||
- build_qt_sse4
|
||||
- build_qt_avx2
|
||||
- build_macos_qt
|
||||
|
||||
@@ -21,7 +21,7 @@ NAME=""
|
||||
|
||||
if [ "${OS}" == "macos" ]; then
|
||||
NAME="PCSX2-${OS}-${GUI_FRAMEWORK}"
|
||||
elif [[ ("${OS}" == "windows" && "$BUILD_SYSTEM" != "cmake") || ("$OS" == "linux" && "$GUI_FRAMEWORK" == "QT") ]]; then
|
||||
elif [[ ("${OS}" == "windows" && "$BUILD_SYSTEM" != "cmake") ]]; then
|
||||
NAME="PCSX2-${OS}-${GUI_FRAMEWORK}-${ARCH}-${SIMD}"
|
||||
else
|
||||
NAME="PCSX2-${OS}-${GUI_FRAMEWORK}-${ARCH}"
|
||||
|
||||
@@ -25,6 +25,9 @@
|
||||
#
|
||||
# For more information, please refer to <http://unlicense.org/>
|
||||
|
||||
SCRIPTDIR=$(dirname "${BASH_SOURCE[0]}")
|
||||
source "$SCRIPTDIR/functions.sh"
|
||||
|
||||
if [ "$#" -ne 4 ]; then
|
||||
echo "Syntax: $0 <path to pcsx2 directory> <path to build directory> <deps prefix> <output name>"
|
||||
exit 1
|
||||
@@ -190,7 +193,7 @@ declare -a QTPLUGINS=(
|
||||
set -e
|
||||
|
||||
if [ ! -f appimagetool-x86_64.AppImage ]; then
|
||||
wget https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage
|
||||
retry_command wget -O appimagetool-x86_64.AppImage https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage
|
||||
chmod +x appimagetool-x86_64.AppImage
|
||||
fi
|
||||
|
||||
|
||||
16
.github/workflows/scripts/linux/functions.sh
vendored
Executable file
16
.github/workflows/scripts/linux/functions.sh
vendored
Executable file
@@ -0,0 +1,16 @@
|
||||
#!/bin/bash
|
||||
|
||||
function retry_command {
|
||||
# Package servers tend to be unreliable at times..
|
||||
# Retry a bunch of times.
|
||||
local RETRIES=10
|
||||
|
||||
for i in $(seq 1 "$RETRIES"); do
|
||||
"$@" && break
|
||||
if [ "$i" == "$RETRIES" ]; then
|
||||
echo "Command \"$@\" failed after ${RETRIES} retries."
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
#!/bin/bash
|
||||
|
||||
SCRIPTDIR=$(dirname "${BASH_SOURCE[0]}")
|
||||
source "$SCRIPTDIR/functions.sh"
|
||||
|
||||
set -e
|
||||
|
||||
# Packages - Build and Qt
|
||||
@@ -57,18 +60,18 @@ declare -a PCSX2_PACKAGES=(
|
||||
)
|
||||
|
||||
if [ "${COMPILER}" = "gcc" ]; then
|
||||
BUILD_PACKAGES+=("g++-10")
|
||||
BUILD_PACKAGES+=("g++-10")
|
||||
else
|
||||
BUILD_PACKAGES+=("llvm-12" "lld-12" "clang-12")
|
||||
BUILD_PACKAGES+=("llvm-12" "lld-12" "clang-12")
|
||||
fi
|
||||
|
||||
sudo apt-get -qq update
|
||||
retry_command sudo apt-get -qq update && break
|
||||
|
||||
# Install packages needed for building
|
||||
echo "Will install the following packages for building - ${BUILD_PACKAGES[*]}"
|
||||
sudo apt-get -y install "${BUILD_PACKAGES[@]}"
|
||||
retry_command sudo apt-get -y install "${BUILD_PACKAGES[@]}"
|
||||
|
||||
# Install packages needed by pcsx2
|
||||
PCSX2_PACKAGES=("${PCSX2_PACKAGES[@]}")
|
||||
echo "Will install the following packages for pcsx2 - ${PCSX2_PACKAGES[*]}"
|
||||
sudo apt-get -y install "${PCSX2_PACKAGES[@]}"
|
||||
retry_command sudo apt-get -y install "${PCSX2_PACKAGES[@]}"
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
# versions as well, avoiding setting policies.
|
||||
cmake_minimum_required(VERSION 3.12...3.24)
|
||||
|
||||
#Enabling this cmake policy gets rid of warnings regarding LTO.
|
||||
cmake_policy(SET CMP0069 NEW)
|
||||
set(CMAKE_POLICY_DEFAULT_CMP0069 NEW)
|
||||
|
||||
if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR})
|
||||
message(FATAL_ERROR "PCSX2 does not support in-tree builds. Please make a build directory that is not the PCSX2 source directory and generate your CMake project there using either `cmake -B build_directory` or by running cmake from the build directory.")
|
||||
endif()
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -383,7 +383,7 @@
|
||||
0300000079000000d218000000000000,Mayflash Magic NS,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:Windows,
|
||||
03000000d620000010a7000000000000,Mayflash Magic NS,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,
|
||||
03000000790000007918000000000000,Mayflash N64 Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,righttrigger:b7,rightx:a3,righty:a2,start:b8,platform:Windows,
|
||||
030000008f0e00001030000000000000,Mayflash Saturn Adapter,a:b0,b:b1,x:b3,y:b4,start:b9,leftshoulder:b5,rightshoulder:b6,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b7,righttrigger:b2,platform:Windows,
|
||||
030000008f0e00001030000000000000,Mayflash Saturn Adapter,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:b7,rightshoulder:b6,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows,
|
||||
0300000025090000e803000000000000,Mayflash Wii Classic Adapter,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:a4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:a5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows,
|
||||
03000000790000000318000000000000,Mayflash Wii DolphinBar,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Windows,
|
||||
03000000790000000018000000000000,Mayflash Wii U Pro Adapter,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:Windows,
|
||||
@@ -407,7 +407,6 @@
|
||||
03000000c62400002b89000000000000,Moga XP5A Plus,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,
|
||||
03000000c62400001a89000000000000,Moga XP5X Plus,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,
|
||||
03000000c62400001b89000000000000,Moga XP5X Plus,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,
|
||||
03000000efbe0000edfe000000000000,Monect Virtual Controller,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:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Windows,
|
||||
03000000250900006688000000000000,MP-8866 Super Dual Box,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,
|
||||
03000000091200004488000000000000,MUSIA PlayStation 2 Input Display,a:b0,b:b2,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b6,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b7,righttrigger:b11,rightx:a2,righty:a3,start:b5,x:b1,y:b3,platform:Windows,
|
||||
03000000f70600000100000000000000,N64 Adaptoid,+rightx:b2,+righty:b1,-rightx:b4,-righty:b5,a:b0,b:b3,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,platform:Windows,
|
||||
@@ -484,8 +483,8 @@
|
||||
030000004c0500006802000000000000,PS3 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b10,lefttrigger:a3~,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:a4~,rightx:a2,righty:a5,start:b8,x:b3,y:b0,platform:Windows,
|
||||
030000004f1f00000800000000000000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000632500007505000000000000,PS3 Controller,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:Windows,
|
||||
03000000888800000803000000000000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b9,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows,
|
||||
03000000888800000804000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,leftshoulder:b10,leftstick:b1,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Windows,
|
||||
03000000888800000803000000000000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b9,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b0,platform:Windows,
|
||||
03000000888800000804000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Windows,
|
||||
030000008f0e00000300000000000000,PS3 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:a5,start:b9,x:b3,y:b0,platform:Windows,
|
||||
030000008f0e00001431000000000000,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,
|
||||
03000000ba2200002010000000000000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b3,y:b2,platform:Windows,
|
||||
@@ -542,8 +541,9 @@
|
||||
030000009b2800005600000000000000,Raphnet SNES Adapter,a:b1,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Windows,
|
||||
030000009b2800005700000000000000,Raphnet SNES Adapter,a:b1,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Windows,
|
||||
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,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,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,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,
|
||||
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,
|
||||
@@ -882,7 +882,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000242f00007300000000020000,Mayflash Magic NS,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b3,platform:Mac OS X,
|
||||
0300000079000000d218000026010000,Mayflash Magic NS,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,
|
||||
03000000d620000010a7000003010000,Mayflash Magic NS,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,
|
||||
030000008f0e00001030000011010000,Mayflash Saturn Adapter,a:b0,b:b2,x:b6,y:b8,start:b18,leftshoulder:b10,rightshoulder:b12,dpup:b24,dpdown:b28,dpleft:b30,dpright:b26,lefttrigger:b14,righttrigger:b4,platform:Mac OS X,
|
||||
030000008f0e00001030000011010000,Mayflash Saturn Adapter,a:b0,b:b2,dpdown:b28,dpleft:b30,dpright:b26,dpup:b24,leftshoulder:b10,lefttrigger:b14,rightshoulder:b12,righttrigger:b4,start:b18,x:b6,y:b8,platform:Mac OS X,
|
||||
0300000025090000e803000000000000,Mayflash Wii Classic Adapter,a:b1,b:b0,back:b8,dpdown:b13,dpleft:b12,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Mac OS X,
|
||||
03000000790000000318000000010000,Mayflash Wii DolphinBar,a:b8,b:b12,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b44,leftshoulder:b16,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b4,platform:Mac OS X,
|
||||
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,
|
||||
@@ -899,6 +899,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000d620000011a7000010050000,Nintendo Switch PowerA 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:Mac OS X,
|
||||
030000007e0500000920000000000000,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,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,
|
||||
030000007e0500000920000001000000,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,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,
|
||||
050000007e05000009200000ff070000,Nintendo Switch Pro Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b3,y:b2,platform:Mac OS X,
|
||||
030000007e0500001920000001000000,NSO N64 Controller,+rightx:b8,+righty:b7,-rightx:b3,-righty:b2,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,righttrigger:b10,start:b9,platform:Mac OS X,
|
||||
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,
|
||||
@@ -945,6 +946,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
030000006b140000130d000000010000,Revolution Pro Controller 3,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,
|
||||
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,
|
||||
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,
|
||||
@@ -1131,6 +1133,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000558500001b06000010010000,GameSir G4 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:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
05000000ac0500002d0200001b010000,GameSir G4s,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b33,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,
|
||||
03000000bc2000005656000011010000,GameSir T4w,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,
|
||||
03000000ac0500001a06000011010000,GameSir-T3 2.02,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,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,
|
||||
0500000047532047616d657061640000,GameStop Gamepad,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,
|
||||
030000006f0e00000104000000010000,Gamestop Logic3 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,
|
||||
030000008f0e00000800000010010000,Gasia PlayStation Gamepad,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:Linux,
|
||||
@@ -1241,10 +1244,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
0300000079000000d218000011010000,Mayflash Magic NS,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,
|
||||
03000000d620000010a7000011010000,Mayflash Magic NS,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,
|
||||
03000000242f0000f700000001010000,Mayflash Magic S 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,
|
||||
030000008f0e00001030000010010000,Mayflash Saturn Adapter,a:b0,b:b1,x:b3,y:b4,start:b9,leftshoulder:b5,rightshoulder:b6,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,lefttrigger:b7,righttrigger:b2,platform:Linux,
|
||||
030000008f0e00001030000010010000,Mayflash Saturn Adapter,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:b7,rightshoulder:b6,righttrigger:b2,start:b9,x:b3,y:b4,platform:Linux,
|
||||
0300000025090000e803000001010000,Mayflash Wii Classic Adapter,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:a4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:a5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux,
|
||||
03000000790000000318000011010000,Mayflash Wii DolphinBar,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Linux,
|
||||
03000000790000000018000011010000,Mayflash Wii U Pro Adapter,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Linux,
|
||||
03000000790000000018000011010000,Mayflash Wii U Pro Adapter,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,
|
||||
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,
|
||||
@@ -1327,7 +1330,6 @@ 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,
|
||||
030000006f0e00008701000011010000,PDP Rock Nintendo Switch Candy Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,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,
|
||||
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,
|
||||
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,
|
||||
@@ -1385,6 +1387,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000300f00001211000011010000,Qanba Arcade Joystick,a:b2,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b6,start:b9,x:b1,y:b3,platform:Linux,
|
||||
03000000222c00000225000011010000,Qanba Dragon Arcade Joystick (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,
|
||||
03000000222c00000025000011010000,Qanba Dragon Arcade Joystick (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,
|
||||
03000000222c00000020000011010000,Qanba Drone Arcade PS4 Joystick,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,rightshoulder:b5,righttrigger:a4,start:b9,x:b0,y:b3,platform:Linux,
|
||||
03000000300f00001210000010010000,Qanba Joystick Plus,a:b0,b:b1,back:b8,leftshoulder:b5,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b6,start:b9,x:b2,y:b3,platform:Linux,
|
||||
03000000222c00000223000011010000,Qanba Obsidian Arcade Joystick (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,
|
||||
03000000222c00000023000011010000,Qanba Obsidian Arcade Joystick (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,
|
||||
@@ -1416,6 +1419,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
030000006b140000130d000011010000,Revolution Pro Controller 3,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,
|
||||
030000006f0e00001f01000000010000,Rock Candy,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,
|
||||
030000006f0e00001e01000011010000,Rock Candy 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:Linux,
|
||||
030000006f0e00008701000011010000,Rock Candy Switch Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,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,
|
||||
03000000c6240000fefa000000010000,Rock Candy Xbox 360 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,
|
||||
030000006f0e00004601000001010000,Rock Candy Xbox One Controller,a:b0,b:b1,back:b6,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,
|
||||
03000000a306000023f6000011010000,Saitek Cyborg V1 PlayStation 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:a4,start:b9,x:b0,y:b3,platform:Linux,
|
||||
@@ -1445,6 +1449,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
030000005e0400008e02000073050000,Speedlink Torid,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,
|
||||
030000005e0400008e02000020200000,SpeedLink Xeox Pro Analog,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,
|
||||
03000000d11800000094000011010000,Stadia 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:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,
|
||||
05000000d11800000094000000010000,Stadia 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:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,
|
||||
03000000de2800000112000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
|
||||
03000000de2800000112000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:+a5,dpleft:-a4,dpright:+a4,dpup:-a5,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,paddle1:b15,paddle2:b16,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux,
|
||||
03000000de2800000211000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
|
||||
|
||||
@@ -23,7 +23,8 @@ cbuffer cb0 : register(b0)
|
||||
float4 BGColor;
|
||||
int EMODA;
|
||||
int EMODC;
|
||||
int cb0_pad[2];
|
||||
int DOFFSET;
|
||||
int cb0_pad;
|
||||
};
|
||||
|
||||
static const float3x3 rgb2yuv =
|
||||
@@ -291,6 +292,41 @@ PS_OUTPUT ps_convert_rgba_8i(PS_INPUT input)
|
||||
return output;
|
||||
}
|
||||
|
||||
PS_OUTPUT ps_convert_clut_4(PS_INPUT input)
|
||||
{
|
||||
// Borrowing the YUV constant buffer.
|
||||
float2 scale = BGColor.xy;
|
||||
uint2 offset = uint2(uint(EMODA), uint(EMODC)) + uint(DOFFSET);
|
||||
|
||||
// CLUT4 is easy, just two rows of 8x8.
|
||||
uint index = uint(input.p.x);
|
||||
uint2 pos = uint2(index % 8u, index / 8u);
|
||||
|
||||
int2 final = int2(floor(float2(offset + pos) * scale));
|
||||
PS_OUTPUT output;
|
||||
output.c = Texture.Load(int3(final, 0), 0);
|
||||
return output;
|
||||
}
|
||||
|
||||
PS_OUTPUT ps_convert_clut_8(PS_INPUT input)
|
||||
{
|
||||
float2 scale = BGColor.xy;
|
||||
uint2 offset = uint2(uint(EMODA), uint(EMODC));
|
||||
uint index = min(uint(input.p.x) + uint(DOFFSET), 255u);
|
||||
|
||||
// CLUT is arranged into 8 groups of 16x2, with the top-right and bottom-left quadrants swapped.
|
||||
// This can probably be done better..
|
||||
uint subgroup = (index / 8u) % 4u;
|
||||
uint2 pos;
|
||||
pos.x = (index % 8u) + ((subgroup >= 2u) ? 8u : 0u);
|
||||
pos.y = ((index / 32u) * 2u) + (subgroup % 2u);
|
||||
|
||||
int2 final = int2(floor(float2(offset + pos) * scale));
|
||||
PS_OUTPUT output;
|
||||
output.c = Texture.Load(int3(final, 0), 0);
|
||||
return output;
|
||||
}
|
||||
|
||||
PS_OUTPUT ps_yuv(PS_INPUT input)
|
||||
{
|
||||
PS_OUTPUT output;
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
#define PS_FST 0
|
||||
#define PS_WMS 0
|
||||
#define PS_WMT 0
|
||||
#define PS_ADJS 0
|
||||
#define PS_ADJT 0
|
||||
#define PS_AEM_FMT FMT_32
|
||||
#define PS_AEM 0
|
||||
#define PS_TFX 0
|
||||
@@ -36,13 +38,13 @@
|
||||
#define PS_POINT_SAMPLER 0
|
||||
#define PS_SHUFFLE 0
|
||||
#define PS_READ_BA 0
|
||||
#define PS_SWAP_GA 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_INVALID_TEX0 0
|
||||
#define PS_SCALE_FACTOR 1.0
|
||||
#define PS_HDR 0
|
||||
#define PS_COLCLIP 0
|
||||
@@ -130,7 +132,6 @@ Texture2D<float4> Palette : register(t1);
|
||||
Texture2D<float4> RtTexture : register(t2);
|
||||
Texture2D<float> PrimMinTexture : register(t3);
|
||||
SamplerState TextureSampler : register(s0);
|
||||
SamplerState PaletteSampler : register(s1);
|
||||
|
||||
#ifdef DX12
|
||||
cbuffer cb0 : register(b0)
|
||||
@@ -159,10 +160,10 @@ cbuffer cb1
|
||||
float2 TA;
|
||||
float MaxDepthPS;
|
||||
float Af;
|
||||
uint4 MskFix;
|
||||
uint4 FbMask;
|
||||
float4 HalfTexel;
|
||||
float4 MinMax;
|
||||
float4 STRange;
|
||||
int4 ChannelShuffle;
|
||||
float2 TC_OffsetHack;
|
||||
float2 STScale;
|
||||
@@ -184,7 +185,20 @@ float4 sample_c(float2 uv, float uv_w)
|
||||
// As of 2018 this issue is still present.
|
||||
uv = (trunc(uv * WH.zw) + float2(0.5, 0.5)) / WH.zw;
|
||||
}
|
||||
#if !PS_ADJS && !PS_ADJT
|
||||
uv *= STScale;
|
||||
#else
|
||||
#if PS_ADJS
|
||||
uv.x = (uv.x - STRange.x) * STRange.z;
|
||||
#else
|
||||
uv.x = uv.x * STScale.x;
|
||||
#endif
|
||||
#if PS_ADJT
|
||||
uv.y = (uv.y - STRange.y) * STRange.w;
|
||||
#else
|
||||
uv.y = uv.y * STScale.y;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if PS_AUTOMATIC_LOD == 1
|
||||
return Texture.Sample(TextureSampler, uv);
|
||||
@@ -207,19 +221,19 @@ float4 sample_c(float2 uv, float uv_w)
|
||||
#endif
|
||||
}
|
||||
|
||||
float4 sample_p(float u)
|
||||
float4 sample_p(uint u)
|
||||
{
|
||||
return Palette.Sample(PaletteSampler, u);
|
||||
return Palette.Load(int3(int(u), 0, 0));
|
||||
}
|
||||
|
||||
float4 sample_p_norm(float u)
|
||||
{
|
||||
return sample_p(uint(u * 255.5f));
|
||||
}
|
||||
|
||||
float4 clamp_wrap_uv(float4 uv)
|
||||
{
|
||||
float4 tex_size;
|
||||
|
||||
if (PS_INVALID_TEX0 == 1)
|
||||
tex_size = WH.zwzw;
|
||||
else
|
||||
tex_size = WH.xyxy;
|
||||
float4 tex_size = WH.xyxy;
|
||||
|
||||
if(PS_WMS == PS_WMT)
|
||||
{
|
||||
@@ -234,7 +248,7 @@ float4 clamp_wrap_uv(float4 uv)
|
||||
// textures. Fixes Xenosaga's hair issue.
|
||||
uv = frac(uv);
|
||||
#endif
|
||||
uv = (float4)(((uint4)(uv * tex_size) & MskFix.xyxy) | MskFix.zwzw) / tex_size;
|
||||
uv = (float4)(((uint4)(uv * tex_size) & asuint(MinMax.xyxy)) | asuint(MinMax.zwzw)) / tex_size;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -248,7 +262,7 @@ float4 clamp_wrap_uv(float4 uv)
|
||||
#if PS_FST == 0
|
||||
uv.xz = frac(uv.xz);
|
||||
#endif
|
||||
uv.xz = (float2)(((uint2)(uv.xz * tex_size.xx) & MskFix.xx) | MskFix.zz) / tex_size.xx;
|
||||
uv.xz = (float2)(((uint2)(uv.xz * tex_size.xx) & asuint(MinMax.xx)) | asuint(MinMax.zz)) / tex_size.xx;
|
||||
}
|
||||
if(PS_WMT == 2)
|
||||
{
|
||||
@@ -259,7 +273,7 @@ float4 clamp_wrap_uv(float4 uv)
|
||||
#if PS_FST == 0
|
||||
uv.yw = frac(uv.yw);
|
||||
#endif
|
||||
uv.yw = (float2)(((uint2)(uv.yw * tex_size.yy) & MskFix.yy) | MskFix.ww) / tex_size.yy;
|
||||
uv.yw = (float2)(((uint2)(uv.yw * tex_size.yy) & asuint(MinMax.yy)) | asuint(MinMax.ww)) / tex_size.yy;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -278,7 +292,7 @@ float4x4 sample_4c(float4 uv, float uv_w)
|
||||
return c;
|
||||
}
|
||||
|
||||
float4 sample_4_index(float4 uv, float uv_w)
|
||||
uint4 sample_4_index(float4 uv, float uv_w)
|
||||
{
|
||||
float4 c;
|
||||
|
||||
@@ -288,25 +302,26 @@ float4 sample_4_index(float4 uv, float uv_w)
|
||||
c.w = sample_c(uv.zw, uv_w).a;
|
||||
|
||||
// Denormalize value
|
||||
uint4 i = uint4(c * 255.0f + 0.5f);
|
||||
uint4 i = uint4(c * 255.5f);
|
||||
|
||||
if (PS_PAL_FMT == 1)
|
||||
{
|
||||
// 4HL
|
||||
c = float4(i & 0xFu) / 255.0f;
|
||||
return i & 0xFu;
|
||||
}
|
||||
else if (PS_PAL_FMT == 2)
|
||||
{
|
||||
// 4HH
|
||||
c = float4(i >> 4u) / 255.0f;
|
||||
return i >> 4u;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 8
|
||||
return i;
|
||||
}
|
||||
|
||||
// Most of texture will hit this code so keep normalized float value
|
||||
// 8 bits
|
||||
return c * 255./256 + 0.5/256;
|
||||
}
|
||||
|
||||
float4x4 sample_4p(float4 u)
|
||||
float4x4 sample_4p(uint4 u)
|
||||
{
|
||||
float4x4 c;
|
||||
|
||||
@@ -348,7 +363,7 @@ float4 fetch_c(int2 uv)
|
||||
|
||||
int2 clamp_wrap_uv_depth(int2 uv)
|
||||
{
|
||||
int4 mask = (int4)MskFix << 4;
|
||||
int4 mask = asint(MinMax) << 4;
|
||||
if (PS_WMS == PS_WMT)
|
||||
{
|
||||
if (PS_WMS == 2)
|
||||
@@ -468,7 +483,7 @@ float4 fetch_red(int2 xy)
|
||||
rt = fetch_raw_color(xy);
|
||||
}
|
||||
|
||||
return sample_p(rt.r) * 255.0f;
|
||||
return sample_p_norm(rt.r) * 255.0f;
|
||||
}
|
||||
|
||||
float4 fetch_green(int2 xy)
|
||||
@@ -485,7 +500,7 @@ float4 fetch_green(int2 xy)
|
||||
rt = fetch_raw_color(xy);
|
||||
}
|
||||
|
||||
return sample_p(rt.g) * 255.0f;
|
||||
return sample_p_norm(rt.g) * 255.0f;
|
||||
}
|
||||
|
||||
float4 fetch_blue(int2 xy)
|
||||
@@ -502,19 +517,19 @@ float4 fetch_blue(int2 xy)
|
||||
rt = fetch_raw_color(xy);
|
||||
}
|
||||
|
||||
return sample_p(rt.b) * 255.0f;
|
||||
return sample_p_norm(rt.b) * 255.0f;
|
||||
}
|
||||
|
||||
float4 fetch_alpha(int2 xy)
|
||||
{
|
||||
float4 rt = fetch_raw_color(xy);
|
||||
return sample_p(rt.a) * 255.0f;
|
||||
return sample_p_norm(rt.a) * 255.0f;
|
||||
}
|
||||
|
||||
float4 fetch_rgb(int2 xy)
|
||||
{
|
||||
float4 rt = fetch_raw_color(xy);
|
||||
float4 c = float4(sample_p(rt.r).r, sample_p(rt.g).g, sample_p(rt.b).b, 1.0);
|
||||
float4 c = float4(sample_p_norm(rt.r).r, sample_p_norm(rt.g).g, sample_p_norm(rt.b).b, 1.0);
|
||||
return c * 255.0f;
|
||||
}
|
||||
|
||||
@@ -671,11 +686,7 @@ float4 fog(float4 c, float f)
|
||||
|
||||
float4 ps_color(PS_INPUT input)
|
||||
{
|
||||
#if PS_FST == 0 && PS_INVALID_TEX0 == 1
|
||||
// Re-normalize coordinate from invalid GS to corrected texture size
|
||||
float2 st = (input.t.xy * WH.xy) / (input.t.w * WH.zw);
|
||||
float2 st_int = (input.ti.zw * WH.xy) / (input.t.w * WH.zw);
|
||||
#elif PS_FST == 0
|
||||
#if PS_FST == 0
|
||||
float2 st = input.t.xy / input.t.w;
|
||||
float2 st_int = input.ti.zw / input.t.w;
|
||||
#else
|
||||
@@ -865,28 +876,37 @@ PS_OUTPUT ps_main(PS_INPUT input)
|
||||
|
||||
if (PS_SHUFFLE)
|
||||
{
|
||||
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_SWAP_GA)
|
||||
{
|
||||
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)));
|
||||
float4 RT = trunc(RtTexture.Load(int3(input.p.xy, 0)) * 255.0f + 0.1f);
|
||||
C.a = C.g;
|
||||
C.g = C.a;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (denorm_c.g & 0x80u)
|
||||
C.ga = (float2)(float((denorm_c.g & 0x7Fu) | (denorm_TA.y & 0x80u)));
|
||||
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.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)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -75,13 +75,12 @@ layout(std140, binding = 0) uniform cb21
|
||||
float MaxDepthPS;
|
||||
float Af;
|
||||
|
||||
uvec4 MskFix;
|
||||
|
||||
uvec4 FbMask;
|
||||
|
||||
vec4 HalfTexel;
|
||||
|
||||
vec4 MinMax;
|
||||
vec4 STRange;
|
||||
|
||||
ivec4 ChannelShuffle;
|
||||
|
||||
@@ -92,11 +91,6 @@ layout(std140, binding = 0) uniform cb21
|
||||
};
|
||||
#endif
|
||||
|
||||
//layout(std140, binding = 22) uniform cb22
|
||||
//{
|
||||
// vec4 rt_size;
|
||||
//};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Default Sampler
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -314,6 +314,41 @@ void ps_hdr_resolve()
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_convert_clut_4
|
||||
uniform uvec3 offset;
|
||||
uniform vec2 scale;
|
||||
|
||||
void ps_convert_clut_4()
|
||||
{
|
||||
// CLUT4 is easy, just two rows of 8x8.
|
||||
uint index = uint(gl_FragCoord.x) + offset.z;
|
||||
uvec2 pos = uvec2(index % 8u, index / 8u);
|
||||
|
||||
ivec2 final = ivec2(floor(vec2(offset.xy + pos) * scale));
|
||||
SV_Target0 = texelFetch(TextureSampler, final, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_convert_clut_8
|
||||
uniform uvec3 offset;
|
||||
uniform vec2 scale;
|
||||
|
||||
void ps_convert_clut_8()
|
||||
{
|
||||
uint index = min(uint(gl_FragCoord.x) + offset.z, 255u);
|
||||
|
||||
// CLUT is arranged into 8 groups of 16x2, with the top-right and bottom-left quadrants swapped.
|
||||
// This can probably be done better..
|
||||
uint subgroup = (index / 8u) % 4u;
|
||||
uvec2 pos;
|
||||
pos.x = (index % 8u) + ((subgroup >= 2u) ? 8u : 0u);
|
||||
pos.y = ((index / 32u) * 2u) + (subgroup % 2u);
|
||||
|
||||
ivec2 final = ivec2(floor(vec2(offset.xy + pos) * scale));
|
||||
SV_Target0 = texelFetch(TextureSampler, final, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_yuv
|
||||
uniform ivec2 EMOD;
|
||||
|
||||
|
||||
@@ -109,7 +109,20 @@ vec4 sample_c(vec2 uv)
|
||||
// As of 2018 this issue is still present.
|
||||
uv = (trunc(uv * WH.zw) + vec2(0.5, 0.5)) / WH.zw;
|
||||
#endif
|
||||
uv *= STScale;
|
||||
#if !PS_ADJS && !PS_ADJT
|
||||
uv *= STScale;
|
||||
#else
|
||||
#if PS_ADJS
|
||||
uv.x = (uv.x - STRange.x) * STRange.z;
|
||||
#else
|
||||
uv.x = uv.x * STScale.x;
|
||||
#endif
|
||||
#if PS_ADJT
|
||||
uv.y = (uv.y - STRange.y) * STRange.w;
|
||||
#else
|
||||
uv.y = uv.y * STScale.y;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if PS_AUTOMATIC_LOD == 1
|
||||
return texture(TextureSampler, uv);
|
||||
@@ -133,19 +146,20 @@ vec4 sample_c(vec2 uv)
|
||||
#endif
|
||||
}
|
||||
|
||||
vec4 sample_p(float idx)
|
||||
vec4 sample_p(uint idx)
|
||||
{
|
||||
return texture(PaletteSampler, vec2(idx, 0.0f));
|
||||
return texelFetch(PaletteSampler, ivec2(int(idx), 0), 0);
|
||||
}
|
||||
|
||||
vec4 sample_p_norm(float u)
|
||||
{
|
||||
return sample_p(uint(u * 255.5f));
|
||||
}
|
||||
|
||||
vec4 clamp_wrap_uv(vec4 uv)
|
||||
{
|
||||
vec4 uv_out = uv;
|
||||
#if PS_INVALID_TEX0 == 1
|
||||
vec4 tex_size = WH.zwzw;
|
||||
#else
|
||||
vec4 tex_size = WH.xyxy;
|
||||
#endif
|
||||
|
||||
#if PS_WMS == PS_WMT
|
||||
|
||||
@@ -157,7 +171,7 @@ vec4 clamp_wrap_uv(vec4 uv)
|
||||
// textures. Fixes Xenosaga's hair issue.
|
||||
uv = fract(uv);
|
||||
#endif
|
||||
uv_out = vec4((uvec4(uv * tex_size) & MskFix.xyxy) | MskFix.zwzw) / tex_size;
|
||||
uv_out = vec4((uvec4(uv * tex_size) & floatBitsToUint(MinMax.xyxy)) | floatBitsToUint(MinMax.zwzw)) / tex_size;
|
||||
#endif
|
||||
|
||||
#else // PS_WMS != PS_WMT
|
||||
@@ -169,7 +183,7 @@ vec4 clamp_wrap_uv(vec4 uv)
|
||||
#if PS_FST == 0
|
||||
uv.xz = fract(uv.xz);
|
||||
#endif
|
||||
uv_out.xz = vec2((uvec2(uv.xz * tex_size.xx) & MskFix.xx) | MskFix.zz) / tex_size.xx;
|
||||
uv_out.xz = vec2((uvec2(uv.xz * tex_size.xx) & floatBitsToUint(MinMax.xx)) | floatBitsToUint(MinMax.zz)) / tex_size.xx;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -180,7 +194,7 @@ vec4 clamp_wrap_uv(vec4 uv)
|
||||
#if PS_FST == 0
|
||||
uv.yw = fract(uv.yw);
|
||||
#endif
|
||||
uv_out.yw = vec2((uvec2(uv.yw * tex_size.yy) & MskFix.yy) | MskFix.ww) / tex_size.yy;
|
||||
uv_out.yw = vec2((uvec2(uv.yw * tex_size.yy) & floatBitsToUint(MinMax.yy)) | floatBitsToUint(MinMax.ww)) / tex_size.yy;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -202,7 +216,7 @@ mat4 sample_4c(vec4 uv)
|
||||
return c;
|
||||
}
|
||||
|
||||
vec4 sample_4_index(vec4 uv)
|
||||
uvec4 sample_4_index(vec4 uv)
|
||||
{
|
||||
vec4 c;
|
||||
|
||||
@@ -218,26 +232,22 @@ vec4 sample_4_index(vec4 uv)
|
||||
c.z = sample_c(uv.xw).a;
|
||||
c.w = sample_c(uv.zw).a;
|
||||
|
||||
uvec4 i = uvec4(c * 255.0f + 0.5f); // Denormalize value
|
||||
uvec4 i = uvec4(c * 255.5f); // Denormalize value
|
||||
|
||||
#if PS_PAL_FMT == 1
|
||||
// 4HL
|
||||
return vec4(i & 0xFu) / 255.0f;
|
||||
|
||||
return i & 0xFu;
|
||||
#elif PS_PAL_FMT == 2
|
||||
// 4HH
|
||||
return vec4(i >> 4u) / 255.0f;
|
||||
|
||||
return i >> 4u;
|
||||
#else
|
||||
// Most of texture will hit this code so keep normalized float value
|
||||
|
||||
// 8 bits
|
||||
return c;
|
||||
// 8
|
||||
return i;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
mat4 sample_4p(vec4 u)
|
||||
mat4 sample_4p(uvec4 u)
|
||||
{
|
||||
mat4 c;
|
||||
|
||||
@@ -287,7 +297,7 @@ ivec2 clamp_wrap_uv_depth(ivec2 uv)
|
||||
|
||||
// Keep the full precision
|
||||
// It allow to multiply the ScalingFactor before the 1/16 coeff
|
||||
ivec4 mask = ivec4(MskFix) << 4;
|
||||
ivec4 mask = floatBitsToInt(MinMax) << 4;
|
||||
|
||||
#if PS_WMS == PS_WMT
|
||||
|
||||
@@ -398,7 +408,7 @@ vec4 fetch_red()
|
||||
#else
|
||||
vec4 rt = fetch_raw_color();
|
||||
#endif
|
||||
return sample_p(rt.r) * 255.0f;
|
||||
return sample_p_norm(rt.r) * 255.0f;
|
||||
}
|
||||
|
||||
vec4 fetch_green()
|
||||
@@ -409,7 +419,7 @@ vec4 fetch_green()
|
||||
#else
|
||||
vec4 rt = fetch_raw_color();
|
||||
#endif
|
||||
return sample_p(rt.g) * 255.0f;
|
||||
return sample_p_norm(rt.g) * 255.0f;
|
||||
}
|
||||
|
||||
vec4 fetch_blue()
|
||||
@@ -420,19 +430,19 @@ vec4 fetch_blue()
|
||||
#else
|
||||
vec4 rt = fetch_raw_color();
|
||||
#endif
|
||||
return sample_p(rt.b) * 255.0f;
|
||||
return sample_p_norm(rt.b) * 255.0f;
|
||||
}
|
||||
|
||||
vec4 fetch_alpha()
|
||||
{
|
||||
vec4 rt = fetch_raw_color();
|
||||
return sample_p(rt.a) * 255.0f;
|
||||
return sample_p_norm(rt.a) * 255.0f;
|
||||
}
|
||||
|
||||
vec4 fetch_rgb()
|
||||
{
|
||||
vec4 rt = fetch_raw_color();
|
||||
vec4 c = vec4(sample_p(rt.r).r, sample_p(rt.g).g, sample_p(rt.b).b, 1.0f);
|
||||
vec4 c = vec4(sample_p_norm(rt.r).r, sample_p_norm(rt.g).g, sample_p_norm(rt.b).b, 1.0f);
|
||||
return c * 255.0f;
|
||||
}
|
||||
|
||||
@@ -590,11 +600,7 @@ void fog(inout vec4 C, float f)
|
||||
vec4 ps_color()
|
||||
{
|
||||
//FIXME: maybe we can set gl_Position.w = q in VS
|
||||
#if (PS_FST == 0) && (PS_INVALID_TEX0 == 1)
|
||||
// Re-normalize coordinate from invalid GS to corrected texture size
|
||||
vec2 st = (PSin.t_float.xy * WH.xy) / (vec2(PSin.t_float.w) * WH.zw);
|
||||
vec2 st_int = (PSin.t_int.zw * WH.xy) / (vec2(PSin.t_float.w) * WH.zw);
|
||||
#elif (PS_FST == 0)
|
||||
#if (PS_FST == 0)
|
||||
vec2 st = PSin.t_float.xy / vec2(PSin.t_float.w);
|
||||
vec2 st_int = PSin.t_int.zw / vec2(PSin.t_float.w);
|
||||
#else
|
||||
|
||||
@@ -274,6 +274,49 @@ void ps_convert_rgba_8i()
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_convert_clut_4
|
||||
layout(push_constant) uniform cb10
|
||||
{
|
||||
vec2 scale;
|
||||
uvec2 offset;
|
||||
uint doffset;
|
||||
};
|
||||
|
||||
void ps_convert_clut_4()
|
||||
{
|
||||
// CLUT4 is easy, just two rows of 8x8.
|
||||
uint index = uint(gl_FragCoord.x) + doffset;
|
||||
uvec2 pos = uvec2(index % 8u, index / 8u);
|
||||
|
||||
ivec2 final = ivec2(floor(vec2(offset + pos) * scale));
|
||||
o_col0 = texelFetch(samp0, final, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_convert_clut_8
|
||||
layout(push_constant) uniform cb10
|
||||
{
|
||||
vec2 scale;
|
||||
uvec2 offset;
|
||||
uint doffset;
|
||||
};
|
||||
|
||||
void ps_convert_clut_8()
|
||||
{
|
||||
uint index = min(uint(gl_FragCoord.x) + doffset, 255u);
|
||||
|
||||
// CLUT is arranged into 8 groups of 16x2, with the top-right and bottom-left quadrants swapped.
|
||||
// This can probably be done better..
|
||||
uint subgroup = (index / 8u) % 4u;
|
||||
uvec2 pos;
|
||||
pos.x = (index % 8u) + ((subgroup >= 2u) ? 8u : 0u);
|
||||
pos.y = ((index / 32u) * 2u) + (subgroup % 2u);
|
||||
|
||||
ivec2 final = ivec2(floor(vec2(offset + pos) * scale));
|
||||
o_col0 = texelFetch(samp0, final, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ps_yuv
|
||||
layout(push_constant) uniform cb10
|
||||
{
|
||||
|
||||
@@ -312,6 +312,8 @@ void main()
|
||||
#define PS_FST 0
|
||||
#define PS_WMS 0
|
||||
#define PS_WMT 0
|
||||
#define PS_ADJS 0
|
||||
#define PS_ADJT 0
|
||||
#define PS_FMT FMT_32
|
||||
#define PS_AEM 0
|
||||
#define PS_TFX 0
|
||||
@@ -332,7 +334,6 @@ void main()
|
||||
#define PS_CHANNEL_FETCH 0
|
||||
#define PS_TALES_OF_ABYSS_HLE 0
|
||||
#define PS_URBAN_CHAOS_HLE 0
|
||||
#define PS_INVALID_TEX0 0
|
||||
#define PS_SCALE_FACTOR 1.0
|
||||
#define PS_HDR 0
|
||||
#define PS_COLCLIP 0
|
||||
@@ -346,6 +347,7 @@ void main()
|
||||
#define PS_ZCLAMP 0
|
||||
#define PS_FEEDBACK_LOOP 0
|
||||
#define PS_TEX_IS_FB 0
|
||||
#define PS_SWAP_GA 0
|
||||
#endif
|
||||
|
||||
#define SW_BLEND (PS_BLEND_A || PS_BLEND_B || PS_BLEND_D)
|
||||
@@ -361,10 +363,10 @@ layout(std140, set = 0, binding = 1) uniform cb1
|
||||
vec2 TA;
|
||||
float MaxDepthPS;
|
||||
float Af;
|
||||
uvec4 MskFix;
|
||||
uvec4 FbMask;
|
||||
vec4 HalfTexel;
|
||||
vec4 MinMax;
|
||||
vec4 STRange;
|
||||
ivec4 ChannelShuffle;
|
||||
vec2 TC_OffsetHack;
|
||||
vec2 STScale;
|
||||
@@ -390,7 +392,7 @@ layout(location = 0) out vec4 o_col0;
|
||||
#endif
|
||||
|
||||
layout(set = 1, binding = 0) uniform sampler2D Texture;
|
||||
layout(set = 1, binding = 1) uniform sampler2D Palette;
|
||||
layout(set = 1, binding = 1) uniform texture2D Palette;
|
||||
|
||||
#if PS_FEEDBACK_LOOP_IS_NEEDED
|
||||
#ifndef DISABLE_TEXTURE_BARRIER
|
||||
@@ -420,7 +422,20 @@ vec4 sample_c(vec2 uv)
|
||||
// As of 2018 this issue is still present.
|
||||
uv = (trunc(uv * WH.zw) + vec2(0.5, 0.5)) / WH.zw;
|
||||
#endif
|
||||
#if !PS_ADJS && !PS_ADJT
|
||||
uv *= STScale;
|
||||
#else
|
||||
#if PS_ADJS
|
||||
uv.x = (uv.x - STRange.x) * STRange.z;
|
||||
#else
|
||||
uv.x = uv.x * STScale.x;
|
||||
#endif
|
||||
#if PS_ADJT
|
||||
uv.y = (uv.y - STRange.y) * STRange.w;
|
||||
#else
|
||||
uv.y = uv.y * STScale.y;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if PS_AUTOMATIC_LOD == 1
|
||||
return texture(Texture, uv);
|
||||
@@ -443,20 +458,19 @@ vec4 sample_c(vec2 uv)
|
||||
#endif
|
||||
}
|
||||
|
||||
vec4 sample_p(float u)
|
||||
vec4 sample_p(uint idx)
|
||||
{
|
||||
return texture(Palette, vec2(u, 0.0f));
|
||||
return texelFetch(Palette, ivec2(int(idx), 0), 0);
|
||||
}
|
||||
|
||||
vec4 sample_p_norm(float u)
|
||||
{
|
||||
return sample_p(uint(u * 255.5f));
|
||||
}
|
||||
|
||||
vec4 clamp_wrap_uv(vec4 uv)
|
||||
{
|
||||
vec4 tex_size;
|
||||
|
||||
#if PS_INVALID_TEX0
|
||||
tex_size = WH.zwzw;
|
||||
#else
|
||||
tex_size = WH.xyxy;
|
||||
#endif
|
||||
vec4 tex_size = WH.xyxy;
|
||||
|
||||
#if PS_WMS == PS_WMT
|
||||
{
|
||||
@@ -471,7 +485,7 @@ vec4 clamp_wrap_uv(vec4 uv)
|
||||
// textures. Fixes Xenosaga's hair issue.
|
||||
uv = fract(uv);
|
||||
#endif
|
||||
uv = vec4((uvec4(uv * tex_size) & MskFix.xyxy) | MskFix.zwzw) / tex_size;
|
||||
uv = vec4((uvec4(uv * tex_size) & floatBitsToUint(MinMax.xyxy)) | floatBitsToUint(MinMax.zwzw)) / tex_size;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -486,7 +500,7 @@ vec4 clamp_wrap_uv(vec4 uv)
|
||||
#if PS_FST == 0
|
||||
uv.xz = fract(uv.xz);
|
||||
#endif
|
||||
uv.xz = vec2((uvec2(uv.xz * tex_size.xx) & MskFix.xx) | MskFix.zz) / tex_size.xx;
|
||||
uv.xz = vec2((uvec2(uv.xz * tex_size.xx) & floatBitsToUint(MinMax.xx)) | floatBitsToUint(MinMax.zz)) / tex_size.xx;
|
||||
}
|
||||
#endif
|
||||
#if PS_WMT == 2
|
||||
@@ -498,7 +512,7 @@ vec4 clamp_wrap_uv(vec4 uv)
|
||||
#if PS_FST == 0
|
||||
uv.yw = fract(uv.yw);
|
||||
#endif
|
||||
uv.yw = vec2((uvec2(uv.yw * tex_size.yy) & MskFix.yy) | MskFix.ww) / tex_size.yy;
|
||||
uv.yw = vec2((uvec2(uv.yw * tex_size.yy) & floatBitsToUint(MinMax.yy)) | floatBitsToUint(MinMax.ww)) / tex_size.yy;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -519,7 +533,7 @@ mat4 sample_4c(vec4 uv)
|
||||
return c;
|
||||
}
|
||||
|
||||
vec4 sample_4_index(vec4 uv)
|
||||
uvec4 sample_4_index(vec4 uv)
|
||||
{
|
||||
vec4 c;
|
||||
|
||||
@@ -529,22 +543,21 @@ vec4 sample_4_index(vec4 uv)
|
||||
c.w = sample_c(uv.zw).a;
|
||||
|
||||
// Denormalize value
|
||||
uvec4 i = uvec4(c * 255.0f + 0.5f);
|
||||
uvec4 i = uvec4(c * 255.5f);
|
||||
|
||||
#if PS_PAL_FMT == 1
|
||||
// 4HL
|
||||
c = vec4(i & 0xFu) / 255.0f;
|
||||
return i & 0xFu;
|
||||
#elif PS_PAL_FMT == 2
|
||||
// 4HH
|
||||
c = vec4(i >> 4u) / 255.0f;
|
||||
return i >> 4u;
|
||||
#else
|
||||
// 8
|
||||
return i;
|
||||
#endif
|
||||
|
||||
// Most of texture will hit this code so keep normalized float value
|
||||
// 8 bits
|
||||
return c * 255./256 + 0.5/256;
|
||||
}
|
||||
|
||||
mat4 sample_4p(vec4 u)
|
||||
mat4 sample_4p(uvec4 u)
|
||||
{
|
||||
mat4 c;
|
||||
|
||||
@@ -586,7 +599,7 @@ vec4 fetch_c(ivec2 uv)
|
||||
|
||||
ivec2 clamp_wrap_uv_depth(ivec2 uv)
|
||||
{
|
||||
ivec4 mask = ivec4(MskFix << 4);
|
||||
ivec4 mask = floatBitsToInt(MinMax) << 4;
|
||||
#if (PS_WMS == PS_WMT)
|
||||
{
|
||||
#if (PS_WMS == 2)
|
||||
@@ -709,7 +722,7 @@ vec4 fetch_red(ivec2 xy)
|
||||
rt = fetch_raw_color(xy);
|
||||
#endif
|
||||
|
||||
return sample_p(rt.r) * 255.0f;
|
||||
return sample_p_norm(rt.r) * 255.0f;
|
||||
}
|
||||
|
||||
vec4 fetch_green(ivec2 xy)
|
||||
@@ -723,7 +736,7 @@ vec4 fetch_green(ivec2 xy)
|
||||
rt = fetch_raw_color(xy);
|
||||
#endif
|
||||
|
||||
return sample_p(rt.g) * 255.0f;
|
||||
return sample_p_norm(rt.g) * 255.0f;
|
||||
}
|
||||
|
||||
vec4 fetch_blue(ivec2 xy)
|
||||
@@ -737,19 +750,19 @@ vec4 fetch_blue(ivec2 xy)
|
||||
rt = fetch_raw_color(xy);
|
||||
#endif
|
||||
|
||||
return sample_p(rt.b) * 255.0f;
|
||||
return sample_p_norm(rt.b) * 255.0f;
|
||||
}
|
||||
|
||||
vec4 fetch_alpha(ivec2 xy)
|
||||
{
|
||||
vec4 rt = fetch_raw_color(xy);
|
||||
return sample_p(rt.a) * 255.0f;
|
||||
return sample_p_norm(rt.a) * 255.0f;
|
||||
}
|
||||
|
||||
vec4 fetch_rgb(ivec2 xy)
|
||||
{
|
||||
vec4 rt = fetch_raw_color(xy);
|
||||
vec4 c = vec4(sample_p(rt.r).r, sample_p(rt.g).g, sample_p(rt.b).b, 1.0);
|
||||
vec4 c = vec4(sample_p_norm(rt.r).r, sample_p_norm(rt.g).g, sample_p_norm(rt.b).b, 1.0);
|
||||
return c * 255.0f;
|
||||
}
|
||||
|
||||
@@ -903,11 +916,7 @@ vec4 fog(vec4 c, float f)
|
||||
|
||||
vec4 ps_color()
|
||||
{
|
||||
#if PS_FST == 0 && PS_INVALID_TEX0 == 1
|
||||
// Re-normalize coordinate from invalid GS to corrected texture size
|
||||
vec2 st = (vsIn.t.xy * WH.xy) / (vsIn.t.w * WH.zw);
|
||||
vec2 st_int = (vsIn.ti.zw * WH.xy) / (vsIn.t.w * WH.zw);
|
||||
#elif PS_FST == 0
|
||||
#if PS_FST == 0
|
||||
vec2 st = vsIn.t.xy / vsIn.t.w;
|
||||
vec2 st_int = vsIn.ti.zw / vsIn.t.w;
|
||||
#else
|
||||
@@ -1165,26 +1174,32 @@ void main()
|
||||
vec4 C = ps_color();
|
||||
|
||||
#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;
|
||||
#if PS_SWAP_GA
|
||||
vec4 RT = trunc(subpassLoad(RtSampler) * 255.0f + 0.1f);
|
||||
C.a = RT.g;
|
||||
C.g = RT.a;
|
||||
#else
|
||||
C.rb = C.rr;
|
||||
#endif
|
||||
uvec4 denorm_c = uvec4(C);
|
||||
uvec2 denorm_TA = uvec2(vec2(TA.xy) * 255.0f + 0.5f);
|
||||
|
||||
#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)));
|
||||
// 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
|
||||
|
||||
|
||||
@@ -201,27 +201,22 @@ endif()
|
||||
# Note: future GCC (aka GCC 5.1.1) has less false positive so warning could maybe put back
|
||||
# -Wno-unused-function: warn for function not used in release build
|
||||
# -Wno-unused-value: lots of warning for this kind of statements "0 && ...". There are used to disable some parts of code in release/dev build.
|
||||
# -Wno-overloaded-virtual: Gives a fair number of warnings under clang over in the wxwidget gui section of the code.
|
||||
# -Wno-deprecated-declarations: The USB plugins dialogs are written in straight gtk 2, which gives a million deprecated warnings. Suppress them until we can deal with them.
|
||||
# -Wno-format*: Yeah, these need to be taken care of, but...
|
||||
# -Wno-stringop-truncation: Who comes up with these compiler warnings, anyways?
|
||||
# -Wno-stringop-overflow: Probably the same people as this one...
|
||||
# -Wno-maybe-uninitialized: Lots of gcc warnings like "‘test.GSVector8i::<anonymous>.GSVector8i::<unnamed union>::m’ may be used uninitialized" if this is removed.
|
||||
|
||||
if (MSVC)
|
||||
set(DEFAULT_WARNINGS)
|
||||
else()
|
||||
set(DEFAULT_WARNINGS -Wall -Wextra -Wno-attributes -Wno-unused-function -Wno-unused-parameter -Wno-missing-field-initializers -Wno-deprecated-declarations -Wno-format -Wno-format-security -Wno-overloaded-virtual)
|
||||
set(DEFAULT_WARNINGS -Wall -Wextra -Wno-attributes -Wno-unused-function -Wno-unused-parameter -Wno-missing-field-initializers -Wno-format -Wno-format-security)
|
||||
if (NOT USE_ICC)
|
||||
list(APPEND DEFAULT_WARNINGS -Wno-unused-value)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (USE_CLANG)
|
||||
list(APPEND DEFAULT_WARNINGS -Wno-overloaded-virtual)
|
||||
endif()
|
||||
|
||||
if (USE_GCC)
|
||||
list(APPEND DEFAULT_WARNINGS -Wno-stringop-truncation -Wno-stringop-overflow)
|
||||
list(APPEND DEFAULT_WARNINGS -Wno-stringop-truncation -Wno-stringop-overflow -Wno-maybe-uninitialized )
|
||||
endif()
|
||||
|
||||
|
||||
@@ -232,11 +227,6 @@ elseif(NOT MSVC)
|
||||
set(AGGRESSIVE_WARNING -Wstrict-aliasing -Wstrict-overflow=1)
|
||||
endif()
|
||||
|
||||
if (USE_CLANG)
|
||||
# -Wno-deprecated-register: glib issue...
|
||||
list(APPEND DEFAULT_WARNINGS -Wno-deprecated-register -Wno-c++14-extensions)
|
||||
endif()
|
||||
|
||||
if (USE_PGO_GENERATE OR USE_PGO_OPTIMIZE)
|
||||
add_compile_options("-fprofile-dir=${CMAKE_SOURCE_DIR}/profile")
|
||||
endif()
|
||||
|
||||
@@ -10,16 +10,14 @@ add_library(common)
|
||||
# x86emitter sources
|
||||
target_sources(common PRIVATE
|
||||
AlignedMalloc.cpp
|
||||
VirtualMemory.cpp
|
||||
EventSource.inl
|
||||
SafeArray.inl
|
||||
Console.cpp
|
||||
CrashHandler.cpp
|
||||
DynamicLibrary.cpp
|
||||
EventSource.cpp
|
||||
Exceptions.cpp
|
||||
FastJmp.cpp
|
||||
FileSystem.cpp
|
||||
General.cpp
|
||||
Image.cpp
|
||||
HTTPDownloader.cpp
|
||||
MemorySettingsInterface.cpp
|
||||
@@ -71,7 +69,6 @@ target_sources(common PRIVATE
|
||||
DynamicLibrary.h
|
||||
Easing.h
|
||||
EnumOps.h
|
||||
EventSource.h
|
||||
Exceptions.h
|
||||
FastJmp.h
|
||||
FileSystem.h
|
||||
@@ -88,7 +85,6 @@ target_sources(common PRIVATE
|
||||
MD5Digest.h
|
||||
MRCHelpers.h
|
||||
Path.h
|
||||
PageFaultSource.h
|
||||
PrecompiledHeader.h
|
||||
ProgressCallback.h
|
||||
ReadbackSpinManager.h
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2010 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 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 PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <mutex>
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// EventSource< template EvtType >
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
template <typename ListenerType>
|
||||
class EventSource
|
||||
{
|
||||
public:
|
||||
typedef typename ListenerType::EvtParams EvtParams;
|
||||
typedef typename std::list<ListenerType*> ListenerList;
|
||||
typedef typename ListenerList::iterator ListenerIterator;
|
||||
|
||||
protected:
|
||||
typedef typename ListenerList::const_iterator ConstIterator;
|
||||
|
||||
ListenerList m_listeners;
|
||||
|
||||
// This is a cached copy of the listener list used to handle standard dispatching, which
|
||||
// allows for self-modification of the EventSource's listener list by the listeners.
|
||||
// Translation: The dispatcher uses this copy instead, to avoid iterator invalidation.
|
||||
ListenerList m_cache_copy;
|
||||
bool m_cache_valid;
|
||||
|
||||
std::mutex m_listeners_lock;
|
||||
|
||||
public:
|
||||
EventSource()
|
||||
{
|
||||
m_cache_valid = false;
|
||||
}
|
||||
|
||||
virtual ~EventSource() = default;
|
||||
|
||||
virtual ListenerIterator Add(ListenerType& listener);
|
||||
virtual void Remove(ListenerType& listener);
|
||||
virtual void Remove(const ListenerIterator& listenerHandle);
|
||||
|
||||
void Add(ListenerType* listener)
|
||||
{
|
||||
if (listener == NULL)
|
||||
return;
|
||||
Add(*listener);
|
||||
}
|
||||
|
||||
void Remove(ListenerType* listener)
|
||||
{
|
||||
if (listener == NULL)
|
||||
return;
|
||||
Remove(*listener);
|
||||
}
|
||||
|
||||
void Dispatch(const EvtParams& params);
|
||||
|
||||
protected:
|
||||
virtual ListenerIterator _AddFast_without_lock(ListenerType& listener);
|
||||
virtual void _DispatchRaw(ListenerIterator iter, const ListenerIterator& iend, const EvtParams& params);
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// IEventDispatcher
|
||||
// --------------------------------------------------------------------------------------
|
||||
// This class is used as a base interface for EventListeners. It allows the listeners to do
|
||||
// customized dispatching of several event types into "user friendly" function overrides.
|
||||
//
|
||||
template <typename EvtParams>
|
||||
class IEventDispatcher
|
||||
{
|
||||
protected:
|
||||
IEventDispatcher() {}
|
||||
|
||||
public:
|
||||
virtual ~IEventDispatcher() = default;
|
||||
virtual void DispatchEvent(const EvtParams& params) = 0;
|
||||
};
|
||||
@@ -1,110 +0,0 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2010 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 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 PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "common/Pcsx2Defs.h"
|
||||
#include "common/Exceptions.h"
|
||||
#include "common/Console.h"
|
||||
|
||||
template <typename ListenerType>
|
||||
typename EventSource<ListenerType>::ListenerIterator EventSource<ListenerType>::Add(ListenerType& listener)
|
||||
{
|
||||
std::unique_lock locker(m_listeners_lock);
|
||||
|
||||
// Check for duplicates before adding the event.
|
||||
if (IsDebugBuild)
|
||||
{
|
||||
ListenerIterator iter = m_listeners.begin();
|
||||
while (iter != m_listeners.end())
|
||||
{
|
||||
if ((*iter) == &listener)
|
||||
return iter;
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
return _AddFast_without_lock(listener);
|
||||
}
|
||||
|
||||
template <typename ListenerType>
|
||||
void EventSource<ListenerType>::Remove(ListenerType& listener)
|
||||
{
|
||||
std::unique_lock locker(m_listeners_lock);
|
||||
m_cache_valid = false;
|
||||
m_listeners.remove(&listener);
|
||||
}
|
||||
|
||||
template <typename ListenerType>
|
||||
void EventSource<ListenerType>::Remove(const ListenerIterator& listenerHandle)
|
||||
{
|
||||
std::unique_lock locker(m_listeners_lock);
|
||||
m_cache_valid = false;
|
||||
m_listeners.erase(listenerHandle);
|
||||
}
|
||||
|
||||
template <typename ListenerType>
|
||||
typename EventSource<ListenerType>::ListenerIterator EventSource<ListenerType>::_AddFast_without_lock(ListenerType& listener)
|
||||
{
|
||||
m_cache_valid = false;
|
||||
m_listeners.push_front(&listener);
|
||||
return m_listeners.begin();
|
||||
}
|
||||
|
||||
|
||||
template <typename ListenerType>
|
||||
__fi void EventSource<ListenerType>::_DispatchRaw(ListenerIterator iter, const ListenerIterator& iend, const EvtParams& evtparams)
|
||||
{
|
||||
while (iter != iend)
|
||||
{
|
||||
try
|
||||
{
|
||||
(*iter)->DispatchEvent(evtparams);
|
||||
}
|
||||
catch (Exception::RuntimeError& ex)
|
||||
{
|
||||
if (IsDevBuild)
|
||||
{
|
||||
pxFailDev(("Ignoring runtime error thrown from event listener (event listeners should not throw exceptions!): " + ex.FormatDiagnosticMessage()).c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Error("Ignoring runtime error thrown from event listener: %s", ex.FormatDiagnosticMessage().c_str());
|
||||
}
|
||||
}
|
||||
catch (BaseException& ex)
|
||||
{
|
||||
if (IsDevBuild)
|
||||
{
|
||||
ex.DiagMsg() = "Non-runtime BaseException thrown from event listener .. " + ex.DiagMsg();
|
||||
throw;
|
||||
}
|
||||
Console.Error("Ignoring non-runtime BaseException thrown from event listener: %s", ex.FormatDiagnosticMessage().c_str());
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ListenerType>
|
||||
void EventSource<ListenerType>::Dispatch(const EvtParams& evtparams)
|
||||
{
|
||||
if (!m_cache_valid)
|
||||
{
|
||||
m_cache_copy = m_listeners;
|
||||
m_cache_valid = true;
|
||||
}
|
||||
|
||||
if (m_cache_copy.empty())
|
||||
return;
|
||||
_DispatchRaw(m_cache_copy.begin(), m_cache_copy.end(), evtparams);
|
||||
}
|
||||
@@ -74,33 +74,6 @@ namespace Exception
|
||||
virtual BaseException* Clone() const = 0;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Ps2Generic Exception
|
||||
// --------------------------------------------------------------------------------------
|
||||
// This class is used as a base exception for things tossed by PS2 cpus (EE, IOP, etc).
|
||||
//
|
||||
// Implementation note: does not derive from BaseException, so that we can use different
|
||||
// catch block hierarchies to handle them (if needed).
|
||||
//
|
||||
// Translation Note: Currently these exceptions are never translated. English/diagnostic
|
||||
// format only. :)
|
||||
//
|
||||
class Ps2Generic
|
||||
{
|
||||
protected:
|
||||
std::string m_message; // a "detailed" message of what disastrous thing has occurred!
|
||||
|
||||
public:
|
||||
virtual ~Ps2Generic() = default;
|
||||
|
||||
virtual u32 GetPc() const = 0;
|
||||
virtual bool IsDelaySlot() const = 0;
|
||||
virtual std::string& Message() { return m_message; }
|
||||
|
||||
virtual void Rethrow() const = 0;
|
||||
virtual Ps2Generic* Clone() const = 0;
|
||||
};
|
||||
|
||||
// Some helper macros for defining the standard constructors of internationalized constructors
|
||||
// Parameters:
|
||||
// classname - Yeah, the name of this class being defined. :)
|
||||
|
||||
@@ -60,7 +60,10 @@ namespace GL
|
||||
GLint info_log_length = 0;
|
||||
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &info_log_length);
|
||||
|
||||
if (status == GL_FALSE || info_log_length > 0)
|
||||
// Log will create a new line when there are no warnings so let's set a minimum log length of 1.
|
||||
constexpr int info_log_min_length = 1;
|
||||
|
||||
if (status == GL_FALSE || info_log_length > info_log_min_length)
|
||||
{
|
||||
std::string info_log;
|
||||
info_log.resize(info_log_length + 1);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2009 PCSX2 Dev Team
|
||||
* Copyright (C) 2002-2010 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
@@ -14,7 +14,26 @@
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "EventSource.h"
|
||||
#include "EventSource.inl"
|
||||
#include "General.h"
|
||||
|
||||
//template class EventSource< int >;
|
||||
// --------------------------------------------------------------------------------------
|
||||
// PageProtectionMode (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
std::string PageProtectionMode::ToString() const
|
||||
{
|
||||
std::string modeStr;
|
||||
|
||||
if (m_read)
|
||||
modeStr += "Read";
|
||||
if (m_write)
|
||||
modeStr += "Write";
|
||||
if (m_exec)
|
||||
modeStr += "Exec";
|
||||
|
||||
if (modeStr.empty())
|
||||
return "NoAccess";
|
||||
if (modeStr.length() <= 5)
|
||||
modeStr += "Only";
|
||||
|
||||
return modeStr;
|
||||
}
|
||||
@@ -116,6 +116,14 @@ static __fi PageProtectionMode PageAccess_Any()
|
||||
return PageProtectionMode().All();
|
||||
}
|
||||
|
||||
struct PageFaultInfo
|
||||
{
|
||||
uptr pc;
|
||||
uptr addr;
|
||||
};
|
||||
|
||||
using PageFaultHandler = bool(*)(const PageFaultInfo& info);
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// HostSys
|
||||
// --------------------------------------------------------------------------------------
|
||||
@@ -141,6 +149,12 @@ namespace HostSys
|
||||
extern void DestroySharedMemory(void* ptr);
|
||||
extern void* MapSharedMemory(void* handle, size_t offset, void* baseaddr, size_t size, const PageProtectionMode& mode);
|
||||
extern void UnmapSharedMemory(void* baseaddr, size_t size);
|
||||
|
||||
/// Installs the specified page fault handler. Only one handler can be active at once.
|
||||
bool InstallPageFaultHandler(PageFaultHandler handler);
|
||||
|
||||
/// Removes the page fault handler. handler is only specified to check against the active callback.
|
||||
void RemovePageFaultHandler(PageFaultHandler handler);
|
||||
}
|
||||
|
||||
class SharedMemoryMappingArea
|
||||
|
||||
@@ -21,13 +21,15 @@
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include "fmt/core.h"
|
||||
|
||||
#include "common/Align.h"
|
||||
#include "common/PageFaultSource.h"
|
||||
#include "common/Assertions.h"
|
||||
#include "common/Console.h"
|
||||
#include "common/Exceptions.h"
|
||||
#include "common/General.h"
|
||||
|
||||
// Apple uses the MAP_ANON define instead of MAP_ANONYMOUS, but they mean
|
||||
// the same thing.
|
||||
@@ -44,34 +46,57 @@
|
||||
#include <ucontext.h>
|
||||
#endif
|
||||
|
||||
extern void SignalExit(int sig);
|
||||
static std::recursive_mutex s_exception_handler_mutex;
|
||||
static PageFaultHandler s_exception_handler_callback;
|
||||
static bool s_in_exception_handler;
|
||||
|
||||
static const uptr m_pagemask = getpagesize() - 1;
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#ifdef __APPLE__
|
||||
static struct sigaction s_old_sigbus_action;
|
||||
#else
|
||||
static struct sigaction s_old_sigsegv_action;
|
||||
#endif
|
||||
|
||||
static void CallExistingSignalHandler(int signal, siginfo_t* siginfo, void* ctx)
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
const struct sigaction& sa = s_old_sigbus_action;
|
||||
#else
|
||||
const struct sigaction& sa = s_old_sigsegv_action;
|
||||
#endif
|
||||
|
||||
if (sa.sa_flags & SA_SIGINFO)
|
||||
{
|
||||
sa.sa_sigaction(signal, siginfo, ctx);
|
||||
}
|
||||
else if (sa.sa_handler == SIG_DFL)
|
||||
{
|
||||
// Re-raising the signal would just queue it, and since we'd restore the handler back to us,
|
||||
// we'd end up right back here again. So just abort, because that's probably what it'd do anyway.
|
||||
abort();
|
||||
}
|
||||
else if (sa.sa_handler != SIG_IGN)
|
||||
{
|
||||
sa.sa_handler(signal);
|
||||
}
|
||||
}
|
||||
|
||||
// Linux implementation of SIGSEGV handler. Bind it using sigaction().
|
||||
static void SysPageFaultSignalFilter(int signal, siginfo_t* siginfo, void* ctx)
|
||||
{
|
||||
// [TODO] : Add a thread ID filter to the Linux Signal handler here.
|
||||
// Rationale: On windows, the __try/__except model allows per-thread specific behavior
|
||||
// for page fault handling. On linux, there is a single signal handler for the whole
|
||||
// process, but the handler is executed by the thread that caused the exception.
|
||||
// Executing the handler concurrently from multiple threads wouldn't go down well.
|
||||
std::unique_lock lock(s_exception_handler_mutex);
|
||||
|
||||
// Prevent recursive exception filtering.
|
||||
if (s_in_exception_handler)
|
||||
{
|
||||
CallExistingSignalHandler(signal, siginfo, ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
// Stdio Usage note: SIGSEGV handling is a synchronous in-thread signal. It is done
|
||||
// from the context of the current thread and stackframe. So long as the thread is not
|
||||
// the main/ui thread, use of the px assertion system should be safe. Use of stdio should
|
||||
// be safe even on the main thread.
|
||||
// (in other words, stdio limitations only really apply to process-level asynchronous
|
||||
// signals)
|
||||
|
||||
// Note: Use of stdio functions isn't safe here. Avoid console logs,
|
||||
// assertions, file logs, or just about anything else useful.
|
||||
// Note: Use of stdio functions isn't safe here. Avoid console logs, assertions, file logs,
|
||||
// or just about anything else useful. However, that's really only a concern if the signal
|
||||
// occurred within those functions. The logging which we do only happens when the exception
|
||||
// occurred within JIT code.
|
||||
|
||||
#if defined(__APPLE__) && defined(__x86_64__)
|
||||
void* const exception_pc = reinterpret_cast<void*>(static_cast<ucontext_t*>(ctx)->uc_mcontext->__ss.__rip);
|
||||
@@ -81,35 +106,62 @@ static void SysPageFaultSignalFilter(int signal, siginfo_t* siginfo, void* ctx)
|
||||
void* const exception_pc = nullptr;
|
||||
#endif
|
||||
|
||||
// Note: This signal can be accessed by the EE or MTVU thread
|
||||
// Source_PageFault is a global variable with its own state information
|
||||
// so for now we lock this exception code unless someone can fix this better...
|
||||
std::unique_lock lock(PageFault_Mutex);
|
||||
const PageFaultInfo pfi{(uptr)exception_pc, (uptr)siginfo->si_addr & ~__pagemask};
|
||||
|
||||
Source_PageFault->Dispatch(PageFaultInfo((uptr)exception_pc, (uptr)siginfo->si_addr & ~m_pagemask));
|
||||
s_in_exception_handler = true;
|
||||
|
||||
// resumes execution right where we left off (re-executes instruction that
|
||||
// caused the SIGSEGV).
|
||||
if (Source_PageFault->WasHandled())
|
||||
const bool handled = s_exception_handler_callback(pfi);
|
||||
|
||||
s_in_exception_handler = false;
|
||||
|
||||
// Resumes execution right where we left off (re-executes instruction that caused the SIGSEGV).
|
||||
if (handled)
|
||||
return;
|
||||
|
||||
std::fprintf(stderr, "Unhandled page fault @ 0x%08x", siginfo->si_addr);
|
||||
pxFailRel("Unhandled page fault");
|
||||
// Call old signal handler, which will likely dump core.
|
||||
CallExistingSignalHandler(signal, siginfo, ctx);
|
||||
}
|
||||
|
||||
void _platform_InstallSignalHandler()
|
||||
bool HostSys::InstallPageFaultHandler(PageFaultHandler handler)
|
||||
{
|
||||
Console.WriteLn("Installing POSIX SIGSEGV handler...");
|
||||
struct sigaction sa;
|
||||
std::unique_lock lock(s_exception_handler_mutex);
|
||||
pxAssertRel(!s_exception_handler_callback, "A page fault handler is already registered.");
|
||||
if (!s_exception_handler_callback)
|
||||
{
|
||||
struct sigaction sa;
|
||||
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_SIGINFO;
|
||||
sa.sa_sigaction = SysPageFaultSignalFilter;
|
||||
#if defined(__APPLE__)
|
||||
// MacOS uses SIGBUS for memory permission violations
|
||||
sigaction(SIGBUS, &sa, &s_old_sigbus_action);
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_SIGINFO;
|
||||
sa.sa_sigaction = SysPageFaultSignalFilter;
|
||||
#ifdef __APPLE__
|
||||
// MacOS uses SIGBUS for memory permission violations
|
||||
if (sigaction(SIGBUS, &sa, &s_old_sigbus_action) != 0)
|
||||
return false;
|
||||
#else
|
||||
sigaction(SIGSEGV, &sa, &s_old_sigsegv_action);
|
||||
if (sigaction(SIGSEGV, &sa, &s_old_sigsegv_action) != 0)
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
s_exception_handler_callback = handler;
|
||||
return true;
|
||||
}
|
||||
|
||||
void HostSys::RemovePageFaultHandler(PageFaultHandler handler)
|
||||
{
|
||||
std::unique_lock lock(s_exception_handler_mutex);
|
||||
pxAssertRel(!s_exception_handler_callback || s_exception_handler_callback == handler,
|
||||
"Not removing the same handler previously registered.");
|
||||
if (!s_exception_handler_callback)
|
||||
return;
|
||||
|
||||
s_exception_handler_callback = nullptr;
|
||||
|
||||
struct sigaction sa;
|
||||
#ifdef __APPLE__
|
||||
sigaction(SIGBUS, &s_old_sigbus_action, &sa);
|
||||
#else
|
||||
sigaction(SIGSEGV, &s_old_sigsegv_action, &sa);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -153,6 +153,9 @@ namespace Vulkan
|
||||
m_provoking_vertex = {};
|
||||
m_provoking_vertex.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_PROVOKING_VERTEX_STATE_CREATE_INFO_EXT;
|
||||
|
||||
m_line_rasterization_state = {};
|
||||
m_line_rasterization_state.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT;
|
||||
|
||||
// set defaults
|
||||
SetNoCullRasterizationState();
|
||||
SetNoDepthTestState();
|
||||
@@ -255,7 +258,17 @@ namespace Vulkan
|
||||
m_ci.pRasterizationState = &m_rasterization_state;
|
||||
}
|
||||
|
||||
void GraphicsPipelineBuilder::SetLineWidth(float width) { m_rasterization_state.lineWidth = width; }
|
||||
void GraphicsPipelineBuilder::SetLineWidth(float width)
|
||||
{
|
||||
m_rasterization_state.lineWidth = width;
|
||||
}
|
||||
|
||||
void GraphicsPipelineBuilder::SetLineRasterizationMode(VkLineRasterizationModeEXT mode)
|
||||
{
|
||||
Util::AddPointerToChain(&m_rasterization_state, &m_line_rasterization_state);
|
||||
|
||||
m_line_rasterization_state.lineRasterizationMode = mode;
|
||||
}
|
||||
|
||||
void GraphicsPipelineBuilder::SetMultisamples(u32 multisamples, bool per_sample_shading)
|
||||
{
|
||||
|
||||
@@ -96,6 +96,7 @@ namespace Vulkan
|
||||
|
||||
void SetRasterizationState(VkPolygonMode polygon_mode, VkCullModeFlags cull_mode, VkFrontFace front_face);
|
||||
void SetLineWidth(float width);
|
||||
void SetLineRasterizationMode(VkLineRasterizationModeEXT mode);
|
||||
void SetMultisamples(u32 multisamples, bool per_sample_shading);
|
||||
void SetNoCullRasterizationState();
|
||||
|
||||
@@ -157,6 +158,7 @@ namespace Vulkan
|
||||
VkPipelineMultisampleStateCreateInfo m_multisample_state;
|
||||
|
||||
VkPipelineRasterizationProvokingVertexStateCreateInfoEXT m_provoking_vertex;
|
||||
VkPipelineRasterizationLineStateCreateInfoEXT m_line_rasterization_state;
|
||||
};
|
||||
|
||||
class ComputePipelineBuilder
|
||||
|
||||
@@ -458,6 +458,8 @@ namespace Vulkan
|
||||
SupportsExtension(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME, false);
|
||||
m_optional_extensions.vk_ext_calibrated_timestamps =
|
||||
SupportsExtension(VK_EXT_CALIBRATED_TIMESTAMPS_EXTENSION_NAME, false);
|
||||
m_optional_extensions.vk_ext_line_rasterization =
|
||||
SupportsExtension(VK_EXT_LINE_RASTERIZATION_EXTENSION_NAME, false);
|
||||
m_optional_extensions.vk_khr_driver_properties =
|
||||
SupportsExtension(VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME, false);
|
||||
m_optional_extensions.vk_arm_rasterization_order_attachment_access =
|
||||
@@ -654,12 +656,19 @@ namespace Vulkan
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT};
|
||||
VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesARM rasterization_order_access_feature = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_ARM};
|
||||
VkPhysicalDeviceLineRasterizationFeaturesEXT line_rasterization_feature = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT};
|
||||
|
||||
if (m_optional_extensions.vk_ext_provoking_vertex)
|
||||
{
|
||||
provoking_vertex_feature.provokingVertexLast = VK_TRUE;
|
||||
Util::AddPointerToChain(&device_info, &provoking_vertex_feature);
|
||||
}
|
||||
if (m_optional_extensions.vk_ext_line_rasterization)
|
||||
{
|
||||
line_rasterization_feature.bresenhamLines = VK_TRUE;
|
||||
Util::AddPointerToChain(&device_info, &line_rasterization_feature);
|
||||
}
|
||||
if (m_optional_extensions.vk_arm_rasterization_order_attachment_access)
|
||||
{
|
||||
rasterization_order_access_feature.rasterizationOrderColorAttachmentAccess = VK_TRUE;
|
||||
@@ -724,12 +733,16 @@ namespace Vulkan
|
||||
VkPhysicalDeviceFeatures2 features2 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2};
|
||||
VkPhysicalDeviceProvokingVertexFeaturesEXT provoking_vertex_features = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT};
|
||||
VkPhysicalDeviceLineRasterizationFeaturesEXT line_rasterization_feature = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT};
|
||||
VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesARM rasterization_order_access_feature = {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_ARM};
|
||||
|
||||
// add in optional feature structs
|
||||
if (m_optional_extensions.vk_ext_provoking_vertex)
|
||||
Util::AddPointerToChain(&features2, &provoking_vertex_features);
|
||||
if (m_optional_extensions.vk_ext_line_rasterization)
|
||||
Util::AddPointerToChain(&features2, &line_rasterization_feature);
|
||||
if (m_optional_extensions.vk_arm_rasterization_order_attachment_access)
|
||||
Util::AddPointerToChain(&features2, &rasterization_order_access_feature);
|
||||
|
||||
@@ -739,6 +752,7 @@ namespace Vulkan
|
||||
// confirm we actually support it
|
||||
m_optional_extensions.vk_ext_provoking_vertex &= (provoking_vertex_features.provokingVertexLast == VK_TRUE);
|
||||
m_optional_extensions.vk_arm_rasterization_order_attachment_access &= (rasterization_order_access_feature.rasterizationOrderColorAttachmentAccess == VK_TRUE);
|
||||
m_optional_extensions.vk_ext_line_rasterization &= (line_rasterization_feature.bresenhamLines == VK_TRUE);
|
||||
|
||||
VkPhysicalDeviceProperties2 properties2 = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2};
|
||||
void** pNext = &properties2.pNext;
|
||||
@@ -789,6 +803,8 @@ namespace Vulkan
|
||||
|
||||
Console.WriteLn("VK_EXT_provoking_vertex is %s",
|
||||
m_optional_extensions.vk_ext_provoking_vertex ? "supported" : "NOT supported");
|
||||
Console.WriteLn("VK_EXT_line_rasterization is %s",
|
||||
m_optional_extensions.vk_ext_line_rasterization ? "supported" : "NOT supported");
|
||||
Console.WriteLn("VK_EXT_calibrated_timestamps is %s",
|
||||
m_optional_extensions.vk_ext_calibrated_timestamps ? "supported" : "NOT supported");
|
||||
Console.WriteLn("VK_ARM_rasterization_order_attachment_access is %s",
|
||||
|
||||
@@ -52,6 +52,7 @@ namespace Vulkan
|
||||
bool vk_ext_provoking_vertex : 1;
|
||||
bool vk_ext_memory_budget : 1;
|
||||
bool vk_ext_calibrated_timestamps : 1;
|
||||
bool vk_ext_line_rasterization : 1;
|
||||
bool vk_khr_driver_properties : 1;
|
||||
bool vk_arm_rasterization_order_attachment_access : 1;
|
||||
bool vk_khr_fragment_shader_barycentric : 1;
|
||||
|
||||
@@ -637,7 +637,7 @@ namespace Vulkan
|
||||
}
|
||||
|
||||
m_images.reserve(image_count);
|
||||
m_current_image = (image_count - 1);
|
||||
m_current_image = 0;
|
||||
for (u32 i = 0; i < image_count; i++)
|
||||
{
|
||||
SwapChainImage image;
|
||||
@@ -650,31 +650,36 @@ namespace Vulkan
|
||||
return false;
|
||||
}
|
||||
|
||||
const VkSemaphoreCreateInfo semaphore_info = {VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, nullptr, 0};
|
||||
res = vkCreateSemaphore(g_vulkan_context->GetDevice(), &semaphore_info, nullptr, &image.available_semaphore);
|
||||
if (res != VK_SUCCESS)
|
||||
{
|
||||
LOG_VULKAN_ERROR(res, "vkCreateSemaphore failed: ");
|
||||
return false;
|
||||
}
|
||||
|
||||
res = vkCreateSemaphore(g_vulkan_context->GetDevice(), &semaphore_info, nullptr, &image.rendering_finished_semaphore);
|
||||
if (res != VK_SUCCESS)
|
||||
{
|
||||
LOG_VULKAN_ERROR(res, "vkCreateSemaphore failed: ");
|
||||
vkDestroySemaphore(g_vulkan_context->GetDevice(), image.available_semaphore, nullptr);
|
||||
return false;
|
||||
}
|
||||
|
||||
image.framebuffer = image.texture.CreateFramebuffer(m_load_render_pass);
|
||||
if (image.framebuffer == VK_NULL_HANDLE)
|
||||
return false;
|
||||
|
||||
m_images.emplace_back(std::move(image));
|
||||
}
|
||||
|
||||
m_semaphores.reserve(image_count);
|
||||
m_current_semaphore = (image_count - 1);
|
||||
for (u32 i = 0; i < image_count; i++)
|
||||
{
|
||||
ImageSemaphores sema;
|
||||
|
||||
const VkSemaphoreCreateInfo semaphore_info = {VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, nullptr, 0};
|
||||
res = vkCreateSemaphore(g_vulkan_context->GetDevice(), &semaphore_info, nullptr, &sema.available_semaphore);
|
||||
if (res != VK_SUCCESS)
|
||||
{
|
||||
vkDestroySemaphore(g_vulkan_context->GetDevice(), image.rendering_finished_semaphore, nullptr);
|
||||
vkDestroySemaphore(g_vulkan_context->GetDevice(), image.available_semaphore, nullptr);
|
||||
LOG_VULKAN_ERROR(res, "vkCreateSemaphore failed: ");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_images.emplace_back(std::move(image));
|
||||
res = vkCreateSemaphore(g_vulkan_context->GetDevice(), &semaphore_info, nullptr, &sema.rendering_finished_semaphore);
|
||||
if (res != VK_SUCCESS)
|
||||
{
|
||||
LOG_VULKAN_ERROR(res, "vkCreateSemaphore failed: ");
|
||||
vkDestroySemaphore(g_vulkan_context->GetDevice(), sema.available_semaphore, nullptr);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_semaphores.push_back(sema);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -685,11 +690,16 @@ namespace Vulkan
|
||||
for (auto& it : m_images)
|
||||
{
|
||||
// Images themselves are cleaned up by the swap chain object
|
||||
vkDestroySemaphore(g_vulkan_context->GetDevice(), it.rendering_finished_semaphore, nullptr);
|
||||
vkDestroySemaphore(g_vulkan_context->GetDevice(), it.available_semaphore, nullptr);
|
||||
vkDestroyFramebuffer(g_vulkan_context->GetDevice(), it.framebuffer, nullptr);
|
||||
}
|
||||
m_images.clear();
|
||||
for (auto& it : m_semaphores)
|
||||
{
|
||||
vkDestroySemaphore(g_vulkan_context->GetDevice(), it.rendering_finished_semaphore, nullptr);
|
||||
vkDestroySemaphore(g_vulkan_context->GetDevice(), it.available_semaphore, nullptr);
|
||||
}
|
||||
m_semaphores.clear();
|
||||
|
||||
m_image_acquire_result.reset();
|
||||
}
|
||||
|
||||
@@ -712,21 +722,11 @@ namespace Vulkan
|
||||
if (!m_swap_chain)
|
||||
return VK_ERROR_SURFACE_LOST_KHR;
|
||||
|
||||
// Unfortunately we can't query the image before providing the semaphore.
|
||||
// So, let's hope we get it correct.
|
||||
const u32 expected_image = (m_current_image + 1) % static_cast<u32>(m_images.size());
|
||||
const VkResult res = vkAcquireNextImageKHR(g_vulkan_context->GetDevice(), m_swap_chain, UINT64_MAX,
|
||||
m_images[expected_image].available_semaphore, VK_NULL_HANDLE, &m_current_image);
|
||||
if (res == VK_SUCCESS)
|
||||
{
|
||||
// Did we get the correct image? If not, we'll just swap the semaphore handles so it lines up.
|
||||
if (m_current_image != expected_image)
|
||||
{
|
||||
std::swap(m_images[expected_image].available_semaphore, m_images[m_current_image].available_semaphore);
|
||||
DevCon.WriteLn("Predicted wrong image (expected %u, got %u), swapped semaphores", expected_image, m_current_image);
|
||||
}
|
||||
}
|
||||
// Use a different semaphore for each image.
|
||||
m_current_semaphore = (m_current_semaphore + 1) % static_cast<u32>(m_semaphores.size());
|
||||
|
||||
const VkResult res = vkAcquireNextImageKHR(g_vulkan_context->GetDevice(), m_swap_chain, UINT64_MAX,
|
||||
m_semaphores[m_current_semaphore].available_semaphore, VK_NULL_HANDLE, &m_current_image);
|
||||
m_image_acquire_result = res;
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -70,10 +70,10 @@ namespace Vulkan
|
||||
__fi VkFramebuffer GetCurrentFramebuffer() const { return m_images[m_current_image].framebuffer; }
|
||||
__fi VkRenderPass GetLoadRenderPass() const { return m_load_render_pass; }
|
||||
__fi VkRenderPass GetClearRenderPass() const { return m_clear_render_pass; }
|
||||
__fi VkSemaphore GetImageAvailableSemaphore() const { return m_images[m_current_image].available_semaphore; }
|
||||
__fi const VkSemaphore* GetImageAvailableSemaphorePtr() const { return &m_images[m_current_image].available_semaphore; }
|
||||
__fi VkSemaphore GetRenderingFinishedSemaphore() const { return m_images[m_current_image].rendering_finished_semaphore; }
|
||||
__fi const VkSemaphore* GetRenderingFinishedSemaphorePtr() const { return &m_images[m_current_image].rendering_finished_semaphore; }
|
||||
__fi VkSemaphore GetImageAvailableSemaphore() const { return m_semaphores[m_current_semaphore].available_semaphore; }
|
||||
__fi const VkSemaphore* GetImageAvailableSemaphorePtr() const { return &m_semaphores[m_current_semaphore].available_semaphore; }
|
||||
__fi VkSemaphore GetRenderingFinishedSemaphore() const { return m_semaphores[m_current_semaphore].rendering_finished_semaphore; }
|
||||
__fi const VkSemaphore* GetRenderingFinishedSemaphorePtr() const { return &m_semaphores[m_current_semaphore].rendering_finished_semaphore; }
|
||||
VkResult AcquireNextImage();
|
||||
void ReleaseCurrentImage();
|
||||
|
||||
@@ -107,6 +107,10 @@ namespace Vulkan
|
||||
VkImage image;
|
||||
Texture texture;
|
||||
VkFramebuffer framebuffer;
|
||||
};
|
||||
|
||||
struct ImageSemaphores
|
||||
{
|
||||
VkSemaphore available_semaphore;
|
||||
VkSemaphore rendering_finished_semaphore;
|
||||
};
|
||||
@@ -123,7 +127,9 @@ namespace Vulkan
|
||||
|
||||
VkSwapchainKHR m_swap_chain = VK_NULL_HANDLE;
|
||||
std::vector<SwapChainImage> m_images;
|
||||
std::vector<ImageSemaphores> m_semaphores;
|
||||
u32 m_current_image = 0;
|
||||
u32 m_current_semaphore = 0;
|
||||
std::optional<VkResult> m_image_acquire_result;
|
||||
};
|
||||
} // namespace Vulkan
|
||||
|
||||
@@ -17,60 +17,78 @@
|
||||
|
||||
#include "common/Align.h"
|
||||
#include "common/RedtapeWindows.h"
|
||||
#include "common/PageFaultSource.h"
|
||||
#include "common/Console.h"
|
||||
#include "common/General.h"
|
||||
#include "common/Exceptions.h"
|
||||
#include "common/StringUtil.h"
|
||||
#include "common/AlignedMalloc.h"
|
||||
#include "fmt/core.h"
|
||||
#include "common/Assertions.h"
|
||||
|
||||
#include "fmt/core.h"
|
||||
#include "fmt/format.h"
|
||||
|
||||
static long DoSysPageFaultExceptionFilter(EXCEPTION_POINTERS* eps)
|
||||
{
|
||||
if (eps->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION)
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
#include <mutex>
|
||||
|
||||
#if defined(_M_AMD64)
|
||||
void* const exception_pc = reinterpret_cast<void*>(eps->ContextRecord->Rip);
|
||||
#else
|
||||
void* const exception_pc = nullptr;
|
||||
#endif
|
||||
|
||||
// Note: This exception can be accessed by the EE or MTVU thread
|
||||
// Source_PageFault is a global variable with its own state information
|
||||
// so for now we lock this exception code unless someone can fix this better...
|
||||
std::unique_lock lock(PageFault_Mutex);
|
||||
Source_PageFault->Dispatch(PageFaultInfo((uptr)exception_pc, (uptr)eps->ExceptionRecord->ExceptionInformation[1]));
|
||||
return Source_PageFault->WasHandled() ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
static std::recursive_mutex s_exception_handler_mutex;
|
||||
static PageFaultHandler s_exception_handler_callback;
|
||||
static void* s_exception_handler_handle;
|
||||
static bool s_in_exception_handler;
|
||||
|
||||
long __stdcall SysPageFaultExceptionFilter(EXCEPTION_POINTERS* eps)
|
||||
{
|
||||
// Prevent recursive exception filtering by catching the exception from the filter here.
|
||||
// In the event that the filter causes an access violation (happened during shutdown
|
||||
// because Source_PageFault was deallocated), this will allow the debugger to catch the
|
||||
// exception.
|
||||
// TODO: find a reliable way to debug the filter itself, I've come up with a few ways that
|
||||
// work but I don't fully understand why some do and some don't.
|
||||
__try
|
||||
{
|
||||
return DoSysPageFaultExceptionFilter(eps);
|
||||
}
|
||||
__except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
|
||||
{
|
||||
// Executing the handler concurrently from multiple threads wouldn't go down well.
|
||||
std::unique_lock lock(s_exception_handler_mutex);
|
||||
|
||||
// Prevent recursive exception filtering.
|
||||
if (s_in_exception_handler)
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
|
||||
// Only interested in page faults.
|
||||
if (eps->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION)
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
|
||||
void* const exception_pc = reinterpret_cast<void*>(eps->ContextRecord->Rip);
|
||||
|
||||
const PageFaultInfo pfi{(uptr)exception_pc, (uptr)eps->ExceptionRecord->ExceptionInformation[1]};
|
||||
|
||||
s_in_exception_handler = true;
|
||||
|
||||
const bool handled = s_exception_handler_callback(pfi);
|
||||
|
||||
s_in_exception_handler = false;
|
||||
|
||||
return handled ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
bool HostSys::InstallPageFaultHandler(PageFaultHandler handler)
|
||||
{
|
||||
std::unique_lock lock(s_exception_handler_mutex);
|
||||
pxAssertRel(!s_exception_handler_callback, "A page fault handler is already registered.");
|
||||
if (!s_exception_handler_handle)
|
||||
{
|
||||
s_exception_handler_handle = AddVectoredExceptionHandler(TRUE, SysPageFaultExceptionFilter);
|
||||
if (!s_exception_handler_handle)
|
||||
return false;
|
||||
}
|
||||
|
||||
s_exception_handler_callback = handler;
|
||||
return true;
|
||||
}
|
||||
|
||||
void HostSys::RemovePageFaultHandler(PageFaultHandler handler)
|
||||
{
|
||||
std::unique_lock lock(s_exception_handler_mutex);
|
||||
pxAssertRel(!s_exception_handler_callback || s_exception_handler_callback == handler,
|
||||
"Not removing the same handler previously registered.");
|
||||
s_exception_handler_callback = nullptr;
|
||||
|
||||
if (s_exception_handler_handle)
|
||||
{
|
||||
RemoveVectoredExceptionHandler(s_exception_handler_handle);
|
||||
s_exception_handler_handle = {};
|
||||
}
|
||||
}
|
||||
|
||||
void _platform_InstallSignalHandler()
|
||||
{
|
||||
#ifdef _WIN64 // We don't handle SEH properly on Win64 so use a vectored exception handler instead
|
||||
AddVectoredExceptionHandler(true, SysPageFaultExceptionFilter);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static DWORD ConvertToWinApi(const PageProtectionMode& mode)
|
||||
{
|
||||
DWORD winmode = PAGE_NOACCESS;
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
<ClCompile Include="FastJmp.cpp">
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="General.cpp" />
|
||||
<ClCompile Include="GL\Context.cpp" />
|
||||
<ClCompile Include="GL\ContextWGL.cpp" />
|
||||
<ClCompile Include="GL\Program.cpp" />
|
||||
@@ -90,7 +91,6 @@
|
||||
<ClCompile Include="StringUtil.cpp" />
|
||||
<ClCompile Include="SettingsWrapper.cpp" />
|
||||
<ClCompile Include="Timer.cpp" />
|
||||
<ClCompile Include="VirtualMemory.cpp" />
|
||||
<ClCompile Include="Vulkan\vk_mem_alloc.cpp" />
|
||||
<ClCompile Include="Vulkan\Builders.cpp" />
|
||||
<ClCompile Include="Vulkan\Context.cpp" />
|
||||
@@ -130,7 +130,6 @@
|
||||
<ClCompile Include="emitter\WinCpuDetect.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="EventSource.inl" />
|
||||
<MASM Include="FastJmp.asm" />
|
||||
<None Include="Vulkan\EntryPoints.inl" />
|
||||
</ItemGroup>
|
||||
@@ -178,7 +177,6 @@
|
||||
<ClInclude Include="SettingsWrapper.h" />
|
||||
<ClInclude Include="Assertions.h" />
|
||||
<ClInclude Include="Console.h" />
|
||||
<ClInclude Include="EventSource.h" />
|
||||
<ClInclude Include="Exceptions.h" />
|
||||
<ClInclude Include="General.h" />
|
||||
<ClInclude Include="MathUtils.h" />
|
||||
|
||||
@@ -67,9 +67,6 @@
|
||||
<ClCompile Include="emitter\simd.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="VirtualMemory.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="emitter\WinCpuDetect.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
@@ -211,6 +208,7 @@
|
||||
<ClCompile Include="WAVWriter.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="General.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="AlignedMalloc.h">
|
||||
@@ -234,9 +232,6 @@
|
||||
<ClInclude Include="emitter\implement\dwshift.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="EventSource.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Exceptions.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
@@ -532,9 +527,6 @@
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="EventSource.inl">
|
||||
<Filter>Source Files</Filter>
|
||||
</None>
|
||||
<None Include="Vulkan\EntryPoints.inl">
|
||||
<Filter>Source Files\Vulkan</Filter>
|
||||
</None>
|
||||
|
||||
@@ -16,6 +16,12 @@
|
||||
#include "common/emitter/internal.h"
|
||||
#include "common/emitter/tools.h"
|
||||
|
||||
// warning: suggest braces around initialization of subobject [-Wmissing-braces]
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wmissing-braces"
|
||||
#endif
|
||||
|
||||
namespace x86Emitter
|
||||
{
|
||||
const xImplAVX_Move xVMOVAPS = {0x00, 0x28, 0x29};
|
||||
|
||||
@@ -170,23 +170,6 @@ void x86capabilities::CountCores()
|
||||
{
|
||||
Identify();
|
||||
|
||||
s32 regs[4];
|
||||
u32 cmds;
|
||||
|
||||
cpuid(regs, 0x80000000);
|
||||
cmds = regs[0];
|
||||
|
||||
// detect multicore for AMD cpu
|
||||
|
||||
if ((cmds >= 0x80000008) && (VendorID == x86Vendor_AMD))
|
||||
{
|
||||
// AMD note: they don't support hyperthreading, but they like to flag this true
|
||||
// anyway. Let's force-unflag it until we come up with a better solution.
|
||||
// (note: seems to affect some Phenom II's only? -- Athlon X2's and PhenomI's do
|
||||
// not seem to do this) --air
|
||||
hasMultiThreading = 0;
|
||||
}
|
||||
|
||||
// This will assign values into LogicalCores and PhysicalCores
|
||||
CountLogicalCores();
|
||||
}
|
||||
|
||||
3
crowdin.yml
Normal file
3
crowdin.yml
Normal file
@@ -0,0 +1,3 @@
|
||||
files:
|
||||
- source: pcsx2-qt/Translations/pcsx2-qt_en.ts
|
||||
translation: '/pcsx2-qt/Translations/pcsx2-qt_%two_letters_code%.ts'
|
||||
@@ -48,6 +48,7 @@
|
||||
#include "pcsx2/HostDisplay.h"
|
||||
#include "pcsx2/HostSettings.h"
|
||||
#include "pcsx2/INISettingsInterface.h"
|
||||
#include "pcsx2/PAD/Host/PAD.h"
|
||||
#include "pcsx2/PerformanceMetrics.h"
|
||||
#include "pcsx2/VMManager.h"
|
||||
|
||||
@@ -79,6 +80,7 @@ static std::optional<bool> s_use_window;
|
||||
|
||||
// Owned by the GS thread.
|
||||
static u32 s_dump_frame_number = 0;
|
||||
static u32 s_loop_number = s_loop_count;
|
||||
|
||||
bool GSRunner::InitializeConfig()
|
||||
{
|
||||
@@ -102,6 +104,13 @@ bool GSRunner::InitializeConfig()
|
||||
// we don't need any sound output
|
||||
si.SetStringValue("SPU2/Output", "OutputModule", "nullout");
|
||||
|
||||
// none of the bindings are going to resolve to anything
|
||||
PAD::ClearPortBindings(si, 0);
|
||||
si.ClearSection("Hotkeys");
|
||||
|
||||
// make sure any gamesettings inis in your tree don't get loaded
|
||||
si.SetBoolValue("EmuCore", "EnablePerGameSettings", false);
|
||||
|
||||
// force logging
|
||||
si.SetBoolValue("Logging", "EnableSystemConsole", true);
|
||||
si.SetBoolValue("Logging", "EnableTimestamps", true);
|
||||
@@ -273,13 +282,15 @@ void Host::ReleaseHostDisplay(bool clear_state)
|
||||
|
||||
bool Host::BeginPresentFrame(bool frame_skip)
|
||||
{
|
||||
// when we wrap around, don't race other files
|
||||
GSJoinSnapshotThreads();
|
||||
|
||||
// queue dumping of this frame
|
||||
std::string dump_path(fmt::format("{}_frame{}.png", s_output_prefix, s_dump_frame_number));
|
||||
GSQueueSnapshot(dump_path);
|
||||
if (s_loop_number == 0)
|
||||
{
|
||||
// when we wrap around, don't race other files
|
||||
GSJoinSnapshotThreads();
|
||||
|
||||
// queue dumping of this frame
|
||||
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;
|
||||
|
||||
@@ -351,10 +362,6 @@ void Host::OnSaveStateSaved(const std::string_view& filename)
|
||||
{
|
||||
}
|
||||
|
||||
void Host::InvalidateSaveStateCache()
|
||||
{
|
||||
}
|
||||
|
||||
void Host::RunOnCPUThread(std::function<void()> function, bool block /* = false */)
|
||||
{
|
||||
pxFailRel("Not implemented");
|
||||
@@ -377,7 +384,7 @@ void Host::SetFullscreen(bool enabled)
|
||||
{
|
||||
}
|
||||
|
||||
void Host::RequestExit(bool save_state_if_running)
|
||||
void Host::RequestExit(bool allow_confirm)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -523,6 +530,29 @@ static bool ParseCommandLineArgs(int argc, char* argv[], VMBootParameters& param
|
||||
s_settings_interface.SetIntValue("EmuCore/GS", "Renderer", static_cast<int>(type));
|
||||
continue;
|
||||
}
|
||||
else if (CHECK_ARG_PARAM("-renderhacks"))
|
||||
{
|
||||
std::string str(argv[++i]);
|
||||
|
||||
s_settings_interface.SetBoolValue("EmuCore/GS", "UserHacks", true);
|
||||
|
||||
if(str.find("af") != std::string::npos)
|
||||
s_settings_interface.SetBoolValue("EmuCore/GS", "UserHacks_AutoFlush", true);
|
||||
if (str.find("cpufb") != std::string::npos)
|
||||
s_settings_interface.SetBoolValue("EmuCore/GS", "UserHacks_CPU_FB_Conversion", true);
|
||||
if (str.find("dds") != std::string::npos)
|
||||
s_settings_interface.SetBoolValue("EmuCore/GS", "UserHacks_DisableDepthSupport", true);
|
||||
if (str.find("dpi") != std::string::npos)
|
||||
s_settings_interface.SetBoolValue("EmuCore/GS", "UserHacks_DisablePartialInvalidation", true);
|
||||
if (str.find("dsf") != std::string::npos)
|
||||
s_settings_interface.SetBoolValue("EmuCore/GS", "UserHacks_DisableSafeFeatures", true);
|
||||
if (str.find("tinrt") != std::string::npos)
|
||||
s_settings_interface.SetBoolValue("EmuCore/GS", "UserHacks_TextureInsideRt", true);
|
||||
if (str.find("plf") != std::string::npos)
|
||||
s_settings_interface.SetBoolValue("EmuCore/GS", "preload_frame_with_gs_data", true);
|
||||
|
||||
continue;
|
||||
}
|
||||
else if (CHECK_ARG_PARAM("-logfile"))
|
||||
{
|
||||
const char* logfile = argv[++i];
|
||||
@@ -631,6 +661,7 @@ int main(int argc, char* argv[])
|
||||
|
||||
// apply new settings (e.g. pick up renderer change)
|
||||
VMManager::ApplySettings();
|
||||
GSDumpReplayer::SetIsDumpRunner(true);
|
||||
|
||||
if (VMManager::Initialize(params))
|
||||
{
|
||||
@@ -644,6 +675,7 @@ int main(int argc, char* argv[])
|
||||
|
||||
InputManager::CloseSources();
|
||||
VMManager::Internal::ReleaseMemory();
|
||||
VMManager::Internal::ReleaseGlobals();
|
||||
PerformanceMetrics::SetCPUThread(Threading::ThreadHandle());
|
||||
GSRunner::DestroyPlatformWindow();
|
||||
|
||||
@@ -654,6 +686,7 @@ void Host::CPUThreadVSync()
|
||||
{
|
||||
// update GS thread copy of frame number
|
||||
GetMTGS().RunOnGSThread([frame_number = GSDumpReplayer::GetFrameNumber()]() { s_dump_frame_number = frame_number; });
|
||||
GetMTGS().RunOnGSThread([loop_number = GSDumpReplayer::GetLoopCount()]() { s_loop_number = loop_number; });
|
||||
|
||||
// process any window messages (but we shouldn't really have any)
|
||||
GSRunner::PumpPlatformMessages();
|
||||
|
||||
@@ -16,7 +16,7 @@ def is_gs_path(path):
|
||||
return False
|
||||
|
||||
|
||||
def run_regression_test(runner, dumpdir, renderer, parallel, gspath):
|
||||
def run_regression_test(runner, dumpdir, renderer, parallel, renderhacks, gspath):
|
||||
args = [runner]
|
||||
gsname = Path(gspath).name
|
||||
while gsname.rfind('.') >= 0:
|
||||
@@ -28,6 +28,10 @@ def run_regression_test(runner, dumpdir, renderer, parallel, gspath):
|
||||
|
||||
if renderer is not None:
|
||||
args.extend(["-renderer", renderer])
|
||||
|
||||
if renderhacks is not None:
|
||||
args.extend(["-renderhacks", renderhacks])
|
||||
|
||||
args.extend(["-dumpdir", real_dumpdir])
|
||||
args.extend(["-logfile", os.path.join(real_dumpdir, "emulog.txt")])
|
||||
|
||||
@@ -46,7 +50,7 @@ def run_regression_test(runner, dumpdir, renderer, parallel, gspath):
|
||||
subprocess.run(args)
|
||||
|
||||
|
||||
def run_regression_tests(runner, gsdir, dumpdir, renderer, parallel=1):
|
||||
def run_regression_tests(runner, gsdir, dumpdir, renderer, renderhacks, parallel=1):
|
||||
paths = glob.glob(gsdir + "/*.*", recursive=True)
|
||||
gamepaths = list(filter(is_gs_path, paths))
|
||||
|
||||
@@ -57,10 +61,10 @@ def run_regression_tests(runner, gsdir, dumpdir, renderer, parallel=1):
|
||||
|
||||
if parallel <= 1:
|
||||
for game in gamepaths:
|
||||
run_regression_test(runner, dumpdir, renderer, parallel, game)
|
||||
run_regression_test(runner, dumpdir, renderer, parallel, renderhacks, game)
|
||||
else:
|
||||
print("Processing %u games on %u processors" % (len(gamepaths), parallel))
|
||||
func = partial(run_regression_test, runner, dumpdir, renderer, parallel)
|
||||
func = partial(run_regression_test, runner, dumpdir, renderer, parallel, renderhacks)
|
||||
pool = multiprocessing.Pool(parallel)
|
||||
pool.map(func, gamepaths)
|
||||
pool.close()
|
||||
@@ -76,10 +80,11 @@ if __name__ == "__main__":
|
||||
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("-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.parallel):
|
||||
if not run_regression_tests(args.runner, os.path.realpath(args.gsdir), os.path.realpath(args.dumpdir), args.renderer, args.renderhacks, args.parallel):
|
||||
sys.exit(1)
|
||||
else:
|
||||
sys.exit(0)
|
||||
|
||||
@@ -465,7 +465,7 @@ void AutoUpdaterDialog::downloadUpdateClicked()
|
||||
else if (result == 1)
|
||||
{
|
||||
// updater started. since we're a modal on the main window, we have to queue this.
|
||||
QMetaObject::invokeMethod(g_main_window, &MainWindow::requestExit, Qt::QueuedConnection);
|
||||
QMetaObject::invokeMethod(g_main_window, "requestExit", Qt::QueuedConnection, Q_ARG(bool, true));
|
||||
done(0);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,8 @@ target_sources(pcsx2-qt PRIVATE
|
||||
AutoUpdaterDialog.cpp
|
||||
AutoUpdaterDialog.h
|
||||
AutoUpdaterDialog.ui
|
||||
ColorPickerButton.cpp
|
||||
ColorPickerButton.h
|
||||
CoverDownloadDialog.cpp
|
||||
CoverDownloadDialog.h
|
||||
CoverDownloadDialog.ui
|
||||
@@ -50,6 +52,7 @@ target_sources(pcsx2-qt PRIVATE
|
||||
Settings/ControllerBindingWidget_DualShock2.ui
|
||||
Settings/ControllerBindingWidgets.cpp
|
||||
Settings/ControllerBindingWidgets.h
|
||||
Settings/ControllerLEDSettingsDialog.ui
|
||||
Settings/ControllerGlobalSettingsWidget.cpp
|
||||
Settings/ControllerGlobalSettingsWidget.h
|
||||
Settings/ControllerGlobalSettingsWidget.ui
|
||||
|
||||
66
pcsx2-qt/ColorPickerButton.cpp
Normal file
66
pcsx2-qt/ColorPickerButton.cpp
Normal file
@@ -0,0 +1,66 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2023 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 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 PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "ColorPickerButton.h"
|
||||
#include "QtUtils.h"
|
||||
|
||||
#include <QtWidgets/QColorDialog>
|
||||
|
||||
ColorPickerButton::ColorPickerButton(QWidget* parent)
|
||||
: QPushButton(parent)
|
||||
{
|
||||
connect(this, &QPushButton::clicked, this, &ColorPickerButton::onClicked);
|
||||
updateBackgroundColor();
|
||||
}
|
||||
|
||||
u32 ColorPickerButton::color()
|
||||
{
|
||||
return m_color;
|
||||
}
|
||||
|
||||
void ColorPickerButton::setColor(u32 rgb)
|
||||
{
|
||||
if (m_color == rgb)
|
||||
return;
|
||||
|
||||
m_color = rgb;
|
||||
updateBackgroundColor();
|
||||
}
|
||||
|
||||
void ColorPickerButton::updateBackgroundColor()
|
||||
{
|
||||
setStyleSheet(QStringLiteral("background-color: #%1;").arg(static_cast<uint>(m_color), 8, 16, QChar('0')));
|
||||
}
|
||||
|
||||
void ColorPickerButton::onClicked()
|
||||
{
|
||||
const u32 red = (m_color >> 16) & 0xff;
|
||||
const u32 green = (m_color >> 8) & 0xff;
|
||||
const u32 blue = m_color & 0xff;
|
||||
|
||||
const QColor initial(QColor::fromRgb(red, green, blue));
|
||||
const QColor selected(QColorDialog::getColor(initial, QtUtils::GetRootWidget(this), tr("Select LED Color")));
|
||||
|
||||
// QColorDialog returns Invalid on cancel, and apparently initial == Invalid is true...
|
||||
if (!selected.isValid() || initial == selected)
|
||||
return;
|
||||
|
||||
const u32 new_rgb =
|
||||
(static_cast<u32>(selected.red()) << 16) | (static_cast<u32>(selected.green()) << 8) | static_cast<u32>(selected.blue());
|
||||
m_color = new_rgb;
|
||||
updateBackgroundColor();
|
||||
emit colorChanged(new_rgb);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2021 PCSX2 Dev Team
|
||||
* Copyright (C) 2002-2023 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
@@ -15,17 +15,28 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
class GSCodeBuffer
|
||||
#include "common/Pcsx2Defs.h"
|
||||
#include <QtWidgets/QPushButton>
|
||||
|
||||
class ColorPickerButton : public QPushButton
|
||||
{
|
||||
std::vector<void*> m_buffers;
|
||||
size_t m_blocksize;
|
||||
size_t m_pos, m_reserved;
|
||||
u8* m_ptr;
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
GSCodeBuffer(size_t blocksize = 4096 * 64); // 256k
|
||||
virtual ~GSCodeBuffer();
|
||||
ColorPickerButton(QWidget* parent);
|
||||
|
||||
void* GetBuffer(size_t size);
|
||||
void ReleaseBuffer(size_t size);
|
||||
Q_SIGNALS:
|
||||
void colorChanged(quint32 new_color);
|
||||
|
||||
public Q_SLOTS:
|
||||
quint32 color();
|
||||
void setColor(quint32 rgb);
|
||||
|
||||
private Q_SLOTS:
|
||||
void onClicked();
|
||||
|
||||
private:
|
||||
void updateBackgroundColor();
|
||||
|
||||
u32 m_color = 0;
|
||||
};
|
||||
@@ -112,11 +112,14 @@ void BreakpointDialog::accept()
|
||||
return;
|
||||
}
|
||||
|
||||
bp->addr = address;
|
||||
|
||||
bp->enabled = m_ui.chkEnable->isChecked();
|
||||
|
||||
if (!m_ui.txtCondition->text().isEmpty())
|
||||
{
|
||||
bp->hasCond = true;
|
||||
bp->cond.debug = m_cpu;
|
||||
|
||||
if (!m_cpu->initExpression(m_ui.txtCondition->text().toLocal8Bit().constData(), expr))
|
||||
{
|
||||
@@ -177,7 +180,7 @@ void BreakpointDialog::accept()
|
||||
m_bpModel.removeRows(m_rowIndex, 1);
|
||||
}
|
||||
|
||||
m_bpModel.insertRows(0, 1, {m_bp_mc});
|
||||
m_bpModel.insertBreakpointRows(0, 1, {m_bp_mc});
|
||||
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
@@ -160,11 +160,11 @@ void CpuWidget::onStepOut()
|
||||
// Allow the cpu to skip this pc if it is a breakpoint
|
||||
CBreakPoints::SetSkipFirst(m_cpu.getCpuType(), m_cpu.getPC());
|
||||
|
||||
if (m_stacklistObjects.size() < 2)
|
||||
if (m_stackModel.rowCount() < 2)
|
||||
return;
|
||||
|
||||
Host::RunOnCPUThread([&] {
|
||||
CBreakPoints::AddBreakPoint(m_cpu.getCpuType(), m_stacklistObjects.at(1).pc, true);
|
||||
CBreakPoints::AddBreakPoint(m_cpu.getCpuType(), m_stackModel.data(m_stackModel.index(1, StackModel::PC), Qt::UserRole).toUInt(), true);
|
||||
m_cpu.resumeCpu();
|
||||
});
|
||||
|
||||
|
||||
@@ -105,8 +105,5 @@ private:
|
||||
ThreadModel m_threadModel;
|
||||
StackModel m_stackModel;
|
||||
|
||||
std::vector<EEThread> m_threadlistObjects;
|
||||
std::vector<StackFrame> m_stacklistObjects;
|
||||
|
||||
bool m_demangleFunctions = true;
|
||||
};
|
||||
|
||||
@@ -88,16 +88,18 @@ void DebuggerWindow::onVMStateChanged()
|
||||
m_actionStepInto->setEnabled(true);
|
||||
m_actionStepOver->setEnabled(true);
|
||||
m_actionStepOut->setEnabled(true);
|
||||
CBreakPoints::ClearTemporaryBreakPoints();
|
||||
|
||||
if (CBreakPoints::GetBreakpointTriggered())
|
||||
{
|
||||
CBreakPoints::SetBreakpointTriggered(false);
|
||||
// Our current PC is on a breakpoint.
|
||||
// When we run the core again, we want to skip this breakpoint and run
|
||||
CBreakPoints::SetSkipFirst(BREAKPOINT_EE, r5900Debug.getPC());
|
||||
CBreakPoints::SetSkipFirst(BREAKPOINT_IOP, r3000Debug.getPC());
|
||||
}
|
||||
Host::RunOnCPUThread([] {
|
||||
if (CBreakPoints::GetBreakpointTriggered())
|
||||
{
|
||||
CBreakPoints::ClearTemporaryBreakPoints();
|
||||
CBreakPoints::SetBreakpointTriggered(false);
|
||||
// Our current PC is on a breakpoint.
|
||||
// When we run the core again, we want to skip this breakpoint and run
|
||||
CBreakPoints::SetSkipFirst(BREAKPOINT_EE, r5900Debug.getPC());
|
||||
CBreakPoints::SetSkipFirst(BREAKPOINT_IOP, r3000Debug.getPC());
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -487,7 +487,7 @@ void DisassemblyWidget::paintEvent(QPaintEvent* event)
|
||||
|
||||
void DisassemblyWidget::mousePressEvent(QMouseEvent* event)
|
||||
{
|
||||
const u32 selectedAddress = (event->y() / m_rowHeight * 4) + m_visibleStart;
|
||||
const u32 selectedAddress = (static_cast<int>(event->position().y()) / m_rowHeight * 4) + m_visibleStart;
|
||||
if (event->buttons() & Qt::LeftButton)
|
||||
{
|
||||
if (event->modifiers() & Qt::ShiftModifier)
|
||||
@@ -523,7 +523,7 @@ void DisassemblyWidget::mouseDoubleClickEvent(QMouseEvent* event)
|
||||
if (!m_cpu->isAlive())
|
||||
return;
|
||||
|
||||
const u32 selectedAddress = (event->y() / m_rowHeight * 4) + m_visibleStart;
|
||||
const u32 selectedAddress = (static_cast<int>(event->position().y()) / m_rowHeight * 4) + m_visibleStart;
|
||||
if (CBreakPoints::IsAddressBreakPoint(m_cpu->getCpuType(), selectedAddress))
|
||||
{
|
||||
Host::RunOnCPUThread([&] { CBreakPoints::RemoveBreakPoint(m_cpu->getCpuType(), selectedAddress); });
|
||||
|
||||
@@ -306,9 +306,9 @@ bool BreakpointModel::removeRows(int row, int count, const QModelIndex& index)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BreakpointModel::insertRows(int row, int count, std::vector<BreakpointMemcheck> breakpoints, const QModelIndex& index)
|
||||
bool BreakpointModel::insertBreakpointRows(int row, int count, std::vector<BreakpointMemcheck> breakpoints, const QModelIndex& index)
|
||||
{
|
||||
if (breakpoints.size() != count)
|
||||
if (breakpoints.size() != static_cast<size_t>(count))
|
||||
return false;
|
||||
|
||||
beginInsertRows(index, row, row + count);
|
||||
|
||||
@@ -47,7 +47,7 @@ public:
|
||||
Qt::ItemFlags flags(const QModelIndex& index) const override;
|
||||
bool setData(const QModelIndex& index, const QVariant& value, int role) override;
|
||||
bool removeRows(int row, int count, const QModelIndex& index = QModelIndex()) override;
|
||||
bool insertRows(int row, int count, std::vector<BreakpointMemcheck> breakpoints, const QModelIndex& index = QModelIndex());
|
||||
bool insertBreakpointRows(int row, int count, std::vector<BreakpointMemcheck> breakpoints, const QModelIndex& index = QModelIndex());
|
||||
|
||||
BreakpointMemcheck at(int row) const { return m_breakpoints.at(row); };
|
||||
|
||||
|
||||
@@ -107,18 +107,15 @@ QVariant StackModel::headerData(int section, Qt::Orientation orientation, int ro
|
||||
|
||||
void StackModel::refreshData()
|
||||
{
|
||||
if (m_cpu.getCpuType() == BREAKPOINT_IOP)
|
||||
return;
|
||||
|
||||
// Hopefully in the near future we can get a stack frame for
|
||||
// each thread
|
||||
beginResetModel();
|
||||
for (const auto& thread : getEEThreads())
|
||||
for (const auto& thread : m_cpu.GetThreadList())
|
||||
{
|
||||
if (thread.data.status == THS_RUN)
|
||||
if (thread->Status() == ThreadStatus::THS_RUN)
|
||||
{
|
||||
m_stackFrames = MipsStackWalk::Walk(&m_cpu, m_cpu.getPC(), m_cpu.getRegister(0, 31), m_cpu.getRegister(0, 29),
|
||||
thread.data.entry_init, thread.data.stack);
|
||||
thread->EntryPoint(), thread->StackTop());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,10 +27,7 @@ ThreadModel::ThreadModel(DebugInterface& cpu, QObject* parent)
|
||||
|
||||
int ThreadModel::rowCount(const QModelIndex&) const
|
||||
{
|
||||
if (m_cpu.getCpuType() == BREAKPOINT_EE)
|
||||
return getEEThreads().size();
|
||||
else
|
||||
return 0;
|
||||
return m_cpu.GetThreadList().size();
|
||||
}
|
||||
|
||||
int ThreadModel::columnCount(const QModelIndex&) const
|
||||
@@ -40,66 +37,65 @@ int ThreadModel::columnCount(const QModelIndex&) const
|
||||
|
||||
QVariant ThreadModel::data(const QModelIndex& index, int role) const
|
||||
{
|
||||
const auto threads = m_cpu.GetThreadList();
|
||||
auto* const thread = threads.at(index.row()).get();
|
||||
|
||||
if (role == Qt::DisplayRole)
|
||||
{
|
||||
const auto thread = getEEThreads().at(index.row());
|
||||
|
||||
switch (index.column())
|
||||
{
|
||||
case ThreadModel::ID:
|
||||
return thread.tid;
|
||||
return thread->TID();
|
||||
case ThreadModel::PC:
|
||||
{
|
||||
if (thread.data.status == THS_RUN)
|
||||
if (thread->Status() == ThreadStatus::THS_RUN)
|
||||
return QtUtils::FilledQStringFromValue(m_cpu.getPC(), 16);
|
||||
else
|
||||
return QtUtils::FilledQStringFromValue(thread.data.entry, 16);
|
||||
|
||||
return QtUtils::FilledQStringFromValue(thread->PC(), 16);
|
||||
}
|
||||
case ThreadModel::ENTRY:
|
||||
return QtUtils::FilledQStringFromValue(thread.data.entry_init, 16);
|
||||
return QtUtils::FilledQStringFromValue(thread->EntryPoint(), 16);
|
||||
case ThreadModel::PRIORITY:
|
||||
return QString::number(thread.data.currentPriority);
|
||||
return QString::number(thread->Priority());
|
||||
case ThreadModel::STATE:
|
||||
{
|
||||
const auto& state = ThreadStateStrings.find(thread.data.status);
|
||||
const auto& state = ThreadStateStrings.find(thread->Status());
|
||||
if (state != ThreadStateStrings.end())
|
||||
return state->second;
|
||||
else
|
||||
return tr("INVALID");
|
||||
|
||||
return tr("INVALID");
|
||||
}
|
||||
case ThreadModel::WAIT_TYPE:
|
||||
{
|
||||
const auto& waitType = ThreadWaitStrings.find(thread.data.waitType);
|
||||
const auto& waitType = ThreadWaitStrings.find(thread->Wait());
|
||||
if (waitType != ThreadWaitStrings.end())
|
||||
return waitType->second;
|
||||
else
|
||||
return tr("INVALID");
|
||||
|
||||
return tr("INVALID");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (role == Qt::UserRole)
|
||||
{
|
||||
const auto& thread = getEEThreads().at(index.row());
|
||||
|
||||
switch (index.column())
|
||||
{
|
||||
case ThreadModel::ID:
|
||||
return thread.tid;
|
||||
return thread->TID();
|
||||
case ThreadModel::PC:
|
||||
{
|
||||
if (thread.data.status == THS_RUN)
|
||||
if (thread->Status() == ThreadStatus::THS_RUN)
|
||||
return m_cpu.getPC();
|
||||
else
|
||||
return thread.data.entry;
|
||||
|
||||
return thread->PC();
|
||||
}
|
||||
case ThreadModel::ENTRY:
|
||||
return thread.data.entry_init;
|
||||
return thread->EntryPoint();
|
||||
case ThreadModel::PRIORITY:
|
||||
return thread.data.currentPriority;
|
||||
return thread->Priority();
|
||||
case ThreadModel::STATE:
|
||||
return thread.data.status;
|
||||
return static_cast<u32>(thread->Status());
|
||||
case ThreadModel::WAIT_TYPE:
|
||||
return thread.data.waitType;
|
||||
return static_cast<u32>(thread->Wait());
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
@@ -48,19 +48,27 @@ public:
|
||||
void refreshData();
|
||||
|
||||
private:
|
||||
const std::map<int, QString> ThreadStateStrings{
|
||||
{THS_BAD, tr("BAD")},
|
||||
{THS_RUN, tr("RUN")},
|
||||
{THS_READY, tr("READY")},
|
||||
{THS_WAIT, tr("WAIT")},
|
||||
{THS_SUSPEND, tr("SUSPEND")},
|
||||
{THS_WAIT_SUSPEND, tr("WAIT SUSPEND")},
|
||||
{THS_DORMANT, tr("DORMANT")}};
|
||||
const std::map<ThreadStatus, QString> ThreadStateStrings{
|
||||
{ThreadStatus::THS_BAD, tr("BAD")},
|
||||
{ThreadStatus::THS_RUN, tr("RUN")},
|
||||
{ThreadStatus::THS_READY, tr("READY")},
|
||||
{ThreadStatus::THS_WAIT, tr("WAIT")},
|
||||
{ThreadStatus::THS_SUSPEND, tr("SUSPEND")},
|
||||
{ThreadStatus::THS_WAIT_SUSPEND, tr("WAIT SUSPEND")},
|
||||
{ThreadStatus::THS_DORMANT, tr("DORMANT")},
|
||||
};
|
||||
|
||||
const std::map<int, QString> ThreadWaitStrings{
|
||||
{WAIT_NONE, tr("NONE")},
|
||||
{WAIT_WAKEUP_REQ, tr("WAKEUP REQUEST")},
|
||||
{WAIT_SEMA, tr("SEMAPHORE")}};
|
||||
const std::map<WaitState, QString> ThreadWaitStrings{
|
||||
{WaitState::NONE, tr("NONE")},
|
||||
{WaitState::WAKEUP_REQ, tr("WAKEUP REQUEST")},
|
||||
{WaitState::SEMA, tr("SEMAPHORE")},
|
||||
{WaitState::SLEEP, tr("SLEEP")},
|
||||
{WaitState::DELAY, tr("DELAY")},
|
||||
{WaitState::EVENTFLAG, tr("EVENTFLAG")},
|
||||
{WaitState::MBOX, tr("MBOX")},
|
||||
{WaitState::VPOOL, tr("VPOOL")},
|
||||
{WaitState::FIXPOOL, tr("FIXPOOL")},
|
||||
};
|
||||
|
||||
DebugInterface& m_cpu;
|
||||
};
|
||||
|
||||
@@ -156,7 +156,7 @@ void DisplayWidget::handleCloseEvent(QCloseEvent* event)
|
||||
}
|
||||
else
|
||||
{
|
||||
QMetaObject::invokeMethod(g_main_window, &MainWindow::requestExit);
|
||||
QMetaObject::invokeMethod(g_main_window, "requestExit", Q_ARG(bool, true));
|
||||
}
|
||||
|
||||
// Cancel the event from closing the window.
|
||||
|
||||
@@ -488,7 +488,7 @@ void GameListWidget::resizeTableViewColumnsToFit()
|
||||
80, // last played
|
||||
80, // size
|
||||
60, // region
|
||||
100 // compatibility
|
||||
120 // compatibility
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2022 PCSX2 Dev Team
|
||||
* Copyright (C) 2002-2023 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
@@ -157,7 +157,7 @@ void MainWindow::initialize()
|
||||
restoreStateFromConfig();
|
||||
switchToGameListView();
|
||||
updateWindowTitle();
|
||||
updateSaveStateMenus(QString(), QString(), 0);
|
||||
updateSaveStateMenusEnableState(false);
|
||||
|
||||
#ifdef _WIN32
|
||||
registerForDeviceNotifications();
|
||||
@@ -346,7 +346,7 @@ void MainWindow::connectSignals()
|
||||
connect(m_ui.actionDiscordServer, &QAction::triggered, this, &MainWindow::onDiscordServerActionTriggered);
|
||||
connect(m_ui.actionAboutQt, &QAction::triggered, qApp, &QApplication::aboutQt);
|
||||
connect(m_ui.actionAbout, &QAction::triggered, this, &MainWindow::onAboutActionTriggered);
|
||||
connect(m_ui.actionCheckForUpdates, &QAction::triggered, this, &MainWindow::onCheckForUpdatesActionTriggered);
|
||||
connect(m_ui.actionCheckForUpdates, &QAction::triggered, this, [this]() { checkForUpdates(true, true); });
|
||||
connect(m_ui.actionOpenDataDirectory, &QAction::triggered, this, &MainWindow::onToolsOpenDataDirectoryTriggered);
|
||||
connect(m_ui.actionCoverDownloader, &QAction::triggered, this, &MainWindow::onToolsCoverDownloaderTriggered);
|
||||
connect(m_ui.actionGridViewShowTitles, &QAction::triggered, m_game_list_widget, &GameListWidget::setShowCoverTitles);
|
||||
@@ -521,7 +521,7 @@ void MainWindow::setStyleFromSettings()
|
||||
qApp->setStyleSheet(QString());
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
}
|
||||
else if (theme == "darkfusion")
|
||||
else if (theme == "darkfusion")
|
||||
{
|
||||
// adapted from https://gist.github.com/QuantumCD/6245215
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
@@ -742,7 +742,7 @@ else if (theme == "darkfusion")
|
||||
// Custom palette by RedDevilus, Blue as main color and Purple as complimentary.
|
||||
// Alternative dark theme.
|
||||
qApp->setStyle(QStyleFactory::create("Fusion"));
|
||||
|
||||
|
||||
const QColor blackishblue(50, 25, 70);
|
||||
const QColor darkerPurple(90, 30, 105);
|
||||
const QColor nauticalPurple(110, 30, 125);
|
||||
@@ -963,10 +963,10 @@ void MainWindow::onToolsVideoCaptureToggled(bool checked)
|
||||
}
|
||||
|
||||
const QString container(QString::fromStdString(
|
||||
Host::GetStringSettingValue("EmuCore/GS", "VideoCaptureContainer", Pcsx2Config::GSOptions::DEFAULT_VIDEO_CAPTURE_CONTAINER)));
|
||||
Host::GetStringSettingValue("EmuCore/GS", "CaptureContainer", Pcsx2Config::GSOptions::DEFAULT_CAPTURE_CONTAINER)));
|
||||
const QString filter(tr("%1 Files (*.%2)").arg(container.toUpper()).arg(container));
|
||||
|
||||
QString path(QStringLiteral("%1.%2").arg(QString::fromStdString(GSGetBaseSnapshotFilename())).arg(container));
|
||||
QString path(QStringLiteral("%1.%2").arg(QString::fromStdString(GSGetBaseVideoFilename())).arg(container));
|
||||
path = QFileDialog::getSaveFileName(this, tr("Video Capture"), path, filter);
|
||||
if (path.isEmpty())
|
||||
{
|
||||
@@ -1259,11 +1259,6 @@ void MainWindow::cancelGameListRefresh()
|
||||
m_game_list_widget->cancelRefresh();
|
||||
}
|
||||
|
||||
void MainWindow::invalidateSaveStateCache()
|
||||
{
|
||||
m_save_states_invalidated = true;
|
||||
}
|
||||
|
||||
void MainWindow::reportError(const QString& title, const QString& message)
|
||||
{
|
||||
QMessageBox::critical(this, title, message);
|
||||
@@ -1280,8 +1275,7 @@ void MainWindow::runOnUIThread(const std::function<void()>& func)
|
||||
func();
|
||||
}
|
||||
|
||||
bool MainWindow::requestShutdown(bool allow_confirm /* = true */, bool allow_save_to_state /* = true */,
|
||||
bool default_save_to_state /* = true */, bool block_until_done /* = false */)
|
||||
bool MainWindow::requestShutdown(bool allow_confirm, bool allow_save_to_state, bool default_save_to_state)
|
||||
{
|
||||
if (!s_vm_valid)
|
||||
return true;
|
||||
@@ -1326,34 +1320,21 @@ bool MainWindow::requestShutdown(bool allow_confirm /* = true */, bool allow_sav
|
||||
|
||||
// Now we can actually shut down the VM.
|
||||
g_emu_thread->shutdownVM(save_state);
|
||||
|
||||
if (block_until_done || m_is_closing || QtHost::InBatchMode())
|
||||
{
|
||||
// We need to yield here, since the display gets destroyed.
|
||||
while (VMManager::GetState() != VMState::Shutdown)
|
||||
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents, 1);
|
||||
}
|
||||
|
||||
if (!m_is_closing && QtHost::InBatchMode())
|
||||
{
|
||||
// If we don't set the closing flag here, the VM shutdown may not complete by the time closeEvent() is called,
|
||||
// leading to a confirm.
|
||||
m_is_closing = true;
|
||||
QGuiApplication::quit();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MainWindow::requestExit()
|
||||
void MainWindow::requestExit(bool allow_confirm)
|
||||
{
|
||||
// this is block, because otherwise closeEvent() will also prompt
|
||||
if (!requestShutdown(true, true, EmuConfig.SaveStateOnShutdown, true))
|
||||
if (!requestShutdown(allow_confirm, true, EmuConfig.SaveStateOnShutdown))
|
||||
return;
|
||||
|
||||
// We could use close here, but if we're not visible (e.g. quitting from fullscreen), closing the window
|
||||
// doesn't quit the application.
|
||||
QGuiApplication::quit();
|
||||
// VM stopped signal won't have fired yet, so queue an exit if we still have one.
|
||||
// Otherwise, immediately exit, because there's no VM to exit us later.
|
||||
if (QtHost::IsVMValid())
|
||||
m_is_closing = true;
|
||||
else
|
||||
QGuiApplication::quit();
|
||||
}
|
||||
|
||||
void MainWindow::checkForSettingChanges()
|
||||
@@ -1374,11 +1355,6 @@ std::optional<WindowInfo> MainWindow::getWindowInfo()
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void Host::InvalidateSaveStateCache()
|
||||
{
|
||||
QMetaObject::invokeMethod(g_main_window, &MainWindow::invalidateSaveStateCache, Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
void MainWindow::onGameListRefreshProgress(const QString& status, int current, int total)
|
||||
{
|
||||
m_ui.statusBar->showMessage(status);
|
||||
@@ -1387,6 +1363,7 @@ void MainWindow::onGameListRefreshProgress(const QString& status, int current, i
|
||||
|
||||
void MainWindow::onGameListRefreshComplete()
|
||||
{
|
||||
m_ui.statusBar->clearMessage();
|
||||
clearProgressBar();
|
||||
}
|
||||
|
||||
@@ -1487,8 +1464,8 @@ void MainWindow::onGameListEntryContextMenuRequested(const QPoint& point)
|
||||
|
||||
if (m_ui.menuDebug->menuAction()->isVisible())
|
||||
{
|
||||
// TODO: Hook this up once it's implemented.
|
||||
action = menu.addAction(tr("Boot and Debug"));
|
||||
connect(action, &QAction::triggered, [this, entry]() { DebugInterface::setPauseOnEntry(true); startGameListEntry(entry); getDebuggerWindow()->show(); });
|
||||
}
|
||||
|
||||
menu.addSeparator();
|
||||
@@ -1580,14 +1557,16 @@ void MainWindow::onChangeDiscMenuAboutToHide()
|
||||
|
||||
void MainWindow::onLoadStateMenuAboutToShow()
|
||||
{
|
||||
if (m_save_states_invalidated)
|
||||
updateSaveStateMenus(m_current_disc_path, m_current_game_serial, m_current_game_crc);
|
||||
m_ui.menuLoadState->clear();
|
||||
updateSaveStateMenusEnableState(!m_current_game_serial.isEmpty());
|
||||
populateLoadStateMenu(m_ui.menuLoadState, m_current_disc_path, m_current_game_serial, m_current_game_crc);
|
||||
}
|
||||
|
||||
void MainWindow::onSaveStateMenuAboutToShow()
|
||||
{
|
||||
if (m_save_states_invalidated)
|
||||
updateSaveStateMenus(m_current_disc_path, m_current_game_serial, m_current_game_crc);
|
||||
m_ui.menuSaveState->clear();
|
||||
updateSaveStateMenusEnableState(!m_current_game_serial.isEmpty());
|
||||
populateSaveStateMenu(m_ui.menuSaveState, m_current_game_serial, m_current_game_crc);
|
||||
}
|
||||
|
||||
void MainWindow::onViewToolbarActionToggled(bool checked)
|
||||
@@ -1640,7 +1619,7 @@ void MainWindow::onViewGamePropertiesActionTriggered()
|
||||
auto lock = GameList::GetLock();
|
||||
const GameList::Entry* entry = m_current_elf_override.isEmpty() ?
|
||||
GameList::GetEntryForPath(m_current_disc_path.toUtf8().constData()) :
|
||||
GameList::GetEntryForPath(m_current_elf_override.toUtf8().constData());
|
||||
GameList::GetEntryForPath(m_current_elf_override.toUtf8().constData());
|
||||
if (entry)
|
||||
{
|
||||
SettingsDialog::openGamePropertiesDialog(
|
||||
@@ -1675,15 +1654,7 @@ void MainWindow::onAboutActionTriggered()
|
||||
about.exec();
|
||||
}
|
||||
|
||||
void MainWindow::onCheckForUpdatesActionTriggered()
|
||||
{
|
||||
// Wipe out the last version, that way it displays the update if we've previously skipped it.
|
||||
Host::RemoveBaseSettingValue("AutoUpdater", "LastVersion");
|
||||
Host::CommitBaseSettingChanges();
|
||||
checkForUpdates(true);
|
||||
}
|
||||
|
||||
void MainWindow::checkForUpdates(bool display_message)
|
||||
void MainWindow::checkForUpdates(bool display_message, bool force_check)
|
||||
{
|
||||
if (!AutoUpdaterDialog::isSupported())
|
||||
{
|
||||
@@ -1714,6 +1685,13 @@ void MainWindow::checkForUpdates(bool display_message)
|
||||
if (m_auto_updater_dialog)
|
||||
return;
|
||||
|
||||
if (force_check)
|
||||
{
|
||||
// Wipe out the last version, that way it displays the update if we've previously skipped it.
|
||||
Host::RemoveBaseSettingValue("AutoUpdater", "LastVersion");
|
||||
Host::CommitBaseSettingChanges();
|
||||
}
|
||||
|
||||
m_auto_updater_dialog = new AutoUpdaterDialog(this);
|
||||
connect(m_auto_updater_dialog, &AutoUpdaterDialog::updateCheckCompleted, this, &MainWindow::onUpdateCheckComplete);
|
||||
m_auto_updater_dialog->queueUpdateCheck(display_message);
|
||||
@@ -1733,7 +1711,7 @@ void MainWindow::startupUpdateCheck()
|
||||
if (!Host::GetBaseBoolSettingValue("AutoUpdater", "CheckAtStartup", true))
|
||||
return;
|
||||
|
||||
checkForUpdates(false);
|
||||
checkForUpdates(false, false);
|
||||
}
|
||||
|
||||
void MainWindow::onToolsOpenDataDirectoryTriggered()
|
||||
@@ -1889,7 +1867,7 @@ void MainWindow::onVMStarting()
|
||||
updateWindowTitle();
|
||||
|
||||
// prevent loading state until we're fully initialized
|
||||
updateSaveStateMenus(QString(), QString(), 0);
|
||||
updateSaveStateMenusEnableState(false);
|
||||
}
|
||||
|
||||
void MainWindow::onVMStarted()
|
||||
@@ -1951,6 +1929,14 @@ void MainWindow::onVMStopped()
|
||||
updateStatusBarWidgetVisibility();
|
||||
updateInputRecordingActions(false);
|
||||
|
||||
// If we're closing or in batch mode, quit the whole application now.
|
||||
if (m_is_closing || QtHost::InBatchMode())
|
||||
{
|
||||
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents, 1);
|
||||
QCoreApplication::quit();
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_display_widget)
|
||||
updateDisplayWidgetCursor();
|
||||
else
|
||||
@@ -1969,7 +1955,7 @@ void MainWindow::onGameChanged(const QString& path, const QString& elf_override,
|
||||
m_current_game_name = name;
|
||||
m_current_game_crc = crc;
|
||||
updateWindowTitle();
|
||||
updateSaveStateMenus(path, serial, crc);
|
||||
updateSaveStateMenusEnableState(!serial.isEmpty());
|
||||
}
|
||||
|
||||
void MainWindow::showEvent(QShowEvent* event)
|
||||
@@ -1990,16 +1976,24 @@ void MainWindow::showEvent(QShowEvent* event)
|
||||
|
||||
void MainWindow::closeEvent(QCloseEvent* event)
|
||||
{
|
||||
if (!requestShutdown(true, true, EmuConfig.SaveStateOnShutdown, true))
|
||||
// If there's no VM, we can just exit as normal.
|
||||
if (!s_vm_valid)
|
||||
{
|
||||
event->ignore();
|
||||
QMainWindow::closeEvent(event);
|
||||
return;
|
||||
}
|
||||
|
||||
// But if there is, we have to cancel the action, regardless of whether we ended exiting
|
||||
// or not. The window still needs to be visible while GS is shutting down.
|
||||
event->ignore();
|
||||
|
||||
// Exit cancelled?
|
||||
if (!requestShutdown(true, true, EmuConfig.SaveStateOnShutdown))
|
||||
return;
|
||||
|
||||
// Application will be exited in VM stopped handler.
|
||||
saveStateToConfig();
|
||||
m_is_closing = true;
|
||||
|
||||
QMainWindow::closeEvent(event);
|
||||
}
|
||||
|
||||
static QString getFilenameFromMimeData(const QMimeData* md)
|
||||
@@ -2264,7 +2258,12 @@ void MainWindow::createDisplayWidget(bool fullscreen, bool render_to_main, bool
|
||||
// Don't risk doing this on Wayland, it really doesn't like window state changes,
|
||||
// and positioning has no effect anyway.
|
||||
if (!s_use_central_widget)
|
||||
restoreDisplayWindowGeometryFromConfig();
|
||||
{
|
||||
if (isVisible() && g_emu_thread->shouldRenderToMain())
|
||||
container->move(pos());
|
||||
else
|
||||
restoreDisplayWindowGeometryFromConfig();
|
||||
}
|
||||
|
||||
if (!is_exclusive_fullscreen)
|
||||
container->showFullScreen();
|
||||
@@ -2825,21 +2824,14 @@ void MainWindow::populateSaveStateMenu(QMenu* menu, const QString& serial, quint
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::updateSaveStateMenus(const QString& filename, const QString& serial, quint32 crc)
|
||||
void MainWindow::updateSaveStateMenusEnableState(bool enable)
|
||||
{
|
||||
const bool load_enabled = !serial.isEmpty();
|
||||
const bool save_enabled = !serial.isEmpty() && s_vm_valid;
|
||||
m_ui.menuLoadState->clear();
|
||||
const bool load_enabled = enable;
|
||||
const bool save_enabled = enable && s_vm_valid;
|
||||
m_ui.menuLoadState->setEnabled(load_enabled);
|
||||
m_ui.actionLoadState->setEnabled(load_enabled);
|
||||
m_ui.menuSaveState->clear();
|
||||
m_ui.menuSaveState->setEnabled(save_enabled);
|
||||
m_ui.actionSaveState->setEnabled(save_enabled);
|
||||
m_save_states_invalidated = false;
|
||||
if (load_enabled)
|
||||
populateLoadStateMenu(m_ui.menuLoadState, filename, serial, crc);
|
||||
if (save_enabled)
|
||||
populateSaveStateMenu(m_ui.menuSaveState, serial, crc);
|
||||
}
|
||||
|
||||
void MainWindow::doStartFile(std::optional<CDVD_SourceType> source, const QString& path)
|
||||
@@ -2869,11 +2861,17 @@ void MainWindow::doDiscChange(CDVD_SourceType source, const QString& path)
|
||||
bool reset_system = false;
|
||||
if (!m_was_disc_change_request)
|
||||
{
|
||||
const int choice = QMessageBox::question(this, tr("Confirm Disc Change"),
|
||||
tr("Do you want to swap discs or boot the new image (via system reset)?"), tr("Swap Disc"), tr("Reset"), tr("Cancel"), 0, 2);
|
||||
if (choice == 2)
|
||||
QMessageBox message(QMessageBox::Question, tr("Confirm Disc Change"),
|
||||
tr("Do you want to swap discs or boot the new image (via system reset)?"));
|
||||
message.addButton(tr("Swap Disc"), QMessageBox::ActionRole);
|
||||
QPushButton* reset_button = message.addButton(tr("Reset"), QMessageBox::ActionRole);
|
||||
QPushButton* cancel_button = message.addButton(QMessageBox::Cancel);
|
||||
message.setDefaultButton(cancel_button);
|
||||
message.exec();
|
||||
|
||||
if (message.clickedButton() == cancel_button)
|
||||
return;
|
||||
reset_system = (choice != 0);
|
||||
reset_system = (message.clickedButton() == reset_button);
|
||||
}
|
||||
|
||||
switchToEmulationView();
|
||||
|
||||
@@ -110,17 +110,17 @@ public:
|
||||
/// Rescans a single file. NOTE: Happens on UI thread.
|
||||
void rescanFile(const std::string& path);
|
||||
|
||||
void openDebugger();
|
||||
|
||||
public Q_SLOTS:
|
||||
void checkForUpdates(bool display_message);
|
||||
void checkForUpdates(bool display_message, bool force_check);
|
||||
void refreshGameList(bool invalidate_cache);
|
||||
void cancelGameListRefresh();
|
||||
void invalidateSaveStateCache();
|
||||
void reportError(const QString& title, const QString& message);
|
||||
bool confirmMessage(const QString& title, const QString& message);
|
||||
void runOnUIThread(const std::function<void()>& func);
|
||||
bool requestShutdown(
|
||||
bool allow_confirm = true, bool allow_save_to_state = true, bool default_save_to_state = true, bool block_until_done = false);
|
||||
void requestExit();
|
||||
bool requestShutdown(bool allow_confirm = true, bool allow_save_to_state = true, bool default_save_to_state = true);
|
||||
void requestExit(bool allow_confirm = true);
|
||||
void checkForSettingChanges();
|
||||
std::optional<WindowInfo> getWindowInfo();
|
||||
|
||||
@@ -162,7 +162,6 @@ private Q_SLOTS:
|
||||
void onSupportForumsActionTriggered();
|
||||
void onDiscordServerActionTriggered();
|
||||
void onAboutActionTriggered();
|
||||
void onCheckForUpdatesActionTriggered();
|
||||
void onToolsOpenDataDirectoryTriggered();
|
||||
void onToolsCoverDownloaderTriggered();
|
||||
void updateTheme();
|
||||
@@ -244,7 +243,6 @@ private:
|
||||
void updateInputRecordingActions(bool started);
|
||||
|
||||
DebuggerWindow* getDebuggerWindow();
|
||||
void openDebugger();
|
||||
|
||||
ControllerSettingsDialog* getControllerSettingsDialog();
|
||||
void doControllerSettings(ControllerSettingsDialog::Category category = ControllerSettingsDialog::Category::Count);
|
||||
@@ -261,7 +259,7 @@ private:
|
||||
void loadSaveStateFile(const QString& filename, const QString& state_filename);
|
||||
void populateLoadStateMenu(QMenu* menu, const QString& filename, const QString& serial, quint32 crc);
|
||||
void populateSaveStateMenu(QMenu* menu, const QString& serial, quint32 crc);
|
||||
void updateSaveStateMenus(const QString& filename, const QString& serial, quint32 crc);
|
||||
void updateSaveStateMenusEnableState(bool enable);
|
||||
void doStartFile(std::optional<CDVD_SourceType> source, const QString& path);
|
||||
void doDiscChange(CDVD_SourceType source, const QString& path);
|
||||
|
||||
@@ -293,7 +291,6 @@ private:
|
||||
|
||||
bool m_display_created = false;
|
||||
bool m_relative_mouse_mode = false;
|
||||
bool m_save_states_invalidated = false;
|
||||
bool m_was_paused_on_surface_loss = false;
|
||||
bool m_was_disc_change_request = false;
|
||||
bool m_is_closing = false;
|
||||
|
||||
@@ -96,6 +96,7 @@ static bool s_nogui_mode = false;
|
||||
static bool s_start_fullscreen_ui = false;
|
||||
static bool s_start_fullscreen_ui_fullscreen = false;
|
||||
static bool s_test_config_and_exit = false;
|
||||
static bool s_boot_and_debug = false;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// CPU Thread
|
||||
@@ -429,6 +430,10 @@ void EmuThread::executeVM()
|
||||
VMManager::Execute();
|
||||
continue;
|
||||
|
||||
case VMState::Resetting:
|
||||
VMManager::Reset();
|
||||
continue;
|
||||
|
||||
case VMState::Stopping:
|
||||
destroyVM();
|
||||
m_event_loop->processEvents(QEventLoop::AllEvents);
|
||||
@@ -861,6 +866,10 @@ void EmuThread::beginCapture(const QString& path)
|
||||
GetMTGS().RunOnGSThread([path = path.toStdString()]() {
|
||||
GSBeginCapture(std::move(path));
|
||||
});
|
||||
|
||||
// Sync GS thread. We want to start adding audio at the same time as video.
|
||||
// TODO: This could be up to 64 frames behind... use the pts to adjust it.
|
||||
GetMTGS().WaitGS(false, false, false);
|
||||
}
|
||||
|
||||
void EmuThread::endCapture()
|
||||
@@ -1220,12 +1229,9 @@ void Host::CancelGameListRefresh()
|
||||
QMetaObject::invokeMethod(g_main_window, "cancelGameListRefresh", Qt::BlockingQueuedConnection);
|
||||
}
|
||||
|
||||
void Host::RequestExit(bool save_state_if_running)
|
||||
void Host::RequestExit(bool allow_confirm)
|
||||
{
|
||||
if (VMManager::HasValidVM())
|
||||
g_emu_thread->shutdownVM(save_state_if_running);
|
||||
|
||||
QMetaObject::invokeMethod(g_main_window, "requestExit", Qt::QueuedConnection);
|
||||
QMetaObject::invokeMethod(g_main_window, "requestExit", Qt::QueuedConnection, Q_ARG(bool, allow_confirm));
|
||||
}
|
||||
|
||||
void Host::RequestVMShutdown(bool allow_confirm, bool allow_save_state, bool default_save_state)
|
||||
@@ -1233,9 +1239,25 @@ void Host::RequestVMShutdown(bool allow_confirm, bool allow_save_state, bool def
|
||||
if (!VMManager::HasValidVM())
|
||||
return;
|
||||
|
||||
// Run it on the host thread, that way we get the confirm prompt (if enabled).
|
||||
QMetaObject::invokeMethod(g_main_window, "requestShutdown", Qt::QueuedConnection, Q_ARG(bool, allow_confirm),
|
||||
Q_ARG(bool, allow_save_state), Q_ARG(bool, default_save_state), Q_ARG(bool, false));
|
||||
// This is a bit messy here - we want to shut down immediately (in case it was requested by the game),
|
||||
// but we also need to exit-on-shutdown for batch mode. So, if we're running on the CPU thread, destroy
|
||||
// the VM, then request the main window to exit.
|
||||
if (allow_confirm || !g_emu_thread->isOnEmuThread())
|
||||
{
|
||||
// Run it on the host thread, that way we get the confirm prompt (if enabled).
|
||||
QMetaObject::invokeMethod(g_main_window, "requestShutdown", Qt::QueuedConnection, Q_ARG(bool, allow_confirm),
|
||||
Q_ARG(bool, allow_save_state), Q_ARG(bool, default_save_state));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Change state to stopping -> return -> shut down VM.
|
||||
g_emu_thread->shutdownVM(allow_save_state && default_save_state);
|
||||
|
||||
// This will probably call shutdownVM() again, but by the time it runs, we'll have already shut down
|
||||
// and it'll be a noop.
|
||||
if (QtHost::InBatchMode())
|
||||
QMetaObject::invokeMethod(g_main_window, "requestExit", Qt::QueuedConnection, Q_ARG(bool, false));
|
||||
}
|
||||
}
|
||||
|
||||
bool Host::IsFullscreen()
|
||||
@@ -1543,7 +1565,7 @@ static void SignalHandler(int signal)
|
||||
graceful_shutdown_attempted = true;
|
||||
|
||||
// This could be a bit risky invoking from a signal handler... hopefully it's okay.
|
||||
QMetaObject::invokeMethod(g_main_window, &MainWindow::requestExit, Qt::QueuedConnection);
|
||||
QMetaObject::invokeMethod(g_main_window, "requestExit", Qt::QueuedConnection, Q_ARG(bool, false));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1600,6 +1622,7 @@ void QtHost::PrintCommandLineHelp(const std::string_view& progname)
|
||||
std::fprintf(stderr, " -nofullscreen: Prevents fullscreen mode from triggering if enabled.\n");
|
||||
std::fprintf(stderr, " -earlyconsolelog: Forces logging of early console messages to console.\n");
|
||||
std::fprintf(stderr, " -testconfig: Initializes configuration and checks version, then exits.\n");
|
||||
std::fprintf(stderr, " -debugger: Open debugger and break on entry point.\n");
|
||||
#ifdef ENABLE_RAINTEGRATION
|
||||
std::fprintf(stderr, " -raintegration: Use RAIntegration instead of built-in achievement support.\n");
|
||||
#endif
|
||||
@@ -1722,6 +1745,11 @@ bool QtHost::ParseCommandLineOptions(const QStringList& args, std::shared_ptr<VM
|
||||
s_test_config_and_exit = true;
|
||||
continue;
|
||||
}
|
||||
else if (CHECK_ARG(QStringLiteral("-debugger")))
|
||||
{
|
||||
s_boot_and_debug = true;
|
||||
continue;
|
||||
}
|
||||
#ifdef ENABLE_RAINTEGRATION
|
||||
else if (CHECK_ARG(QStringLiteral("-raintegration")))
|
||||
{
|
||||
@@ -1812,8 +1840,6 @@ int main(int argc, char* argv[])
|
||||
{
|
||||
CrashHandler::Install();
|
||||
|
||||
QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||
QGuiApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
|
||||
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
|
||||
RegisterTypes();
|
||||
|
||||
@@ -1861,6 +1887,12 @@ int main(int argc, char* argv[])
|
||||
if (s_start_fullscreen_ui)
|
||||
g_emu_thread->startFullscreenUI(s_start_fullscreen_ui_fullscreen);
|
||||
|
||||
if (s_boot_and_debug)
|
||||
{
|
||||
DebugInterface::setPauseOnEntry(true);
|
||||
main_window->openDebugger();
|
||||
}
|
||||
|
||||
// Skip the update check if we're booting a game directly.
|
||||
if (autoboot)
|
||||
g_emu_thread->startVM(std::move(autoboot));
|
||||
|
||||
@@ -595,7 +595,7 @@ namespace SettingWidgetBinder
|
||||
/// Binds a widget's value to a setting, updating it when the value changes.
|
||||
|
||||
template <typename WidgetType>
|
||||
static void BindWidgetToBoolSetting(
|
||||
static inline void BindWidgetToBoolSetting(
|
||||
SettingsInterface* sif, WidgetType* widget, std::string section, std::string key, bool default_value)
|
||||
{
|
||||
using Accessor = SettingAccessor<WidgetType>;
|
||||
@@ -636,7 +636,7 @@ namespace SettingWidgetBinder
|
||||
}
|
||||
|
||||
template <typename WidgetType>
|
||||
static void BindWidgetToIntSetting(
|
||||
static inline void BindWidgetToIntSetting(
|
||||
SettingsInterface* sif, WidgetType* widget, std::string section, std::string key, int default_value, int option_offset = 0)
|
||||
{
|
||||
using Accessor = SettingAccessor<WidgetType>;
|
||||
@@ -677,7 +677,7 @@ namespace SettingWidgetBinder
|
||||
}
|
||||
|
||||
template <typename WidgetType>
|
||||
static void BindWidgetToFloatSetting(
|
||||
static inline void BindWidgetToFloatSetting(
|
||||
SettingsInterface* sif, WidgetType* widget, std::string section, std::string key, float default_value)
|
||||
{
|
||||
using Accessor = SettingAccessor<WidgetType>;
|
||||
@@ -718,7 +718,7 @@ namespace SettingWidgetBinder
|
||||
}
|
||||
|
||||
template <typename WidgetType>
|
||||
static void BindWidgetToNormalizedSetting(
|
||||
static inline void BindWidgetToNormalizedSetting(
|
||||
SettingsInterface* sif, WidgetType* widget, std::string section, std::string key, float range, float default_value)
|
||||
{
|
||||
using Accessor = SettingAccessor<WidgetType>;
|
||||
@@ -759,7 +759,7 @@ namespace SettingWidgetBinder
|
||||
}
|
||||
|
||||
template <typename WidgetType>
|
||||
static void BindWidgetToStringSetting(
|
||||
static inline void BindWidgetToStringSetting(
|
||||
SettingsInterface* sif, WidgetType* widget, std::string section, std::string key, std::string default_value = std::string())
|
||||
{
|
||||
using Accessor = SettingAccessor<WidgetType>;
|
||||
@@ -804,7 +804,7 @@ namespace SettingWidgetBinder
|
||||
}
|
||||
|
||||
template <typename WidgetType, typename DataType>
|
||||
static void BindWidgetToEnumSetting(SettingsInterface* sif, WidgetType* widget, std::string section, std::string key,
|
||||
static inline void BindWidgetToEnumSetting(SettingsInterface* sif, WidgetType* widget, std::string section, std::string key,
|
||||
std::optional<DataType> (*from_string_function)(const char* str), const char* (*to_string_function)(DataType value),
|
||||
DataType default_value)
|
||||
{
|
||||
@@ -866,7 +866,7 @@ namespace SettingWidgetBinder
|
||||
}
|
||||
|
||||
template <typename WidgetType, typename DataType>
|
||||
static void BindWidgetToEnumSetting(
|
||||
static inline void BindWidgetToEnumSetting(
|
||||
SettingsInterface* sif, WidgetType* widget, std::string section, std::string key, const char** enum_names, DataType default_value)
|
||||
{
|
||||
using Accessor = SettingAccessor<WidgetType>;
|
||||
@@ -928,7 +928,7 @@ namespace SettingWidgetBinder
|
||||
}
|
||||
|
||||
template <typename WidgetType>
|
||||
static void BindWidgetToEnumSetting(SettingsInterface* sif, WidgetType* widget, std::string section, std::string key,
|
||||
static inline void BindWidgetToEnumSetting(SettingsInterface* sif, WidgetType* widget, std::string section, std::string key,
|
||||
const char** enum_names, const char** enum_values, const char* default_value)
|
||||
{
|
||||
using Accessor = SettingAccessor<WidgetType>;
|
||||
@@ -992,7 +992,7 @@ namespace SettingWidgetBinder
|
||||
}
|
||||
|
||||
template <typename WidgetType>
|
||||
static void BindWidgetToFolderSetting(SettingsInterface* sif, WidgetType* widget, QAbstractButton* browse_button,
|
||||
static inline void BindWidgetToFolderSetting(SettingsInterface* sif, WidgetType* widget, QAbstractButton* browse_button,
|
||||
QAbstractButton* open_button, QAbstractButton* reset_button, std::string section, std::string key, std::string default_value,
|
||||
bool use_relative = true)
|
||||
{
|
||||
@@ -1068,7 +1068,7 @@ namespace SettingWidgetBinder
|
||||
}
|
||||
}
|
||||
|
||||
static void BindSliderToIntSetting(SettingsInterface* sif, QSlider* slider, QLabel* label, const QString& label_suffix,
|
||||
static inline void BindSliderToIntSetting(SettingsInterface* sif, QSlider* slider, QLabel* label, const QString& label_suffix,
|
||||
std::string section, std::string key, s32 default_value)
|
||||
{
|
||||
const s32 global_value = Host::GetBaseIntSettingValue(section.c_str(), key.c_str(), default_value);
|
||||
@@ -1093,7 +1093,7 @@ namespace SettingWidgetBinder
|
||||
[sif, slider, label, label_suffix, orig_font = std::move(orig_font), section, key, default_value](const QPoint& pt) {
|
||||
QMenu menu(slider);
|
||||
slider->connect(menu.addAction(qApp->translate("SettingWidgetBinder", "Reset")), &QAction::triggered, slider,
|
||||
[sif, slider, label, label_suffix, orig_font, section, key, default_value]() {
|
||||
[sif, label, label_suffix, orig_font, section, key, default_value]() {
|
||||
const s32 global_value = Host::GetBaseIntSettingValue(section.c_str(), key.c_str(), default_value);
|
||||
label->setText(QStringLiteral("%1%2").arg(global_value).arg(label_suffix));
|
||||
label->setFont(orig_font);
|
||||
@@ -1109,8 +1109,8 @@ namespace SettingWidgetBinder
|
||||
});
|
||||
|
||||
slider->connect(slider, &QSlider::valueChanged, slider,
|
||||
[sif, label, label_suffix, section = std::move(section), key = std::move(key), default_value,
|
||||
orig_font = std::move(orig_font), bold_font = std::move(bold_font)](int value) {
|
||||
[sif, label, label_suffix, section = std::move(section), key = std::move(key), orig_font = std::move(orig_font),
|
||||
bold_font = std::move(bold_font)](int value) {
|
||||
label->setText(QStringLiteral("%1%2").arg(value).arg(label_suffix));
|
||||
|
||||
if (label->font() != bold_font)
|
||||
@@ -1126,7 +1126,7 @@ namespace SettingWidgetBinder
|
||||
label->setText(QStringLiteral("%1%2").arg(global_value).arg(label_suffix));
|
||||
|
||||
slider->connect(slider, &QSlider::valueChanged, slider,
|
||||
[sif, label, label_suffix, section = std::move(section), key = std::move(key), default_value](int value) {
|
||||
[label, label_suffix, section = std::move(section), key = std::move(key)](int value) {
|
||||
label->setText(QStringLiteral("%1%2").arg(value).arg(label_suffix));
|
||||
Host::SetBaseIntSettingValue(section.c_str(), key.c_str(), value);
|
||||
Host::CommitBaseSettingChanges();
|
||||
|
||||
@@ -105,14 +105,13 @@ void AchievementSettingsWidget::updateEnableState()
|
||||
{
|
||||
const bool enabled = m_dialog->getEffectiveBoolValue("Achievements", "Enabled", false);
|
||||
const bool challenge = m_dialog->getEffectiveBoolValue("Achievements", "ChallengeMode", false);
|
||||
const bool notifications = m_dialog->getEffectiveBoolValue("Achievements", "Notifications", true);
|
||||
m_ui.testMode->setEnabled(enabled);
|
||||
m_ui.unofficialTestMode->setEnabled(enabled);
|
||||
m_ui.richPresence->setEnabled(enabled);
|
||||
m_ui.challengeMode->setEnabled(enabled);
|
||||
m_ui.leaderboards->setEnabled(enabled && challenge);
|
||||
m_ui.notifications->setEnabled(enabled);
|
||||
m_ui.soundEffects->setEnabled(enabled && notifications);
|
||||
m_ui.soundEffects->setEnabled(enabled);
|
||||
m_ui.primedIndicators->setEnabled(enabled);
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ AdvancedSettingsWidget::AdvancedSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.eeINTCSpinDetection, "EmuCore/Speedhacks", "IntcStat", true);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.eeWaitLoopDetection, "EmuCore/Speedhacks", "WaitLoop", true);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.eeFastmem, "EmuCore/CPU/Recompiler", "EnableFastmem", true);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pauseOnTLBMiss, "EmuCore/CPU/Recompiler", "PauseOnTLBMiss", false);
|
||||
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.vu0Recompiler, "EmuCore/CPU/Recompiler", "EnableVU0", true);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.vu1Recompiler, "EmuCore/CPU/Recompiler", "EnableVU1", true);
|
||||
@@ -84,6 +85,11 @@ AdvancedSettingsWidget::AdvancedSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
dialog->registerWidgetHelp(m_ui.eeFastmem, tr("Enable Fast Memory Access"), tr("Checked"),
|
||||
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 "
|
||||
"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(""));
|
||||
|
||||
|
||||
@@ -165,6 +165,13 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QCheckBox" name="pauseOnTLBMiss">
|
||||
<property name="text">
|
||||
<string>Pause On TLB Miss</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2022 PCSX2 Dev Team
|
||||
* Copyright (C) 2002-2023 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
@@ -28,12 +28,11 @@
|
||||
#include "SettingWidgetBinder.h"
|
||||
#include "SettingsDialog.h"
|
||||
|
||||
static constexpr s32 DEFAULT_INTERPOLATION_MODE = 5;
|
||||
static constexpr s32 DEFAULT_SYNCHRONIZATION_MODE = 0;
|
||||
static constexpr s32 DEFAULT_EXPANSION_MODE = 0;
|
||||
static constexpr s32 DEFAULT_DPL_DECODING_LEVEL = 0;
|
||||
static const char* DEFAULT_OUTPUT_MODULE = "cubeb";
|
||||
static constexpr s32 DEFAULT_TARGET_LATENCY = 100;
|
||||
static constexpr s32 DEFAULT_TARGET_LATENCY = 60;
|
||||
static constexpr s32 DEFAULT_OUTPUT_LATENCY = 20;
|
||||
static constexpr s32 DEFAULT_VOLUME = 100;
|
||||
static constexpr s32 DEFAULT_SOUNDTOUCH_SEQUENCE_LENGTH = 30;
|
||||
@@ -109,7 +108,8 @@ AudioSettingsWidget::AudioSettingsWidget(SettingsDialog* dialog, QWidget* parent
|
||||
onMinimalOutputLatencyStateChanged();
|
||||
updateLatencyLabels();
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.syncMode, tr("Synchronization"), tr("TimeStretch (Recommended)"), tr(""));
|
||||
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."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.expansionMode, tr("Expansion"), tr("Stereo (None, Default)"), tr(""));
|
||||
|
||||
@@ -117,7 +117,7 @@ AudioSettingsWidget::AudioSettingsWidget(SettingsDialog* dialog, QWidget* parent
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.backend, tr("Output Backend"), tr("Default"), tr(""));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.targetLatency, tr("Target Latency"), tr("100 ms"),
|
||||
dialog->registerWidgetHelp(m_ui.targetLatency, tr("Target Latency"), tr("60 ms"),
|
||||
tr("Determines the buffer size which the time stretcher will try to keep filled. It effectively selects the average latency, as "
|
||||
"audio will be stretched/shrunk to keep the buffer size within check."));
|
||||
dialog->registerWidgetHelp(m_ui.outputLatency, tr("Output Latency"), tr("20 ms"),
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>754</width>
|
||||
<height>464</height>
|
||||
<height>485</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@@ -49,6 +49,9 @@
|
||||
<property name="maximum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>30</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
@@ -63,7 +66,7 @@
|
||||
<item>
|
||||
<widget class="QLabel" name="sequenceLengthLabel">
|
||||
<property name="text">
|
||||
<string>100</string>
|
||||
<string>30</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -86,6 +89,9 @@
|
||||
<property name="maximum">
|
||||
<number>30</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>20</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
@@ -100,7 +106,7 @@
|
||||
<item>
|
||||
<widget class="QLabel" name="seekWindowSizeLabel">
|
||||
<property name="text">
|
||||
<string>100</string>
|
||||
<string>20</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -123,6 +129,9 @@
|
||||
<property name="maximum">
|
||||
<number>15</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
@@ -137,7 +146,7 @@
|
||||
<item>
|
||||
<widget class="QLabel" name="overlapLabel">
|
||||
<property name="text">
|
||||
<string>100</string>
|
||||
<string>10</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -201,6 +210,9 @@
|
||||
<property name="maximum">
|
||||
<number>200</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
@@ -366,7 +378,7 @@
|
||||
<number>200</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>100</number>
|
||||
<number>60</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
@@ -382,7 +394,7 @@
|
||||
<item>
|
||||
<widget class="QLabel" name="targetLatencyLabel">
|
||||
<property name="text">
|
||||
<string>100 ms</string>
|
||||
<string>60 ms</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -425,7 +437,7 @@
|
||||
<number>200</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>100</number>
|
||||
<number>20</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
@@ -441,7 +453,7 @@
|
||||
<item>
|
||||
<widget class="QLabel" name="outputLatencyLabel">
|
||||
<property name="text">
|
||||
<string>100 ms</string>
|
||||
<string>20 ms</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -42,10 +42,12 @@
|
||||
ControllerBindingWidget::ControllerBindingWidget(QWidget* parent, ControllerSettingsDialog* dialog, u32 port)
|
||||
: QWidget(parent)
|
||||
, m_dialog(dialog)
|
||||
, m_config_section(StringUtil::StdStringFromFormat("Pad%u", port + 1u))
|
||||
, m_config_section(fmt::format("Pad{}", port + 1))
|
||||
, m_port_number(port)
|
||||
{
|
||||
m_ui.setupUi(this);
|
||||
m_ui.groupBox->setTitle(tr("Controller Port %1").arg(port + 1));
|
||||
|
||||
populateControllerTypes();
|
||||
onTypeChanged();
|
||||
|
||||
@@ -113,10 +115,9 @@ void ControllerBindingWidget::onTypeChanged()
|
||||
|
||||
if (has_settings)
|
||||
{
|
||||
const QString settings_title(tr("%1 Settings").arg(qApp->translate("PAD", cinfo->display_name)));
|
||||
const gsl::span<const SettingInfo> settings(cinfo->settings, cinfo->num_settings);
|
||||
m_settings_widget = new ControllerCustomSettingsWidget(
|
||||
settings, m_config_section, std::string(), settings_title, cinfo->name, getDialog(), m_ui.stackedWidget);
|
||||
m_settings_widget =
|
||||
new ControllerCustomSettingsWidget(settings, m_config_section, std::string(), cinfo->name, getDialog(), m_ui.stackedWidget);
|
||||
m_ui.stackedWidget->addWidget(m_settings_widget);
|
||||
}
|
||||
|
||||
@@ -458,8 +459,7 @@ void ControllerMacroEditWidget::updateBinds()
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ControllerCustomSettingsWidget::ControllerCustomSettingsWidget(gsl::span<const SettingInfo> settings, std::string config_section,
|
||||
std::string config_prefix, const QString& group_title, const char* translation_ctx, ControllerSettingsDialog* dialog,
|
||||
QWidget* parent_widget)
|
||||
std::string config_prefix, const char* translation_ctx, ControllerSettingsDialog* dialog, QWidget* parent_widget)
|
||||
: QWidget(parent_widget)
|
||||
, m_settings(settings)
|
||||
, m_config_section(std::move(config_section))
|
||||
@@ -469,22 +469,19 @@ ControllerCustomSettingsWidget::ControllerCustomSettingsWidget(gsl::span<const S
|
||||
if (settings.empty())
|
||||
return;
|
||||
|
||||
QGroupBox* gbox = new QGroupBox(group_title, this);
|
||||
QGridLayout* gbox_layout = new QGridLayout(gbox);
|
||||
createSettingWidgets(translation_ctx, gbox, gbox_layout);
|
||||
QScrollArea* sarea = new QScrollArea(this);
|
||||
QWidget* swidget = new QWidget(sarea);
|
||||
sarea->setWidget(swidget);
|
||||
sarea->setWidgetResizable(true);
|
||||
sarea->setFrameShape(QFrame::StyledPanel);
|
||||
sarea->setFrameShadow(QFrame::Sunken);
|
||||
|
||||
QGridLayout* swidget_layout = new QGridLayout(swidget);
|
||||
createSettingWidgets(translation_ctx, swidget, swidget_layout);
|
||||
|
||||
QVBoxLayout* layout = new QVBoxLayout(this);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->addWidget(gbox);
|
||||
|
||||
QHBoxLayout* bottom_hlayout = new QHBoxLayout();
|
||||
QPushButton* restore_defaults = new QPushButton(tr("Restore Default Settings"), this);
|
||||
restore_defaults->setIcon(QIcon::fromTheme(QStringLiteral("restart-line")));
|
||||
connect(restore_defaults, &QPushButton::clicked, this, &ControllerCustomSettingsWidget::restoreDefaults);
|
||||
bottom_hlayout->addStretch(1);
|
||||
bottom_hlayout->addWidget(restore_defaults);
|
||||
layout->addLayout(bottom_hlayout);
|
||||
layout->addStretch(1);
|
||||
layout->addWidget(sarea);
|
||||
}
|
||||
|
||||
ControllerCustomSettingsWidget::~ControllerCustomSettingsWidget() = default;
|
||||
@@ -503,8 +500,6 @@ static std::tuple<QString, QString> getPrefixAndSuffixForIntFormat(const QString
|
||||
return std::tie(prefix, suffix);
|
||||
}
|
||||
|
||||
#if 0
|
||||
// Unused until we handle multiplier below.
|
||||
static std::tuple<QString, QString, int> getPrefixAndSuffixForFloatFormat(const QString& format)
|
||||
{
|
||||
QString prefix, suffix;
|
||||
@@ -532,7 +527,6 @@ static std::tuple<QString, QString, int> getPrefixAndSuffixForFloatFormat(const
|
||||
|
||||
return std::tie(prefix, suffix, decimals);
|
||||
}
|
||||
#endif
|
||||
|
||||
void ControllerCustomSettingsWidget::createSettingWidgets(const char* translation_ctx, QWidget* widget_parent, QGridLayout* layout)
|
||||
{
|
||||
@@ -569,7 +563,8 @@ void ControllerCustomSettingsWidget::createSettingWidgets(const char* translatio
|
||||
sb->setPrefix(prefix);
|
||||
sb->setSuffix(suffix);
|
||||
}
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, sb, m_config_section, std::move(key_name), si.IntegerDefaultValue());
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileInt(
|
||||
sif, sb, m_config_section, std::move(key_name), si.IntegerDefaultValue());
|
||||
layout->addWidget(new QLabel(qApp->translate(translation_ctx, si.display_name), widget_parent), current_row, 0);
|
||||
layout->addWidget(sb, current_row, 1, 1, 3);
|
||||
current_row++;
|
||||
@@ -582,7 +577,7 @@ void ControllerCustomSettingsWidget::createSettingWidgets(const char* translatio
|
||||
cb->setObjectName(QString::fromUtf8(si.name));
|
||||
for (u32 i = 0; si.options[i] != nullptr; i++)
|
||||
cb->addItem(qApp->translate(translation_ctx, si.options[i]));
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileInt(
|
||||
sif, cb, m_config_section, std::move(key_name), si.IntegerDefaultValue(), si.IntegerMinValue());
|
||||
layout->addWidget(new QLabel(qApp->translate(translation_ctx, si.display_name), widget_parent), current_row, 0);
|
||||
layout->addWidget(cb, current_row, 1, 1, 3);
|
||||
@@ -594,11 +589,10 @@ void ControllerCustomSettingsWidget::createSettingWidgets(const char* translatio
|
||||
{
|
||||
QDoubleSpinBox* sb = new QDoubleSpinBox(widget_parent);
|
||||
sb->setObjectName(QString::fromUtf8(si.name));
|
||||
sb->setMinimum(si.FloatMinValue());
|
||||
sb->setMaximum(si.FloatMaxValue());
|
||||
sb->setSingleStep(si.FloatStepValue());
|
||||
#if 0
|
||||
// We can't use this until we handle multiplier.
|
||||
sb->setMinimum(si.FloatMinValue() * si.multiplier);
|
||||
sb->setMaximum(si.FloatMaxValue() * si.multiplier);
|
||||
sb->setSingleStep(si.FloatStepValue() * si.multiplier);
|
||||
|
||||
if (si.format)
|
||||
{
|
||||
const auto [prefix, suffix, decimals] = getPrefixAndSuffixForFloatFormat(QString::fromUtf8(si.format));
|
||||
@@ -607,8 +601,9 @@ void ControllerCustomSettingsWidget::createSettingWidgets(const char* translatio
|
||||
sb->setDecimals(decimals);
|
||||
sb->setSuffix(suffix);
|
||||
}
|
||||
#endif
|
||||
SettingWidgetBinder::BindWidgetToFloatSetting(sif, sb, m_config_section, std::move(key_name), si.FloatDefaultValue());
|
||||
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileFloat(
|
||||
sif, sb, m_config_section, std::move(key_name), si.FloatDefaultValue(), si.multiplier);
|
||||
layout->addWidget(new QLabel(qApp->translate(translation_ctx, si.display_name), widget_parent), current_row, 0);
|
||||
layout->addWidget(sb, current_row, 1, 1, 3);
|
||||
current_row++;
|
||||
@@ -619,7 +614,8 @@ void ControllerCustomSettingsWidget::createSettingWidgets(const char* translatio
|
||||
{
|
||||
QLineEdit* le = new QLineEdit(widget_parent);
|
||||
le->setObjectName(QString::fromUtf8(si.name));
|
||||
SettingWidgetBinder::BindWidgetToStringSetting(sif, le, m_config_section, std::move(key_name), si.StringDefaultValue());
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileString(
|
||||
sif, le, m_config_section, std::move(key_name), si.StringDefaultValue());
|
||||
layout->addWidget(new QLabel(qApp->translate(translation_ctx, si.display_name), widget_parent), current_row, 0);
|
||||
layout->addWidget(le, current_row, 1, 1, 3);
|
||||
current_row++;
|
||||
@@ -641,7 +637,8 @@ void ControllerCustomSettingsWidget::createSettingWidgets(const char* translatio
|
||||
for (u32 i = 0; si.options[i] != nullptr; i++)
|
||||
cb->addItem(qApp->translate(translation_ctx, si.options[i]), QString::fromUtf8(si.options[i]));
|
||||
}
|
||||
SettingWidgetBinder::BindWidgetToStringSetting(sif, cb, m_config_section, std::move(key_name), si.StringDefaultValue());
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileString(
|
||||
sif, cb, m_config_section, std::move(key_name), si.StringDefaultValue());
|
||||
layout->addWidget(new QLabel(qApp->translate(translation_ctx, si.display_name), widget_parent), current_row, 0);
|
||||
layout->addWidget(cb, current_row, 1, 1, 3);
|
||||
current_row++;
|
||||
@@ -653,7 +650,8 @@ void ControllerCustomSettingsWidget::createSettingWidgets(const char* translatio
|
||||
QLineEdit* le = new QLineEdit(widget_parent);
|
||||
le->setObjectName(QString::fromUtf8(si.name));
|
||||
QPushButton* browse_button = new QPushButton(tr("Browse..."), widget_parent);
|
||||
SettingWidgetBinder::BindWidgetToStringSetting(sif, le, m_config_section, std::move(key_name), si.StringDefaultValue());
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileString(
|
||||
sif, le, m_config_section, std::move(key_name), si.StringDefaultValue());
|
||||
connect(browse_button, &QPushButton::clicked, [this, le]() {
|
||||
const QString path(QDir::toNativeSeparators(QFileDialog::getOpenFileName(this, tr("Select File"))));
|
||||
if (!path.isEmpty())
|
||||
@@ -677,6 +675,16 @@ void ControllerCustomSettingsWidget::createSettingWidgets(const char* translatio
|
||||
|
||||
layout->addItem(new QSpacerItem(1, 10, QSizePolicy::Minimum, QSizePolicy::Fixed), current_row++, 0, 1, 4);
|
||||
}
|
||||
|
||||
QHBoxLayout* bottom_hlayout = new QHBoxLayout();
|
||||
QPushButton* restore_defaults = new QPushButton(tr("Restore Default Settings"), this);
|
||||
restore_defaults->setIcon(QIcon::fromTheme(QStringLiteral("restart-line")));
|
||||
connect(restore_defaults, &QPushButton::clicked, this, &ControllerCustomSettingsWidget::restoreDefaults);
|
||||
bottom_hlayout->addStretch(1);
|
||||
bottom_hlayout->addWidget(restore_defaults);
|
||||
layout->addLayout(bottom_hlayout, current_row++, 0, 1, 4);
|
||||
|
||||
layout->addItem(new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::Expanding), current_row++, 0, 1, 4);
|
||||
}
|
||||
|
||||
void ControllerCustomSettingsWidget::restoreDefaults()
|
||||
@@ -715,7 +723,7 @@ void ControllerCustomSettingsWidget::restoreDefaults()
|
||||
{
|
||||
QDoubleSpinBox* widget = findChild<QDoubleSpinBox*>(QString::fromStdString(si.name));
|
||||
if (widget)
|
||||
widget->setValue(si.FloatDefaultValue());
|
||||
widget->setValue(si.FloatDefaultValue() * si.multiplier);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -851,10 +859,12 @@ ControllerBindingWidget_Base* ControllerBindingWidget_DualShock2::createInstance
|
||||
USBDeviceWidget::USBDeviceWidget(QWidget* parent, ControllerSettingsDialog* dialog, u32 port)
|
||||
: QWidget(parent)
|
||||
, m_dialog(dialog)
|
||||
, m_config_section(StringUtil::StdStringFromFormat("USB%u", port + 1u))
|
||||
, m_config_section(fmt::format("USB{}", port + 1))
|
||||
, m_port_number(port)
|
||||
{
|
||||
m_ui.setupUi(this);
|
||||
m_ui.groupBox->setTitle(tr("USB Port %1").arg(port + 1));
|
||||
|
||||
populateDeviceTypes();
|
||||
populatePages();
|
||||
|
||||
@@ -926,9 +936,8 @@ void USBDeviceWidget::populatePages()
|
||||
|
||||
if (!settings.empty())
|
||||
{
|
||||
const QString settings_title(tr("Device Settings"));
|
||||
m_settings_widget = new ControllerCustomSettingsWidget(
|
||||
settings, m_config_section, m_device_type + "_", settings_title, m_device_type.c_str(), m_dialog, m_ui.stackedWidget);
|
||||
settings, m_config_section, m_device_type + "_", m_device_type.c_str(), m_dialog, m_ui.stackedWidget);
|
||||
m_ui.stackedWidget->addWidget(m_settings_widget);
|
||||
}
|
||||
|
||||
|
||||
@@ -139,7 +139,7 @@ class ControllerCustomSettingsWidget : public QWidget
|
||||
|
||||
public:
|
||||
ControllerCustomSettingsWidget(gsl::span<const SettingInfo> settings, std::string config_section, std::string config_prefix,
|
||||
const QString& group_title, const char* translation_ctx, ControllerSettingsDialog* dialog, QWidget* parent_widget);
|
||||
const char* translation_ctx, ControllerSettingsDialog* dialog, QWidget* parent_widget);
|
||||
~ControllerCustomSettingsWidget();
|
||||
|
||||
private Q_SLOTS:
|
||||
|
||||
@@ -22,6 +22,10 @@
|
||||
#include "QtUtils.h"
|
||||
#include "SettingWidgetBinder.h"
|
||||
|
||||
#ifdef SDL_BUILD
|
||||
#include "pcsx2/Frontend/SDLInputSource.h"
|
||||
#endif
|
||||
|
||||
ControllerGlobalSettingsWidget::ControllerGlobalSettingsWidget(QWidget* parent, ControllerSettingsDialog* dialog)
|
||||
: QWidget(parent)
|
||||
, m_dialog(dialog)
|
||||
@@ -30,8 +34,16 @@ ControllerGlobalSettingsWidget::ControllerGlobalSettingsWidget(QWidget* parent,
|
||||
|
||||
SettingsInterface* sif = dialog->getProfileSettingsInterface();
|
||||
|
||||
#ifdef SDL_BUILD
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableSDLSource, "InputSources", "SDL", true);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableSDLEnhancedMode, "InputSources", "SDLControllerEnhancedMode", false);
|
||||
connect(m_ui.enableSDLSource, &QCheckBox::stateChanged, this, &ControllerGlobalSettingsWidget::updateSDLOptionsEnabled);
|
||||
connect(m_ui.ledSettings, &QToolButton::clicked, this, &ControllerGlobalSettingsWidget::ledSettingsClicked);
|
||||
#else
|
||||
m_ui.enableSDLSource->setEnabled(false);
|
||||
m_ui.ledSettings->setEnabled(false);
|
||||
#endif
|
||||
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableMouseMapping, "UI", "EnableMouseMapping", false);
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, m_ui.multitapPort1, "Pad", "MultitapPort1", false);
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, m_ui.multitapPort2, "Pad", "MultitapPort2", false);
|
||||
@@ -66,12 +78,13 @@ ControllerGlobalSettingsWidget::ControllerGlobalSettingsWidget(QWidget* parent,
|
||||
m_ui.profileSettings = nullptr;
|
||||
}
|
||||
|
||||
connect(m_ui.enableSDLSource, &QCheckBox::stateChanged, this, &ControllerGlobalSettingsWidget::updateSDLOptionsEnabled);
|
||||
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)); });
|
||||
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()));
|
||||
|
||||
@@ -106,4 +119,40 @@ void ControllerGlobalSettingsWidget::updateSDLOptionsEnabled()
|
||||
{
|
||||
const bool enabled = m_ui.enableSDLSource->isChecked();
|
||||
m_ui.enableSDLEnhancedMode->setEnabled(enabled);
|
||||
m_ui.ledSettings->setEnabled(enabled);
|
||||
}
|
||||
|
||||
void ControllerGlobalSettingsWidget::ledSettingsClicked()
|
||||
{
|
||||
ControllerLEDSettingsDialog dialog(this, m_dialog);
|
||||
dialog.exec();
|
||||
}
|
||||
|
||||
ControllerLEDSettingsDialog::ControllerLEDSettingsDialog(QWidget* parent, ControllerSettingsDialog* dialog)
|
||||
: QDialog(parent)
|
||||
, m_dialog(dialog)
|
||||
{
|
||||
m_ui.setupUi(this);
|
||||
|
||||
linkButton(m_ui.SDL0LED, 0);
|
||||
linkButton(m_ui.SDL1LED, 1);
|
||||
linkButton(m_ui.SDL2LED, 2);
|
||||
linkButton(m_ui.SDL3LED, 3);
|
||||
|
||||
connect(m_ui.buttonBox->button(QDialogButtonBox::Close), &QPushButton::clicked, this, &QDialog::accept);
|
||||
}
|
||||
|
||||
ControllerLEDSettingsDialog::~ControllerLEDSettingsDialog() = default;
|
||||
|
||||
void ControllerLEDSettingsDialog::linkButton(ColorPickerButton* button, u32 player_id)
|
||||
{
|
||||
#ifdef SDL_BUILD
|
||||
std::string key(fmt::format("Player{}LED", player_id));
|
||||
const u32 current_value = SDLInputSource::ParseRGBForPlayerId(m_dialog->getStringValue("SDLExtra", key.c_str(), ""), player_id);
|
||||
button->setColor(current_value);
|
||||
|
||||
connect(button, &ColorPickerButton::colorChanged, this, [this, key = std::move(key)](u32 new_rgb) {
|
||||
m_dialog->setStringValue("SDLExtra", key.c_str(), fmt::format("{:06X}", new_rgb).c_str());
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -20,7 +20,10 @@
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
#include "ColorPickerButton.h"
|
||||
|
||||
#include "ui_ControllerGlobalSettingsWidget.h"
|
||||
#include "ui_ControllerLEDSettingsDialog.h"
|
||||
|
||||
class ControllerSettingsDialog;
|
||||
|
||||
@@ -38,9 +41,26 @@ public:
|
||||
Q_SIGNALS:
|
||||
void bindingSetupChanged();
|
||||
|
||||
private:
|
||||
private Q_SLOTS:
|
||||
void updateSDLOptionsEnabled();
|
||||
void ledSettingsClicked();
|
||||
|
||||
private:
|
||||
Ui::ControllerGlobalSettingsWidget m_ui;
|
||||
ControllerSettingsDialog* m_dialog;
|
||||
};
|
||||
|
||||
class ControllerLEDSettingsDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ControllerLEDSettingsDialog(QWidget* parent, ControllerSettingsDialog* dialog);
|
||||
~ControllerLEDSettingsDialog();
|
||||
|
||||
private:
|
||||
void linkButton(ColorPickerButton* button, u32 player_id);
|
||||
|
||||
Ui::ControllerLEDSettingsDialog m_ui;
|
||||
ControllerSettingsDialog* m_dialog;
|
||||
};
|
||||
|
||||
@@ -50,11 +50,27 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="enableSDLEnhancedMode">
|
||||
<property name="text">
|
||||
<string>DualShock 4 / DualSense Enhanced Mode</string>
|
||||
</property>
|
||||
</widget>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="enableSDLEnhancedMode">
|
||||
<property name="text">
|
||||
<string>DualShock 4 / DualSense Enhanced Mode</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="ledSettings">
|
||||
<property name="toolTip">
|
||||
<string>Controller LED Settings</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="lightbulb-line">
|
||||
<normaloff>.</normaloff>.
|
||||
</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
|
||||
83
pcsx2-qt/Settings/ControllerLEDSettingsDialog.ui
Normal file
83
pcsx2-qt/Settings/ControllerLEDSettingsDialog.ui
Normal file
@@ -0,0 +1,83 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ControllerLEDSettingsDialog</class>
|
||||
<widget class="QDialog" name="ControllerLEDSettingsDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>501</width>
|
||||
<height>108</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Controller LED Settings</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>SDL-0 LED</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<widget class="ColorPickerButton" name="SDL0LED"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>SDL-1 LED</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="ColorPickerButton" name="SDL1LED"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QGroupBox" name="groupBox_3">
|
||||
<property name="title">
|
||||
<string>SDL-2 LED</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="ColorPickerButton" name="SDL2LED"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QGroupBox" name="groupBox_4">
|
||||
<property name="title">
|
||||
<string>SDL-3 LED</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="ColorPickerButton" name="SDL3LED"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="4">
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Close</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>ColorPickerButton</class>
|
||||
<extends>QPushButton</extends>
|
||||
<header>ColorPickerButton.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -38,7 +38,8 @@ namespace ControllerSettingWidgetBinder
|
||||
{
|
||||
/// Interface specific method of BindWidgetToBoolSetting().
|
||||
template <typename WidgetType>
|
||||
static void BindWidgetToInputProfileBool(SettingsInterface* sif, WidgetType* widget, std::string section, std::string key, bool default_value)
|
||||
static inline void BindWidgetToInputProfileBool(
|
||||
SettingsInterface* sif, WidgetType* widget, std::string section, std::string key, bool default_value)
|
||||
{
|
||||
using Accessor = SettingWidgetBinder::SettingAccessor<WidgetType>;
|
||||
|
||||
@@ -68,19 +69,53 @@ namespace ControllerSettingWidgetBinder
|
||||
}
|
||||
}
|
||||
|
||||
/// Interface specific method of BindWidgetToIntSetting().
|
||||
template <typename WidgetType>
|
||||
static inline void BindWidgetToInputProfileInt(
|
||||
SettingsInterface* sif, WidgetType* widget, std::string section, std::string key, s32 default_value, s32 option_offset = 0)
|
||||
{
|
||||
using Accessor = SettingWidgetBinder::SettingAccessor<WidgetType>;
|
||||
|
||||
if (sif)
|
||||
{
|
||||
const s32 value = sif->GetIntValue(section.c_str(), key.c_str(), default_value);
|
||||
Accessor::setIntValue(widget, value - option_offset);
|
||||
|
||||
Accessor::connectValueChanged(widget, [sif, widget, section = std::move(section), key = std::move(key), option_offset]() {
|
||||
const float new_value = Accessor::getIntValue(widget);
|
||||
sif->SetIntValue(section.c_str(), key.c_str(), new_value + option_offset);
|
||||
sif->Save();
|
||||
g_emu_thread->reloadGameSettings();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
const s32 value = Host::GetBaseIntSettingValue(section.c_str(), key.c_str(), default_value);
|
||||
Accessor::setIntValue(widget, value - option_offset);
|
||||
|
||||
Accessor::connectValueChanged(widget, [widget, section = std::move(section), key = std::move(key), option_offset]() {
|
||||
const s32 new_value = Accessor::getIntValue(widget);
|
||||
Host::SetBaseIntSettingValue(section.c_str(), key.c_str(), new_value + option_offset);
|
||||
Host::CommitBaseSettingChanges();
|
||||
g_emu_thread->applySettings();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Interface specific method of BindWidgetToFloatSetting().
|
||||
template <typename WidgetType>
|
||||
static void BindWidgetToInputProfileFloat(SettingsInterface* sif, WidgetType* widget, std::string section, std::string key, float default_value)
|
||||
static inline void BindWidgetToInputProfileFloat(
|
||||
SettingsInterface* sif, WidgetType* widget, std::string section, std::string key, float default_value, float multiplier = 1.0f)
|
||||
{
|
||||
using Accessor = SettingWidgetBinder::SettingAccessor<WidgetType>;
|
||||
|
||||
if (sif)
|
||||
{
|
||||
const float value = sif->GetFloatValue(section.c_str(), key.c_str(), default_value);
|
||||
Accessor::setFloatValue(widget, value);
|
||||
Accessor::setFloatValue(widget, value * multiplier);
|
||||
|
||||
Accessor::connectValueChanged(widget, [sif, widget, section = std::move(section), key = std::move(key)]() {
|
||||
const float new_value = Accessor::getFloatValue(widget);
|
||||
Accessor::connectValueChanged(widget, [sif, widget, section = std::move(section), key = std::move(key), multiplier]() {
|
||||
const float new_value = Accessor::getFloatValue(widget) / multiplier;
|
||||
sif->SetFloatValue(section.c_str(), key.c_str(), new_value);
|
||||
sif->Save();
|
||||
g_emu_thread->reloadGameSettings();
|
||||
@@ -89,10 +124,10 @@ namespace ControllerSettingWidgetBinder
|
||||
else
|
||||
{
|
||||
const float value = Host::GetBaseFloatSettingValue(section.c_str(), key.c_str(), default_value);
|
||||
Accessor::setFloatValue(widget, value);
|
||||
Accessor::setFloatValue(widget, value * multiplier);
|
||||
|
||||
Accessor::connectValueChanged(widget, [widget, section = std::move(section), key = std::move(key)]() {
|
||||
const float new_value = Accessor::getFloatValue(widget);
|
||||
Accessor::connectValueChanged(widget, [widget, section = std::move(section), key = std::move(key), multiplier]() {
|
||||
const float new_value = Accessor::getFloatValue(widget) / multiplier;
|
||||
Host::SetBaseFloatSettingValue(section.c_str(), key.c_str(), new_value);
|
||||
Host::CommitBaseSettingChanges();
|
||||
g_emu_thread->applySettings();
|
||||
@@ -102,12 +137,11 @@ namespace ControllerSettingWidgetBinder
|
||||
|
||||
/// Interface specific method of BindWidgetToNormalizedSetting().
|
||||
template <typename WidgetType>
|
||||
static void BindWidgetToInputProfileNormalized(
|
||||
static inline void BindWidgetToInputProfileNormalized(
|
||||
SettingsInterface* sif, WidgetType* widget, std::string section, std::string key, float range, float default_value)
|
||||
{
|
||||
using Accessor = SettingWidgetBinder::SettingAccessor<WidgetType>;
|
||||
|
||||
|
||||
if (sif)
|
||||
{
|
||||
const float value = sif->GetFloatValue(section.c_str(), key.c_str(), default_value);
|
||||
@@ -136,7 +170,7 @@ namespace ControllerSettingWidgetBinder
|
||||
|
||||
/// Interface specific method of BindWidgetToStringSetting().
|
||||
template <typename WidgetType>
|
||||
static void BindWidgetToInputProfileString(
|
||||
static inline void BindWidgetToInputProfileString(
|
||||
SettingsInterface* sif, WidgetType* widget, std::string section, std::string key, std::string default_value = std::string())
|
||||
{
|
||||
using Accessor = SettingWidgetBinder::SettingAccessor<WidgetType>;
|
||||
@@ -160,7 +194,8 @@ namespace ControllerSettingWidgetBinder
|
||||
}
|
||||
else
|
||||
{
|
||||
const QString value(QString::fromStdString(Host::GetBaseStringSettingValue(section.c_str(), key.c_str(), default_value.c_str())));
|
||||
const QString value(
|
||||
QString::fromStdString(Host::GetBaseStringSettingValue(section.c_str(), key.c_str(), default_value.c_str())));
|
||||
|
||||
Accessor::setStringValue(widget, value);
|
||||
|
||||
|
||||
@@ -447,7 +447,7 @@ void ControllerSettingsDialog::updateListDescription(u32 global_slot, Controller
|
||||
{
|
||||
QListWidgetItem* item = m_ui.settingsCategory->item(i);
|
||||
const QVariant data(item->data(Qt::UserRole));
|
||||
if (data.type() == QVariant::UInt && data.toUInt() == global_slot)
|
||||
if (data.metaType().id() == QMetaType::UInt && data.toUInt() == global_slot)
|
||||
{
|
||||
const auto [port, slot] = sioConvertPadToPortAndSlot(global_slot);
|
||||
const bool mtap_enabled = getBoolValue("Pad", (port == 0) ? "MultitapPort1" : "MultitapPort2", false);
|
||||
@@ -469,7 +469,7 @@ void ControllerSettingsDialog::updateListDescription(u32 port, USBDeviceWidget*
|
||||
{
|
||||
QListWidgetItem* item = m_ui.settingsCategory->item(i);
|
||||
const QVariant data(item->data(Qt::UserRole));
|
||||
if (data.type() == QVariant::UInt && data.toUInt() == (MAX_PORTS + port))
|
||||
if (data.metaType().id() == QMetaType::UInt && data.toUInt() == (MAX_PORTS + port))
|
||||
{
|
||||
const std::string dtype(getStringValue(fmt::format("USB{}", port + 1).c_str(), "Type", "None"));
|
||||
const QString display_name(qApp->translate("USB", USB::GetDeviceName(dtype)));
|
||||
|
||||
@@ -260,9 +260,13 @@ DEV9SettingsWidget::DEV9SettingsWidget(SettingsDialog* dialog, QWidget* parent)
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.hddEnabled, "DEV9/Hdd", "HddEnable", false);
|
||||
|
||||
connect(m_ui.hddFile, &QLineEdit::editingFinished, this, &DEV9SettingsWidget::onHddFileEdit);
|
||||
SettingWidgetBinder::BindWidgetToStringSetting(sif, m_ui.hddFile, "DEV9/Hdd", "HddFile", "DEV9hdd.raw");
|
||||
if (m_dialog->isPerGameSettings())
|
||||
{
|
||||
m_ui.hddFile->setText(QString::fromUtf8(m_dialog->getStringValue("DEV9/Hdd", "HddFile", "").value().c_str()));
|
||||
m_ui.hddFile->setPlaceholderText(QString::fromUtf8(Host::GetBaseStringSettingValue("DEV9/Hdd", "HddFile", "DEV9hdd.raw")));
|
||||
}
|
||||
else
|
||||
m_ui.hddFile->setText(QString::fromUtf8(m_dialog->getStringValue("DEV9/Hdd", "HddFile", "DEV9hdd.raw").value().c_str()));
|
||||
connect(m_ui.hddBrowseFile, &QPushButton::clicked, this, &DEV9SettingsWidget::onHddBrowseFileClicked);
|
||||
|
||||
//TODO: need a getUintValue for if 48bit support occurs
|
||||
@@ -270,18 +274,27 @@ DEV9SettingsWidget::DEV9SettingsWidget(SettingsDialog* dialog, QWidget* parent)
|
||||
|
||||
if (m_dialog->isPerGameSettings())
|
||||
{
|
||||
std::optional<int> sizeOpt = std::nullopt;
|
||||
if (size > 0)
|
||||
sizeOpt = size;
|
||||
const int sizeGlobal = (u64)Host::GetBaseIntSettingValue("DEV9/Hdd", "HddSizeSectors", 0) * 512 / (1024 * 1024 * 1024);
|
||||
m_ui.hddSizeSpinBox->setMinimum(39);
|
||||
m_ui.hddSizeSpinBox->setSpecialValueText(tr("Global [%1]").arg(sizeGlobal));
|
||||
|
||||
SettingWidgetBinder::SettingAccessor<QSpinBox>::makeNullableInt(m_ui.hddSizeSpinBox, sizeGlobal);
|
||||
SettingWidgetBinder::SettingAccessor<QSpinBox>::setNullableIntValue(m_ui.hddSizeSpinBox, sizeOpt);
|
||||
|
||||
m_ui.hddSizeSlider->setValue(sizeOpt.value_or(sizeGlobal));
|
||||
|
||||
m_ui.hddSizeSlider->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(m_ui.hddSizeSlider, &QSlider::customContextMenuRequested, this, &DEV9SettingsWidget::onHddSizeSliderContext);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ui.hddSizeSlider->setValue(size);
|
||||
SettingWidgetBinder::SettingAccessor<QSpinBox>::setIntValue(m_ui.hddSizeSpinBox, size);
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
m_ui.hddSizeSlider ->setValue(size);
|
||||
m_ui.hddSizeSpinBox->setValue(size);
|
||||
|
||||
connect(m_ui.hddSizeSlider, QOverload<int>::of(&QSlider ::valueChanged), this, &DEV9SettingsWidget::onHddSizeSlide);
|
||||
connect(m_ui.hddSizeSpinBox, QOverload<int>::of(&QSpinBox::valueChanged), this, &DEV9SettingsWidget::onHddSizeSpin );
|
||||
// clang-format on
|
||||
connect(m_ui.hddSizeSlider, QOverload<int>::of(&QSlider::valueChanged), this, &DEV9SettingsWidget::onHddSizeSlide);
|
||||
SettingWidgetBinder::SettingAccessor<QSpinBox>::connectValueChanged(m_ui.hddSizeSpinBox, [&]() { onHddSizeAccessorSpin(); });
|
||||
|
||||
connect(m_ui.hddCreate, &QPushButton::clicked, this, &DEV9SettingsWidget::onHddCreateClicked);
|
||||
}
|
||||
@@ -682,7 +695,7 @@ void DEV9SettingsWidget::onEthHostEdit(QStandardItem* item)
|
||||
|
||||
void DEV9SettingsWidget::onHddEnabledChanged(int state)
|
||||
{
|
||||
const bool enabled = state == Qt::CheckState::PartiallyChecked ? m_dialog->getEffectiveBoolValue("DEV9/Hdd", "HddEnable", false) : state;
|
||||
const bool enabled = state == Qt::CheckState::PartiallyChecked ? Host::GetBaseBoolSettingValue("DEV9/Hdd", "HddEnable", false) : state;
|
||||
|
||||
m_ui.hddFile->setEnabled(enabled);
|
||||
m_ui.hddFileLabel->setEnabled(enabled);
|
||||
@@ -699,8 +712,8 @@ void DEV9SettingsWidget::onHddBrowseFileClicked()
|
||||
{
|
||||
QString path =
|
||||
QDir::toNativeSeparators(QFileDialog::getSaveFileName(QtUtils::GetRootWidget(this), tr("HDD Image File"),
|
||||
!m_ui.hddFile->text().isEmpty() ? m_ui.hddFile->text() : "DEV9hdd.raw", tr("HDD (*.raw)"), nullptr,
|
||||
QFileDialog::DontConfirmOverwrite));
|
||||
!m_ui.hddFile->text().isEmpty() ? m_ui.hddFile->text() : (!m_ui.hddFile->placeholderText().isEmpty() ? m_ui.hddFile->placeholderText() : "DEV9hdd.raw"),
|
||||
tr("HDD (*.raw)"), nullptr, QFileDialog::DontConfirmOverwrite));
|
||||
|
||||
if (path.isEmpty())
|
||||
return;
|
||||
@@ -711,10 +724,16 @@ void DEV9SettingsWidget::onHddBrowseFileClicked()
|
||||
|
||||
void DEV9SettingsWidget::onHddFileEdit()
|
||||
{
|
||||
//Check if file exists, if so set HddSize to correct value
|
||||
// Check if file exists, if so set HddSize to correct value.
|
||||
// Also save the hddPath setting
|
||||
std::string hddPath(m_ui.hddFile->text().toStdString());
|
||||
if (hddPath.empty())
|
||||
{
|
||||
m_dialog->setStringSettingValue("DEV9/Hdd", "HddFile", std::nullopt);
|
||||
return;
|
||||
}
|
||||
else
|
||||
m_dialog->setStringSettingValue("DEV9/Hdd", "HddFile", hddPath.c_str());
|
||||
|
||||
if (!Path::IsAbsolute(hddPath))
|
||||
hddPath = Path::Combine(EmuFolders::Settings, hddPath);
|
||||
@@ -739,22 +758,49 @@ void DEV9SettingsWidget::onHddFileEdit()
|
||||
|
||||
void DEV9SettingsWidget::onHddSizeSlide(int i)
|
||||
{
|
||||
// We have to call onHddSizeAccessorSpin() ourself, as the value could still be considered null when the valueChanged signal is fired
|
||||
QSignalBlocker sb(m_ui.hddSizeSpinBox);
|
||||
m_ui.hddSizeSpinBox->setValue(i);
|
||||
|
||||
m_dialog->setIntSettingValue("DEV9/Hdd", "HddSizeSectors", (int)((s64)i * 1024 * 1024 * 1024 / 512));
|
||||
SettingWidgetBinder::SettingAccessor<QSpinBox>::setNullableIntValue(m_ui.hddSizeSpinBox, i);
|
||||
onHddSizeAccessorSpin();
|
||||
}
|
||||
|
||||
void DEV9SettingsWidget::onHddSizeSpin(int i)
|
||||
void DEV9SettingsWidget::onHddSizeSliderContext(const QPoint& pt)
|
||||
{
|
||||
QSignalBlocker sb(m_ui.hddSizeSlider);
|
||||
m_ui.hddSizeSlider->setValue(i);
|
||||
QMenu menu(m_ui.hddSizeSlider);
|
||||
connect(menu.addAction(qApp->translate("SettingWidgetBinder", "Reset")), &QAction::triggered, this, &DEV9SettingsWidget::onHddSizeSliderReset);
|
||||
menu.exec(m_ui.hddSizeSlider->mapToGlobal(pt));
|
||||
}
|
||||
|
||||
//TODO: need a setUintSettingValue for if 48bit support occurs
|
||||
if (i == 39)
|
||||
m_dialog->setIntSettingValue("DEV9/Hdd", "HddSizeSectors", std::nullopt);
|
||||
void DEV9SettingsWidget::onHddSizeSliderReset([[maybe_unused]] bool checked)
|
||||
{
|
||||
// We have to call onHddSizeAccessorSpin() ourself, as the value could still be considered non-null when the valueChanged signal is fired
|
||||
QSignalBlocker sb(m_ui.hddSizeSpinBox);
|
||||
SettingWidgetBinder::SettingAccessor<QSpinBox>::setNullableIntValue(m_ui.hddSizeSpinBox, std::nullopt);
|
||||
onHddSizeAccessorSpin();
|
||||
}
|
||||
|
||||
void DEV9SettingsWidget::onHddSizeAccessorSpin()
|
||||
{
|
||||
//TODO: need a getUintValue for if 48bit support occurs
|
||||
QSignalBlocker sb(m_ui.hddSizeSlider);
|
||||
if (m_dialog->isPerGameSettings())
|
||||
{
|
||||
std::optional<int> new_value = SettingWidgetBinder::SettingAccessor<QSpinBox>::getNullableIntValue(m_ui.hddSizeSpinBox);
|
||||
|
||||
const int sizeGlobal = (u64)Host::GetBaseIntSettingValue("DEV9/Hdd", "HddSizeSectors", 0) * 512 / (1024 * 1024 * 1024);
|
||||
m_ui.hddSizeSlider->setValue(new_value.value_or(sizeGlobal));
|
||||
|
||||
if (new_value.has_value())
|
||||
m_dialog->setIntSettingValue("DEV9/Hdd", "HddSizeSectors", new_value.value() * (1024 * 1024 * 1024 / 512));
|
||||
else
|
||||
m_dialog->setIntSettingValue("DEV9/Hdd", "HddSizeSectors", std::nullopt);
|
||||
}
|
||||
else
|
||||
m_dialog->setIntSettingValue("DEV9/Hdd", "HddSizeSectors", i * (1024 * 1024 * 1024 / 512));
|
||||
{
|
||||
const int new_value = SettingWidgetBinder::SettingAccessor<QSpinBox>::getIntValue(m_ui.hddSizeSpinBox);
|
||||
m_ui.hddSizeSlider->setValue(new_value);
|
||||
m_dialog->setIntSettingValue("DEV9/Hdd", "HddSizeSectors", new_value * (1024 * 1024 * 1024 / 512));
|
||||
}
|
||||
}
|
||||
|
||||
void DEV9SettingsWidget::onHddCreateClicked()
|
||||
@@ -774,7 +820,7 @@ void DEV9SettingsWidget::onHddCreateClicked()
|
||||
if (!Path::IsAbsolute(hddPath))
|
||||
hddPath = Path::Combine(EmuFolders::Settings, hddPath);
|
||||
|
||||
if (!FileSystem::FileExists(hddPath.c_str()))
|
||||
if (FileSystem::FileExists(hddPath.c_str()))
|
||||
{
|
||||
//GHC uses UTF8 on all platforms
|
||||
QMessageBox::StandardButton selection =
|
||||
|
||||
@@ -49,7 +49,11 @@ private Q_SLOTS:
|
||||
void onHddBrowseFileClicked();
|
||||
void onHddFileEdit();
|
||||
void onHddSizeSlide(int i);
|
||||
void onHddSizeSpin(int i);
|
||||
// Per game only.
|
||||
void onHddSizeSliderContext(const QPoint& pt);
|
||||
void onHddSizeSliderReset(bool checked = false);
|
||||
//
|
||||
void onHddSizeAccessorSpin();
|
||||
void onHddCreateClicked();
|
||||
|
||||
public:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2022 PCSX2 Dev Team
|
||||
* Copyright (C) 2002-2023 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
@@ -100,9 +100,12 @@ EmulationSettingsWidget::EmulationSettingsWidget(SettingsDialog* dialog, QWidget
|
||||
dialog->registerWidgetHelp(m_ui.eeCycleRate, tr("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("None"),
|
||||
dialog->registerWidgetHelp(m_ui.eeCycleSkipping, tr("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"),
|
||||
tr("Generally a speedup on CPUs with 3 or more threads. "
|
||||
"Safe for most games, but a few are incompatible and may hang."));
|
||||
|
||||
@@ -346,6 +346,11 @@
|
||||
<string>In-Game</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Playable</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Perfect</string>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2022 PCSX2 Dev Team
|
||||
* Copyright (C) 2002-2023 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
@@ -97,7 +97,8 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.fmvAspectRatio, "EmuCore/GS", "FMVAspectRatioSwitch",
|
||||
Pcsx2Config::GSOptions::FMVAspectRatioSwitchNames, FMVAspectRatioSwitchType::Off);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.interlacing, "EmuCore/GS", "deinterlace_mode", DEFAULT_INTERLACE_MODE);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.bilinearFiltering, "EmuCore/GS", "linear_present_mode", static_cast<int>(GSPostBilinearMode::BilinearSmooth));
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(
|
||||
sif, m_ui.bilinearFiltering, "EmuCore/GS", "linear_present_mode", static_cast<int>(GSPostBilinearMode::BilinearSmooth));
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.widescreenPatches, "EmuCore", "EnableWideScreenPatches", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.noInterlacingPatches, "EmuCore", "EnableNoInterlacingPatches", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.integerScaling, "EmuCore/GS", "IntegerScaling", false);
|
||||
@@ -105,8 +106,10 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.PCRTCOverscan, "EmuCore/GS", "pcrtc_overscan", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.PCRTCAntiBlur, "EmuCore/GS", "pcrtc_antiblur", true);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.DisableInterlaceOffset, "EmuCore/GS", "disable_interlace_offset", false);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.screenshotSize, "EmuCore/GS", "ScreenshotSize", static_cast<int>(GSScreenshotSize::WindowResolution));
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.screenshotFormat, "EmuCore/GS", "ScreenshotFormat", static_cast<int>(GSScreenshotFormat::PNG));
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(
|
||||
sif, m_ui.screenshotSize, "EmuCore/GS", "ScreenshotSize", static_cast<int>(GSScreenshotSize::WindowResolution));
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(
|
||||
sif, m_ui.screenshotFormat, "EmuCore/GS", "ScreenshotFormat", static_cast<int>(GSScreenshotFormat::PNG));
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.screenshotQuality, "EmuCore/GS", "ScreenshotQuality", 50);
|
||||
SettingWidgetBinder::BindWidgetToFloatSetting(sif, m_ui.stretchY, "EmuCore/GS", "StretchY", 100.0f);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.cropLeft, "EmuCore/GS", "CropLeft", 0);
|
||||
@@ -114,7 +117,8 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.cropRight, "EmuCore/GS", "CropRight", 0);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.cropBottom, "EmuCore/GS", "CropBottom", 0);
|
||||
|
||||
connect(m_ui.fullscreenModes, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &GraphicsSettingsWidget::onFullscreenModeChanged);
|
||||
connect(
|
||||
m_ui.fullscreenModes, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &GraphicsSettingsWidget::onFullscreenModeChanged);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// OSD Settings
|
||||
@@ -147,55 +151,33 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// HW Settings
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
static const char* upscale_entries[] = {
|
||||
"Native (PS2) (Default)",
|
||||
"1.25x Native",
|
||||
"1.5x Native",
|
||||
"1.75x Native",
|
||||
"2x Native (~720p)",
|
||||
"2.25x Native",
|
||||
"2.5x Native",
|
||||
"2.75x Native",
|
||||
"3x Native (~1080p)",
|
||||
"3.5x Native",
|
||||
"4x Native (~1440p/2K)",
|
||||
"5x Native (~1620p)",
|
||||
"6x Native (~2160p/4K)",
|
||||
"7x Native (~2520p)",
|
||||
"8x Native (~2880p/5K)",
|
||||
nullptr};
|
||||
static const char* upscale_entries[] = {"Native (PS2) (Default)", "1.25x Native", "1.5x Native", "1.75x Native", "2x Native (~720p)",
|
||||
"2.25x Native", "2.5x Native", "2.75x Native", "3x Native (~1080p)", "3.5x Native", "4x Native (~1440p/2K)", "5x Native (~1620p)",
|
||||
"6x Native (~2160p/4K)", "7x Native (~2520p)", "8x Native (~2880p/5K)", nullptr};
|
||||
static const char* upscale_values[] = {
|
||||
"1",
|
||||
"1.25",
|
||||
"1.5",
|
||||
"1.75",
|
||||
"2",
|
||||
"2.25",
|
||||
"2.5",
|
||||
"2.75",
|
||||
"3",
|
||||
"3.5",
|
||||
"4",
|
||||
"5",
|
||||
"6",
|
||||
"7",
|
||||
"8",
|
||||
nullptr };
|
||||
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.upscaleMultiplier, "EmuCore/GS", "upscale_multiplier", upscale_entries, upscale_values, "1.0");
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.textureFiltering, "EmuCore/GS", "filter", static_cast<int>(BiFiltering::PS2));
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.trilinearFiltering, "EmuCore/GS", "TriFilter", static_cast<int>(TriFiltering::Automatic), -1);
|
||||
"1", "1.25", "1.5", "1.75", "2", "2.25", "2.5", "2.75", "3", "3.5", "4", "5", "6", "7", "8", nullptr};
|
||||
SettingWidgetBinder::BindWidgetToEnumSetting(
|
||||
sif, m_ui.anisotropicFiltering, "EmuCore/GS", "MaxAnisotropy", s_anisotropic_filtering_entries, s_anisotropic_filtering_values, "0");
|
||||
sif, m_ui.upscaleMultiplier, "EmuCore/GS", "upscale_multiplier", upscale_entries, upscale_values, "1.0");
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.textureFiltering, "EmuCore/GS", "filter", static_cast<int>(BiFiltering::PS2));
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(
|
||||
sif, m_ui.trilinearFiltering, "EmuCore/GS", "TriFilter", static_cast<int>(TriFiltering::Automatic), -1);
|
||||
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.anisotropicFiltering, "EmuCore/GS", "MaxAnisotropy",
|
||||
s_anisotropic_filtering_entries, s_anisotropic_filtering_values, "0");
|
||||
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::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));
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(
|
||||
sif, m_ui.texturePreloading, "EmuCore/GS", "texture_preloading", static_cast<int>(TexturePreloadingLevel::Off));
|
||||
|
||||
connect(m_ui.trilinearFiltering, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &GraphicsSettingsWidget::onTrilinearFilteringChanged);
|
||||
connect(m_ui.gpuPaletteConversion, QOverload<int>::of(&QCheckBox::stateChanged), this, &GraphicsSettingsWidget::onGpuPaletteConversionChanged);
|
||||
connect(m_ui.trilinearFiltering, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
||||
&GraphicsSettingsWidget::onTrilinearFilteringChanged);
|
||||
connect(m_ui.gpuPaletteConversion, QOverload<int>::of(&QCheckBox::stateChanged), this,
|
||||
&GraphicsSettingsWidget::onGpuPaletteConversionChanged);
|
||||
onTrilinearFilteringChanged();
|
||||
onGpuPaletteConversionChanged(m_ui.gpuPaletteConversion->checkState());
|
||||
|
||||
@@ -205,6 +187,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
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);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.gpuTargetCLUTMode, "EmuCore/GS", "UserHacks_GPUTargetCLUTMode", 0);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.skipDrawStart, "EmuCore/GS", "UserHacks_SkipDraw_Start", 0);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.skipDrawEnd, "EmuCore/GS", "UserHacks_SkipDraw_End", 0);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.hwAutoFlush, "EmuCore/GS", "UserHacks_AutoFlush", false);
|
||||
@@ -212,7 +195,8 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.disableDepthEmulation, "EmuCore/GS", "UserHacks_DisableDepthSupport", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.disableSafeFeatures, "EmuCore/GS", "UserHacks_Disable_Safe_Features", false);
|
||||
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.disablePartialInvalidation, "EmuCore/GS", "UserHacks_DisablePartialInvalidation", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.textureInsideRt, "EmuCore/GS", "UserHacks_TextureInsideRt", false);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -233,7 +217,8 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.dumpReplaceableMipmaps, "EmuCore/GS", "DumpReplaceableMipmaps", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.dumpTexturesWithFMVActive, "EmuCore/GS", "DumpTexturesWithFMVActive", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.loadTextureReplacements, "EmuCore/GS", "LoadTextureReplacements", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.loadTextureReplacementsAsync, "EmuCore/GS", "LoadTextureReplacementsAsync", true);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(
|
||||
sif, m_ui.loadTextureReplacementsAsync, "EmuCore/GS", "LoadTextureReplacementsAsync", true);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.precacheTextureReplacements, "EmuCore/GS", "PrecacheTextureReplacements", false);
|
||||
SettingWidgetBinder::BindWidgetToFolderSetting(sif, m_ui.texturesDirectory, m_ui.texturesBrowse, m_ui.texturesOpen, m_ui.texturesReset,
|
||||
"Folders", "Textures", Path::Combine(EmuFolders::DataRoot, "textures"));
|
||||
@@ -247,10 +232,12 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.threadedPresentation, "EmuCore/GS", "DisableThreadedPresentation", false);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.overrideTextureBarriers, "EmuCore/GS", "OverrideTextureBarriers", -1, -1);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.overrideGeometryShader, "EmuCore/GS", "OverrideGeometryShaders", -1, -1);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.gsDumpCompression, "EmuCore/GS", "GSDumpCompression", static_cast<int>(GSDumpCompressionMethod::Zstandard));
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(
|
||||
sif, m_ui.gsDumpCompression, "EmuCore/GS", "GSDumpCompression", static_cast<int>(GSDumpCompressionMethod::Zstandard));
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.disableFramebufferFetch, "EmuCore/GS", "DisableFramebufferFetch", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.disableDualSource, "EmuCore/GS", "DisableDualSourceBlend", false);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.gsDownloadMode, "EmuCore/GS", "HWDownloadMode", static_cast<int>(GSHardwareDownloadMode::Enabled));
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(
|
||||
sif, m_ui.gsDownloadMode, "EmuCore/GS", "HWDownloadMode", static_cast<int>(GSHardwareDownloadMode::Enabled));
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// SW Settings
|
||||
@@ -314,19 +301,53 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
|
||||
// Capture settings
|
||||
{
|
||||
for (const char** container = Pcsx2Config::GSOptions::VideoCaptureContainers; *container; container++)
|
||||
for (const char** container = Pcsx2Config::GSOptions::CaptureContainers; *container; container++)
|
||||
{
|
||||
const QString name(QString::fromUtf8(*container));
|
||||
m_ui.videoCaptureContainer->addItem(name.toUpper(), name);
|
||||
m_ui.captureContainer->addItem(name.toUpper(), name);
|
||||
}
|
||||
|
||||
SettingWidgetBinder::BindWidgetToStringSetting(sif, m_ui.videoCaptureContainer, "EmuCore/GS", "VideoCaptureContainer");
|
||||
connect(m_ui.videoCaptureContainer, &QComboBox::currentIndexChanged, this, &GraphicsSettingsWidget::onVideoCaptureContainerChanged);
|
||||
SettingWidgetBinder::BindWidgetToFolderSetting(sif, m_ui.videoDumpingDirectory, m_ui.videoDumpingDirectoryBrowse,
|
||||
m_ui.videoDumpingDirectoryOpen, m_ui.videoDumpingDirectoryReset, "Folders", "Videos",
|
||||
Path::Combine(EmuFolders::DataRoot, "videos"));
|
||||
|
||||
SettingWidgetBinder::BindWidgetToStringSetting(sif, m_ui.captureContainer, "EmuCore/GS", "CaptureContainer");
|
||||
connect(m_ui.captureContainer, &QComboBox::currentIndexChanged, this, &GraphicsSettingsWidget::onCaptureContainerChanged);
|
||||
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableVideoCapture, "EmuCore/GS", "EnableVideoCapture", true);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(
|
||||
sif, m_ui.videoCaptureBitrate, "EmuCore/GS", "VideoCaptureBitrate", Pcsx2Config::GSOptions::DEFAULT_VIDEO_CAPTURE_BITRATE);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(
|
||||
sif, m_ui.videoCaptureWidth, "EmuCore/GS", "VideoCaptureWidth", Pcsx2Config::GSOptions::DEFAULT_VIDEO_CAPTURE_WIDTH);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(
|
||||
sif, m_ui.videoCaptureHeight, "EmuCore/GS", "VideoCaptureHeight", Pcsx2Config::GSOptions::DEFAULT_VIDEO_CAPTURE_HEIGHT);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(
|
||||
sif, m_ui.videoCaptureResolutionAuto, "EmuCore/GS", "VideoCaptureAutoResolution", true);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(
|
||||
sif, m_ui.enableVideoCaptureArguments, "EmuCore/GS", "EnableVideoCaptureParameters", false);
|
||||
SettingWidgetBinder::BindWidgetToStringSetting(sif, m_ui.videoCaptureArguments, "EmuCore/GS", "VideoCaptureParameters");
|
||||
connect(m_ui.enableVideoCapture, &QCheckBox::stateChanged, this, &GraphicsSettingsWidget::onEnableVideoCaptureChanged);
|
||||
connect(
|
||||
m_ui.videoCaptureResolutionAuto, &QCheckBox::stateChanged, this, &GraphicsSettingsWidget::onVideoCaptureAutoResolutionChanged);
|
||||
connect(m_ui.enableVideoCaptureArguments, &QCheckBox::stateChanged, this,
|
||||
&GraphicsSettingsWidget::onEnableVideoCaptureArgumentsChanged);
|
||||
|
||||
onVideoCaptureContainerChanged();
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableAudioCapture, "EmuCore/GS", "EnableAudioCapture", true);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(
|
||||
sif, m_ui.audioCaptureBitrate, "EmuCore/GS", "AudioCaptureBitrate", Pcsx2Config::GSOptions::DEFAULT_AUDIO_CAPTURE_BITRATE);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(
|
||||
sif, m_ui.enableAudioCaptureArguments, "EmuCore/GS", "EnableAudioCaptureParameters", false);
|
||||
SettingWidgetBinder::BindWidgetToStringSetting(sif, m_ui.audioCaptureArguments, "EmuCore/GS", "AudioCaptureParameters");
|
||||
connect(m_ui.enableAudioCapture, &QCheckBox::stateChanged, this, &GraphicsSettingsWidget::onEnableAudioCaptureChanged);
|
||||
connect(m_ui.enableAudioCaptureArguments, &QCheckBox::stateChanged, this,
|
||||
&GraphicsSettingsWidget::onEnableAudioCaptureArgumentsChanged);
|
||||
|
||||
onCaptureContainerChanged();
|
||||
onEnableVideoCaptureChanged();
|
||||
onEnableVideoCaptureArgumentsChanged();
|
||||
onVideoCaptureAutoResolutionChanged();
|
||||
onEnableAudioCaptureChanged();
|
||||
onEnableAudioCaptureArgumentsChanged();
|
||||
}
|
||||
|
||||
// Display tab
|
||||
@@ -341,42 +362,50 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
tr("Disables interlacing offset which may reduce blurring in some situations."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.bilinearFiltering, tr("Bilinear Filtering"), tr("Bilinear (Smooth)"),
|
||||
tr("Enables bilinear post processing filter. Smooths the overall picture as it is displayed on the screen. Corrects positioning between pixels."));
|
||||
tr("Enables bilinear post processing filter. Smooths the overall picture as it is displayed on the screen. Corrects "
|
||||
"positioning between pixels."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.PCRTCOffsets, tr("Screen Offsets"), tr("Unchecked"),
|
||||
tr("Enables PCRTC Offsets which position the screen as the game requests. Useful for some games such as WipEout Fusion for its screen shake effect, but can make the picture blurry."));
|
||||
tr("Enables PCRTC Offsets which position the screen as the game requests. Useful for some games such as WipEout Fusion for its "
|
||||
"screen shake effect, but can make the picture blurry."));
|
||||
|
||||
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 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."));
|
||||
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.vsync, tr("VSync"), tr("Unchecked"),
|
||||
tr("Enable this option to match PCSX2's refresh rate with your current monitor or screen. VSync is automatically disabled when it is not possible (eg. running at non-100% speed)."));
|
||||
tr("Enable this option to match PCSX2's refresh rate with your current monitor or screen. VSync is automatically disabled when "
|
||||
"it is not possible (eg. running at non-100% speed)."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.integerScaling, tr("Integer Scaling"), tr("Unchecked"),
|
||||
tr("Adds padding to the display area to ensure that the ratio between pixels on the host to pixels in the console is an integer number. May result in a sharper image in some 2D games."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.aspectRatio, tr("Aspect Ratio"), tr("Auto Standard (4:3/3:2 Progressive)"), tr(""));
|
||||
tr("Adds padding to the display area to ensure that the ratio between pixels on the host to pixels in the console is an "
|
||||
"integer number. May result in a sharper image in some 2D games."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.aspectRatio, tr("Aspect Ratio"), tr("Auto Standard (4:3/3:2 Progressive)"),
|
||||
tr("Changes the aspect ratio used to display the console's output to the screen. The default is Auto Standard (4:3/3:2 "
|
||||
"Progressive) which automatically adjusts the aspect ratio to match how a game would be shown on a typical TV of the era."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.interlacing, tr("Deinterlacing"), tr("Automatic (Default)"), tr(""));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.screenshotSize, tr("Screenshot Size"), tr("Screen Resolution"),
|
||||
tr("Determines the resolution at which screenshots will be saved. Internal resolutions preserve more detail at the cost of file size."));
|
||||
tr("Determines the resolution at which screenshots will be saved. Internal resolutions preserve more detail at the cost of "
|
||||
"file size."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.screenshotFormat, tr("Screenshot Format"), tr("PNG"),
|
||||
tr("Selects the format which will be used to save screenshots. JPEG produces smaller files, but loses detail."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.screenshotQuality, tr("Screenshot Quality"), tr("50%"),
|
||||
tr("Selects the quality at which screenshots will be compressed. Higher values preserve more detail for JPEG, and reduce file size for PNG."));
|
||||
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.fullscreenModes, tr("Fullscreen Mode"), tr("Borderless Fullscreen"), tr(""));
|
||||
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(""));
|
||||
|
||||
@@ -392,11 +421,11 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
// Hardware
|
||||
dialog->registerWidgetHelp(m_ui.upscaleMultiplier, tr("Internal Resolution"), tr("Native (PS2) (Default)"), tr(""));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.mipmapping, tr("Mipmapping"), tr("Automatic (Default)"),
|
||||
tr("Control the accuracy level of the mipmapping emulation."));
|
||||
dialog->registerWidgetHelp(
|
||||
m_ui.mipmapping, tr("Mipmapping"), tr("Automatic (Default)"), tr("Control the accuracy level of the mipmapping emulation."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.textureFiltering, tr("Texture Filtering"), tr("Bilinear (PS2)"),
|
||||
tr("Control the texture filtering of the emulation."));
|
||||
dialog->registerWidgetHelp(
|
||||
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."));
|
||||
@@ -414,8 +443,9 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
tr("Control the number of Auto-CRC fixes and hacks applied to games."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.blending, tr("Blending Accuracy"), tr("Basic (Recommended)"),
|
||||
tr("Control the accuracy level of the GS blending unit emulation. "
|
||||
"The higher the setting, the more blending is emulated in the shader accurately, and the higher the speed penalty will be. "
|
||||
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"));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.texturePreloading, tr("Texture Preloading"), tr("Full (Hash Cache)"),
|
||||
@@ -442,15 +472,16 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
// Software
|
||||
dialog->registerWidgetHelp(m_ui.extraSWThreads, tr("Extra Rendering Threads"), tr("2 threads"),
|
||||
tr("Number of rendering threads: 0 for single thread, 2 or more for multithread (1 is for debugging). "
|
||||
"If you have 4 threads on your CPU pick 2 or 3. You can calculate how to get the best performance (amount of CPU threads - 2). "
|
||||
"If you have 4 threads on your CPU pick 2 or 3. You can calculate how to get the best performance (amount of CPU threads - "
|
||||
"2). "
|
||||
"7+ threads will not give much more performance and could perhaps even lower it."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.swAutoFlush, tr("Auto Flush"), tr("Checked"),
|
||||
tr("Force a primitive flush when a framebuffer is also an input texture. "
|
||||
"Fixes some processing effects such as the shadows in the Jak series and radiosity in GTA:SA."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.swMipmap, tr("Mipmapping"), tr("Checked"),
|
||||
tr("Enables mipmapping, which some games require to render correctly."));
|
||||
dialog->registerWidgetHelp(
|
||||
m_ui.swMipmap, tr("Mipmapping"), tr("Checked"), tr("Enables mipmapping, which some games require to render correctly."));
|
||||
}
|
||||
|
||||
// Hardware Fixes tab
|
||||
@@ -479,7 +510,8 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
dialog->registerWidgetHelp(m_ui.disableSafeFeatures, tr("Disable Safe Features"), tr("Unchecked"),
|
||||
tr("This option disables multiple safe features. "
|
||||
"Disables accurate Unscale Point and Line rendering which can help Xenosaga games. "
|
||||
"Disables accurate GS Memory Clearing to be done on the CPU, and let the GPU handle it, which can help Kingdom Hearts games."));
|
||||
"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"),
|
||||
tr("By default, the texture cache handles partial invalidations. Unfortunately it is very costly to compute CPU wise. "
|
||||
@@ -505,13 +537,16 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.roundSprite, tr("Round Sprite"), tr("Off (Default)"),
|
||||
tr("Corrects the sampling of 2D sprite textures when upscaling. "
|
||||
"Fixes lines in sprites of games like Ar tonelico when upscaling. Half option is for flat sprites, Full is for all sprites."));
|
||||
"Fixes lines in sprites of games like Ar tonelico when upscaling. Half option is for flat sprites, Full is for all "
|
||||
"sprites."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.textureOffsetX, tr("Texture Offsets X"), tr("0"),
|
||||
tr("Offset for the ST/UV texture coordinates. Fixes some odd texture issues and might fix some post processing alignment too."));
|
||||
tr("Offset for the ST/UV texture coordinates. Fixes some odd texture issues and might fix some post processing alignment "
|
||||
"too."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.textureOffsetY, tr("Texture Offsets Y"), tr("0"),
|
||||
tr("Offset for the ST/UV texture coordinates. Fixes some odd texture issues and might fix some post processing alignment too."));
|
||||
tr("Offset for the ST/UV texture coordinates. Fixes some odd texture issues and might fix some post processing alignment "
|
||||
"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."));
|
||||
@@ -545,10 +580,11 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
dialog->registerWidgetHelp(m_ui.casSharpness, tr("Sharpness"), tr("50%"), tr(""));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.shadeBoost, tr("Shade Boost"), tr("Unchecked"),
|
||||
tr("Enables saturation, contrast, and brightness to be adjusted. Values of brightness, saturation, and contrast are at default 50."));
|
||||
tr("Enables saturation, contrast, and brightness to be adjusted. Values of brightness, saturation, and contrast are at default "
|
||||
"50."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.fxaa, tr("FXAA"), tr("Unchecked"),
|
||||
tr("Applies the FXAA anti-aliasing algorithm to improve the visual quality of games."));
|
||||
dialog->registerWidgetHelp(
|
||||
m_ui.fxaa, tr("FXAA"), tr("Unchecked"), tr("Applies the FXAA anti-aliasing algorithm to improve the visual quality of games."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.shadeBoostBrightness, tr("Brightness"), tr("50"), tr(""));
|
||||
|
||||
@@ -561,7 +597,8 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
|
||||
// OSD tab
|
||||
{
|
||||
dialog->registerWidgetHelp(m_ui.osdScale, tr("OSD Scale"), tr("100%"), tr(""));
|
||||
dialog->registerWidgetHelp(
|
||||
m_ui.osdScale, tr("OSD Scale"), tr("100%"), tr("Scales the size of the onscreen OSD from 100% 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 "
|
||||
@@ -576,11 +613,9 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
dialog->registerWidgetHelp(m_ui.osdShowResolution, tr("Show Resolution"), tr("Unchecked"),
|
||||
tr("Shows the resolution of the game in the top-right corner of the display."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.osdShowCPU, tr("Show CPU Usage"), tr("Unchecked"),
|
||||
tr("Shows host's CPU utilization."));
|
||||
dialog->registerWidgetHelp(m_ui.osdShowCPU, tr("Show CPU Usage"), tr("Unchecked"), tr("Shows host's CPU utilization."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.osdShowGPU, tr("Show GPU Usage"), tr("Unchecked"),
|
||||
tr("Shows host's GPU utilization."));
|
||||
dialog->registerWidgetHelp(m_ui.osdShowGPU, tr("Show GPU Usage"), tr("Unchecked"), tr("Shows host's GPU utilization."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.osdShowGSStats, tr("Show Statistics"), tr("Unchecked"),
|
||||
tr("Shows counters for internal graphical utilization, useful for debugging."));
|
||||
@@ -588,14 +623,27 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
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."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.osdShowSettings, tr("Show Settings"), tr("Unchecked"), tr(""));
|
||||
dialog->registerWidgetHelp(m_ui.osdShowSettings, tr("Show Settings"), tr("Unchecked"),
|
||||
tr("Displays various settings and the current values of those settings, useful for debugging."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.osdShowInputs, tr("Show Inputs"), tr("Unchecked"), tr(""));
|
||||
dialog->registerWidgetHelp(m_ui.osdShowInputs, tr("Show Inputs"), tr("Unchecked"),
|
||||
tr("Shows the current controler state of the system in the bottom left corner of the display."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.osdShowFrameTimes, tr("Show Frame Times"), tr("Unchecked"), tr(""));
|
||||
dialog->registerWidgetHelp(
|
||||
m_ui.osdShowFrameTimes, tr("Show Frame Times"), tr("Unchecked"), tr("Displays a graph showing the average frametimes."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.warnAboutUnsafeSettings, tr("Warn About Unsafe Settings"),
|
||||
tr("Checked"), tr("Displays warnings when settings are enabled which may break games."));
|
||||
dialog->registerWidgetHelp(m_ui.warnAboutUnsafeSettings, tr("Warn About Unsafe Settings"), tr("Checked"),
|
||||
tr("Displays warnings when settings are enabled which may break games."));
|
||||
}
|
||||
|
||||
// Recording tab
|
||||
{
|
||||
dialog->registerWidgetHelp(m_ui.enableVideoCaptureArguments, tr("Enable Extra Arguments"), tr("Unchecked"), tr(""));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.videoCaptureArguments, tr("Extra Arguments"), tr("Leave It Blank"),
|
||||
tr("Parameters passed to selected video codec.<br> "
|
||||
"You must use '=' to separate key from value and ':' to separate two pairs from each other.<br> "
|
||||
"For example: \"crf = 21 : preset = veryfast\""));
|
||||
}
|
||||
|
||||
// Advanced tab
|
||||
@@ -620,8 +668,10 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
dialog->registerWidgetHelp(m_ui.disableFramebufferFetch, tr("Disable Frame Buffer 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 rendered, it just means "
|
||||
"the GPU has more time to complete it (this is NOT frame skipping). Can smooth our frame time fluctuations when the CPU/GPU are near maximum "
|
||||
tr("Detects when idle frames are being presented in 25/30fps games, and skips presenting those frames. The frame is still "
|
||||
"rendered, it just means "
|
||||
"the GPU has more time to complete it (this is NOT frame skipping). Can smooth our frame time fluctuations when the CPU/GPU "
|
||||
"are near maximum "
|
||||
"utilization, but makes frame pacing more inconsistent and can increase input lag."));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.threadedPresentation, tr("Disable Threaded Presentation"), tr("Unchecked"),
|
||||
@@ -700,9 +750,8 @@ void GraphicsSettingsWidget::onFullscreenModeChanged(int index)
|
||||
|
||||
void GraphicsSettingsWidget::onTrilinearFilteringChanged()
|
||||
{
|
||||
const bool forced_bilinear =
|
||||
(m_dialog->getEffectiveIntValue("EmuCore/GS", "TriFilter", static_cast<int>(TriFiltering::Automatic))
|
||||
>= static_cast<int>(TriFiltering::Forced));
|
||||
const bool forced_bilinear = (m_dialog->getEffectiveIntValue("EmuCore/GS", "TriFilter", static_cast<int>(TriFiltering::Automatic)) >=
|
||||
static_cast<int>(TriFiltering::Forced));
|
||||
m_ui.textureFiltering->setDisabled(forced_bilinear);
|
||||
}
|
||||
|
||||
@@ -714,16 +763,15 @@ void GraphicsSettingsWidget::onShadeBoostChanged()
|
||||
m_ui.shadeBoostSaturation->setEnabled(enabled);
|
||||
}
|
||||
|
||||
void GraphicsSettingsWidget::onVideoCaptureContainerChanged()
|
||||
void GraphicsSettingsWidget::onCaptureContainerChanged()
|
||||
{
|
||||
const std::string container(
|
||||
m_dialog->getEffectiveStringValue("EmuCore/GS", "VideoCaptureContainer", Pcsx2Config::GSOptions::DEFAULT_VIDEO_CAPTURE_CONTAINER));
|
||||
m_dialog->getEffectiveStringValue("EmuCore/GS", "CaptureContainer", Pcsx2Config::GSOptions::DEFAULT_CAPTURE_CONTAINER));
|
||||
|
||||
m_ui.videoCaptureCodec->disconnect();
|
||||
m_ui.videoCaptureCodec->clear();
|
||||
const std::vector<std::pair<std::string, std::string>> vcapture_formats(GSCapture::GetVideoCodecList(container.c_str()));
|
||||
m_ui.videoCaptureCodec->addItem(tr("Default"), QString());
|
||||
for (const auto& [format, name] : vcapture_formats)
|
||||
for (const auto& [format, name] : GSCapture::GetVideoCodecList(container.c_str()))
|
||||
{
|
||||
const QString qformat(QString::fromStdString(format));
|
||||
const QString qname(QString::fromStdString(name));
|
||||
@@ -732,6 +780,50 @@ void GraphicsSettingsWidget::onVideoCaptureContainerChanged()
|
||||
|
||||
SettingWidgetBinder::BindWidgetToStringSetting(
|
||||
m_dialog->getSettingsInterface(), m_ui.videoCaptureCodec, "EmuCore/GS", "VideoCaptureCodec");
|
||||
|
||||
m_ui.audioCaptureCodec->disconnect();
|
||||
m_ui.audioCaptureCodec->clear();
|
||||
m_ui.audioCaptureCodec->addItem(tr("Default"), QString());
|
||||
for (const auto& [format, name] : GSCapture::GetAudioCodecList(container.c_str()))
|
||||
{
|
||||
const QString qformat(QString::fromStdString(format));
|
||||
const QString qname(QString::fromStdString(name));
|
||||
m_ui.audioCaptureCodec->addItem(QStringLiteral("%1 [%2]").arg(qformat).arg(qname), qformat);
|
||||
}
|
||||
|
||||
SettingWidgetBinder::BindWidgetToStringSetting(
|
||||
m_dialog->getSettingsInterface(), m_ui.audioCaptureCodec, "EmuCore/GS", "AudioCaptureCodec");
|
||||
}
|
||||
|
||||
void GraphicsSettingsWidget::onEnableVideoCaptureChanged()
|
||||
{
|
||||
const bool enabled = m_dialog->getEffectiveBoolValue("EmuCore/GS", "EnableVideoCapture", true);
|
||||
m_ui.videoCaptureOptions->setEnabled(enabled);
|
||||
}
|
||||
|
||||
void GraphicsSettingsWidget::onEnableVideoCaptureArgumentsChanged()
|
||||
{
|
||||
const bool enabled = m_dialog->getEffectiveBoolValue("EmuCore/GS", "EnableVideoCaptureParameters", false);
|
||||
m_ui.videoCaptureArguments->setEnabled(enabled);
|
||||
}
|
||||
|
||||
void GraphicsSettingsWidget::onVideoCaptureAutoResolutionChanged()
|
||||
{
|
||||
const bool enabled = !m_dialog->getEffectiveBoolValue("EmuCore/GS", "VideoCaptureAutoResolution", true);
|
||||
m_ui.videoCaptureWidth->setEnabled(enabled);
|
||||
m_ui.videoCaptureHeight->setEnabled(enabled);
|
||||
}
|
||||
|
||||
void GraphicsSettingsWidget::onEnableAudioCaptureChanged()
|
||||
{
|
||||
const bool enabled = m_dialog->getEffectiveBoolValue("EmuCore/GS", "EnableAudioCapture", true);
|
||||
m_ui.audioCaptureOptions->setEnabled(enabled);
|
||||
}
|
||||
|
||||
void GraphicsSettingsWidget::onEnableAudioCaptureArgumentsChanged()
|
||||
{
|
||||
const bool enabled = m_dialog->getEffectiveBoolValue("EmuCore/GS", "EnableAudioCaptureParameters", false);
|
||||
m_ui.audioCaptureArguments->setEnabled(enabled);
|
||||
}
|
||||
|
||||
void GraphicsSettingsWidget::onGpuPaletteConversionChanged(int state)
|
||||
@@ -760,7 +852,8 @@ void GraphicsSettingsWidget::updateRendererDependentOptions()
|
||||
const bool is_sw_dx = false;
|
||||
#endif
|
||||
|
||||
const bool is_hardware = (type == GSRendererType::DX11 || type == GSRendererType::DX12 || type == GSRendererType::OGL || type == GSRendererType::VK || type == GSRendererType::Metal);
|
||||
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 int prev_tab = m_ui.tabs->currentIndex();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2022 PCSX2 Dev Team
|
||||
* Copyright (C) 2002-2023 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
@@ -43,7 +43,12 @@ private Q_SLOTS:
|
||||
void onGpuPaletteConversionChanged(int state);
|
||||
void onFullscreenModeChanged(int index);
|
||||
void onShadeBoostChanged();
|
||||
void onVideoCaptureContainerChanged();
|
||||
void onCaptureContainerChanged();
|
||||
void onEnableVideoCaptureChanged();
|
||||
void onEnableVideoCaptureArgumentsChanged();
|
||||
void onVideoCaptureAutoResolutionChanged();
|
||||
void onEnableAudioCaptureChanged();
|
||||
void onEnableAudioCaptureArgumentsChanged();
|
||||
|
||||
private:
|
||||
GSRendererType getEffectiveRenderer() const;
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>861</width>
|
||||
<height>501</height>
|
||||
<width>720</width>
|
||||
<height>466</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@@ -920,14 +920,14 @@
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_12">
|
||||
<property name="text">
|
||||
<string>Skipdraw Range:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<item row="4" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QSpinBox" name="skipDrawStart">
|
||||
@@ -945,7 +945,7 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="4" column="0" colspan="2">
|
||||
<item row="5" column="0" colspan="2">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="hwAutoFlush">
|
||||
@@ -1030,6 +1030,32 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_47">
|
||||
<property name="text">
|
||||
<string>GPU Target CLUT:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QComboBox" name="gpuTargetCLUTMode">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Disabled (Default)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Enabled (Exact Match)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Enabled (Check Inside Target)</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QGroupBox" name="upscalingFixesTab">
|
||||
@@ -1623,6 +1649,285 @@
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QGroupBox" name="recordingTab">
|
||||
<attribute name="title">
|
||||
<string>Recording</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="videoDumpDirectory">
|
||||
<property name="title">
|
||||
<string>Video Dumping Directory</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_7">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_8">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="videoDumpingDirectory"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="videoDumpingDirectoryBrowse">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="videoDumpingDirectoryOpen">
|
||||
<property name="text">
|
||||
<string>Open...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="videoDumpingDirectoryReset">
|
||||
<property name="text">
|
||||
<string>Reset</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>Capture Setup</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_3">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="captureContainerLabel">
|
||||
<property name="text">
|
||||
<string>Container:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="captureContainer"/>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<layout class="QGridLayout" name="gridLayout_10" columnstretch="1,1">
|
||||
<property name="horizontalSpacing">
|
||||
<number>20</number>
|
||||
</property>
|
||||
<property name="verticalSpacing">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<item row="1" column="1">
|
||||
<widget class="QWidget" name="audioCaptureOptions" native="true">
|
||||
<layout class="QFormLayout" name="formLayout_10">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="audioCaptureCodecLabel">
|
||||
<property name="text">
|
||||
<string>Codec:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="audioCaptureCodec"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="audioCaptureBitrateLabel">
|
||||
<property name="text">
|
||||
<string>Bitrate:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QSpinBox" name="audioCaptureBitrate">
|
||||
<property name="suffix">
|
||||
<string> kbps</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>16</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>2048</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="enableAudioCaptureArguments">
|
||||
<property name="text">
|
||||
<string>Extra Arguments</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="2">
|
||||
<widget class="QLineEdit" name="audioCaptureArguments"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="enableAudioCapture">
|
||||
<property name="text">
|
||||
<string>Capture Audio</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QWidget" name="videoCaptureOptions" native="true">
|
||||
<layout class="QFormLayout" name="formLayout_6">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="videoCaptureCodecLabel">
|
||||
<property name="text">
|
||||
<string>Codec:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="videoCaptureCodec"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="videoCaptureBitrateLabel">
|
||||
<property name="text">
|
||||
<string>Bitrate:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QSpinBox" name="videoCaptureBitrate">
|
||||
<property name="suffix">
|
||||
<string> kbps</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>100000</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>100</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="videoCaptureResolutionLabel">
|
||||
<property name="text">
|
||||
<string>Resolution:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_10" stretch="1,0,1,0">
|
||||
<item>
|
||||
<widget class="QSpinBox" name="videoCaptureWidth">
|
||||
<property name="minimum">
|
||||
<number>320</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>32768</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>16</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>640</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_46">
|
||||
<property name="text">
|
||||
<string>x</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="videoCaptureHeight">
|
||||
<property name="minimum">
|
||||
<number>240</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>32768</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>16</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>240</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="videoCaptureResolutionAuto">
|
||||
<property name="text">
|
||||
<string>Auto</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="enableVideoCaptureArguments">
|
||||
<property name="text">
|
||||
<string>Extra Arguments</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0" colspan="2">
|
||||
<widget class="QLineEdit" name="videoCaptureArguments"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="enableVideoCapture">
|
||||
<property name="text">
|
||||
<string>Capture Video</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_6">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QGroupBox" name="advancedTab">
|
||||
<attribute name="title">
|
||||
<string>Advanced</string>
|
||||
@@ -1716,46 +2021,6 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_45">
|
||||
<property name="text">
|
||||
<string>Video Capture Codec:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5" stretch="1,0,0,0">
|
||||
<item>
|
||||
<widget class="QComboBox" name="videoCaptureCodec"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="videoCaptureContainer"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_46">
|
||||
<property name="text">
|
||||
<string>Bitrate:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="videoCaptureBitrate">
|
||||
<property name="suffix">
|
||||
<string> kbps</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>100000</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>100</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
#include "QtHost.h"
|
||||
#include "QtUtils.h"
|
||||
#include "Settings/ControllerSettingWidgetBinder.h"
|
||||
#include "Settings/InputBindingDialog.h"
|
||||
#include "Settings/InputBindingWidget.h"
|
||||
#include <QtCore/QTimer>
|
||||
@@ -24,6 +25,8 @@
|
||||
#include <QtGui/QMouseEvent>
|
||||
#include <QtGui/QWheelEvent>
|
||||
|
||||
#include "fmt/format.h"
|
||||
|
||||
// _BitScanForward()
|
||||
#include "pcsx2/GS/GSIntrin.h"
|
||||
|
||||
@@ -45,6 +48,26 @@ InputBindingDialog::InputBindingDialog(SettingsInterface* sif, InputBindingInfo:
|
||||
connect(m_ui.clearBindings, &QPushButton::clicked, this, &InputBindingDialog::onClearBindingsButtonClicked);
|
||||
connect(m_ui.buttonBox, &QDialogButtonBox::rejected, [this]() { done(0); });
|
||||
updateList();
|
||||
|
||||
// Only show the sensitivity controls for binds where it's applicable.
|
||||
if (bind_type == InputBindingInfo::Type::Button || bind_type == InputBindingInfo::Type::Axis ||
|
||||
bind_type == InputBindingInfo::Type::HalfAxis)
|
||||
{
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileNormalized(
|
||||
sif, m_ui.sensitivity, m_section_name, fmt::format("{}Scale", m_key_name), 100.0f, 1.0f);
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileNormalized(
|
||||
sif, m_ui.deadzone, m_section_name, fmt::format("{}Deadzone", m_key_name), 100.0f, 0.0f);
|
||||
|
||||
connect(m_ui.sensitivity, &QSlider::valueChanged, this, &InputBindingDialog::onSensitivityChanged);
|
||||
connect(m_ui.deadzone, &QSlider::valueChanged, this, &InputBindingDialog::onDeadzoneChanged);
|
||||
|
||||
onSensitivityChanged(m_ui.sensitivity->value());
|
||||
onDeadzoneChanged(m_ui.deadzone->value());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ui.verticalLayout->removeWidget(m_ui.sensitivityWidget);
|
||||
}
|
||||
}
|
||||
|
||||
InputBindingDialog::~InputBindingDialog()
|
||||
@@ -109,7 +132,7 @@ bool InputBindingDialog::eventFilter(QObject* watched, QEvent* event)
|
||||
// if we've moved more than a decent distance from the center of the widget, bind it.
|
||||
// this is so we don't accidentally bind to the mouse if you bump it while reaching for your pad.
|
||||
static constexpr const s32 THRESHOLD = 50;
|
||||
const QPoint diff(static_cast<QMouseEvent*>(event)->globalPos() - m_input_listen_start_position);
|
||||
const QPoint diff(static_cast<QMouseEvent*>(event)->globalPosition().toPoint() - m_input_listen_start_position);
|
||||
bool has_one = false;
|
||||
|
||||
if (std::abs(diff.x()) >= THRESHOLD)
|
||||
@@ -318,6 +341,16 @@ void InputBindingDialog::inputManagerHookCallback(InputBindingKey key, float val
|
||||
}
|
||||
}
|
||||
|
||||
void InputBindingDialog::onSensitivityChanged(int value)
|
||||
{
|
||||
m_ui.sensitivityValue->setText(tr("%1%").arg(value));
|
||||
}
|
||||
|
||||
void InputBindingDialog::onDeadzoneChanged(int value)
|
||||
{
|
||||
m_ui.deadzoneValue->setText(tr("%1%").arg(value));
|
||||
}
|
||||
|
||||
void InputBindingDialog::hookInputManager()
|
||||
{
|
||||
InputManager::SetHook([this](InputBindingKey key, float value) {
|
||||
|
||||
@@ -41,6 +41,9 @@ protected Q_SLOTS:
|
||||
void onInputListenTimerTimeout();
|
||||
void inputManagerHookCallback(InputBindingKey key, float value);
|
||||
|
||||
void onSensitivityChanged(int value);
|
||||
void onDeadzoneChanged(int value);
|
||||
|
||||
protected:
|
||||
enum : u32
|
||||
{
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>533</width>
|
||||
<height>283</height>
|
||||
<height>266</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@@ -30,6 +30,93 @@
|
||||
<item>
|
||||
<widget class="QListWidget" name="bindingList"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="sensitivityWidget" native="true">
|
||||
<layout class="QGridLayout" name="sensitivityLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="sensitivityLabel">
|
||||
<property name="text">
|
||||
<string>Sensitivity:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QSlider" name="sensitivity">
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>200</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 row="0" column="2">
|
||||
<widget class="QLabel" name="sensitivityValue">
|
||||
<property name="text">
|
||||
<string>100%</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="deadzoneLabel">
|
||||
<property name="text">
|
||||
<string>Deadzone:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QSlider" name="deadzone">
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="tickPosition">
|
||||
<enum>QSlider::TicksBelow</enum>
|
||||
</property>
|
||||
<property name="tickInterval">
|
||||
<number>5</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QLabel" name="deadzoneValue">
|
||||
<property name="text">
|
||||
<string>100%</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="status">
|
||||
<property name="text">
|
||||
|
||||
@@ -166,7 +166,7 @@ bool InputBindingWidget::eventFilter(QObject* watched, QEvent* event)
|
||||
// if we've moved more than a decent distance from the center of the widget, bind it.
|
||||
// this is so we don't accidentally bind to the mouse if you bump it while reaching for your pad.
|
||||
static constexpr const s32 THRESHOLD = 50;
|
||||
const QPoint diff(static_cast<QMouseEvent*>(event)->globalPos() - m_input_listen_start_position);
|
||||
const QPoint diff(static_cast<QMouseEvent*>(event)->globalPosition().toPoint() - m_input_listen_start_position);
|
||||
bool has_one = false;
|
||||
|
||||
if (std::abs(diff.x()) >= THRESHOLD)
|
||||
|
||||
@@ -98,7 +98,7 @@ InterfaceSettingsWidget::InterfaceSettingsWidget(SettingsDialog* dialog, QWidget
|
||||
AutoUpdaterDialog::getDefaultTag());
|
||||
|
||||
m_ui.autoUpdateCurrentVersion->setText(tr("%1 (%2)").arg(AutoUpdaterDialog::getCurrentVersion()).arg(AutoUpdaterDialog::getCurrentVersionDate()));
|
||||
connect(m_ui.checkForUpdates, &QPushButton::clicked, this, []() { g_main_window->checkForUpdates(true); });
|
||||
connect(m_ui.checkForUpdates, &QPushButton::clicked, this, []() { g_main_window->checkForUpdates(true, true); });
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -191,7 +191,7 @@ void SettingsDialog::setupUi(const GameList::Entry* game)
|
||||
m_ui.settingsContainer->setCurrentIndex(0);
|
||||
m_ui.helpText->setText(m_category_help_text[0]);
|
||||
connect(m_ui.settingsCategory, &QListWidget::currentRowChanged, this, &SettingsDialog::onCategoryCurrentRowChanged);
|
||||
connect(m_ui.closeButton, &QPushButton::clicked, this, &SettingsDialog::accept);
|
||||
connect(m_ui.closeButton, &QPushButton::clicked, this, &SettingsDialog::close);
|
||||
connect(m_ui.restoreDefaultsButton, &QPushButton::clicked, this, &SettingsDialog::onRestoreDefaultsClicked);
|
||||
}
|
||||
|
||||
|
||||
8476
pcsx2-qt/Translations/pcsx2-qt_en.ts
Normal file
8476
pcsx2-qt/Translations/pcsx2-qt_en.ts
Normal file
File diff suppressed because it is too large
Load Diff
@@ -46,6 +46,7 @@
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\lzma\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\demangler\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\rapidyaml\rapidyaml\ext\c4core\src\c4\ext\fast_float\include;%(AdditionalIncludeDirectories);</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)3rdparty\sdl2\include;$(SolutionDir)3rdparty\sdl2\SDL\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir);$(SolutionDir)pcsx2;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<!-- Needed for moc pch -->
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(ProjectDir)\Settings;$(ProjectDir)\GameList;$(ProjectDir)\Tools\InputRecording;$(ProjectDir)\Debugger;$(ProjectDir)\Debugger\Models</AdditionalIncludeDirectories>
|
||||
@@ -70,6 +71,8 @@
|
||||
<FloatingPointModel>Precise</FloatingPointModel>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<!-- Current Qt debug builds assert on RTTI. Remove this once we next build Qt. -->
|
||||
<RuntimeTypeInfo Condition="$(Configuration.Contains(Clang)) And $(Configuration.Contains(Debug))">true</RuntimeTypeInfo>
|
||||
<AdditionalOptions>/Zc:__cplusplus /Zo /utf-8%(AdditionalOptions)</AdditionalOptions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
@@ -135,6 +138,7 @@
|
||||
<Manifest Include="..\pcsx2\windows\PCSX2.manifest" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="ColorPickerButton.cpp" />
|
||||
<ClCompile Include="EarlyHardwareCheck.cpp" />
|
||||
<ClCompile Include="QtProgressCallback.cpp" />
|
||||
<ClCompile Include="Settings\DebugSettingsWidget.cpp" />
|
||||
@@ -211,6 +215,7 @@
|
||||
<QtMoc Include="Settings\DEV9SettingsWidget.h" />
|
||||
<QtMoc Include="Settings\DEV9UiCommon.h" />
|
||||
<QtMoc Include="QtProgressCallback.h" />
|
||||
<QtMoc Include="ColorPickerButton.h" />
|
||||
<ClInclude Include="Settings\ControllerSettingWidgetBinder.h" />
|
||||
<QtMoc Include="Settings\FolderSettingsWidget.h" />
|
||||
<QtMoc Include="Settings\DebugSettingsWidget.h" />
|
||||
@@ -292,6 +297,7 @@
|
||||
<ClCompile Include="$(IntDir)GameList\moc_GameListWidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_AboutDialog.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_AutoUpdaterDialog.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_ColorPickerButton.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_CoverDownloadDialog.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_DisplayWidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_MainWindow.cpp" />
|
||||
@@ -414,6 +420,9 @@
|
||||
<QtUi Include="Settings\DebugSettingsWidget.ui">
|
||||
<FileType>Document</FileType>
|
||||
</QtUi>
|
||||
<QtUi Include="Settings\ControllerLEDSettingsDialog.ui">
|
||||
<FileType>Document</FileType>
|
||||
</QtUi>
|
||||
<None Include="Settings\USBBindingWidget_DrivingForce.ui" />
|
||||
<None Include="Settings\USBBindingWidget_GTForce.ui" />
|
||||
<QtUi Include="Settings\USBDeviceWidget.ui">
|
||||
@@ -430,4 +439,4 @@
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<Import Project="$(SolutionDir)common\vsprops\QtCompile.targets" />
|
||||
<ImportGroup Label="ExtensionTargets" />
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
@@ -27,9 +27,7 @@
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="..\pcsx2\PCSX2.rc">
|
||||
<Filter>Resources</Filter>
|
||||
</ResourceCompile>
|
||||
<ResourceCompile Include="..\pcsx2\windows\PCSX2.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="PrecompiledHeader.cpp" />
|
||||
@@ -313,6 +311,10 @@
|
||||
<ClCompile Include="$(IntDir)Debugger\Models\moc_StackModel.cpp">
|
||||
<Filter>moc</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ColorPickerButton.cpp" />
|
||||
<ClCompile Include="$(IntDir)moc_ColorPickerButton.cpp">
|
||||
<Filter>moc</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Manifest Include="..\pcsx2\windows\PCSX2.manifest">
|
||||
@@ -459,6 +461,7 @@
|
||||
<QtMoc Include="Debugger\Models\StackModel.h">
|
||||
<Filter>Debugger\Models</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="ColorPickerButton.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtResource Include="resources\resources.qrc">
|
||||
@@ -577,6 +580,9 @@
|
||||
<QtUi Include="Debugger\BreakpointDialog.ui">
|
||||
<Filter>Debugger</Filter>
|
||||
</QtUi>
|
||||
<QtUi Include="Settings\ControllerLEDSettingsDialog.ui">
|
||||
<Filter>Settings</Filter>
|
||||
</QtUi>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Settings\FolderSettingsWidget.ui">
|
||||
|
||||
1
pcsx2-qt/resources/icons/black/svg/lightbulb-line.svg
Normal file
1
pcsx2-qt/resources/icons/black/svg/lightbulb-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="M9.973 18H11v-5h2v5h1.027c.132-1.202.745-2.194 1.74-3.277.113-.122.832-.867.917-.973a6 6 0 1 0-9.37-.002c.086.107.807.853.918.974.996 1.084 1.609 2.076 1.741 3.278zM10 20v1h4v-1h-4zm-4.246-5a8 8 0 1 1 12.49.002C17.624 15.774 16 17 16 18.5V21a2 2 0 0 1-2 2h-4a2 2 0 0 1-2-2v-2.5C8 17 6.375 15.774 5.754 15z" fill="#000000"/></svg>
|
||||
|
After Width: | Height: | Size: 458 B |
1
pcsx2-qt/resources/icons/white/svg/lightbulb-line.svg
Normal file
1
pcsx2-qt/resources/icons/white/svg/lightbulb-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="M9.973 18H11v-5h2v5h1.027c.132-1.202.745-2.194 1.74-3.277.113-.122.832-.867.917-.973a6 6 0 1 0-9.37-.002c.086.107.807.853.918.974.996 1.084 1.609 2.076 1.741 3.278zM10 20v1h4v-1h-4zm-4.246-5a8 8 0 1 1 12.49.002C17.624 15.774 16 17 16 18.5V21a2 2 0 0 1-2 2h-4a2 2 0 0 1-2-2v-2.5C8 17 6.375 15.774 5.754 15z" fill="#ffffff"/></svg>
|
||||
|
After Width: | Height: | Size: 458 B |
@@ -37,6 +37,7 @@
|
||||
<file>icons/black/svg/image-fill.svg</file>
|
||||
<file>icons/black/svg/keyboard-line.svg</file>
|
||||
<file>icons/black/svg/layout-grid-line.svg</file>
|
||||
<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/pause-line.svg</file>
|
||||
@@ -96,6 +97,7 @@
|
||||
<file>icons/white/svg/image-fill.svg</file>
|
||||
<file>icons/white/svg/keyboard-line.svg</file>
|
||||
<file>icons/white/svg/layout-grid-line.svg</file>
|
||||
<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/pause-line.svg</file>
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
#include "Elfheader.h"
|
||||
#include "ps2/BiosTools.h"
|
||||
#include "Recording/InputRecording.h"
|
||||
#include "VMManager.h"
|
||||
#include "Host.h"
|
||||
|
||||
// This typically reflects the Sony-assigned serial code for the Disc, if one exists.
|
||||
// (examples: SLUS-2113, etc).
|
||||
@@ -2440,8 +2440,8 @@ static void cdvdWrite16(u8 rt) // SCOMMAND
|
||||
|
||||
|
||||
case 0x0F: // sceCdPowerOff (0:1)- Call74 from Xcdvdman
|
||||
Console.WriteLn(Color_StrongBlack, "sceCdPowerOff called. Resetting VM.");
|
||||
VMManager::Reset();
|
||||
Console.WriteLn(Color_StrongBlack, "sceCdPowerOff called. Shutting down VM.");
|
||||
Host::RequestVMShutdown(false, false, false);
|
||||
break;
|
||||
|
||||
case 0x12: // sceCdReadILinkId (0:9)
|
||||
|
||||
@@ -430,9 +430,7 @@ bool DoCDVDopen()
|
||||
|
||||
Host::AddKeyedOSDMessage("BlockDumpCreate", fmt::format("Saving CDVD block dump to '{}'.", temp), Host::OSD_INFO_DURATION);
|
||||
|
||||
blockDumpFile.Create(std::move(temp), 2);
|
||||
|
||||
if (blockDumpFile.IsOpened())
|
||||
if (blockDumpFile.Create(std::move(temp), 2))
|
||||
{
|
||||
int blockofs = 0;
|
||||
uint blocksize = CD_FRAMESIZE_RAW;
|
||||
|
||||
@@ -51,15 +51,8 @@ s32 CALLBACK ISOopen(const char* pTitle)
|
||||
return -1;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
iso.Open(pTitle);
|
||||
}
|
||||
catch (BaseException& ex)
|
||||
{
|
||||
Console.Error(ex.FormatDiagnosticMessage());
|
||||
if (!iso.Open(pTitle))
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (iso.GetType())
|
||||
{
|
||||
|
||||
115
pcsx2/CDVD/Darwin/DriveUtility.cpp
Normal file
115
pcsx2/CDVD/Darwin/DriveUtility.cpp
Normal file
@@ -0,0 +1,115 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2022 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 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 PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "CDVD/CDVDdiscReader.h"
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
|
||||
#include <IOKit/storage/IOMedia.h>
|
||||
#include <IOKit/storage/IOCDMedia.h>
|
||||
#include <IOKit/storage/IODVDMedia.h>
|
||||
#include <IOKit/IOBSD.h>
|
||||
#include <IOKit/IOKitLib.h>
|
||||
#endif
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
std::vector<std::string> GetDriveListFromClasses(CFMutableDictionaryRef classes)
|
||||
{
|
||||
io_iterator_t iterator = IO_OBJECT_NULL;
|
||||
kern_return_t result;
|
||||
std::vector<std::string> drives;
|
||||
|
||||
CFDictionarySetValue(classes, CFSTR(kIOMediaEjectableKey), kCFBooleanTrue);
|
||||
result = IOServiceGetMatchingServices(kIOMasterPortDefault, classes, &iterator);
|
||||
if (result != KERN_SUCCESS)
|
||||
return drives;
|
||||
while (io_object_t media = IOIteratorNext(iterator))
|
||||
{
|
||||
CFTypeRef path_cfstr = IORegistryEntryCreateCFProperty(media, CFSTR(kIOBSDNameKey), kCFAllocatorDefault, 0);
|
||||
if (path_cfstr)
|
||||
{
|
||||
char path[PATH_MAX] = {0};
|
||||
strlcpy(path, "/dev/r", PATH_MAX);
|
||||
size_t path_prefix_len = strnlen(path, PATH_MAX);
|
||||
result = CFStringGetCString((CFStringRef)path_cfstr, path + path_prefix_len, PATH_MAX - path_prefix_len, kCFStringEncodingUTF8);
|
||||
if (result)
|
||||
{
|
||||
drives.emplace_back(path);
|
||||
}
|
||||
CFRelease(path_cfstr);
|
||||
}
|
||||
IOObjectRelease(media);
|
||||
}
|
||||
IOObjectRelease(iterator);
|
||||
return drives;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
std::vector<std::string> GetOpticalDriveList()
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
std::vector<std::string> drives;
|
||||
|
||||
if (CFMutableDictionaryRef cd_classes = IOServiceMatching(kIOCDMediaClass))
|
||||
{
|
||||
std::vector<std::string> cd = GetDriveListFromClasses(cd_classes);
|
||||
drives.insert(drives.end(), cd.begin(), cd.end());
|
||||
}
|
||||
|
||||
if (CFMutableDictionaryRef dvd_classes = IOServiceMatching(kIODVDMediaClass))
|
||||
{
|
||||
std::vector<std::string> dvd = GetDriveListFromClasses(dvd_classes);
|
||||
drives.insert(drives.end(), dvd.begin(), dvd.end());
|
||||
}
|
||||
return drives;
|
||||
#else
|
||||
return {};
|
||||
#endif
|
||||
}
|
||||
|
||||
void GetValidDrive(std::string& drive)
|
||||
{
|
||||
if (!drive.empty())
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
int fd = open(drive.c_str(), O_RDONLY | O_NONBLOCK);
|
||||
if (fd != -1)
|
||||
{
|
||||
close(fd);
|
||||
}
|
||||
else
|
||||
{
|
||||
drive.clear();
|
||||
}
|
||||
#else
|
||||
drive.clear();
|
||||
#endif
|
||||
}
|
||||
if (drive.empty())
|
||||
{
|
||||
auto drives = GetOpticalDriveList();
|
||||
if (!drives.empty())
|
||||
drive = drives.front();
|
||||
}
|
||||
if (!drive.empty())
|
||||
DevCon.WriteLn("CDVD: Opening drive '%s'...", drive.c_str());
|
||||
}
|
||||
263
pcsx2/CDVD/Darwin/IOCtlSrc.cpp
Normal file
263
pcsx2/CDVD/Darwin/IOCtlSrc.cpp
Normal file
@@ -0,0 +1,263 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2022 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 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 PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "CDVD/CDVDdiscReader.h"
|
||||
#include "CDVD/CDVD.h"
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <IOKit/storage/IOCDMediaBSDClient.h>
|
||||
#include <IOKit/storage/IODVDMediaBSDClient.h>
|
||||
#endif
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
|
||||
IOCtlSrc::IOCtlSrc(decltype(m_filename) filename)
|
||||
: m_filename(filename)
|
||||
{
|
||||
if (!Reopen())
|
||||
throw std::runtime_error(" * CDVD: Error opening source.\n");
|
||||
}
|
||||
|
||||
IOCtlSrc::~IOCtlSrc()
|
||||
{
|
||||
if (m_device != -1)
|
||||
{
|
||||
SetSpindleSpeed(true);
|
||||
close(m_device);
|
||||
}
|
||||
}
|
||||
|
||||
bool IOCtlSrc::Reopen()
|
||||
{
|
||||
if (m_device != -1)
|
||||
close(m_device);
|
||||
|
||||
// O_NONBLOCK allows a valid file descriptor to be returned even if the
|
||||
// drive is empty. Probably does other things too.
|
||||
m_device = open(m_filename.c_str(), O_RDONLY | O_NONBLOCK);
|
||||
if (m_device == -1)
|
||||
return false;
|
||||
|
||||
// DVD detection MUST be first on Linux - The TOC ioctls work for both
|
||||
// CDs and DVDs.
|
||||
if (ReadDVDInfo() || ReadCDInfo())
|
||||
SetSpindleSpeed(false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void IOCtlSrc::SetSpindleSpeed(bool restore_defaults) const
|
||||
{
|
||||
u16 speed = restore_defaults ? 0xFFFF : m_media_type >= 0 ? 5540 :
|
||||
3600;
|
||||
int ioctl_code = m_media_type >= 0 ? DKIOCDVDSETSPEED : DKIOCCDSETSPEED;
|
||||
if (ioctl(m_device, ioctl_code, &speed) == -1)
|
||||
{
|
||||
DevCon.Warning("CDVD: Failed to set spindle speed: %s", strerror(errno));
|
||||
}
|
||||
else if (!restore_defaults)
|
||||
{
|
||||
DevCon.WriteLn("CDVD: Spindle speed set to %d", speed);
|
||||
}
|
||||
}
|
||||
|
||||
u32 IOCtlSrc::GetSectorCount() const
|
||||
{
|
||||
return m_sectors;
|
||||
}
|
||||
|
||||
u32 IOCtlSrc::GetLayerBreakAddress() const
|
||||
{
|
||||
return m_layer_break;
|
||||
}
|
||||
|
||||
s32 IOCtlSrc::GetMediaType() const
|
||||
{
|
||||
return m_media_type;
|
||||
}
|
||||
|
||||
const std::vector<toc_entry>& IOCtlSrc::ReadTOC() const
|
||||
{
|
||||
return m_toc;
|
||||
}
|
||||
|
||||
bool IOCtlSrc::ReadSectors2048(u32 sector, u32 count, u8* buffer) const
|
||||
{
|
||||
const ssize_t bytes_to_read = 2048 * count;
|
||||
ssize_t bytes_read = pread(m_device, buffer, bytes_to_read, sector * 2048ULL);
|
||||
if (bytes_read == bytes_to_read)
|
||||
return true;
|
||||
|
||||
if (bytes_read == -1)
|
||||
DevCon.Warning("CDVD: read sectors %u-%u failed: %s",
|
||||
sector, sector + count - 1, strerror(errno));
|
||||
else
|
||||
DevCon.Warning("CDVD: read sectors %u-%u: %zd bytes read, %zd bytes expected",
|
||||
sector, sector + count - 1, bytes_read, bytes_to_read);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IOCtlSrc::ReadSectors2352(u32 sector, u32 count, u8* buffer) const
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
dk_cd_read_t desc;
|
||||
memset(&desc, 0, sizeof(dk_cd_read_t));
|
||||
desc.sectorArea = kCDSectorAreaSync | kCDSectorAreaHeader | kCDSectorAreaSubHeader | kCDSectorAreaUser | kCDSectorAreaAuxiliary;
|
||||
desc.sectorType = kCDSectorTypeUnknown;
|
||||
for (u32 i = 0; i < count; ++i)
|
||||
{
|
||||
desc.offset = (sector + i) * 2352ULL;
|
||||
desc.buffer = buffer + i * 2352;
|
||||
desc.bufferLength = 2352;
|
||||
if (ioctl(m_device, DKIOCCDREAD, &desc) == -1)
|
||||
{
|
||||
DevCon.Warning("CDVD: DKIOCCDREAD sector %u failed: %s",
|
||||
sector + i, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool IOCtlSrc::ReadDVDInfo()
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
dk_dvd_read_structure_t dvdrs;
|
||||
memset(&dvdrs, 0, sizeof(dk_dvd_read_structure_t));
|
||||
dvdrs.format = kDVDStructureFormatPhysicalFormatInfo;
|
||||
dvdrs.layer = 0;
|
||||
|
||||
DVDPhysicalFormatInfo layer0;
|
||||
dvdrs.buffer = &layer0;
|
||||
dvdrs.bufferLength = sizeof(DVDPhysicalFormatInfo);
|
||||
|
||||
int ret = ioctl(m_device, DKIOCDVDREADSTRUCTURE, &dvdrs);
|
||||
if (ret == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
u32 start_sector = *(u32*)layer0.startingPhysicalSectorNumberOfDataArea;
|
||||
u32 end_sector = *(u32*)layer0.endPhysicalSectorNumberOfDataArea;
|
||||
if (layer0.numberOfLayers == 0)
|
||||
{
|
||||
// Single layer
|
||||
m_media_type = 0;
|
||||
m_layer_break = 0;
|
||||
m_sectors = end_sector - start_sector + 1;
|
||||
}
|
||||
else if (layer0.trackPath == 0)
|
||||
{
|
||||
// Dual layer, Parallel Track Path
|
||||
DVDPhysicalFormatInfo layer1;
|
||||
dvdrs.layer = 1;
|
||||
dvdrs.buffer = &layer1;
|
||||
dvdrs.bufferLength = sizeof(DVDPhysicalFormatInfo);
|
||||
ret = ioctl(m_device, DKIOCDVDREADSTRUCTURE, &dvdrs);
|
||||
if (ret == -1)
|
||||
return false;
|
||||
u32 layer1_start_sector = *(u32*)layer1.startingPhysicalSectorNumberOfDataArea;
|
||||
u32 layer1_end_sector = *(u32*)layer1.endPhysicalSectorNumberOfDataArea;
|
||||
|
||||
m_media_type = 1;
|
||||
m_layer_break = end_sector - start_sector;
|
||||
m_sectors = end_sector - start_sector + 1 + layer1_end_sector - layer1_start_sector + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Dual layer, Opposite Track Path
|
||||
u32 end_sector_layer0 = *(u32*)layer0.endSectorNumberInLayerZero;
|
||||
m_media_type = 2;
|
||||
m_layer_break = end_sector_layer0 - start_sector;
|
||||
m_sectors = end_sector_layer0 - start_sector + 1 + end_sector - (~end_sector_layer0 & 0xFFFFFFU) + 1;
|
||||
}
|
||||
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool IOCtlSrc::ReadCDInfo()
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
u8* buffer = (u8*)malloc(2048);
|
||||
dk_cd_read_toc_t cdrt;
|
||||
memset(&cdrt, 0, sizeof(dk_cd_read_toc_t));
|
||||
cdrt.format = kCDTOCFormatTOC;
|
||||
cdrt.formatAsTime = 1;
|
||||
cdrt.address.track = 0;
|
||||
cdrt.buffer = buffer;
|
||||
cdrt.bufferLength = 2048;
|
||||
memset(buffer, 0, 2048);
|
||||
|
||||
if (ioctl(m_device, DKIOCCDREADTOC, &cdrt) == -1)
|
||||
{
|
||||
DevCon.Warning("CDVD: DKIOCCDREADTOC failed: %s\n", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
CDTOC* toc = (CDTOC*)buffer;
|
||||
|
||||
u32 desc_count = CDTOCGetDescriptorCount(toc);
|
||||
|
||||
for (u32 i = 0; i < desc_count; ++i)
|
||||
{
|
||||
CDTOCDescriptor desc = toc->descriptors[i];
|
||||
if (desc.point < 0xa0 && desc.adr == 1)
|
||||
{
|
||||
u32 lba = CDConvertMSFToLBA(desc.p);
|
||||
m_toc.push_back({lba, desc.point, desc.adr, desc.control});
|
||||
}
|
||||
else if (desc.point == 0xa2) // lead out, use to get total sector count
|
||||
{
|
||||
m_sectors = CDConvertMSFToLBA(desc.p);
|
||||
}
|
||||
}
|
||||
|
||||
m_media_type = -1;
|
||||
|
||||
free(buffer);
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool IOCtlSrc::DiscReady()
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
if (m_device == -1)
|
||||
return false;
|
||||
|
||||
if (!m_sectors)
|
||||
{
|
||||
Reopen();
|
||||
}
|
||||
|
||||
return !!m_sectors;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
@@ -293,7 +293,7 @@ bool GzippedFileReader::OkIndex()
|
||||
Console.Warning("This may take a while (but only once). Scanning compressed file to generate a quick access index...");
|
||||
|
||||
const s64 prevoffset = FileSystem::FTell64(m_src);
|
||||
Access* index;
|
||||
Access* index = nullptr;
|
||||
int len = build_index(m_src, GZFILE_SPAN_DEFAULT, &index);
|
||||
printf("\n"); // build_index prints progress without \n's
|
||||
FileSystem::FSeek64(m_src, prevoffset, SEEK_SET);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user