mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-07-31 11:18:41 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
140fc28b3e | ||
|
|
f9833bb8af | ||
|
|
4b6ddaf09e | ||
|
|
d427db4a15 | ||
|
|
deb39cc20f | ||
|
|
3a4c25e916 | ||
|
|
f416eb3d4f | ||
|
|
87cbb1f90c | ||
|
|
68f43121fb | ||
|
|
51ceab1f3c | ||
|
|
2257992a3f | ||
|
|
40ead584d7 | ||
|
|
6f2be7bd17 | ||
|
|
af9ca4cf7d | ||
|
|
ea98203ac5 | ||
|
|
e908bbfae6 | ||
|
|
fa00069068 | ||
|
|
efae58de52 | ||
|
|
39c7f703cb | ||
|
|
96220e509c | ||
|
|
4de495ad59 | ||
|
|
56a950a074 | ||
|
|
2b47254bdd | ||
|
|
da28e2cc37 | ||
|
|
3d64f4a548 | ||
|
|
abf03b0c79 | ||
|
|
8381742422 | ||
|
|
724bb09aec | ||
|
|
ad5de248b4 | ||
|
|
1a1fdf6a5a | ||
|
|
c469b17350 | ||
|
|
01842a3c6b | ||
|
|
4cd385dbff | ||
|
|
72787d103f | ||
|
|
59072272a9 | ||
|
|
ef76666e5a | ||
|
|
0a0994b19c | ||
|
|
ab68c570a9 | ||
|
|
dcdf3b39a3 | ||
|
|
476cb2db34 | ||
|
|
34a7e00413 | ||
|
|
413ba09ee0 | ||
|
|
33eefefffb | ||
|
|
b3c822e31b | ||
|
|
14a458a275 | ||
|
|
6c49f9cf52 | ||
|
|
803ea4dda5 | ||
|
|
c9b23e6e4e | ||
|
|
509c9318af | ||
|
|
46e1e3d904 | ||
|
|
7a045d837b | ||
|
|
574ea820f7 | ||
|
|
7061d48dde | ||
|
|
53633b7279 | ||
|
|
05bb126af9 | ||
|
|
436fba77ac | ||
|
|
91c0e64159 | ||
|
|
7207681485 | ||
|
|
eef53f1b54 | ||
|
|
150d8d3214 | ||
|
|
a14376abb6 | ||
|
|
dfb45a8ebc | ||
|
|
00137c3031 | ||
|
|
b9c7dacbd1 | ||
|
|
3a03b579d2 | ||
|
|
e2bbe5cd8b | ||
|
|
c7347a3a16 | ||
|
|
8749b3c782 | ||
|
|
10389dc3f1 | ||
|
|
5e191a6cd8 | ||
|
|
a247625095 | ||
|
|
0fb234f3e4 | ||
|
|
e3e35d3bc6 | ||
|
|
6b12ca5b39 | ||
|
|
44e2837efb | ||
|
|
27dcd1bba2 | ||
|
|
ebf8cba6a4 | ||
|
|
e06cf23a03 | ||
|
|
dd55887f4b | ||
|
|
39b7b29af8 | ||
|
|
6f0aef3344 | ||
|
|
85c3a413fa | ||
|
|
b6c365b89d | ||
|
|
9eedf3901a | ||
|
|
2a6ecaeb09 | ||
|
|
027db2480a | ||
|
|
f4cabca62d | ||
|
|
0b3edc5fd4 | ||
|
|
b05152da0f | ||
|
|
2e0988ff03 | ||
|
|
ec12d9b657 | ||
|
|
f388de26ab | ||
|
|
68df8bf8ea | ||
|
|
4a960bba5e | ||
|
|
3a72b3fe3f | ||
|
|
47f372f215 | ||
|
|
7dc93bee7e | ||
|
|
69ff64149a | ||
|
|
4795f0a7dd | ||
|
|
e9411a3db5 | ||
|
|
6a064a4fa5 | ||
|
|
f036cdaaad | ||
|
|
46a68e2118 | ||
|
|
d020ea8f63 | ||
|
|
a4b40ab9e1 | ||
|
|
7c62b86ed9 | ||
|
|
96fb49e35c | ||
|
|
8e5fc236ca | ||
|
|
0784b5930b | ||
|
|
6de792c465 | ||
|
|
e9a2c89930 | ||
|
|
9d9f3acbe6 | ||
|
|
b67126e917 | ||
|
|
bcbf390334 | ||
|
|
714e355c87 | ||
|
|
f258ea2906 | ||
|
|
9445018586 | ||
|
|
97310b8912 | ||
|
|
47073040d4 | ||
|
|
a93663af0b | ||
|
|
ecd3b87cc0 | ||
|
|
5c34f208bd | ||
|
|
47f8d8c71c | ||
|
|
b2a0dba3bb | ||
|
|
fc1304dff5 | ||
|
|
0e15de7103 | ||
|
|
182375314e | ||
|
|
69ac4ddedc | ||
|
|
68b31347f4 | ||
|
|
6be2d1cbc0 | ||
|
|
5fac15c449 | ||
|
|
ecb86b01c8 | ||
|
|
1744a6ffeb | ||
|
|
fb393c22b6 | ||
|
|
fe2ed74020 | ||
|
|
5f51050b2f | ||
|
|
913253d861 | ||
|
|
8172b2e5ed | ||
|
|
0a7fc06510 | ||
|
|
a81b20d9d5 | ||
|
|
90a09eb520 | ||
|
|
4ffbe0bbf9 | ||
|
|
8f991c311f | ||
|
|
367f839934 | ||
|
|
6c15359137 | ||
|
|
fa05d656ad | ||
|
|
76e32f55de | ||
|
|
30ca79a23a | ||
|
|
0ce6961972 | ||
|
|
b0ae2caef8 | ||
|
|
3eb4a64517 | ||
|
|
61a80b59d1 | ||
|
|
71eaef35e3 | ||
|
|
b7ae453d84 | ||
|
|
33958fed96 | ||
|
|
59d29b3648 | ||
|
|
911d7f6533 | ||
|
|
9d49015c0c | ||
|
|
d585712b40 | ||
|
|
fb15893521 | ||
|
|
308f8c5112 | ||
|
|
86edc0dbe2 | ||
|
|
f461bc9176 | ||
|
|
b121e5af25 | ||
|
|
d292835941 | ||
|
|
88aee00a02 | ||
|
|
2fa806bbee | ||
|
|
ae3faa1540 | ||
|
|
e1e9c428f1 | ||
|
|
443ca9da56 | ||
|
|
ef05da1860 | ||
|
|
e5a87c7463 | ||
|
|
da2f419b86 | ||
|
|
4586a12859 | ||
|
|
9c416bdbc1 | ||
|
|
f43255a1fb | ||
|
|
59949c50d3 | ||
|
|
4608579c31 |
@@ -6,3 +6,7 @@ updates:
|
||||
schedule:
|
||||
# Check for updates to GitHub Actions every week
|
||||
interval: "weekly"
|
||||
groups:
|
||||
ci-deps:
|
||||
patterns:
|
||||
- "*"
|
||||
|
||||
+147
-87
@@ -2,127 +2,187 @@
|
||||
|
||||
# General Labels
|
||||
'Build | Project System':
|
||||
- '.github/*'
|
||||
- '.github/**/*'
|
||||
- '*.sln'
|
||||
- '**/*.sln'
|
||||
- '*.vcxproj*'
|
||||
- '**/*.vcxproj*'
|
||||
- 'cmake/*'
|
||||
- 'cmake/**/*'
|
||||
- 'CMakeLists.txt'
|
||||
- '**/CMakeLists.txt'
|
||||
- 'build.sh'
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- '.github/*'
|
||||
- '.github/**/*'
|
||||
- '*.sln'
|
||||
- '**/*.sln'
|
||||
- '*.vcxproj*'
|
||||
- '**/*.vcxproj*'
|
||||
- 'cmake/*'
|
||||
- 'cmake/**/*'
|
||||
- 'CMakeLists.txt'
|
||||
- '**/CMakeLists.txt'
|
||||
- 'build.sh'
|
||||
'Dependencies':
|
||||
- '3rdparty/*'
|
||||
- '3rdparty/**/*'
|
||||
- '**/3rdpartyDeps.props'
|
||||
- '.gitmodules'
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- '3rdparty/*'
|
||||
- '3rdparty/**/*'
|
||||
- '**/3rdpartyDeps.props'
|
||||
- '.gitmodules'
|
||||
'Documentation':
|
||||
- '*.md'
|
||||
- '**/*.md'
|
||||
- '*.pdf'
|
||||
- '**/*.pdf'
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- '*.md'
|
||||
- '**/*.md'
|
||||
- '*.pdf'
|
||||
- '**/*.pdf'
|
||||
'GUI/Qt':
|
||||
- 'pcsx2-qt/*'
|
||||
- 'pcsx2-qt/**/*'
|
||||
- '3rdparty/Qt/*'
|
||||
- '3rdparty/Qt/**/*'
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'pcsx2-qt/*'
|
||||
- 'pcsx2-qt/**/*'
|
||||
- '3rdparty/Qt/*'
|
||||
- '3rdparty/Qt/**/*'
|
||||
'GameDB':
|
||||
- '**/GameIndex.*'
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- '**/GameIndex.*'
|
||||
'Installer | Package':
|
||||
- 'build.sh'
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'build.sh'
|
||||
'Translations':
|
||||
- 'pcsx2-qt/Translations/*'
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'pcsx2-qt/Translations/*'
|
||||
|
||||
# Tools / Features
|
||||
'Debugger':
|
||||
- 'pcsx2/DebugTools/*'
|
||||
- 'pcsx2/DebugTools/**/*'
|
||||
- 'pcsx2-qt/Debugger/*'
|
||||
- 'pcsx2-qt/Debugger/**/*'
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'pcsx2/DebugTools/*'
|
||||
- 'pcsx2/DebugTools/**/*'
|
||||
- 'pcsx2-qt/Debugger/*'
|
||||
- 'pcsx2-qt/Debugger/**/*'
|
||||
'IPC':
|
||||
- 'pcsx2/IPC*'
|
||||
- 'pcsx2/**/IPC*'
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'pcsx2/IPC*'
|
||||
- 'pcsx2/**/IPC*'
|
||||
'TAS Functionality':
|
||||
- 'pcsx2/Recording/*'
|
||||
- 'pcsx2/Recording/**/*'
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'pcsx2/Recording/*'
|
||||
- 'pcsx2/Recording/**/*'
|
||||
'RetroAchievements':
|
||||
- 'pcsx2/Frontend/Achievements.*'
|
||||
- 'pcsx2/Achievements.*'
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'pcsx2/Frontend/Achievements.*'
|
||||
- 'pcsx2/Achievements.*'
|
||||
|
||||
# Emulation Components
|
||||
'Counters':
|
||||
- 'pcsx2/Counters.*'
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'pcsx2/Counters.*'
|
||||
'Vector Units':
|
||||
- 'pcsx2/VU*'
|
||||
- 'pcsx2/**/VU*'
|
||||
- 'pcsx2/*VU*'
|
||||
- 'pcsx2/**/*VU*'
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'pcsx2/VU*'
|
||||
- 'pcsx2/**/VU*'
|
||||
- 'pcsx2/*VU*'
|
||||
- 'pcsx2/**/*VU*'
|
||||
'VIF':
|
||||
- 'pcsx2/Vif*'
|
||||
- 'pcsx2/**/Vif*'
|
||||
- 'pcsx2/VIF*'
|
||||
- 'pcsx2/**/VIF*'
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'pcsx2/Vif*'
|
||||
- 'pcsx2/**/Vif*'
|
||||
- 'pcsx2/VIF*'
|
||||
- 'pcsx2/**/VIF*'
|
||||
|
||||
# GS Related Labels
|
||||
'GS':
|
||||
- 'pcsx2/GS/*'
|
||||
- 'pcsx2/GS/**/*'
|
||||
- 'bin/resources/shaders/*'
|
||||
- 'bin/resources/shaders/**/*'
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- '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/**/*'
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- '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/**/*'
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- '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/**/*'
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- '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/**/*'
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- '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/**/*'
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- '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/**/*'
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'pcsx2/GS/Renderers/Metal/*'
|
||||
- 'pcsx2/GS/Renderers/Metal/**/*'
|
||||
'GS: Texture Cache':
|
||||
- 'pcsx2/GS/Renderers/*TextureCache*.*'
|
||||
- 'pcsx2/GS/Renderers/**/*TextureCache*.*'
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'pcsx2/GS/Renderers/*TextureCache*.*'
|
||||
- 'pcsx2/GS/Renderers/**/*TextureCache*.*'
|
||||
'GS: Software':
|
||||
- 'pcsx2/GS/Renderers/SW/*'
|
||||
- 'pcsx2/GS/Renderers/SW/**/*'
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'pcsx2/GS/Renderers/SW/*'
|
||||
- 'pcsx2/GS/Renderers/SW/**/*'
|
||||
|
||||
# Other Core Components
|
||||
'CDVD':
|
||||
- 'pcsx2/CDVD/*'
|
||||
- 'pcsx2/CDVD/**/*'
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'pcsx2/CDVD/*'
|
||||
- 'pcsx2/CDVD/**/*'
|
||||
'DEV9':
|
||||
- 'pcsx2/DEV9/*'
|
||||
- 'pcsx2/DEV9/**/*'
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'pcsx2/DEV9/*'
|
||||
- 'pcsx2/DEV9/**/*'
|
||||
'IPU':
|
||||
- 'pcsx2/IPU/*'
|
||||
- 'pcsx2/IPU/**/*'
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'pcsx2/IPU/*'
|
||||
- 'pcsx2/IPU/**/*'
|
||||
'Memory Card':
|
||||
- 'pcsx2/SIO/Memcard/*'
|
||||
- 'pcsx2/SIO/Memcard/**/*'
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'pcsx2/SIO/Memcard/*'
|
||||
- 'pcsx2/SIO/Memcard/**/*'
|
||||
'PAD':
|
||||
- 'pcsx2/SIO/Pad/*'
|
||||
- 'pcsx2/SIO/Pad/**/*'
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'pcsx2/SIO/Pad/*'
|
||||
- 'pcsx2/SIO/Pad/**/*'
|
||||
'SPU2':
|
||||
- 'pcsx2/SPU2/*'
|
||||
- 'pcsx2/SPU2/**/*'
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'pcsx2/SPU2/*'
|
||||
- 'pcsx2/SPU2/**/*'
|
||||
'USB':
|
||||
- 'pcsx2/USB/*'
|
||||
- 'pcsx2/USB/**/*'
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'pcsx2/USB/*'
|
||||
- 'pcsx2/USB/**/*'
|
||||
|
||||
@@ -33,6 +33,7 @@ jobs:
|
||||
uses: ./.github/workflows/linux_build_flatpak.yml
|
||||
with:
|
||||
jobName: "Qt"
|
||||
artifactPrefixName: "PCSX2-linux-Qt-x64-flatpak"
|
||||
compiler: clang
|
||||
cmakeflags: ""
|
||||
publish: true
|
||||
|
||||
@@ -6,6 +6,9 @@ on:
|
||||
jobName:
|
||||
required: true
|
||||
type: string
|
||||
artifactPrefixName:
|
||||
required: true
|
||||
type: string
|
||||
os:
|
||||
required: false
|
||||
type: string
|
||||
@@ -36,6 +39,10 @@ on:
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
stableBuild:
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
jobs:
|
||||
build_linux:
|
||||
@@ -56,13 +63,18 @@ jobs:
|
||||
if: ${{ inputs.fetchTags }}
|
||||
run: git fetch --tags --no-recurse-submodules
|
||||
|
||||
- name: Add stable release identifier file
|
||||
if: ${{ inputs.stableBuild == true || inputs.stableBuild == 'true' }}
|
||||
shell: bash
|
||||
run: |
|
||||
echo "#define DEFAULT_UPDATER_CHANNEL \"stable\"" > ./pcsx2-qt/DefaultUpdaterChannel.h
|
||||
cat ./pcsx2-qt/DefaultUpdaterChannel.h
|
||||
|
||||
- name: Prepare Artifact Metadata
|
||||
id: artifact-metadata
|
||||
shell: bash
|
||||
env:
|
||||
OS: linux
|
||||
BUILD_SYSTEM: flatpak
|
||||
ARCH: ${{ inputs.platform }}
|
||||
PREFIX: ${{ inputs.artifactPrefixName }}
|
||||
EVENT_NAME: ${{ github.event_name }}
|
||||
PR_TITLE: ${{ github.event.pull_request.title }}
|
||||
PR_NUM: ${{ github.event.pull_request.number }}
|
||||
@@ -90,9 +102,11 @@ jobs:
|
||||
flatpak run --command=flatpak-builder-lint org.flatpak.Builder manifest .github/workflows/scripts/linux/flatpak/net.pcsx2.PCSX2.json
|
||||
|
||||
- name: Build Flatpak
|
||||
uses: flatpak/flatpak-github-actions/flatpak-builder@v6.3
|
||||
# TODO - based on v6.3, switch back to the main action once change is accepted (or they release a breaking change that uses upload-artifact@v4)
|
||||
uses: xTVaser/flatpak-github-actions/flatpak-builder@64267d4cf01f7955a40128039d0abab17bb48aac
|
||||
with:
|
||||
bundle: ${{ steps.artifact-metadata.outputs.artifact-name }}.flatpak
|
||||
upload-artifact: false
|
||||
manifest-path: .github/workflows/scripts/linux/flatpak/net.pcsx2.PCSX2.json
|
||||
arch: x86_64
|
||||
build-bundle: true
|
||||
@@ -131,3 +145,16 @@ jobs:
|
||||
repository: stable
|
||||
token: ${{ secrets.FLATHUB_TOKEN }}
|
||||
|
||||
# NOTE - this is done after on purpose so the flatpak file is wherever it needs to be for the previous pushes
|
||||
- name: Prepare artifacts folder
|
||||
# NOTE - 'flatpak-builder' dumps the artifact out into the current directory
|
||||
run: |
|
||||
mkdir -p "$GITHUB_WORKSPACE"/ci-artifacts/
|
||||
mv "./${{ steps.artifact-metadata.outputs.artifact-name }}.flatpak" "$GITHUB_WORKSPACE"/ci-artifacts/
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ steps.artifact-metadata.outputs.artifact-name }}
|
||||
path: ci-artifacts
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ jobs:
|
||||
uses: ./.github/workflows/linux_build_qt.yml
|
||||
with:
|
||||
jobName: "AppImage Build"
|
||||
artifactPrefixName: "PCSX2-linux-Qt-x64-appimage-sse4"
|
||||
compiler: clang
|
||||
cmakeflags: ""
|
||||
buildAppImage: true
|
||||
@@ -25,6 +26,7 @@ jobs:
|
||||
uses: ./.github/workflows/linux_build_flatpak.yml
|
||||
with:
|
||||
jobName: "Flatpak Build"
|
||||
artifactPrefixName: "PCSX2-linux-Qt-x64-flatpak-sse4"
|
||||
compiler: clang
|
||||
cmakeflags: ""
|
||||
publish: false
|
||||
|
||||
@@ -6,6 +6,9 @@ on:
|
||||
jobName:
|
||||
required: true
|
||||
type: string
|
||||
artifactPrefixName:
|
||||
required: true
|
||||
type: string
|
||||
os:
|
||||
required: false
|
||||
type: string
|
||||
@@ -36,6 +39,10 @@ on:
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
stableBuild:
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
jobs:
|
||||
build_linux:
|
||||
@@ -69,12 +76,18 @@ jobs:
|
||||
if: ${{ inputs.fetchTags }}
|
||||
run: git fetch --tags --no-recurse-submodules
|
||||
|
||||
- name: Add stable release identifier file
|
||||
if: ${{ inputs.stableBuild == true || inputs.stableBuild == 'true' }}
|
||||
shell: bash
|
||||
run: |
|
||||
echo "#define DEFAULT_UPDATER_CHANNEL \"stable\"" > ./pcsx2-qt/DefaultUpdaterChannel.h
|
||||
cat ./pcsx2-qt/DefaultUpdaterChannel.h
|
||||
|
||||
- name: Prepare Artifact Metadata
|
||||
id: artifact-metadata
|
||||
shell: bash
|
||||
env:
|
||||
OS: linux
|
||||
ARCH: ${{ inputs.platform }}
|
||||
PREFIX: ${{ inputs.artifactPrefixName }}
|
||||
EVENT_NAME: ${{ github.event_name }}
|
||||
PR_TITLE: ${{ github.event.pull_request.title }}
|
||||
PR_NUM: ${{ github.event.pull_request.number }}
|
||||
@@ -142,7 +155,7 @@ jobs:
|
||||
|
||||
- name: Upload artifact
|
||||
if: inputs.buildAppImage == true
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ steps.artifact-metadata.outputs.artifact-name }}
|
||||
path: ci-artifacts
|
||||
|
||||
@@ -6,6 +6,9 @@ on:
|
||||
jobName:
|
||||
required: true
|
||||
type: string
|
||||
artifactPrefixName:
|
||||
required: true
|
||||
type: string
|
||||
os:
|
||||
required: false
|
||||
type: string
|
||||
@@ -18,6 +21,10 @@ on:
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
stableBuild:
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
jobs:
|
||||
build_macos:
|
||||
@@ -44,6 +51,13 @@ jobs:
|
||||
if: ${{ inputs.fetchTags }}
|
||||
run: git fetch --tags --no-recurse-submodules
|
||||
|
||||
- name: Add stable release identifier file
|
||||
if: ${{ inputs.stableBuild == true || inputs.stableBuild == 'true' }}
|
||||
shell: bash
|
||||
run: |
|
||||
echo "#define DEFAULT_UPDATER_CHANNEL \"stable\"" > ./pcsx2-qt/DefaultUpdaterChannel.h
|
||||
cat ./pcsx2-qt/DefaultUpdaterChannel.h
|
||||
|
||||
- name: Use Xcode 14.3.1
|
||||
run: sudo xcode-select -s /Applications/Xcode_14.3.1.app
|
||||
|
||||
@@ -51,7 +65,7 @@ jobs:
|
||||
id: artifact-metadata
|
||||
shell: bash
|
||||
env:
|
||||
OS: macos
|
||||
PREFIX: ${{ inputs.artifactPrefixName }}
|
||||
EVENT_NAME: ${{ github.event_name }}
|
||||
PR_TITLE: ${{ github.event.pull_request.title }}
|
||||
PR_NUM: ${{ github.event.pull_request.number }}
|
||||
@@ -79,7 +93,8 @@ jobs:
|
||||
|
||||
- name: Build Dependencies
|
||||
if: steps.cache-deps.outputs.cache-hit != 'true'
|
||||
run: .github/workflows/scripts/macos/build-dependencies.sh
|
||||
run: |
|
||||
.github/workflows/scripts/macos/build-dependencies.sh "$HOME/deps"
|
||||
|
||||
- name: Download patches
|
||||
run: |
|
||||
@@ -148,7 +163,7 @@ jobs:
|
||||
cp "${{ steps.artifact-metadata.outputs.artifact-name }}.tar.xz" ci-artifacts/macOS.tar.xz
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ steps.artifact-metadata.outputs.artifact-name }}
|
||||
path: "*.tar.xz"
|
||||
|
||||
@@ -15,4 +15,5 @@ jobs:
|
||||
uses: ./.github/workflows/macos_build.yml
|
||||
with:
|
||||
jobName: "MacOS Build"
|
||||
artifactPrefixName: "PCSX2-macos-Qt"
|
||||
secrets: inherit
|
||||
|
||||
@@ -10,16 +10,19 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
# TODO - future work
|
||||
# workflow_dispatch:
|
||||
# inputs:
|
||||
# isStable:
|
||||
# description: 'Should it be a stable release?'
|
||||
# required: true
|
||||
# default: 'false'
|
||||
# versionTag:
|
||||
# description: 'The version to tag with'
|
||||
# required: true
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
is_prelease:
|
||||
description: 'Should be a pre-release?'
|
||||
required: true
|
||||
default: 'true'
|
||||
type: choice
|
||||
options:
|
||||
- 'true'
|
||||
- 'false'
|
||||
tag_value:
|
||||
description: 'Create a new release from latest master with the given tag, if this is left blank it will bump the patch version. You dont need to include the "v" prefix'
|
||||
required: false
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
@@ -42,6 +45,8 @@ jobs:
|
||||
github_token: ${{ github.token }}
|
||||
tag_prefix: v
|
||||
default_bump: patch
|
||||
# if set, it will overwrite the bump settings
|
||||
custom_tag: ${{ github.event.inputs.tag_value == '' && null || github.event.inputs.tag_value }}
|
||||
|
||||
# TODO - we could do this and remove the node.js script, but auto-generated notes only work
|
||||
# with PRs -- not commits (determine how much we care).
|
||||
@@ -62,9 +67,18 @@ jobs:
|
||||
node index.js
|
||||
mv ./release-notes.md ${GITHUB_WORKSPACE}/release-notes.md
|
||||
|
||||
- name: Create a GitHub Release
|
||||
- name: Create a GitHub Release (Manual)
|
||||
uses: softprops/action-gh-release@v1
|
||||
if: steps.tag_version.outputs.new_tag
|
||||
if: steps.tag_version.outputs.new_tag && github.event_name == 'workflow_dispatch'
|
||||
with:
|
||||
body_path: ./release-notes.md
|
||||
draft: true
|
||||
prerelease: ${{ github.event_name != 'workflow_dispatch' || inputs.is_prelease == 'true' }}
|
||||
tag_name: ${{ steps.tag_version.outputs.new_tag }}
|
||||
|
||||
- name: Create a GitHub Release (Push)
|
||||
uses: softprops/action-gh-release@v1
|
||||
if: steps.tag_version.outputs.new_tag && github.event_name != 'workflow_dispatch'
|
||||
with:
|
||||
body_path: ./release-notes.md
|
||||
draft: true
|
||||
@@ -81,10 +95,12 @@ jobs:
|
||||
uses: ./.github/workflows/linux_build_qt.yml
|
||||
with:
|
||||
jobName: "AppImage Build"
|
||||
artifactPrefixName: "PCSX2-linux-Qt-x64-appimage"
|
||||
compiler: clang
|
||||
cmakeflags: ""
|
||||
buildAppImage: true
|
||||
fetchTags: true
|
||||
stableBuild: ${{ github.event_name == 'workflow_dispatch' && inputs.is_prelease == 'false' }}
|
||||
secrets: inherit
|
||||
|
||||
build_linux_flatpak:
|
||||
@@ -95,11 +111,13 @@ jobs:
|
||||
uses: ./.github/workflows/linux_build_flatpak.yml
|
||||
with:
|
||||
jobName: "Flatpak Build"
|
||||
artifactPrefixName: "PCSX2-linux-Qt-x64-flatpak"
|
||||
compiler: clang
|
||||
cmakeflags: ""
|
||||
branch: "stable"
|
||||
publish: false
|
||||
fetchTags: true
|
||||
stableBuild: ${{ github.event_name == 'workflow_dispatch' && inputs.is_prelease == 'false' }}
|
||||
secrets: inherit
|
||||
|
||||
# Windows
|
||||
@@ -111,10 +129,12 @@ jobs:
|
||||
uses: ./.github/workflows/windows_build_qt.yml
|
||||
with:
|
||||
jobName: "Windows Build"
|
||||
artifactPrefixName: "PCSX2-windows-Qt-x64"
|
||||
configuration: CMake
|
||||
buildSystem: cmake
|
||||
cmakeFlags: -DCMAKE_C_COMPILER=clang-cl -DCMAKE_CXX_COMPILER=clang-cl
|
||||
fetchTags: true
|
||||
stableBuild: ${{ github.event_name == 'workflow_dispatch' && inputs.is_prelease == 'false' }}
|
||||
secrets: inherit
|
||||
|
||||
# MacOS
|
||||
@@ -126,7 +146,9 @@ jobs:
|
||||
uses: ./.github/workflows/macos_build.yml
|
||||
with:
|
||||
jobName: "MacOS Build"
|
||||
artifactPrefixName: "PCSX2-macos-Qt"
|
||||
fetchTags: true
|
||||
stableBuild: ${{ github.event_name == 'workflow_dispatch' && inputs.is_prelease == 'false' }}
|
||||
secrets: inherit
|
||||
|
||||
# Upload the Artifacts
|
||||
@@ -146,7 +168,7 @@ jobs:
|
||||
- name: Prepare Artifact Folder
|
||||
run: mkdir ./ci-artifacts/
|
||||
|
||||
- uses: actions/download-artifact@v3
|
||||
- uses: actions/download-artifact@v4
|
||||
name: Download all Artifacts
|
||||
with:
|
||||
path: ./ci-artifacts/
|
||||
@@ -159,9 +181,6 @@ jobs:
|
||||
working-directory: ./ci-artifacts/
|
||||
run: for d in *windows*/; do 7z a "${d}asset.7z" ./$d/*; done
|
||||
|
||||
# Artifact Naming:
|
||||
# MacOS: PCSX2-<tag>-macOS-[additional hyphen seperated tags]
|
||||
# Windows|Linux: PCSX2-<tag>-<windows|linux>-<32bit|64bit>--[additional hyphen seperated tags]
|
||||
- name: Name and Upload the Release Assets
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
|
||||
@@ -1,39 +1,26 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Artifact Naming Scheme:
|
||||
# PCSX2-<OS>-Qt-[ARCH]-[SIMD]-[pr\[PR_NUM\]]-[title|sha\[SHA|PR_TITLE\]
|
||||
# PCSX2-<OS>-Qt-[BUILD_SYSTEM]-[ARCH]-[SIMD]-[pr\[PR_NUM\]]-[title|sha\[SHA|PR_TITLE\]
|
||||
# -- limited to 200 chars
|
||||
# Outputs:
|
||||
# - artifact-name
|
||||
|
||||
# Example - PCSX2-linux-Qt-x64-flatpak-sse4-sha[e880a2749]
|
||||
|
||||
# Inputs as env-vars
|
||||
# OS
|
||||
# BUILD_SYSTEM
|
||||
# ARCH
|
||||
# SIMD
|
||||
# PREFIX
|
||||
# EVENT_NAME
|
||||
# PR_TITLE
|
||||
# PR_NUM
|
||||
# PR_SHA
|
||||
|
||||
NAME=""
|
||||
|
||||
if [ "${OS}" == "macos" ]; then
|
||||
# MacOS has combined binaries for x64 and ARM64.
|
||||
NAME="PCSX2-${OS}-Qt"
|
||||
elif [[ ("${OS}" == "windows" && "$BUILD_SYSTEM" != "cmake") ]]; then
|
||||
NAME="PCSX2-${OS}-Qt-${ARCH}-${SIMD}"
|
||||
else
|
||||
NAME="PCSX2-${OS}-Qt-${ARCH}"
|
||||
if [[ -z "${PREFIX}" ]]; then
|
||||
echo "PREFIX is not set, can't name artifact without it!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Add cmake if used to differentate it from msbuild builds
|
||||
# Else the two artifacts will have the same name and the files will be merged
|
||||
if [[ ! -z "${BUILD_SYSTEM}" ]]; then
|
||||
if [[ "${BUILD_SYSTEM}" == "cmake" ]] || [[ "${BUILD_SYSTEM}" == "flatpak" ]]; then
|
||||
NAME="${NAME}-${BUILD_SYSTEM}"
|
||||
fi
|
||||
fi
|
||||
NAME="${PREFIX}"
|
||||
|
||||
# Add PR / Commit Metadata
|
||||
if [ "$EVENT_NAME" == "pull_request" ]; then
|
||||
|
||||
@@ -38,13 +38,9 @@ cmake \
|
||||
$ADDITIONAL_CMAKE_ARGS \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DQT_BUILD=ON \
|
||||
-DCUBEB_API=ON \
|
||||
-DX11_API=ON \
|
||||
-DWAYLAND_API=ON \
|
||||
-DENABLE_SETCAP=OFF \
|
||||
-DCMAKE_PREFIX_PATH="${DEPS_PREFIX}" \
|
||||
-DUSE_SYSTEM_SDL2=ON \
|
||||
-DUSE_SYSTEM_ZSTD=OFF \
|
||||
-DDISABLE_ADVANCE_SIMD=TRUE
|
||||
|
||||
|
||||
@@ -19,9 +19,11 @@ declare -a BUILD_PACKAGES=(
|
||||
"libfontconfig1-dev"
|
||||
"libharfbuzz-dev"
|
||||
"libjpeg-dev"
|
||||
"liblz4-dev"
|
||||
"libpng-dev"
|
||||
"libfreetype-dev"
|
||||
"libinput-dev"
|
||||
"libwebp-dev"
|
||||
"libxcb-*-dev"
|
||||
"libxkbcommon-dev"
|
||||
"libxkbcommon-x11-dev"
|
||||
|
||||
@@ -2,27 +2,39 @@
|
||||
|
||||
set -e
|
||||
|
||||
if [ "$#" -ne 1 ]; then
|
||||
echo "Syntax: $0 <output directory>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
export MACOSX_DEPLOYMENT_TARGET=11.0
|
||||
|
||||
INSTALLDIR="$HOME/deps"
|
||||
INSTALLDIR="$1"
|
||||
NPROCS="$(getconf _NPROCESSORS_ONLN)"
|
||||
SDL=SDL2-2.28.5
|
||||
XZ=5.4.5
|
||||
ZSTD=1.5.5
|
||||
LZ4=b8fd2d15309dd4e605070bd4486e26b6ef814e29
|
||||
PNG=1.6.37
|
||||
JPG=9e
|
||||
WEBP=1.3.2
|
||||
FFMPEG=6.0
|
||||
QT=6.6.0
|
||||
|
||||
mkdir deps-build
|
||||
mkdir -p deps-build
|
||||
cd deps-build
|
||||
|
||||
export PKG_CONFIG_PATH="$INSTALLDIR/lib/pkgconfig:$PKG_CONFIG_PATH"
|
||||
export LDFLAGS="-L$INSTALLDIR/lib -dead_strip $LDFLAGS"
|
||||
export CFLAGS="-I$INSTALLDIR/include -Os $CFLAGS"
|
||||
export CXXFLAGS="-I$INSTALLDIR/include -Os $CXXFLAGS"
|
||||
export LDFLAGS="-L$INSTALLDIR/lib $LDFLAGS"
|
||||
export CFLAGS="-I$INSTALLDIR/include $CFLAGS"
|
||||
export CXXFLAGS="-I$INSTALLDIR/include $CXXFLAGS"
|
||||
|
||||
cat > SHASUMS <<EOF
|
||||
332cb37d0be20cb9541739c61f79bae5a477427d79ae85e352089afdaf6666e4 $SDL.tar.gz
|
||||
135c90b934aee8fbc0d467de87a05cb70d627da36abe518c357a873709e5b7d6 xz-$XZ.tar.gz
|
||||
9c4396cc829cfae319a6e2615202e82aad41372073482fce286fac78646d3ee4 zstd-$ZSTD.tar.gz
|
||||
0728800155f3ed0a0c87e03addbd30ecbe374f7b080678bbca1506051d50dec3 $LZ4.tar.gz
|
||||
505e70834d35383537b6491e7ae8641f1a4bed1876dbfe361201fc80868d88ca libpng-$PNG.tar.xz
|
||||
2a499607df669e40258e53d0ade8035ba4ec0175244869d1025d460562aa09b4 libwebp-$WEBP.tar.gz
|
||||
57be87c22d9b49c112b6d24bc67d42508660e6b718b3db89c44e47e289137082 ffmpeg-$FFMPEG.tar.xz
|
||||
039d53312acb5897a9054bd38c9ccbdab72500b71fdccdb3f4f0844b0dd39e0e qtbase-everywhere-src-$QT.tar.xz
|
||||
e1542cb50176e237809895c6549598c08587c63703d100be54ac2d806834e384 qtimageformats-everywhere-src-$QT.tar.xz
|
||||
@@ -33,7 +45,11 @@ EOF
|
||||
|
||||
curl -L \
|
||||
-O "https://libsdl.org/release/$SDL.tar.gz" \
|
||||
-O "https://github.com/tukaani-project/xz/releases/download/v$XZ/xz-$XZ.tar.gz" \
|
||||
-O "https://github.com/facebook/zstd/releases/download/v$ZSTD/zstd-$ZSTD.tar.gz" \
|
||||
-O "https://github.com/lz4/lz4/archive/$LZ4.tar.gz" \
|
||||
-O "https://downloads.sourceforge.net/project/libpng/libpng16/$PNG/libpng-$PNG.tar.xz" \
|
||||
-O "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-$WEBP.tar.gz" \
|
||||
-O "https://ffmpeg.org/releases/ffmpeg-$FFMPEG.tar.xz" \
|
||||
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtbase-everywhere-src-$QT.tar.xz" \
|
||||
-O "https://download.qt.io/official_releases/qt/${QT%.*}/$QT/submodules/qtimageformats-everywhere-src-$QT.tar.xz" \
|
||||
@@ -64,23 +80,18 @@ patch -u CMakeLists.txt <<EOF
|
||||
|
||||
EOF
|
||||
|
||||
cmake -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DSDL_X11=OFF
|
||||
cmake -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DCMAKE_OSX_ARCHITECTURES="x86_64" -DSDL_X11=OFF -DBUILD_SHARED_LIBS=ON
|
||||
make -C build "-j$NPROCS"
|
||||
make -C build install
|
||||
cd ..
|
||||
|
||||
echo "Installing libpng..."
|
||||
tar xf "libpng-$PNG.tar.xz"
|
||||
cd "libpng-$PNG"
|
||||
./configure --prefix "$INSTALLDIR" --disable-dependency-tracking
|
||||
make "-j$NPROCS"
|
||||
make install
|
||||
cd ..
|
||||
|
||||
echo "Installing FFmpeg..."
|
||||
tar xf "ffmpeg-$FFMPEG.tar.xz"
|
||||
cd "ffmpeg-$FFMPEG"
|
||||
./configure --prefix="$INSTALLDIR" --disable-all --disable-autodetect --disable-static --enable-shared \
|
||||
LDFLAGS="-dead_strip $LDFLAGS" CFLAGS="-Os $CFLAGS" CXXFLAGS="-Os $CXXFLAGS" \
|
||||
./configure --prefix="$INSTALLDIR" \
|
||||
--enable-cross-compile --arch=x86_64 --cc='clang -arch x86_64' --cxx='clang++ -arch x86_64' --disable-x86asm \
|
||||
--disable-all --disable-autodetect --disable-static --enable-shared \
|
||||
--enable-avcodec --enable-avformat --enable-avutil --enable-swresample --enable-swscale \
|
||||
--enable-audiotoolbox --enable-videotoolbox \
|
||||
--enable-encoder=ffv1,qtrle,pcm_s16be,pcm_s16le,*_at,*_videotoolbox \
|
||||
@@ -90,27 +101,101 @@ make "-j$NPROCS"
|
||||
make install
|
||||
cd ..
|
||||
|
||||
echo "Installing XZ..."
|
||||
tar xf "xz-$XZ.tar.gz"
|
||||
cd "xz-$XZ"
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DCMAKE_OSX_ARCHITECTURES="x86_64" -DBUILD_SHARED_LIBS=ON -DBUILD_TESTING=OFF -B build
|
||||
make -C build "-j$NPROCS"
|
||||
make -C build install
|
||||
make install
|
||||
cd ..
|
||||
|
||||
echo "Installing Zstd..."
|
||||
tar xf "zstd-$ZSTD.tar.gz"
|
||||
cd "zstd-$ZSTD"
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DCMAKE_OSX_ARCHITECTURES="x86_64" -DBUILD_SHARED_LIBS=ON -DZSTD_BUILD_PROGRAMS=OFF -B build-dir build/cmake
|
||||
make -C build-dir "-j$NPROCS"
|
||||
make -C build-dir install
|
||||
cd ..
|
||||
|
||||
echo "Installing LZ4..."
|
||||
tar xf "$LZ4.tar.gz"
|
||||
cd "lz4-$LZ4"
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DCMAKE_OSX_ARCHITECTURES="x86_64" -DBUILD_SHARED_LIBS=ON -DLZ4_BUILD_CLI=OFF -DLZ4_BUILD_LEGACY_LZ4C=OFF -B build-dir build/cmake
|
||||
make -C build-dir "-j$NPROCS"
|
||||
make -C build-dir install
|
||||
cd ..
|
||||
|
||||
echo "Installing libpng..."
|
||||
tar xf "libpng-$PNG.tar.xz"
|
||||
cd "libpng-$PNG"
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DCMAKE_OSX_ARCHITECTURES="x86_64" -DBUILD_SHARED_LIBS=ON -DPNG_TESTS=OFF -B build
|
||||
make -C build "-j$NPROCS"
|
||||
make -C build install
|
||||
cd ..
|
||||
|
||||
echo "Installing WebP..."
|
||||
tar xf "libwebp-$WEBP.tar.gz"
|
||||
cd "libwebp-$WEBP"
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DCMAKE_OSX_ARCHITECTURES="x86_64" -B build \
|
||||
-DWEBP_BUILD_ANIM_UTILS=OFF -DWEBP_BUILD_CWEBP=OFF -DWEBP_BUILD_DWEBP=OFF -DWEBP_BUILD_GIF2WEBP=OFF -DWEBP_BUILD_IMG2WEBP=OFF \
|
||||
-DWEBP_BUILD_VWEBP=OFF -DWEBP_BUILD_WEBPINFO=OFF -DWEBP_BUILD_WEBPMUX=OFF -DWEBP_BUILD_EXTRAS=OFF -DBUILD_SHARED_LIBS=ON
|
||||
make -C build "-j$NPROCS"
|
||||
make -C build install
|
||||
cd ..
|
||||
|
||||
echo "Installing Qt Base..."
|
||||
tar xf "qtbase-everywhere-src-$QT.tar.xz"
|
||||
cd "qtbase-everywhere-src-$QT"
|
||||
cmake -B build -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DCMAKE_BUILD_TYPE=Release -DFEATURE_optimize_size=ON -DFEATURE_dbus=OFF -DFEATURE_framework=OFF -DFEATURE_icu=OFF -DFEATURE_opengl=OFF -DFEATURE_printsupport=OFF -DFEATURE_sql=OFF -DFEATURE_gssapi=OFF
|
||||
# since we don't have a direct reference to QtSvg, it doesn't deployed directly from the main binary
|
||||
# (only indirectly from iconengines), and the libqsvg.dylib imageformat plugin does not get deployed.
|
||||
# We could run macdeployqt twice, but that's even more janky than patching it.
|
||||
patch -u src/tools/macdeployqt/shared/shared.cpp <<EOF
|
||||
--- shared.cpp
|
||||
+++ shared.cpp
|
||||
@@ -1119,14 +1119,8 @@
|
||||
addPlugins(QStringLiteral("networkinformation"));
|
||||
}
|
||||
|
||||
- // All image formats (svg if QtSvg is used)
|
||||
- const bool usesSvg = deploymentInfo.containsModule("Svg", libInfix);
|
||||
- addPlugins(QStringLiteral("imageformats"), [usesSvg](const QString &lib) {
|
||||
- if (lib.contains(QStringLiteral("qsvg")) && !usesSvg)
|
||||
- return false;
|
||||
- return true;
|
||||
- });
|
||||
-
|
||||
+ // All image formats
|
||||
+ addPlugins(QStringLiteral("imageformats"));
|
||||
addPlugins(QStringLiteral("iconengines"));
|
||||
|
||||
// Platforminputcontext plugins if QtGui is in use
|
||||
EOF
|
||||
cmake -B build -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_ARCHITECTURES="x86_64" -DFEATURE_dbus=OFF -DFEATURE_framework=OFF -DFEATURE_icu=OFF -DFEATURE_opengl=OFF -DFEATURE_printsupport=OFF -DFEATURE_sql=OFF -DFEATURE_gssapi=OFF
|
||||
make -C build "-j$NPROCS"
|
||||
make -C build install
|
||||
cd ..
|
||||
|
||||
echo "Installing Qt SVG..."
|
||||
tar xf "qtsvg-everywhere-src-$QT.tar.xz"
|
||||
cd "qtsvg-everywhere-src-$QT"
|
||||
cmake -B build -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DCMAKE_BUILD_TYPE=MinSizeRel
|
||||
make -C build "-j$NPROCS"
|
||||
make -C build install
|
||||
cd ..
|
||||
mkdir build
|
||||
cd build
|
||||
"$INSTALLDIR/bin/qt-configure-module" ..
|
||||
make "-j$NPROCS"
|
||||
make install
|
||||
cd ../..
|
||||
|
||||
echo "Installing Qt Image Formats..."
|
||||
tar xf "qtimageformats-everywhere-src-$QT.tar.xz"
|
||||
cd "qtimageformats-everywhere-src-$QT"
|
||||
cmake -B build -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DCMAKE_BUILD_TYPE=MinSizeRel
|
||||
make -C build "-j$NPROCS"
|
||||
make -C build install
|
||||
cd ..
|
||||
mkdir build
|
||||
cd build
|
||||
"$INSTALLDIR/bin/qt-configure-module" ..
|
||||
make "-j$NPROCS"
|
||||
make install
|
||||
cd ../..
|
||||
|
||||
echo "Installing Qt Tools..."
|
||||
tar xf "qttools-everywhere-src-$QT.tar.xz"
|
||||
cd "qttools-everywhere-src-$QT"
|
||||
@@ -128,18 +213,23 @@ patch -u src/linguist/CMakeLists.txt <<EOF
|
||||
add_subdirectory(linguist)
|
||||
endif()
|
||||
EOF
|
||||
cmake -B build -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DCMAKE_BUILD_TYPE=Release -DFEATURE_assistant=OFF -DFEATURE_clang=OFF -DFEATURE_designer=OFF -DFEATURE_kmap2qmap=OFF -DFEATURE_pixeltool=OFF -DFEATURE_pkg_config=OFF -DFEATURE_qev=OFF -DFEATURE_qtattributionsscanner=OFF -DFEATURE_qtdiag=OFF -DFEATURE_qtplugininfo=OFF
|
||||
make -C build "-j$NPROCS"
|
||||
make -C build install
|
||||
cd ..
|
||||
mkdir build
|
||||
cd build
|
||||
"$INSTALLDIR/bin/qt-configure-module" .. -- -DFEATURE_assistant=OFF -DFEATURE_clang=OFF -DFEATURE_designer=OFF -DFEATURE_kmap2qmap=OFF -DFEATURE_pixeltool=OFF -DFEATURE_pkg_config=OFF -DFEATURE_qev=OFF -DFEATURE_qtattributionsscanner=OFF -DFEATURE_qtdiag=OFF -DFEATURE_qtplugininfo=OFF
|
||||
make "-j$NPROCS"
|
||||
make install
|
||||
cd ../..
|
||||
|
||||
echo "Installing Qt Translations..."
|
||||
tar xf "qttranslations-everywhere-src-$QT.tar.xz"
|
||||
cd "qttranslations-everywhere-src-$QT"
|
||||
cmake -B build -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DCMAKE_BUILD_TYPE=Release
|
||||
make -C build "-j$NPROCS"
|
||||
make -C build install
|
||||
cd ..
|
||||
mkdir build
|
||||
cd build
|
||||
"$INSTALLDIR/bin/qt-configure-module" ..
|
||||
make "-j$NPROCS"
|
||||
make install
|
||||
cd ../..
|
||||
|
||||
echo "Cleaning up..."
|
||||
cd ..
|
||||
rm -r deps-build
|
||||
rm -rf deps-build
|
||||
|
||||
@@ -8,7 +8,7 @@ jobs:
|
||||
if: github.repository == 'PCSX2/pcsx2'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/labeler@v4.3.0
|
||||
- uses: actions/labeler@v5
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ jobs:
|
||||
uses: ./.github/workflows/windows_build_qt.yml
|
||||
with:
|
||||
jobName: "MSVC SSE4"
|
||||
artifactPrefixName: "PCSX2-windows-Qt-x64-sse4-msvc"
|
||||
configuration: Release
|
||||
simd: "SSE4"
|
||||
secrets: inherit
|
||||
@@ -38,6 +39,7 @@ jobs:
|
||||
uses: ./.github/workflows/windows_build_qt.yml
|
||||
with:
|
||||
jobName: "MSVC AVX2"
|
||||
artifactPrefixName: "PCSX2-windows-Qt-x64-avx2-msvc"
|
||||
configuration: Release AVX2
|
||||
secrets: inherit
|
||||
|
||||
@@ -47,6 +49,7 @@ jobs:
|
||||
uses: ./.github/workflows/windows_build_qt.yml
|
||||
with:
|
||||
jobName: "CMake MSVC"
|
||||
artifactPrefixName: "PCSX2-windows-Qt-x64-cmake-msvc"
|
||||
configuration: CMake
|
||||
buildSystem: cmake
|
||||
secrets: inherit
|
||||
@@ -58,6 +61,7 @@ jobs:
|
||||
uses: ./.github/workflows/windows_build_qt.yml
|
||||
with:
|
||||
jobName: "Clang SSE4"
|
||||
artifactPrefixName: "PCSX2-windows-Qt-x64-sse4-clang"
|
||||
configuration: Release Clang
|
||||
simd: "SSE4"
|
||||
secrets: inherit
|
||||
@@ -69,6 +73,7 @@ jobs:
|
||||
uses: ./.github/workflows/windows_build_qt.yml
|
||||
with:
|
||||
jobName: "Clang AVX2"
|
||||
artifactPrefixName: "PCSX2-windows-Qt-x64-avx2-clang"
|
||||
configuration: Release Clang AVX2
|
||||
secrets: inherit
|
||||
|
||||
@@ -78,6 +83,7 @@ jobs:
|
||||
uses: ./.github/workflows/windows_build_qt.yml
|
||||
with:
|
||||
jobName: "CMake Clang"
|
||||
artifactPrefixName: "PCSX2-windows-Qt-x64-cmake-clang"
|
||||
configuration: CMake
|
||||
buildSystem: cmake
|
||||
cmakeFlags: -DCMAKE_C_COMPILER=clang-cl -DCMAKE_CXX_COMPILER=clang-cl -DPCSX2_EXE_NAME=pcsx2-qt-clang
|
||||
|
||||
@@ -6,6 +6,9 @@ on:
|
||||
jobName:
|
||||
required: true
|
||||
type: string
|
||||
artifactPrefixName:
|
||||
required: true
|
||||
type: string
|
||||
os:
|
||||
required: false
|
||||
type: string
|
||||
@@ -37,6 +40,10 @@ on:
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
stableBuild:
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
jobs:
|
||||
build_windows_qt:
|
||||
@@ -58,14 +65,18 @@ jobs:
|
||||
if: ${{ inputs.fetchTags }}
|
||||
run: git fetch --tags --no-recurse-submodules
|
||||
|
||||
- name: Add stable release identifier file
|
||||
if: ${{ inputs.stableBuild == true || inputs.stableBuild == 'true' }}
|
||||
shell: bash
|
||||
run: |
|
||||
echo "#define DEFAULT_UPDATER_CHANNEL \"stable\"" > ./pcsx2-qt/DefaultUpdaterChannel.h
|
||||
cat ./pcsx2-qt/DefaultUpdaterChannel.h
|
||||
|
||||
- name: Prepare Artifact Metadata
|
||||
id: artifact-metadata
|
||||
shell: bash
|
||||
env:
|
||||
OS: windows
|
||||
BUILD_SYSTEM: ${{ inputs.buildSystem }}
|
||||
ARCH: ${{ inputs.platform }}
|
||||
SIMD: ${{ inputs.simd }}
|
||||
PREFIX: ${{ inputs.artifactPrefixName }}
|
||||
EVENT_NAME: ${{ github.event_name }}
|
||||
PR_TITLE: ${{ github.event.pull_request.title }}
|
||||
PR_NUM: ${{ github.event.pull_request.number }}
|
||||
@@ -122,7 +133,7 @@ jobs:
|
||||
cmake --build build --config Release --target unittests
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ steps.artifact-metadata.outputs.artifact-name }}
|
||||
path: |
|
||||
@@ -136,7 +147,7 @@ jobs:
|
||||
!./bin/**/*.lib
|
||||
|
||||
- name: Upload artifact - with symbols
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ steps.artifact-metadata.outputs.artifact-name }}-symbols
|
||||
path: ./bin/**/*.pdb
|
||||
|
||||
+12
@@ -56,6 +56,10 @@ oprofile_data/
|
||||
/UpgradeLog*.htm
|
||||
/.vscode*
|
||||
|
||||
# KDevelop 4 Workspace Configuration Files
|
||||
*.kdev4
|
||||
/.kdev4*
|
||||
|
||||
/bin/**/*.dll
|
||||
/bin/**/*.dmp
|
||||
/bin/**/*.exp
|
||||
@@ -67,6 +71,7 @@ oprofile_data/
|
||||
/bin/bios
|
||||
/bin/cache
|
||||
/bin/cheats
|
||||
/bin/patches
|
||||
/bin/covers
|
||||
/bin/dumps
|
||||
/bin/gamesettings
|
||||
@@ -80,6 +85,13 @@ oprofile_data/
|
||||
/bin/textures
|
||||
/bin/translations
|
||||
/bin/inputprofiles
|
||||
|
||||
# Resources that are runtime downloaded.
|
||||
/bin/resources/NotoSansJP-Regular.ttf
|
||||
/bin/resources/NotoSansKR-Regular.ttf
|
||||
/bin/resources/NotoSansSC-Regular.ttf
|
||||
/bin/resources/NotoSansTC-Regular.ttf
|
||||
|
||||
/deps
|
||||
/ipch
|
||||
|
||||
|
||||
Vendored
+13
@@ -327,3 +327,16 @@
|
||||
#define ICON_PF_EXIT_QUIT_LEAVE "\xF0\x9F\x9A\xAA"
|
||||
#define ICON_PF_INFORMATION "\xF0\x9F\x9B\x88"
|
||||
#define ICON_PF_SHOPPING_CART "\xF0\x9F\x9B\x92"
|
||||
#define ICON_PF_ACHIEVEMENTS_PROGRESSION "\xE2\x8E\xB2"
|
||||
#define ICON_PF_ACHIEVEMENTS_MISSABLE "\xE2\x8E\xB3"
|
||||
#define ICON_PF_ACHIEVEMENTS_WIN "\xE2\x8E\xB4"
|
||||
#define ICON_PF_POPN_CONTROLLER "\xE2\x8A\xBF"
|
||||
#define ICON_PF_POPN_BLUE_LEFT "\xE2\x8B\x80"
|
||||
#define ICON_PF_POPN_BLUE_RIGHT "\xE2\x8B\x81"
|
||||
#define ICON_PF_POPN_GREEN_LEFT "\xE2\x8B\x82"
|
||||
#define ICON_PF_POPN_GREEN_RIGHT "\xE2\x8B\x83"
|
||||
#define ICON_PF_POPN_YELLOW_LEFT "\xE2\x8B\x84"
|
||||
#define ICON_PF_POPN_YELLOW_RIGHT "\xE2\x8B\x85"
|
||||
#define ICON_PF_POPN_WHITE_LEFT "\xE2\x8B\x86"
|
||||
#define ICON_PF_POPN_WHITE_RIGHT "\xE2\x8B\x87"
|
||||
#define ICON_PF_POPN_RED "\xE2\x8B\x88"
|
||||
Vendored
+67
-156
@@ -28,103 +28,83 @@ include(TestBigEndian)
|
||||
# Request ISO C secure library functions (memcpy_s &c)
|
||||
list(APPEND CMAKE_REQUIRED_DEFINITIONS -D__STDC_WANT_LIB_EXT1__=1)
|
||||
|
||||
check_function_exists(_close HAVE__CLOSE)
|
||||
check_function_exists(_dup HAVE__DUP)
|
||||
check_function_exists(_fdopen HAVE__FDOPEN)
|
||||
check_function_exists(_fileno HAVE__FILENO)
|
||||
check_function_exists(_setmode HAVE__SETMODE)
|
||||
check_symbol_exists(_snprintf stdio.h HAVE__SNPRINTF)
|
||||
check_symbol_exists(_snprintf_s stdio.h HAVE__SNPRINTF_S)
|
||||
check_symbol_exists(_snwprintf_s stdio.h HAVE__SNWPRINTF_S)
|
||||
check_function_exists(_strdup HAVE__STRDUP)
|
||||
check_symbol_exists(_stricmp string.h HAVE__STRICMP)
|
||||
check_function_exists(_strtoi64 HAVE__STRTOI64)
|
||||
check_function_exists(_strtoui64 HAVE__STRTOUI64)
|
||||
check_function_exists(_unlink HAVE__UNLINK)
|
||||
check_function_exists(arc4random HAVE_ARC4RANDOM)
|
||||
check_function_exists(clonefile HAVE_CLONEFILE)
|
||||
check_function_exists(explicit_bzero HAVE_EXPLICIT_BZERO)
|
||||
check_function_exists(explicit_memset HAVE_EXPLICIT_MEMSET)
|
||||
check_function_exists(fchmod HAVE_FCHMOD)
|
||||
check_function_exists(fileno HAVE_FILENO)
|
||||
check_function_exists(fseeko HAVE_FSEEKO)
|
||||
check_function_exists(ftello HAVE_FTELLO)
|
||||
check_function_exists(getprogname HAVE_GETPROGNAME)
|
||||
check_symbol_exists(localtime_r time.h HAVE_LOCALTIME_R)
|
||||
check_symbol_exists(localtime_s time.h HAVE_LOCALTIME_S)
|
||||
check_function_exists(memcpy_s HAVE_MEMCPY_S)
|
||||
check_function_exists(random HAVE_RANDOM)
|
||||
check_function_exists(setmode HAVE_SETMODE)
|
||||
check_symbol_exists(snprintf stdio.h HAVE_SNPRINTF)
|
||||
check_symbol_exists(snprintf_s stdio.h HAVE_SNPRINTF_S)
|
||||
check_symbol_exists(strcasecmp strings.h HAVE_STRCASECMP)
|
||||
check_function_exists(strdup HAVE_STRDUP)
|
||||
check_function_exists(strerror_s HAVE_STRERROR_S)
|
||||
check_function_exists(strerrorlen_s HAVE_STRERRORLEN_S)
|
||||
check_function_exists(stricmp HAVE_STRICMP)
|
||||
check_function_exists(strncpy_s HAVE_STRNCPY_S)
|
||||
check_function_exists(strtoll HAVE_STRTOLL)
|
||||
check_function_exists(strtoull HAVE_STRTOULL)
|
||||
# Replaced these dynamic checks with static, otherwise XCode is slow to configure.
|
||||
set(HAVE__CLOSE ${MSVC})
|
||||
set(HAVE__DUP ${MSVC})
|
||||
set(HAVE__FDOPEN ${MSVC})
|
||||
set(HAVE__FILENO ${MSVC})
|
||||
set(HAVE__SETMODE ${MSVC})
|
||||
set(HAVE__SNPRINTF ${MSVC})
|
||||
set(HAVE__SNPRINTF_S ${MSVC})
|
||||
set(HAVE__SNWPRINTF_S ${MSVC})
|
||||
set(HAVE__STRDUP ${MSVC})
|
||||
set(HAVE__STRICMP ${MSVC})
|
||||
set(HAVE__STRTOI64 ${MSVC})
|
||||
set(HAVE__STRTOUI64 ${MSVC})
|
||||
set(HAVE__UNLINK ${MSVC})
|
||||
set(HAVE_ARC4RANDOM ${APPLE})
|
||||
set(HAVE_CLONEFILE ${APPLE})
|
||||
set(HAVE_EXPLICIT_BZERO ${LINUX})
|
||||
set(HAVE_EXPLICIT_MEMSET ${LINUX})
|
||||
set(HAVE_FCHMOD ${UNIX})
|
||||
set(HAVE_FILENO TRUE)
|
||||
set(HAVE_FSEEKO ${UNIX})
|
||||
set(HAVE_FTELLO ${UNIX})
|
||||
set(HAVE_GETPROGNAME ${APPLE})
|
||||
set(HAVE_LOCALTIME_R ${UNIX})
|
||||
set(HAVE_LOCALTIME_S ${MSVC})
|
||||
set(HAVE_MEMCPY_S ${MSVC})
|
||||
set(HAVE_RANDOM ${UNIX})
|
||||
set(HAVE_SETMODE ${APPLE})
|
||||
set(HAVE_SNPRINTF TRUE)
|
||||
set(HAVE_SNPRINTF_S FALSE)
|
||||
set(HAVE_STRCASECMP ${UNIX})
|
||||
set(HAVE_STRDUP TRUE)
|
||||
set(HAVE_STRERROR_S ${MSVC})
|
||||
set(HAVE_STRERRORLEN_S FALSE)
|
||||
set(HAVE_STRICMP ${MSVC})
|
||||
set(HAVE_STRNCPY_S ${MSVC})
|
||||
set(HAVE_STRTOLL TRUE)
|
||||
set(HAVE_STRTOULL TRUE)
|
||||
|
||||
check_include_files("sys/types.h;sys/stat.h;fts.h" HAVE_FTS_H)
|
||||
# fts functions may be in external library
|
||||
if(HAVE_FTS_H)
|
||||
if(UNIX)
|
||||
set(HAVE_FTS_H TRUE)
|
||||
check_function_exists(fts_open HAVE_FTS_OPEN)
|
||||
if(NOT HAVE_FTS_OPEN)
|
||||
check_library_exists(fts fts_open "" HAVE_LIB_FTS)
|
||||
else(NOT HAVE_FTS_OPEN)
|
||||
set(HAVE_LIB_FTS "" CACHE INTERNAL "")
|
||||
set(HAVE_LIB_FTS "")
|
||||
endif(NOT HAVE_FTS_OPEN)
|
||||
else(HAVE_FTS_H)
|
||||
set(HAVE_LIB_FTS "" CACHE INTERNAL "")
|
||||
endif(HAVE_FTS_H)
|
||||
|
||||
if(HAVE_LIB_FTS)
|
||||
set(FTS_LIB fts CACHE INTERNAL "")
|
||||
else()
|
||||
set(FTS_LIB "" CACHE INTERNAL "")
|
||||
set(HAVE_LIB_FTS "")
|
||||
endif()
|
||||
|
||||
check_include_files(stdbool.h HAVE_STDBOOL_H)
|
||||
check_include_files(strings.h HAVE_STRINGS_H)
|
||||
check_include_files(unistd.h HAVE_UNISTD_H)
|
||||
if(HAVE_LIB_FTS)
|
||||
set(FTS_LIB fts)
|
||||
else()
|
||||
set(FTS_LIB "")
|
||||
endif()
|
||||
|
||||
check_include_files(inttypes.h HAVE_INTTYPES_H_LIBZIP)
|
||||
check_include_files(stdint.h HAVE_STDINT_H_LIBZIP)
|
||||
check_include_files(sys/types.h HAVE_SYS_TYPES_H_LIBZIP)
|
||||
set(HAVE_STDBOOL_H TRUE)
|
||||
set(HAVE_STRINGS_H ${UNIX})
|
||||
set(HAVE_UNISTD_H ${UNIX})
|
||||
|
||||
# TODO: fix test
|
||||
# this test does not find __progname even when it exists
|
||||
#check_symbol_exists(__progname stdlib.h HAVE___PROGNAME)
|
||||
|
||||
check_type_size(__int8 __INT8_LIBZIP)
|
||||
check_type_size(int8_t INT8_T_LIBZIP)
|
||||
check_type_size(uint8_t UINT8_T_LIBZIP)
|
||||
check_type_size(__int16 __INT16_LIBZIP)
|
||||
check_type_size(int16_t INT16_T_LIBZIP)
|
||||
check_type_size(uint16_t UINT16_T_LIBZIP)
|
||||
check_type_size(__int32 __INT32_LIBZIP)
|
||||
check_type_size(int32_t INT32_T_LIBZIP)
|
||||
check_type_size(uint32_t UINT32_T_LIBZIP)
|
||||
check_type_size(__int64 __INT64_LIBZIP)
|
||||
check_type_size(int64_t INT64_T_LIBZIP)
|
||||
check_type_size(uint64_t UINT64_T_LIBZIP)
|
||||
check_type_size("short" SHORT_LIBZIP)
|
||||
check_type_size("int" INT_LIBZIP)
|
||||
check_type_size("long" LONG_LIBZIP)
|
||||
check_type_size("long long" LONG_LONG_LIBZIP)
|
||||
check_type_size("off_t" SIZEOF_OFF_T)
|
||||
check_type_size("size_t" SIZEOF_SIZE_T)
|
||||
|
||||
check_c_source_compiles("#include <sys/ioctl.h>
|
||||
#include <linux/fs.h>
|
||||
int main(int argc, char *argv[]) { unsigned long x = FICLONERANGE; }" HAVE_FICLONERANGE)
|
||||
if(LINUX)
|
||||
check_c_source_compiles("#include <sys/ioctl.h>
|
||||
#include <linux/fs.h>
|
||||
int main(int argc, char *argv[]) { unsigned long x = FICLONERANGE; }" HAVE_FICLONERANGE)
|
||||
else()
|
||||
set(HAVE_FICLONERANGE FALSE)
|
||||
endif()
|
||||
|
||||
check_c_source_compiles("
|
||||
int foo(char * _Nullable bar);
|
||||
int main(int argc, char *argv[]) { }" HAVE_NULLABLE)
|
||||
|
||||
test_big_endian(WORDS_BIGENDIAN)
|
||||
set(WORDS_BIGENDIAN FALSE)
|
||||
|
||||
if(MSVC)
|
||||
add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
|
||||
@@ -133,88 +113,19 @@ endif(MSVC)
|
||||
|
||||
# fixed size integral types
|
||||
|
||||
if(HAVE_INTTYPES_H_LIBZIP)
|
||||
set(LIBZIP_TYPES_INCLUDE "#if !defined(__STDC_FORMAT_MACROS)
|
||||
set(LIBZIP_TYPES_INCLUDE "#if !defined(__STDC_FORMAT_MACROS)
|
||||
#define __STDC_FORMAT_MACROS 1
|
||||
#endif
|
||||
#include <inttypes.h>")
|
||||
elseif(HAVE_STDINT_H_LIBZIP)
|
||||
set(LIBZIP_TYPES_INCLUDE "#include <stdint.h>")
|
||||
elseif(HAVE_SYS_TYPES_H_LIBZIP)
|
||||
set(LIBZIP_TYPES_INCLUDE "#include <sys/types.h>")
|
||||
endif()
|
||||
|
||||
if(HAVE_INT8_T_LIBZIP)
|
||||
set(ZIP_INT8_T int8_t)
|
||||
elseif(HAVE___INT8_LIBZIP)
|
||||
set(ZIP_INT8_T __int8)
|
||||
else()
|
||||
set(ZIP_INT8_T "signed char")
|
||||
endif()
|
||||
|
||||
if(HAVE_UINT8_T_LIBZIP)
|
||||
set(ZIP_UINT8_T uint8_t)
|
||||
elseif(HAVE___INT8_LIBZIP)
|
||||
set(ZIP_UINT8_T "unsigned __int8")
|
||||
else()
|
||||
set(ZIP_UINT8_T "unsigned char")
|
||||
endif()
|
||||
|
||||
if(HAVE_INT16_T_LIBZIP)
|
||||
set(ZIP_INT16_T int16_t)
|
||||
elseif(HAVE___INT16_LIBZIP)
|
||||
set(INT16_T_LIBZIP __int16)
|
||||
elseif(SHORT_LIBZIP EQUAL 2)
|
||||
set(INT16_T_LIBZIP short)
|
||||
endif()
|
||||
|
||||
if(HAVE_UINT16_T_LIBZIP)
|
||||
set(ZIP_UINT16_T uint16_t)
|
||||
elseif(HAVE___INT16_LIBZIP)
|
||||
set(UINT16_T_LIBZIP "unsigned __int16")
|
||||
elseif(SHORT_LIBZIP EQUAL 2)
|
||||
set(UINT16_T_LIBZIP "unsigned short")
|
||||
endif()
|
||||
|
||||
if(HAVE_INT32_T_LIBZIP)
|
||||
set(ZIP_INT32_T int32_t)
|
||||
elseif(HAVE___INT32_LIBZIP)
|
||||
set(ZIP_INT32_T __int32)
|
||||
elseif(INT_LIBZIP EQUAL 4)
|
||||
set(ZIP_INT32_T int)
|
||||
elseif(LONG_LIBZIP EQUAL 4)
|
||||
set(ZIP_INT32_T long)
|
||||
endif()
|
||||
|
||||
if(HAVE_UINT32_T_LIBZIP)
|
||||
set(ZIP_UINT32_T uint32_t)
|
||||
elseif(HAVE___INT32_LIBZIP)
|
||||
set(ZIP_UINT32_T "unsigned __int32")
|
||||
elseif(INT_LIBZIP EQUAL 4)
|
||||
set(ZIP_UINT32_T "unsigned int")
|
||||
elseif(LONG_LIBZIP EQUAL 4)
|
||||
set(ZIP_UINT32_T "unsigned long")
|
||||
endif()
|
||||
|
||||
if(HAVE_INT64_T_LIBZIP)
|
||||
set(ZIP_INT64_T int64_t)
|
||||
elseif(HAVE___INT64_LIBZIP)
|
||||
set(ZIP_INT64_T __int64)
|
||||
elseif(LONG_LIBZIP EQUAL 8)
|
||||
set(ZIP_INT64_T long)
|
||||
elseif(LONG_LONG_LIBZIP EQUAL 8)
|
||||
set(ZIP_INT64_T "long long")
|
||||
endif()
|
||||
|
||||
if(HAVE_UINT64_T_LIBZIP)
|
||||
set(ZIP_UINT64_T uint64_t)
|
||||
elseif(HAVE___INT64_LIBZIP)
|
||||
set(ZIP_UINT64_T "unsigned __int64")
|
||||
elseif(LONG_LIBZIP EQUAL 8)
|
||||
set(ZIP_UINT64_T "unsigned long")
|
||||
elseif(LONG_LONG_LIBZIP EQUAL 8)
|
||||
set(ZIP_UINT64_T "unsigned long long")
|
||||
endif()
|
||||
set(ZIP_INT8_T int8_t)
|
||||
set(ZIP_UINT8_T uint8_t)
|
||||
set(ZIP_INT16_T int16_t)
|
||||
set(ZIP_UINT16_T uint16_t)
|
||||
set(ZIP_INT32_T int32_t)
|
||||
set(ZIP_UINT32_T uint32_t)
|
||||
set(ZIP_INT64_T int64_t)
|
||||
set(ZIP_UINT64_T uint64_t)
|
||||
|
||||
if(HAVE_NULLABLE)
|
||||
set(ZIP_NULLABLE_DEFINES)
|
||||
|
||||
Vendored
+91
@@ -0,0 +1,91 @@
|
||||
This Font Software is licensed under the SIL Open Font License,
|
||||
Version 1.1. This license is copied below, and is also available
|
||||
with a FAQ at <http://scripts.sil.org/OFL>
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
Vendored
+33333
File diff suppressed because it is too large
Load Diff
Vendored
+1
-1
Submodule 3rdparty/rcheevos/rcheevos updated: 8afec6c55e...3cadf84c30
Vendored
+1
-1
@@ -28,7 +28,7 @@ add_library(pcsx2-zstd
|
||||
zstd/lib/decompress/zstd_decompress.c
|
||||
)
|
||||
|
||||
if(NOT MSVC AND ${PCSX2_TARGET_ARCHITECTURES} MATCHES "x86_64")
|
||||
if(_M_X86 AND (NOT MSVC OR USE_CLANG_CL))
|
||||
target_sources(pcsx2-zstd PRIVATE zstd/lib/decompress/huf_decompress_amd64.S)
|
||||
endif()
|
||||
|
||||
|
||||
+15
-8
@@ -1,8 +1,8 @@
|
||||
# Setting it to a range tells it that it supports the features on the newer
|
||||
# versions as well, avoiding setting policies.
|
||||
cmake_minimum_required(VERSION 3.16...3.24)
|
||||
cmake_minimum_required(VERSION 3.16...3.25)
|
||||
|
||||
#Enabling this cmake policy gets rid of warnings regarding LTO.
|
||||
# Enabling this cmake policy gets rid of warnings regarding LTO.
|
||||
cmake_policy(SET CMP0069 NEW)
|
||||
set(CMAKE_POLICY_DEFAULT_CMP0069 NEW)
|
||||
|
||||
@@ -11,7 +11,7 @@ if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR})
|
||||
endif()
|
||||
|
||||
# Project Name
|
||||
project(Pcsx2)
|
||||
project(Pcsx2 C CXX)
|
||||
|
||||
# Variable to check that people use the good file
|
||||
set(TOP_CMAKE_WAS_SOURCED TRUE)
|
||||
@@ -30,14 +30,11 @@ endif()
|
||||
include(Pcsx2Utils)
|
||||
|
||||
check_no_parenthesis_in_path()
|
||||
detectOperatingSystem()
|
||||
check_compiler_version("7.0" "7.0")
|
||||
detect_operating_system()
|
||||
detect_compiler()
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Include specific module
|
||||
# GNUInstallDirs must be done before BuildParameters
|
||||
include(GNUInstallDirs)
|
||||
# BuildParameters Must be done before SearchForStuff
|
||||
include(BuildParameters)
|
||||
include(SearchForStuff)
|
||||
|
||||
@@ -62,3 +59,13 @@ if(ACTUALLY_ENABLE_TESTS)
|
||||
add_subdirectory(tests/ctest)
|
||||
endif()
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
if(NOT IS_SUPPORTED_COMPILER)
|
||||
message(WARNING "
|
||||
*************** UNSUPPORTED CONFIGURATION ***************
|
||||
You are not compiling PCSX2 with a supported compiler.
|
||||
It may not even build successfully.
|
||||
PCSX2 only supports the Clang and MSVC compilers.
|
||||
No support will be provided, continue at your own risk.
|
||||
*********************************************************")
|
||||
endif()
|
||||
|
||||
+1
-68
@@ -6,13 +6,6 @@
|
||||
"patch": 0
|
||||
},
|
||||
"configurePresets": [
|
||||
{
|
||||
"name": "gcc-base",
|
||||
"displayName": "GCC Base",
|
||||
"description": "Base preset for GCC. Only for inheriting from.",
|
||||
"hidden": true,
|
||||
"binaryDir": "${sourceDir}/build"
|
||||
},
|
||||
{
|
||||
"name": "clang-base",
|
||||
"displayName": "Base",
|
||||
@@ -32,69 +25,9 @@
|
||||
"name": "ninja-multi",
|
||||
"displayName": "Ninja Multi Config",
|
||||
"description": "Generate multiple ninja build files.",
|
||||
"inherits": "gcc-base",
|
||||
"inherits": "clang-base",
|
||||
"generator": "Ninja Multi-Config"
|
||||
},
|
||||
{
|
||||
"name": "gcc-debug",
|
||||
"displayName": "GCC Debug",
|
||||
"description": "GCC Debug build with make.",
|
||||
"inherits": "gcc-base",
|
||||
"generator": "Unix Makefiles",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "gcc-devel",
|
||||
"displayName": "GCC Devel",
|
||||
"description": "GCC Developer build using make.",
|
||||
"inherits": "gcc-base",
|
||||
"generator": "Unix Makefiles",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Devel"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "gcc-release",
|
||||
"displayName": "GCC Release",
|
||||
"description": "GCC Release build using make.",
|
||||
"inherits": "gcc-base",
|
||||
"generator": "Unix Makefiles",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Release"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "gcc-debug-ninja",
|
||||
"displayName": "GCC Debug Ninja",
|
||||
"description": "Debug build using ninja.",
|
||||
"inherits": "gcc-base",
|
||||
"generator": "Ninja",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "gcc-devel-ninja",
|
||||
"displayName": "GCC Devel Ninja",
|
||||
"description": "GCC Developer build using ninja.",
|
||||
"inherits": "gcc-base",
|
||||
"generator": "Ninja",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Devel"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "gcc-release-ninja",
|
||||
"displayName": "GCC Release Ninja",
|
||||
"description": "GCC Release build using ninja.",
|
||||
"inherits": "gcc-base",
|
||||
"generator": "Ninja",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Release"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "clang-debug",
|
||||
"displayName": "Clang Debug",
|
||||
|
||||
@@ -10,51 +10,17 @@ PCSX2 is a free and open-source PlayStation 2 (PS2) emulator. Its purpose is to
|
||||
|
||||
## Project Details
|
||||
|
||||
The PCSX2 project has been running for more than twenty years. Past versions could only run a few public domain game demos, but newer versions can run most games at full speed, including popular titles such as Final Fantasy X and Devil May Cry 3. Visit the [PCSX2 compatibility list](https://pcsx2.net/compat/) to check the latest compatibility status of games (with more than 2500 titles tested), or ask for help in the [official forums](https://forums.pcsx2.net/).
|
||||
PCSX2 has been in development for more than 20 years. Past versions could only run a few public domain game demos, but newer versions can run most games at full speed, including popular titles such as Final Fantasy X and Devil May Cry 3. Visit the [PCSX2 compatibility list](https://pcsx2.net/compat/) to check the latest compatibility status of games (with more than 2500 titles tested).
|
||||
|
||||
The latest officially released stable version is version 1.6.0.
|
||||
|
||||
Installers and binaries for both stable and development builds are available from [our website](https://pcsx2.net/downloads/).
|
||||
Installers and binaries for both stable and nightly builds are available from [our website](https://pcsx2.net/downloads/).
|
||||
|
||||
## System Requirements
|
||||
|
||||
### Minimum
|
||||
PCSX2 supports Windows, Linux, and Mac platforms. Our [setup documentation page](https://pcsx2.net/docs/usage/setup/requirements) contains additional details on software and hardware requirements.
|
||||
|
||||
| Operating System | CPU | GPU | RAM |
|
||||
| ------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---- |
|
||||
| - Windows 10 Version 1809 or later (64-bit) <br/> - Ubuntu 22.04/Debian or newer, Arch Linux, or other distro (64-bit) <br/> - macOS 11.0 | - Supports SSE4.1 <br/> - [PassMark Thread Performance](https://www.cpubenchmark.net/CPU_mega_page.html) rating near or greater than 1500<br/> - Two physical cores, with hyperthreading | - Direct3D 11 (Feature Level 11.0) support <br/> - OpenGL 3.3 support <br/> - Vulkan 1.1 support <br/> - Metal support <br/> - [PassMark G3D Mark](https://www.videocardbenchmark.net/high_end_gpus.html) rating around 3000 (Geforce GTX 750, Radeon RX 560, Intel Arc A380) <br/> - 2 GB Video Memory | 4 GB |
|
||||
|
||||
### Recommended
|
||||
|
||||
| Operating System | CPU | GPU | RAM |
|
||||
| ----------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---- |
|
||||
| - Windows 10 22H2 (64-bit) <br/> - Ubuntu 23.04/Debian or newer, Arch Linux, or other distro (64-bit) <br/> - macOS 11.0 | - Supports AVX2 <br/> - [PassMark Single Thread Performance](https://www.cpubenchmark.net/CPU_mega_page.html) rating near or greater than 2000<br/> - Four physical cores, with or without hyperthreading | - Direct3D12 support <br/> - OpenGL 4.6 support <br/> - Vulkan 1.3 support <br/> - Metal support <br/> - [PassMark G3D Mark](https://www.videocardbenchmark.net/high_end_gpus.html) rating around 6000 (GeForce GTX 1650, Radeon RX 570) <br/> - 4 GB Video Memory | 8 GB |
|
||||
|
||||
### Heavy
|
||||
|
||||
| Operating System | CPU | GPU | RAM |
|
||||
| ----------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---- |
|
||||
| - Windows 10 22H2 (64-bit) <br/> - Ubuntu 23.04/Debian or newer, Arch Linux, or other distro (64-bit) <br/> - macOS 11.0 | - Supports AVX2 <br/> - [PassMark Single Thread Performance](https://www.cpubenchmark.net/CPU_mega_page.html) rating near or greater than 2600<br/> - Four physical cores, with or without hyperthreading | - Direct3D12 support <br/> - OpenGL 4.6 support <br/> - Vulkan 1.3 support <br/> - Metal support <br/> - [PassMark G3D Mark](https://www.videocardbenchmark.net/high_end_gpus.html) rating around 6000 (GeForce GTX 1650, Radeon RX 570) <br/> - 4 GB Video Memory | 8 GB |
|
||||
|
||||
_Note1: Recommended Single Thread Performance is based on moderately complex games. Games that pushed the PS2 hardware to its limits will struggle on CPUs at this level. Some release titles and 2D games which underutilized the PS2 hardware may run on CPUs rated as low as 1200. A quick reference for CPU **intensive games**: [Wiki](https://wiki.pcsx2.net/Category:CPU_intensive_games), [Forum](https://forums.pcsx2.net/Thread-LIST-The-Most-CPU-Intensive-Games) and CPU **light** games: [Forum](https://forums.pcsx2.net/Thread-LIST-Games-that-don-t-need-a-strong-CPU-to-emulate)_
|
||||
|
||||
_Note2: Recommended GPU is based on 3x Internal, ~1080p resolution requirements. Higher resolutions will require stronger cards; 6x Internal, ~4K resolution will require a [PassMark G3D Mark](https://www.videocardbenchmark.net/high_end_gpus.html) rating around 12000 (GeForce RTX 2060 Radeon RX 6600 Intel Arc A750). Just like CPU requirements, this is also highly game dependent. A quick reference for GPU **intensive games**: [Wiki](https://wiki.pcsx2.net/Category:GPU_intensive_games)_
|
||||
|
||||
## Technical Notes
|
||||
|
||||
- You need the [Visual C++ 2019 x64 Redistributables](https://support.microsoft.com/en-us/help/2977003/) to run PCSX2 on Windows.
|
||||
- Windows XP and Direct3D9 support was dropped after stable release 1.4.0.
|
||||
- Windows 7, Windows 8.0, and Windows 8.1 support was dropped after stable release 1.6.0.
|
||||
- 32-bit and wxWidgets support was dropped after stable release 1.6.0, with the wxWidgets code being removed completely on 25th December 2022.
|
||||
- Make sure to update your operating system and drivers to ensure you have the best experience possible. Having a newer GPU is also recommended so you have the latest supported drivers.
|
||||
- Because of copyright issues, and the complexity of trying to work around it, you need a BIOS dump extracted from a legitimately-owned PS2 console to use the emulator. For more information about the BIOS and how to get it from your console, visit [this page](pcsx2/Docs/PCSX2_FAQ.md#question-13-where-do-i-get-a-ps2-bios).
|
||||
- PCSX2 uses two CPU cores for emulation by default. A third core can be used via the MTVU speed hack, which is compatible with most games. This can be a significant speedup on CPUs with 3+ cores, but it may be a slowdown on GS-limited games (or on CPUs with fewer than 2 cores). Software renderers will then additionally use however many rendering threads it is set to and will need higher core counts to run efficiently.
|
||||
- Requirements benchmarks are based on a statistic from the Passmark CPU bench marking software. When we say "STR", we are referring to Passmark's "Single Thread Rating" statistic. You can look up your CPU on [Passmark's website for CPUs](https://cpubenchmark.net) to see how it compares to PCSX2's requirements.
|
||||
- Vulkan requires an up-to-date GPU driver; old drivers may cause graphical problems.
|
||||
Please note that a BIOS dump from a legitimately-owned PS2 console is required to use the emulator. For more information, visit [this page](https://pcsx2.net/docs/usage/setup/gather/#how-to-dump-your-ps2-bios).
|
||||
|
||||
## Contributing / Building
|
||||
Want to contribute to the development of PCSX2?
|
||||
PCSX2 supports translation into other languages using [Crowdin](https://crowdin.com/project/pcsx2-emulator).
|
||||
|
||||
See the [Contributing Guidelines](https://github.com/PCSX2/pcsx2/blob/master/.github/CONTRIBUTING.md) or visit the [GitHub Wiki](https://github.com/PCSX2/pcsx2/wiki)
|
||||
|
||||
Want more? [Check out the PCSX2 website](https://pcsx2.net/).
|
||||
See the [Contributing Guidelines](https://github.com/PCSX2/pcsx2/blob/master/.github/CONTRIBUTING.md) or visit the [GitHub Wiki](https://github.com/PCSX2/pcsx2/wiki) for more info on how to contribute.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+361
-280
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -352,7 +352,7 @@
|
||||
030000006d040000d2ca000000000000,Logitech Cordless Precision,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,
|
||||
030000006d04000011c2000000000000,Logitech Cordless Wingman,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b5,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b2,righttrigger:b7,rightx:a3,righty:a4,x:b4,platform:Windows,
|
||||
030000006d04000016c2000000000000,Logitech Dual Action,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,
|
||||
030000006d0400001dc2000000000000,Logitech F310,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,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
|
||||
030000006d0400001dc2000000000000,Logitech F310,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,rightx:a3,righty:a4,start:b7,x:b2,y:b3,lefttrigger:a2,righttrigger:a5,platform:Windows,
|
||||
030000006d04000018c2000000000000,Logitech F510,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,
|
||||
030000006d0400001ec2000000000000,Logitech F510,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,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
|
||||
030000006d04000019c2000000000000,Logitech F710,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,
|
||||
@@ -452,7 +452,7 @@
|
||||
03000000550900001072000000000000,NVIDIA Shield,a:b9,b:b8,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b3,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b2,righttrigger:a4,rightx:a2,righty:a5,start:b0,x:b7,y:b6,platform:Windows,
|
||||
030000005509000000b4000000000000,NVIDIA Virtual,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
|
||||
03000000120c00000288000000000000,Nyko Air Flo Xbox Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows,
|
||||
030000004b120000014d000000000000,Nyko Airflo,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:a3,leftstick:a0,lefttrigger:b6,rightshoulder:b5,rightstick:a2,righttrigger:b7,start:b9,x:b2,y:b3,platform:Windows,
|
||||
030000004b120000014d000000000000,NYKO Airflo EX,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Windows,
|
||||
03000000d62000001d57000000000000,Nyko Airflo 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,
|
||||
03000000791d00000900000000000000,Nyko Playpad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
|
||||
03000000782300000a10000000000000,Onlive Controller,a:b15,b:b14,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b11,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b13,y:b12,platform:Windows,
|
||||
@@ -534,6 +534,7 @@
|
||||
030000004c050000a00b000000000000,PS4 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:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
|
||||
030000004c050000c405000000000000,PS4 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:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
|
||||
030000004c050000cc09000000000000,PS4 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:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
|
||||
030000004c0500005f0e000000000000,PS5 Access 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:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
|
||||
030000004c050000e60c000000000000,PS5 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:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
|
||||
030000004c050000f20d000000000000,PS5 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:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows,
|
||||
03000000830500005020000000000000,PSX,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b2,y:b3,platform:Windows,
|
||||
@@ -558,8 +559,8 @@
|
||||
030000009b2800003200000000000000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows,
|
||||
030000009b2800006000000000000000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows,
|
||||
030000009b2800001800000000000000,Raphnet Jaguar Adapter,a:b2,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b10,start:b3,x:b11,y:b12,platform:Windows,
|
||||
030000009b2800006300000000000000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Windows,
|
||||
030000009b2800006100000000000000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Windows,
|
||||
030000009b2800006300000000000000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Windows,
|
||||
030000009b2800000200000000000000,Raphnet NES Adapter,a:b7,b:b6,back:b5,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,start:b4,platform:Windows,
|
||||
030000009b2800004400000000000000,Raphnet PS1 and PS2 Adapter,a:b1,b:b2,back:b5,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b9,rightx:a3,righty:a4,start:b4,x:b0,y:b3,platform:Windows,
|
||||
030000009b2800004300000000000000,Raphnet Saturn,a:b0,b:b1,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows,
|
||||
@@ -964,6 +965,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
030000004c050000c405000000000000,PS4 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: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,
|
||||
030000004c050000c405000000010000,PS4 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: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,
|
||||
030000004c050000cc09000000010000,PS4 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: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,
|
||||
0300004b4c0500005f0e000000010000,PS5 Access 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:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
|
||||
030000004c050000e60c000000010000,PS5 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:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
|
||||
030000004c050000f20d000000010000,PS5 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:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
|
||||
050000004c050000e60c000000010000,PS5 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:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X,
|
||||
@@ -1175,6 +1177,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000120c0000210e000011010000,Brook Mars PS4 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,
|
||||
03000000120c0000f70e000011010000,Brook Universal Fighting Board,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,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
|
||||
03000000e82000006058000001010000,Cideko AK08b,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,
|
||||
03000000af1e00002400000010010000,ClockworkPI DevTerm,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b9,x:b3,y:b0,platform:Linux,
|
||||
030000000b0400003365000000010000,Competition Pro,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,platform:Linux,
|
||||
03000000260900008888000000010000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Linux,
|
||||
03000000a306000022f6000011010000,Cyborg V3 Rumble,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux,
|
||||
@@ -1391,6 +1394,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000550900001072000011010000,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b8,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,
|
||||
03000000550900001472000011010000,NVIDIA Controller v01.04,a:b0,b:b1,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,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:Linux,
|
||||
05000000550900001472000001000000,NVIDIA Controller v01.04,a:b0,b:b1,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,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:Linux,
|
||||
030000004b120000014d000000010000,NYKO Airflo EX,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux,
|
||||
03000000451300000830000010010000,NYKO CORE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
|
||||
19000000010000000100000001010000,ODROID Go 2,a:b1,b:b0,dpdown:b7,dpleft:b8,dpright:b9,dpup:b6,guide:b10,leftshoulder:b4,leftstick:b12,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b13,righttrigger:b14,start:b15,x:b2,y:b3,platform:Linux,
|
||||
19000000010000000200000011000000,ODROID Go 2,a:b1,b:b0,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b12,leftshoulder:b4,leftstick:b14,lefttrigger:b13,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b15,righttrigger:b16,start:b17,x:b2,y:b3,platform:Linux,
|
||||
@@ -1409,7 +1413,7 @@ 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,
|
||||
030000006f0e00002801000011010000,PDP PS3 Rock Candy Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
030000006f0e00000901000011010000,PDP PS3 Versus Fighting,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
|
||||
030000006f0e00002f01000011010000,PDP Wired PS3 Controller,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,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,
|
||||
030000006f0e00002f01000011010000,PDP Wired 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,
|
||||
03000000ad1b000004f9000000010000,PDP Xbox 360 Versus Fighting,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000006f0e0000a802000023020000,PDP Xbox One Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
|
||||
030000006f0e0000a702000023020000,PDP Xbox One Raven Black,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
@@ -1466,6 +1470,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
050000004c050000cc09000000010000,PS4 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:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
|
||||
050000004c050000cc09000000810000,PS4 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:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
|
||||
050000004c050000cc09000001800000,PS4 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:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
|
||||
0300004b4c0500005f0e000011010000,PS5 Access 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:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
|
||||
030000004c050000e60c000011010000,PS5 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:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
|
||||
030000004c050000e60c000011810000,PS5 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:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
|
||||
030000004c050000f20d000011010000,PS5 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:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux,
|
||||
|
||||
@@ -742,6 +742,25 @@ float4 ps_color(PS_INPUT input)
|
||||
float4 T = sample_color(st, input.t.w);
|
||||
#endif
|
||||
|
||||
if (PS_SHUFFLE && !PS_SHUFFLE_SAME && !PS_READ16_SRC)
|
||||
{
|
||||
uint4 denorm_c_before = uint4(T);
|
||||
if (PS_READ_BA)
|
||||
{
|
||||
T.r = float((denorm_c_before.b << 3) & 0xF8);
|
||||
T.g = float(((denorm_c_before.b >> 2) & 0x38) | ((denorm_c_before.a << 6) & 0xC0));
|
||||
T.b = float((denorm_c_before.a << 1) & 0xF8);
|
||||
T.a = float(denorm_c_before.a & 0x80);
|
||||
}
|
||||
else
|
||||
{
|
||||
T.r = float((denorm_c_before.r << 3) & 0xF8);
|
||||
T.g = float(((denorm_c_before.r >> 2) & 0x38) | ((denorm_c_before.g << 6) & 0xC0));
|
||||
T.b = float((denorm_c_before.g << 1) & 0xF8);
|
||||
T.a = float(denorm_c_before.g & 0x80);
|
||||
}
|
||||
}
|
||||
|
||||
float4 C = tfx(T, input.c);
|
||||
|
||||
atst(C);
|
||||
@@ -925,48 +944,6 @@ PS_OUTPUT ps_main(PS_INPUT input)
|
||||
discard;
|
||||
}
|
||||
|
||||
if (PS_SHUFFLE)
|
||||
{
|
||||
uint4 denorm_c = uint4(C);
|
||||
uint2 denorm_TA = uint2(float2(TA.xy) * 255.0f + 0.5f);
|
||||
|
||||
// Special case for 32bit input and 16bit output, shuffle used by The Godfather
|
||||
if (PS_SHUFFLE_SAME)
|
||||
{
|
||||
if (PS_READ_BA)
|
||||
C = (float4)(float((denorm_c.b & 0x7Fu) | (denorm_c.a & 0x80u)));
|
||||
else
|
||||
C.ga = C.rg;
|
||||
}
|
||||
// Copy of a 16bit source in to this target
|
||||
else if (PS_READ16_SRC)
|
||||
{
|
||||
C.rb = (float2)float((denorm_c.r >> 3) | (((denorm_c.g >> 3) & 0x7u) << 5));
|
||||
if (denorm_c.a & 0x80u)
|
||||
C.ga = (float2)float((denorm_c.g >> 6) | ((denorm_c.b >> 3) << 2) | (denorm_TA.y & 0x80u));
|
||||
else
|
||||
C.ga = (float2)float((denorm_c.g >> 6) | ((denorm_c.b >> 3) << 2) | (denorm_TA.x & 0x80u));
|
||||
}
|
||||
// Write RB part. Mask will take care of the correct destination
|
||||
else if (PS_READ_BA)
|
||||
{
|
||||
C.rb = C.bb;
|
||||
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
|
||||
{
|
||||
C.rb = C.rr;
|
||||
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)));
|
||||
}
|
||||
}
|
||||
|
||||
// Must be done before alpha correction
|
||||
|
||||
// AA (Fixed one) will output a coverage of 1.0 as alpha
|
||||
@@ -1023,6 +1000,63 @@ PS_OUTPUT ps_main(PS_INPUT input)
|
||||
|
||||
ps_blend(C, alpha_blend, input.p.xy);
|
||||
|
||||
if (PS_SHUFFLE)
|
||||
{
|
||||
if (!PS_SHUFFLE_SAME && !PS_READ16_SRC)
|
||||
{
|
||||
uint4 denorm_c_after = uint4(C);
|
||||
if (PS_READ_BA)
|
||||
{
|
||||
C.b = float(((denorm_c_after.r >> 3) & 0x1F) | ((denorm_c_after.g << 2) & 0xE0));
|
||||
C.a = float(((denorm_c_after.g >> 6) & 0x3) | ((denorm_c_after.b >> 1) & 0x7C) | (denorm_c_after.a & 0x80));
|
||||
}
|
||||
else
|
||||
{
|
||||
C.r = float(((denorm_c_after.r >> 3) & 0x1F) | ((denorm_c_after.g << 2) & 0xE0));
|
||||
C.g = float(((denorm_c_after.g >> 6) & 0x3) | ((denorm_c_after.b >> 1) & 0x7C) | (denorm_c_after.a & 0x80));
|
||||
}
|
||||
}
|
||||
|
||||
uint4 denorm_c = uint4(C);
|
||||
uint2 denorm_TA = uint2(float2(TA.xy) * 255.0f + 0.5f);
|
||||
|
||||
// Special case for 32bit input and 16bit output, shuffle used by The Godfather
|
||||
if (PS_SHUFFLE_SAME)
|
||||
{
|
||||
if (PS_READ_BA)
|
||||
C = (float4)(float((denorm_c.b & 0x7Fu) | (denorm_c.a & 0x80u)));
|
||||
else
|
||||
C.ga = C.rg;
|
||||
}
|
||||
// Copy of a 16bit source in to this target
|
||||
else if (PS_READ16_SRC)
|
||||
{
|
||||
C.rb = (float2)float((denorm_c.r >> 3) | (((denorm_c.g >> 3) & 0x7u) << 5));
|
||||
if (denorm_c.a & 0x80u)
|
||||
C.ga = (float2)float((denorm_c.g >> 6) | ((denorm_c.b >> 3) << 2) | (denorm_TA.y & 0x80u));
|
||||
else
|
||||
C.ga = (float2)float((denorm_c.g >> 6) | ((denorm_c.b >> 3) << 2) | (denorm_TA.x & 0x80u));
|
||||
}
|
||||
// Write RB part. Mask will take care of the correct destination
|
||||
else if (PS_READ_BA)
|
||||
{
|
||||
C.rb = C.bb;
|
||||
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
|
||||
{
|
||||
C.rb = C.rr;
|
||||
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)));
|
||||
}
|
||||
}
|
||||
|
||||
ps_dither(C.rgb, input.p.xy);
|
||||
|
||||
// Color clamp/wrap needs to be done after sw blending and dithering
|
||||
|
||||
@@ -687,6 +687,21 @@ vec4 ps_color()
|
||||
vec4 T = sample_color(st);
|
||||
#endif
|
||||
|
||||
#if PS_SHUFFLE && !PS_SHUFFLE_SAME && !PS_READ16_SRC
|
||||
uvec4 denorm_c_before = uvec4(T);
|
||||
#if PS_READ_BA
|
||||
T.r = float((denorm_c_before.b << 3) & 0xF8);
|
||||
T.g = float(((denorm_c_before.b >> 2) & 0x38) | ((denorm_c_before.a << 6) & 0xC0));
|
||||
T.b = float((denorm_c_before.a << 1) & 0xF8);
|
||||
T.a = float(denorm_c_before.a & 0x80);
|
||||
#else
|
||||
T.r = float((denorm_c_before.r << 3) & 0xF8);
|
||||
T.g = float(((denorm_c_before.r >> 2) & 0x38) | ((denorm_c_before.g << 6) & 0xC0));
|
||||
T.b = float((denorm_c_before.g << 1) & 0xF8);
|
||||
T.a = float(denorm_c_before.g & 0x80);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
vec4 C = tfx(T, PSin.c);
|
||||
|
||||
atst(C);
|
||||
@@ -937,7 +952,56 @@ void ps_main()
|
||||
|
||||
vec4 C = ps_color();
|
||||
|
||||
// Must be done before alpha correction
|
||||
|
||||
// AA (Fixed one) will output a coverage of 1.0 as alpha
|
||||
#if PS_FIXED_ONE_A
|
||||
C.a = 128.0f;
|
||||
#endif
|
||||
|
||||
#if SW_AD_TO_HW
|
||||
vec4 RT = trunc(fetch_rt() * 255.0f + 0.1f);
|
||||
vec4 alpha_blend = vec4(RT.a / 128.0f);
|
||||
#else
|
||||
vec4 alpha_blend = vec4(C.a / 128.0f);
|
||||
#endif
|
||||
|
||||
// Correct the ALPHA value based on the output format
|
||||
#if (PS_DST_FMT == FMT_16)
|
||||
float A_one = 128.0f; // alpha output will be 0x80
|
||||
C.a = (PS_FBA != 0) ? A_one : step(128.0f, C.a) * A_one;
|
||||
#elif (PS_DST_FMT == FMT_32) && (PS_FBA != 0)
|
||||
if(C.a < 128.0f) C.a += 128.0f;
|
||||
#endif
|
||||
|
||||
// Get first primitive that will write a failling alpha value
|
||||
#if PS_DATE == 1
|
||||
// DATM == 0
|
||||
// Pixel with alpha equal to 1 will failed (128-255)
|
||||
SV_Target0 = (C.a > 127.5f) ? vec4(gl_PrimitiveID) : vec4(0x7FFFFFFF);
|
||||
return;
|
||||
#elif PS_DATE == 2
|
||||
// DATM == 1
|
||||
// Pixel with alpha equal to 0 will failed (0-127)
|
||||
SV_Target0 = (C.a < 127.5f) ? vec4(gl_PrimitiveID) : vec4(0x7FFFFFFF);
|
||||
return;
|
||||
#endif
|
||||
|
||||
ps_blend(C, alpha_blend);
|
||||
|
||||
|
||||
#if PS_SHUFFLE
|
||||
#if !PS_SHUFFLE_SAME && !PS_READ16_SRC
|
||||
uvec4 denorm_c_after = uvec4(C);
|
||||
#if PS_READ_BA
|
||||
C.b = float(((denorm_c_after.r >> 3) & 0x1F) | ((denorm_c_after.g << 2) & 0xE0));
|
||||
C.a = float(((denorm_c_after.g >> 6) & 0x3) | ((denorm_c_after.b >> 1) & 0x7C) | (denorm_c_after.a & 0x80));
|
||||
#else
|
||||
C.r = float(((denorm_c_after.r >> 3) & 0x1F) | ((denorm_c_after.g << 2) & 0xE0));
|
||||
C.g = float(((denorm_c_after.g >> 6) & 0x3) | ((denorm_c_after.b >> 1) & 0x7C) | (denorm_c_after.a & 0x80));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
uvec4 denorm_c = uvec4(C);
|
||||
uvec2 denorm_TA = uvec2(vec2(TA.xy) * 255.0f + 0.5f);
|
||||
|
||||
@@ -991,43 +1055,6 @@ void ps_main()
|
||||
#endif // PS_SHUFFLE_SAME
|
||||
#endif // PS_SHUFFLE
|
||||
|
||||
// Must be done before alpha correction
|
||||
|
||||
// AA (Fixed one) will output a coverage of 1.0 as alpha
|
||||
#if PS_FIXED_ONE_A
|
||||
C.a = 128.0f;
|
||||
#endif
|
||||
|
||||
#if SW_AD_TO_HW
|
||||
vec4 RT = trunc(fetch_rt() * 255.0f + 0.1f);
|
||||
vec4 alpha_blend = vec4(RT.a / 128.0f);
|
||||
#else
|
||||
vec4 alpha_blend = vec4(C.a / 128.0f);
|
||||
#endif
|
||||
|
||||
// Correct the ALPHA value based on the output format
|
||||
#if (PS_DST_FMT == FMT_16)
|
||||
float A_one = 128.0f; // alpha output will be 0x80
|
||||
C.a = (PS_FBA != 0) ? A_one : step(128.0f, C.a) * A_one;
|
||||
#elif (PS_DST_FMT == FMT_32) && (PS_FBA != 0)
|
||||
if(C.a < 128.0f) C.a += 128.0f;
|
||||
#endif
|
||||
|
||||
// Get first primitive that will write a failling alpha value
|
||||
#if PS_DATE == 1
|
||||
// DATM == 0
|
||||
// Pixel with alpha equal to 1 will failed (128-255)
|
||||
SV_Target0 = (C.a > 127.5f) ? vec4(gl_PrimitiveID) : vec4(0x7FFFFFFF);
|
||||
return;
|
||||
#elif PS_DATE == 2
|
||||
// DATM == 1
|
||||
// Pixel with alpha equal to 0 will failed (0-127)
|
||||
SV_Target0 = (C.a < 127.5f) ? vec4(gl_PrimitiveID) : vec4(0x7FFFFFFF);
|
||||
return;
|
||||
#endif
|
||||
|
||||
ps_blend(C, alpha_blend);
|
||||
|
||||
ps_dither(C.rgb);
|
||||
|
||||
// Color clamp/wrap needs to be done after sw blending and dithering
|
||||
|
||||
@@ -933,6 +933,21 @@ vec4 ps_color()
|
||||
vec4 T = sample_color(st);
|
||||
#endif
|
||||
|
||||
#if PS_SHUFFLE && !PS_SHUFFLE_SAME && !PS_READ16_SRC
|
||||
uvec4 denorm_c_before = uvec4(T);
|
||||
#if PS_READ_BA
|
||||
T.r = float((denorm_c_before.b << 3) & 0xF8);
|
||||
T.g = float(((denorm_c_before.b >> 2) & 0x38) | ((denorm_c_before.a << 6) & 0xC0));
|
||||
T.b = float((denorm_c_before.a << 1) & 0xF8);
|
||||
T.a = float(denorm_c_before.a & 0x80);
|
||||
#else
|
||||
T.r = float((denorm_c_before.r << 3) & 0xF8);
|
||||
T.g = float(((denorm_c_before.r >> 2) & 0x38) | ((denorm_c_before.g << 6) & 0xC0));
|
||||
T.b = float((denorm_c_before.g << 1) & 0xF8);
|
||||
T.a = float(denorm_c_before.g & 0x80);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
vec4 C = tfx(T, vsIn.c);
|
||||
|
||||
atst(C);
|
||||
@@ -1184,40 +1199,6 @@ 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);
|
||||
|
||||
// Special case for 32bit input and 16bit output, shuffle used by The Godfather
|
||||
#if PS_SHUFFLE_SAME
|
||||
#if (PS_READ_BA)
|
||||
C = vec4(float((denorm_c.b & 0x7Fu) | (denorm_c.a & 0x80u)));
|
||||
#else
|
||||
C.ga = C.rg;
|
||||
#endif
|
||||
// Copy of a 16bit source in to this target
|
||||
#elif PS_READ16_SRC
|
||||
C.rb = vec2(float((denorm_c.r >> 3) | (((denorm_c.g >> 3) & 0x7u) << 5)));
|
||||
if ((denorm_c.a & 0x80u) != 0u)
|
||||
C.ga = vec2(float((denorm_c.g >> 6) | ((denorm_c.b >> 3) << 2) | (denorm_TA.y & 0x80u)));
|
||||
else
|
||||
C.ga = vec2(float((denorm_c.g >> 6) | ((denorm_c.b >> 3) << 2) | (denorm_TA.x & 0x80u)));
|
||||
// Write RB part. Mask will take care of the correct destination
|
||||
#elif PS_READ_BA
|
||||
C.rb = C.bb;
|
||||
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
|
||||
C.rb = C.rr;
|
||||
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 // PS_SHUFFLE_SAME
|
||||
#endif // PS_SHUFFLE
|
||||
|
||||
// Must be done before alpha correction
|
||||
|
||||
// AA (Fixed one) will output a coverage of 1.0 as alpha
|
||||
@@ -1254,9 +1235,53 @@ void main()
|
||||
o_col0 = (C.a < 127.5f) ? vec4(gl_PrimitiveID) : vec4(0x7FFFFFFF);
|
||||
|
||||
#else
|
||||
|
||||
ps_blend(C, alpha_blend);
|
||||
|
||||
#if PS_SHUFFLE
|
||||
#if !PS_SHUFFLE_SAME && !PS_READ16_SRC
|
||||
uvec4 denorm_c_after = uvec4(C);
|
||||
#if PS_READ_BA
|
||||
C.b = float(((denorm_c_after.r >> 3) & 0x1F) | ((denorm_c_after.g << 2) & 0xE0));
|
||||
C.a = float(((denorm_c_after.g >> 6) & 0x3) | ((denorm_c_after.b >> 1) & 0x7C) | (denorm_c_after.a & 0x80));
|
||||
#else
|
||||
C.r = float(((denorm_c_after.r >> 3) & 0x1F) | ((denorm_c_after.g << 2) & 0xE0));
|
||||
C.g = float(((denorm_c_after.g >> 6) & 0x3) | ((denorm_c_after.b >> 1) & 0x7C) | (denorm_c_after.a & 0x80));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
uvec4 denorm_c = uvec4(C);
|
||||
uvec2 denorm_TA = uvec2(vec2(TA.xy) * 255.0f + 0.5f);
|
||||
|
||||
// Special case for 32bit input and 16bit output, shuffle used by The Godfather
|
||||
#if PS_SHUFFLE_SAME
|
||||
#if (PS_READ_BA)
|
||||
C = vec4(float((denorm_c.b & 0x7Fu) | (denorm_c.a & 0x80u)));
|
||||
#else
|
||||
C.ga = C.rg;
|
||||
#endif
|
||||
// Copy of a 16bit source in to this target
|
||||
#elif PS_READ16_SRC
|
||||
C.rb = vec2(float((denorm_c.r >> 3) | (((denorm_c.g >> 3) & 0x7u) << 5)));
|
||||
if ((denorm_c.a & 0x80u) != 0u)
|
||||
C.ga = vec2(float((denorm_c.g >> 6) | ((denorm_c.b >> 3) << 2) | (denorm_TA.y & 0x80u)));
|
||||
else
|
||||
C.ga = vec2(float((denorm_c.g >> 6) | ((denorm_c.b >> 3) << 2) | (denorm_TA.x & 0x80u)));
|
||||
// Write RB part. Mask will take care of the correct destination
|
||||
#elif PS_READ_BA
|
||||
C.rb = C.bb;
|
||||
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
|
||||
C.rb = C.rr;
|
||||
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 // PS_SHUFFLE_SAME
|
||||
#endif // PS_SHUFFLE
|
||||
|
||||
ps_dither(C.rgb);
|
||||
|
||||
// Color clamp/wrap needs to be done after sw blending and dithering
|
||||
|
||||
+29
-65
@@ -38,21 +38,6 @@ endif()
|
||||
#-------------------------------------------------------------------------------
|
||||
option(USE_ASAN "Enable address sanitizer")
|
||||
|
||||
if(MSVC AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
set(USE_CLANG_CL TRUE)
|
||||
message(STATUS "Building with Clang-CL.")
|
||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
|
||||
set(USE_CLANG TRUE)
|
||||
message(STATUS "Building with Clang/LLVM.")
|
||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
set(USE_GCC TRUE)
|
||||
message(STATUS "Building with GNU GCC")
|
||||
elseif(MSVC)
|
||||
message(STATUS "Building with MSVC")
|
||||
else()
|
||||
message(FATAL_ERROR "Unknown compiler: ${CMAKE_CXX_COMPILER_ID}")
|
||||
endif()
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# if no build type is set, use Devel as default
|
||||
# Note without the CMAKE_BUILD_TYPE options the value is still defined to ""
|
||||
@@ -81,52 +66,41 @@ mark_as_advanced(CMAKE_C_FLAGS_DEVEL CMAKE_CXX_FLAGS_DEVEL CMAKE_LINKER_FLAGS_DE
|
||||
#-------------------------------------------------------------------------------
|
||||
# Select the architecture
|
||||
#-------------------------------------------------------------------------------
|
||||
option(DISABLE_ADVANCE_SIMD "Disable advance use of SIMD (SSE2+ & AVX)" OFF)
|
||||
if("${CMAKE_HOST_SYSTEM_PROCESSOR}" STREQUAL "x86_64" OR "${CMAKE_HOST_SYSTEM_PROCESSOR}" STREQUAL "amd64" OR
|
||||
"${CMAKE_HOST_SYSTEM_PROCESSOR}" STREQUAL "AMD64" OR "${CMAKE_OSX_ARCHITECTURES}" STREQUAL "x86_64")
|
||||
# Multi-ISA only exists on x86.
|
||||
option(DISABLE_ADVANCE_SIMD "Disable advance use of SIMD (SSE2+ & AVX)" OFF)
|
||||
|
||||
# Print if we are cross compiling.
|
||||
if(CMAKE_CROSSCOMPILING)
|
||||
message(STATUS "Cross compilation is enabled.")
|
||||
else()
|
||||
message(STATUS "Cross compilation is disabled.")
|
||||
endif()
|
||||
|
||||
# Architecture bitness detection
|
||||
include(TargetArch)
|
||||
target_architecture(PCSX2_TARGET_ARCHITECTURES)
|
||||
if(${PCSX2_TARGET_ARCHITECTURES} MATCHES "x86_64")
|
||||
message(STATUS "Compiling a ${PCSX2_TARGET_ARCHITECTURES} build on a ${CMAKE_HOST_SYSTEM_PROCESSOR} host.")
|
||||
|
||||
# x86_64 requires -fPIC
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
if(NOT DEFINED ARCH_FLAG AND NOT MSVC)
|
||||
if (DISABLE_ADVANCE_SIMD)
|
||||
set(ARCH_FLAG "-msse -msse2 -msse4.1 -mfxsr")
|
||||
else()
|
||||
#set(ARCH_FLAG "-march=native -fabi-version=6")
|
||||
set(ARCH_FLAG "-march=native")
|
||||
endif()
|
||||
elseif(NOT DEFINED ARCH_FLAG AND USE_CLANG_CL)
|
||||
set(ARCH_FLAG "-msse4.1")
|
||||
endif()
|
||||
list(APPEND PCSX2_DEFS _M_X86=1)
|
||||
set(_M_X86 1)
|
||||
set(_M_X86 TRUE)
|
||||
if(DISABLE_ADVANCE_SIMD)
|
||||
message(STATUS "Building for x86-64 (Multi-ISA).")
|
||||
else()
|
||||
message(STATUS "Building for x86-64.")
|
||||
endif()
|
||||
|
||||
# SSE4.1 is not set by MSVC, it uses _M_SSE instead.
|
||||
if(MSVC)
|
||||
# SSE4.1 is not set by MSVC, it uses _M_SSE instead.
|
||||
list(APPEND PCSX2_DEFS __SSE4_1__=1)
|
||||
|
||||
if(USE_CLANG_CL)
|
||||
# clang-cl => need to explicitly enable SSE4.1.
|
||||
add_compile_options("-msse4.1")
|
||||
endif()
|
||||
else()
|
||||
# Multi-ISA => SSE4, otherwise native.
|
||||
if (DISABLE_ADVANCE_SIMD)
|
||||
add_compile_options("-msse" "-msse2" "-msse4.1" "-mfxsr")
|
||||
else()
|
||||
# Can't use march=native on Apple Silicon.
|
||||
if(NOT APPLE OR "${CMAKE_HOST_SYSTEM_PROCESSOR}" STREQUAL "x86_64")
|
||||
add_compile_options("-march=native")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
message(FATAL_ERROR "Unsupported architecture: ${PCSX2_TARGET_ARCHITECTURES}")
|
||||
message(FATAL_ERROR "Unsupported architecture: ${CMAKE_HOST_SYSTEM_PROCESSOR}")
|
||||
endif()
|
||||
string(REPLACE " " ";" ARCH_FLAG_LIST "${ARCH_FLAG}")
|
||||
add_compile_options("${ARCH_FLAG_LIST}")
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Set some default compiler flags
|
||||
#-------------------------------------------------------------------------------
|
||||
option(USE_PGO_GENERATE "Enable PGO optimization (generate profile)")
|
||||
option(USE_PGO_OPTIMIZE "Enable PGO optimization (use profile)")
|
||||
|
||||
# Require C++20.
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
@@ -183,7 +157,7 @@ endif()
|
||||
|
||||
# Enable debug information in release builds for Linux.
|
||||
# Makes the backtrace actually meaningful.
|
||||
if(UNIX AND NOT APPLE)
|
||||
if(LINUX)
|
||||
add_compile_options($<$<CONFIG:Release>:-g1>)
|
||||
endif()
|
||||
|
||||
@@ -221,22 +195,12 @@ endif()
|
||||
|
||||
# -Wno-attributes: "always_inline function might not be inlinable" <= real spam (thousand of warnings!!!)
|
||||
# -Wno-missing-field-initializers: standard allow to init only the begin of struct/array in static init. Just a silly warning.
|
||||
# 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-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-format -Wno-format-security -Wno-unused-value)
|
||||
endif()
|
||||
|
||||
if (USE_GCC)
|
||||
list(APPEND DEFAULT_WARNINGS -Wno-stringop-truncation -Wno-stringop-overflow -Wno-maybe-uninitialized )
|
||||
set(DEFAULT_WARNINGS -Wall -Wextra -Wno-unused-function -Wno-unused-parameter -Wno-missing-field-initializers)
|
||||
endif()
|
||||
|
||||
if (USE_PGO_GENERATE OR USE_PGO_OPTIMIZE)
|
||||
|
||||
@@ -7,7 +7,7 @@ endmacro()
|
||||
macro(check_lib var lib)
|
||||
set(_arg_list ${ARGN})
|
||||
|
||||
if(PKG_CONFIG_FOUND AND NOT CMAKE_CROSSCOMPILING AND NOT DEFINED pcsx2_manually_found_${var})
|
||||
if(PKG_CONFIG_FOUND AND NOT DEFINED pcsx2_manually_found_${var})
|
||||
string(TOLOWER ${lib} lower_lib)
|
||||
pkg_search_module(${var} QUIET IMPORTED_TARGET ${lower_lib})
|
||||
endif()
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# Finds liblz4.
|
||||
#
|
||||
# This module defines:
|
||||
# LZ4_FOUND
|
||||
# LZ4_INCLUDE_DIR
|
||||
# LZ4_LIBRARY
|
||||
#
|
||||
|
||||
find_path(LZ4_INCLUDE_DIR NAMES lz4.h)
|
||||
|
||||
find_library(LZ4_LIBRARY_DEBUG NAMES lz4d)
|
||||
find_library(LZ4_LIBRARY_RELEASE NAMES lz4)
|
||||
|
||||
include(SelectLibraryConfigurations)
|
||||
SELECT_LIBRARY_CONFIGURATIONS(LZ4)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(
|
||||
LZ4 DEFAULT_MSG
|
||||
LZ4_LIBRARY LZ4_INCLUDE_DIR
|
||||
)
|
||||
|
||||
mark_as_advanced(LZ4_INCLUDE_DIR LZ4_LIBRARY)
|
||||
|
||||
if(LZ4_FOUND AND NOT (TARGET LZ4::LZ4))
|
||||
add_library (LZ4::LZ4 UNKNOWN IMPORTED)
|
||||
set_target_properties(LZ4::LZ4
|
||||
PROPERTIES
|
||||
IMPORTED_LOCATION ${LZ4_LIBRARY}
|
||||
INTERFACE_INCLUDE_DIRECTORIES ${LZ4_INCLUDE_DIR})
|
||||
endif()
|
||||
@@ -1,32 +0,0 @@
|
||||
# Once done, this will define
|
||||
#
|
||||
# LIBC_FOUND - system has libc
|
||||
# LIBC_LIBRARIES - link these to use libc
|
||||
|
||||
if(LIBC_LIBRARIES)
|
||||
set(LIBC_FIND_QUIETLY TRUE)
|
||||
endif(LIBC_LIBRARIES)
|
||||
|
||||
find_library(libm NAMES m)
|
||||
|
||||
# OSX doesn't have rt. On Linux timer and aio dependency.
|
||||
if(APPLE)
|
||||
find_library(libdl NAMES dl)
|
||||
set(LIBC_LIBRARIES ${librt} ${libdl} ${libm})
|
||||
elseif(Linux)
|
||||
find_library(libdl NAMES dl)
|
||||
find_library(librt NAMES rt)
|
||||
set(LIBC_LIBRARIES ${librt} ${libdl} ${libm})
|
||||
else()
|
||||
# FreeBSD doesn't have libdl
|
||||
find_library(librt NAMES rt)
|
||||
set(LIBC_LIBRARIES ${librt} ${libm})
|
||||
endif()
|
||||
|
||||
# handle the QUIETLY and REQUIRED arguments and set LIBC_FOUND to TRUE if
|
||||
# all listed variables are TRUE
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(Libc DEFAULT_MSG LIBC_LIBRARIES)
|
||||
|
||||
mark_as_advanced(LIBC_LIBRARIES)
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
# Copyright (C) 2020 Sony Interactive Entertainment Inc.
|
||||
# Copyright (C) 2012 Raphael Kubo da Costa <rakuco@webkit.org>
|
||||
# Copyright (C) 2013 Igalia S.L.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND ITS CONTRIBUTORS ``AS
|
||||
# IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR ITS
|
||||
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#[=======================================================================[.rst:
|
||||
FindWebP
|
||||
--------------
|
||||
|
||||
Find WebP headers and libraries.
|
||||
|
||||
Imported Targets
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
``WebP::libwebp``
|
||||
The WebP library, if found.
|
||||
|
||||
``WebP::demux``
|
||||
The WebP demux library, if found.
|
||||
|
||||
Result Variables
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
This will define the following variables in your project:
|
||||
|
||||
``WebP_FOUND``
|
||||
true if (the requested version of) WebP is available.
|
||||
``WebP_VERSION``
|
||||
the version of WebP.
|
||||
``WebP_LIBRARIES``
|
||||
the libraries to link against to use WebP.
|
||||
``WebP_INCLUDE_DIRS``
|
||||
where to find the WebP headers.
|
||||
``WebP_COMPILE_OPTIONS``
|
||||
this should be passed to target_compile_options(), if the
|
||||
target is not used for linking
|
||||
|
||||
#]=======================================================================]
|
||||
|
||||
find_package(PkgConfig QUIET)
|
||||
pkg_check_modules(PC_WEBP QUIET libwebp)
|
||||
set(WebP_COMPILE_OPTIONS ${PC_WEBP_CFLAGS_OTHER})
|
||||
set(WebP_VERSION ${PC_WEBP_CFLAGS_VERSION})
|
||||
|
||||
find_path(WebP_INCLUDE_DIR
|
||||
NAMES webp/decode.h
|
||||
HINTS ${PC_WEBP_INCLUDEDIR} ${PC_WEBP_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
find_library(WebP_LIBRARY
|
||||
NAMES ${WebP_NAMES} webp libwebp
|
||||
HINTS ${PC_WEBP_LIBDIR} ${PC_WEBP_LIBRARY_DIRS}
|
||||
)
|
||||
|
||||
# There's nothing in the WebP headers that could be used to detect the exact
|
||||
# WebP version being used so don't attempt to do so. A version can only be found
|
||||
# through pkg-config
|
||||
if ("${WebP_FIND_VERSION}" VERSION_GREATER "${WebP_VERSION}")
|
||||
if (WebP_VERSION)
|
||||
message(FATAL_ERROR "Required version (" ${WebP_FIND_VERSION} ") is higher than found version (" ${WebP_VERSION} ")")
|
||||
else ()
|
||||
message(WARNING "Cannot determine WebP version without pkg-config")
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
# Find components
|
||||
if (WebP_INCLUDE_DIR AND WebP_LIBRARY)
|
||||
set(_WebP_REQUIRED_LIBS_FOUND ON)
|
||||
set(WebP_LIBS_FOUND "WebP (required): ${WebP_LIBRARY}")
|
||||
else ()
|
||||
set(_WebP_REQUIRED_LIBS_FOUND OFF)
|
||||
set(WebP_LIBS_NOT_FOUND "WebP (required)")
|
||||
endif ()
|
||||
|
||||
if ("demux" IN_LIST WebP_FIND_COMPONENTS)
|
||||
find_library(WebP_DEMUX_LIBRARY
|
||||
NAMES ${WebP_DEMUX_NAMES} webpdemux libwebpdemux
|
||||
HINTS ${PC_WEBP_LIBDIR} ${PC_WEBP_LIBRARY_DIRS}
|
||||
)
|
||||
|
||||
if (WebP_DEMUX_LIBRARY)
|
||||
if (WebP_FIND_REQUIRED_demux)
|
||||
list(APPEND WebP_LIBS_FOUND "demux (required): ${WebP_DEMUX_LIBRARY}")
|
||||
else ()
|
||||
list(APPEND WebP_LIBS_FOUND "demux (optional): ${WebP_DEMUX_LIBRARY}")
|
||||
endif ()
|
||||
else ()
|
||||
if (WebP_FIND_REQUIRED_demux)
|
||||
set(_WebP_REQUIRED_LIBS_FOUND OFF)
|
||||
list(APPEND WebP_LIBS_NOT_FOUND "demux (required)")
|
||||
else ()
|
||||
list(APPEND WebP_LIBS_NOT_FOUND "demux (optional)")
|
||||
endif ()
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
if (NOT WebP_FIND_QUIETLY)
|
||||
if (WebP_LIBS_FOUND)
|
||||
message(STATUS "Found the following WebP libraries:")
|
||||
foreach (found ${WebP_LIBS_FOUND})
|
||||
message(STATUS " ${found}")
|
||||
endforeach ()
|
||||
endif ()
|
||||
if (WebP_LIBS_NOT_FOUND)
|
||||
message(STATUS "The following WebP libraries were not found:")
|
||||
foreach (found ${WebP_LIBS_NOT_FOUND})
|
||||
message(STATUS " ${found}")
|
||||
endforeach ()
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(WebP
|
||||
FOUND_VAR WebP_FOUND
|
||||
REQUIRED_VARS WebP_INCLUDE_DIR WebP_LIBRARY _WebP_REQUIRED_LIBS_FOUND
|
||||
VERSION_VAR WebP_VERSION
|
||||
)
|
||||
|
||||
if (WebP_LIBRARY AND NOT TARGET WebP::libwebp)
|
||||
add_library(WebP::libwebp UNKNOWN IMPORTED GLOBAL)
|
||||
set_target_properties(WebP::libwebp PROPERTIES
|
||||
IMPORTED_LOCATION "${WebP_LIBRARY}"
|
||||
INTERFACE_COMPILE_OPTIONS "${WebP_COMPILE_OPTIONS}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${WebP_INCLUDE_DIR}"
|
||||
)
|
||||
endif ()
|
||||
|
||||
if (WebP_DEMUX_LIBRARY AND NOT TARGET WebP::demux)
|
||||
add_library(WebP::demux UNKNOWN IMPORTED GLOBAL)
|
||||
set_target_properties(WebP::demux PROPERTIES
|
||||
IMPORTED_LOCATION "${WebP_DEMUX_LIBRARY}"
|
||||
INTERFACE_COMPILE_OPTIONS "${WebP_COMPILE_OPTIONS}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${WebP_INCLUDE_DIR}"
|
||||
)
|
||||
endif ()
|
||||
|
||||
mark_as_advanced(
|
||||
WebP_INCLUDE_DIR
|
||||
WebP_LIBRARY
|
||||
WebP_DEMUX_LIBRARY
|
||||
)
|
||||
|
||||
if (WebP_FOUND)
|
||||
set(WebP_LIBRARIES ${WebP_LIBRARY} ${WebP_DEMUX_LIBRARY})
|
||||
set(WebP_INCLUDE_DIRS ${WebP_INCLUDE_DIR})
|
||||
endif ()
|
||||
@@ -0,0 +1,45 @@
|
||||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
#
|
||||
# - Try to find Facebook zstd library
|
||||
# This will define
|
||||
# Zstd_FOUND
|
||||
# Zstd_INCLUDE_DIR
|
||||
# Zstd_LIBRARY
|
||||
#
|
||||
|
||||
find_path(Zstd_INCLUDE_DIR NAMES zstd.h)
|
||||
|
||||
find_library(Zstd_LIBRARY_DEBUG NAMES zstdd zstd_staticd)
|
||||
find_library(Zstd_LIBRARY_RELEASE NAMES zstd zstd_static)
|
||||
|
||||
include(SelectLibraryConfigurations)
|
||||
SELECT_LIBRARY_CONFIGURATIONS(Zstd)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(
|
||||
Zstd DEFAULT_MSG
|
||||
Zstd_LIBRARY Zstd_INCLUDE_DIR
|
||||
)
|
||||
|
||||
mark_as_advanced(Zstd_INCLUDE_DIR Zstd_LIBRARY)
|
||||
|
||||
if(Zstd_FOUND AND NOT (TARGET Zstd::Zstd))
|
||||
add_library (Zstd::Zstd UNKNOWN IMPORTED)
|
||||
set_target_properties(Zstd::Zstd
|
||||
PROPERTIES
|
||||
IMPORTED_LOCATION ${Zstd_LIBRARY}
|
||||
INTERFACE_INCLUDE_DIRECTORIES ${Zstd_INCLUDE_DIR})
|
||||
endif()
|
||||
+57
-74
@@ -1,38 +1,45 @@
|
||||
#-------------------------------------------------------------------------------
|
||||
# detectOperatingSystem
|
||||
#-------------------------------------------------------------------------------
|
||||
# This function detects on which OS cmake is run and set a flag to control the
|
||||
# build process. Supported OS: Linux, MacOSX, Windows
|
||||
#
|
||||
# On linux, it also set a flag for specific distribution (ie Fedora)
|
||||
#-------------------------------------------------------------------------------
|
||||
function(detectOperatingSystem)
|
||||
function(detect_operating_system)
|
||||
message(STATUS "CMake Version: ${CMAKE_VERSION}")
|
||||
message(STATUS "CMake System Name: ${CMAKE_SYSTEM_NAME}")
|
||||
|
||||
# LINUX wasn't added until CMake 3.25.
|
||||
if (CMAKE_VERSION VERSION_LESS 3.25.0 AND CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||
# Have to make it visible in this scope as well for below.
|
||||
set(LINUX TRUE PARENT_SCOPE)
|
||||
set(LINUX TRUE)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
set(Windows TRUE PARENT_SCOPE)
|
||||
elseif(UNIX AND APPLE)
|
||||
if(IOS)
|
||||
message(WARNING "iOS isn't supported, the build will most likely fail")
|
||||
endif()
|
||||
set(MacOSX TRUE PARENT_SCOPE)
|
||||
elseif(UNIX)
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||
set(Linux TRUE PARENT_SCOPE)
|
||||
if (EXISTS /etc/os-release)
|
||||
# Read the file without CR character
|
||||
file(STRINGS /etc/os-release OS_RELEASE)
|
||||
if("${OS_RELEASE}" MATCHES "^.*ID=fedora.*$")
|
||||
set(Fedora TRUE PARENT_SCOPE)
|
||||
message(STATUS "Build Fedora specific")
|
||||
elseif("${OS_RELEASE}" MATCHES "^.*ID=.*suse.*$")
|
||||
set(openSUSE TRUE PARENT_SCOPE)
|
||||
message(STATUS "Build openSUSE specific")
|
||||
endif()
|
||||
endif()
|
||||
elseif(CMAKE_SYSTEM_NAME MATCHES "kFreeBSD")
|
||||
set(kFreeBSD TRUE PARENT_SCOPE)
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "GNU")
|
||||
set(GNU TRUE PARENT_SCOPE)
|
||||
endif()
|
||||
message(STATUS "Building for Windows.")
|
||||
elseif(APPLE AND NOT IOS)
|
||||
message(STATUS "Building for MacOS.")
|
||||
elseif(LINUX)
|
||||
message(STATUS "Building for Linux.")
|
||||
elseif(BSD)
|
||||
message(STATUS "Building for *BSD.")
|
||||
else()
|
||||
message(FATAL_ERROR "Unsupported platform.")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(detect_compiler)
|
||||
if(MSVC AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
set(USE_CLANG_CL TRUE PARENT_SCOPE)
|
||||
set(IS_SUPPORTED_COMPILER TRUE PARENT_SCOPE)
|
||||
message(STATUS "Building with Clang-CL.")
|
||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
|
||||
set(USE_CLANG TRUE PARENT_SCOPE)
|
||||
set(IS_SUPPORTED_COMPILER TRUE PARENT_SCOPE)
|
||||
message(STATUS "Building with Clang/LLVM.")
|
||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
set(USE_GCC TRUE PARENT_SCOPE)
|
||||
set(IS_SUPPORTED_COMPILER FALSE PARENT_SCOPE)
|
||||
message(STATUS "Building with GNU GCC.")
|
||||
elseif(MSVC)
|
||||
set(IS_SUPPORTED_COMPILER TRUE PARENT_SCOPE)
|
||||
message(STATUS "Building with MSVC.")
|
||||
else()
|
||||
message(FATAL_ERROR "Unknown compiler: ${CMAKE_CXX_COMPILER_ID}")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
@@ -54,11 +61,24 @@ function(get_git_version_info)
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_QUIET)
|
||||
|
||||
EXECUTE_PROCESS(WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} COMMAND ${GIT_EXECUTABLE} tag --points-at HEAD
|
||||
OUTPUT_VARIABLE PCSX2_GIT_TAG
|
||||
EXECUTE_PROCESS(WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} COMMAND ${GIT_EXECUTABLE} tag --points-at HEAD --sort=version:refname
|
||||
OUTPUT_VARIABLE PCSX2_GIT_TAG_LIST
|
||||
RESULT_VARIABLE TAG_RESULT
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_QUIET)
|
||||
|
||||
# CAUTION: There is a race here, this solves the problem of a commit being tagged multiple times (take the last tag)
|
||||
# however, if simultaneous builds are pushing tags to the same commit you might get inconsistent results (it's a race)
|
||||
#
|
||||
# The easy solution is, don't do that, but just something to be aware of.
|
||||
if(PCSX2_GIT_TAG_LIST AND TAG_RESULT EQUAL 0)
|
||||
string(REPLACE "\n" ";" PCSX2_GIT_TAG_LIST "${PCSX2_GIT_TAG_LIST}")
|
||||
if (PCSX2_GIT_TAG_LIST)
|
||||
list(GET PCSX2_GIT_TAG_LIST -1 PCSX2_GIT_TAG)
|
||||
message("Using tag: ${PCSX2_GIT_TAG}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
EXECUTE_PROCESS(WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} COMMAND ${GIT_EXECUTABLE} rev-parse HEAD
|
||||
OUTPUT_VARIABLE PCSX2_GIT_HASH
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
@@ -109,7 +129,7 @@ function(write_svnrev_h)
|
||||
)
|
||||
endif()
|
||||
else()
|
||||
file(WRITE ${CMAKE_BINARY_DIR}/common/include/svnrev.h
|
||||
file(WRITE ${CMAKE_BINARY_DIR}/common/include/svnrev.h
|
||||
"#define SVN_REV ${PCSX2_WC_TIME}ll\n"
|
||||
"#define GIT_TAG \"${PCSX2_GIT_TAG}\"\n"
|
||||
"#define GIT_TAGGED_COMMIT 0\n"
|
||||
@@ -119,24 +139,6 @@ function(write_svnrev_h)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(check_compiler_version version_warn version_err)
|
||||
if(CMAKE_COMPILER_IS_GNUCXX)
|
||||
execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION)
|
||||
string(STRIP "${GCC_VERSION}" GCC_VERSION)
|
||||
if(GCC_VERSION VERSION_LESS ${version_err})
|
||||
message(FATAL_ERROR "PCSX2 doesn't support your old GCC ${GCC_VERSION}! Please upgrade it!
|
||||
|
||||
The minimum supported version is ${version_err} but ${version_warn} is warmly recommended")
|
||||
else()
|
||||
if(GCC_VERSION VERSION_LESS ${version_warn})
|
||||
message(WARNING "PCSX2 will stop supporting GCC ${GCC_VERSION} in the near future. Please upgrade to at least GCC ${version_warn}.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(GCC_VERSION "${GCC_VERSION}" PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(check_no_parenthesis_in_path)
|
||||
if ("${CMAKE_BINARY_DIR}" MATCHES "[()]" OR "${CMAKE_SOURCE_DIR}" MATCHES "[()]")
|
||||
message(FATAL_ERROR "Your path contains some parenthesis. Unfortunately Cmake doesn't support them correctly.\nPlease rename your directory to avoid '(' and ')' characters\n")
|
||||
@@ -163,25 +165,6 @@ function(alias_library new old)
|
||||
add_library(${new} ALIAS _alias_${library_no_namespace})
|
||||
endfunction()
|
||||
|
||||
# Helper macro to generate resources on linux (based on glib)
|
||||
macro(add_custom_glib_res out xml prefix)
|
||||
set(RESOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/res")
|
||||
set(RESOURCE_FILES "${ARGN}")
|
||||
# Note: trying to combine --generate-source and --generate-header doesn't work.
|
||||
# It outputs whichever one comes last into the file named by the first
|
||||
add_custom_command(
|
||||
OUTPUT ${out}.h
|
||||
COMMAND glib-compile-resources --sourcedir "${RESOURCE_DIR}" --generate-header
|
||||
--c-name ${prefix} "${RESOURCE_DIR}/${xml}" --target=${out}.h
|
||||
DEPENDS res/${xml} ${RESOURCE_FILES})
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${out}.cpp
|
||||
COMMAND glib-compile-resources --sourcedir "${RESOURCE_DIR}" --generate-source
|
||||
--c-name ${prefix} "${RESOURCE_DIR}/${xml}" --target=${out}.cpp
|
||||
DEPENDS res/${xml} ${RESOURCE_FILES})
|
||||
endmacro()
|
||||
|
||||
function(source_groups_from_vcxproj_filters file)
|
||||
file(READ "${file}" filecontent)
|
||||
get_filename_component(parent "${file}" DIRECTORY)
|
||||
|
||||
+13
-30
@@ -8,7 +8,10 @@ if (WIN32)
|
||||
# We bundle everything on Windows
|
||||
add_subdirectory(3rdparty/zlib EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(3rdparty/libpng EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(3rdparty/libwebp EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(3rdparty/xz EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(3rdparty/zstd EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(3rdparty/lz4 EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(3rdparty/D3D12MemAlloc EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(3rdparty/winpixeventruntime EXCLUDE_FROM_ALL)
|
||||
set(FFMPEG_INCLUDE_DIRS "${CMAKE_SOURCE_DIR}/3rdparty/ffmpeg/include")
|
||||
@@ -47,9 +50,9 @@ else()
|
||||
endif()
|
||||
|
||||
find_package(ZLIB REQUIRED)
|
||||
|
||||
## Use pcsx2 package to find module
|
||||
include(FindLibc)
|
||||
find_package(Zstd REQUIRED)
|
||||
find_package(LZ4 REQUIRED)
|
||||
find_package(WebP REQUIRED)
|
||||
|
||||
## Use CheckLib package to find module
|
||||
include(CheckLib)
|
||||
@@ -59,17 +62,9 @@ else()
|
||||
check_lib(EGL EGL EGL/egl.h)
|
||||
endif()
|
||||
|
||||
if(Linux)
|
||||
if(LINUX)
|
||||
check_lib(AIO aio libaio.h)
|
||||
# There are two udev pkg config files - udev.pc (wrong), libudev.pc (correct)
|
||||
# When cross compiling, pkg-config will be skipped so we have to look for
|
||||
# udev (it'll automatically be prefixed with lib). But when not cross
|
||||
# compiling, we have to look for libudev.pc. Argh. Hence the silliness below.
|
||||
if(CMAKE_CROSSCOMPILING)
|
||||
check_lib(LIBUDEV udev libudev.h)
|
||||
else()
|
||||
check_lib(LIBUDEV libudev libudev.h)
|
||||
endif()
|
||||
check_lib(LIBUDEV libudev libudev.h)
|
||||
endif()
|
||||
|
||||
if(X11_API)
|
||||
@@ -95,7 +90,7 @@ endif(WIN32)
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
# Also need SDL2.
|
||||
find_package(SDL2 2.28.4 REQUIRED)
|
||||
find_package(SDL2 2.28.5 REQUIRED)
|
||||
|
||||
set(ACTUALLY_ENABLE_TESTS ${ENABLE_TESTS})
|
||||
if(ENABLE_TESTS)
|
||||
@@ -105,19 +100,6 @@ if(ENABLE_TESTS)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(GCC_VERSION VERSION_GREATER_EQUAL "9.0" AND GCC_VERSION VERSION_LESS "9.2")
|
||||
message(WARNING "
|
||||
It looks like you are compiling with 9.0.x or 9.1.x. Using these versions is not recommended,
|
||||
as there is a bug known to cause the compiler to segfault while compiling. See patch
|
||||
https://gitweb.gentoo.org/proj/gcc-patches.git/commit/?id=275ab714637a64672c6630cfd744af2c70957d5a
|
||||
Even with that patch, compiling with LTO may still segfault. Use at your own risk!
|
||||
This text being in a compile log in an open issue may cause it to be closed.")
|
||||
endif()
|
||||
|
||||
# Prevent fmt from being built with exceptions, or being thrown at call sites.
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DFMT_EXCEPTIONS=0")
|
||||
|
||||
add_subdirectory(3rdparty/fmt/fmt EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(3rdparty/rapidyaml/rapidyaml EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(3rdparty/lzma EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(3rdparty/libchdr EXCLUDE_FROM_ALL)
|
||||
@@ -133,18 +115,15 @@ add_library(fast_float INTERFACE)
|
||||
target_include_directories(fast_float INTERFACE 3rdparty/rapidyaml/rapidyaml/ext/c4core/src/c4/ext/fast_float/include)
|
||||
|
||||
add_subdirectory(3rdparty/jpgd EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(3rdparty/libwebp EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(3rdparty/simpleini EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(3rdparty/imgui EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(3rdparty/cpuinfo EXCLUDE_FROM_ALL)
|
||||
disable_compiler_warnings_for_target(cpuinfo)
|
||||
add_subdirectory(3rdparty/zydis EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(3rdparty/zstd EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(3rdparty/libzip EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(3rdparty/rcheevos EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(3rdparty/rapidjson EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(3rdparty/discord-rpc EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(3rdparty/lz4 EXCLUDE_FROM_ALL)
|
||||
|
||||
if(USE_OPENGL)
|
||||
add_subdirectory(3rdparty/glad EXCLUDE_FROM_ALL)
|
||||
@@ -169,6 +148,10 @@ endif()
|
||||
# Demangler for the debugger
|
||||
add_subdirectory(3rdparty/demangler EXCLUDE_FROM_ALL)
|
||||
|
||||
# Prevent fmt from being built with exceptions, or being thrown at call sites.
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DFMT_EXCEPTIONS=0")
|
||||
add_subdirectory(3rdparty/fmt/fmt EXCLUDE_FROM_ALL)
|
||||
|
||||
# Deliberately at the end. We don't want to set the flag on third-party projects.
|
||||
if(MSVC)
|
||||
# Don't warn about "deprecated" POSIX functions.
|
||||
|
||||
@@ -1,169 +0,0 @@
|
||||
# Copyright (c) 2014 PCSX2 Dev Team
|
||||
# Copyright (c) 2012 Petroules Corporation. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice, this
|
||||
# list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
# https://github.com/petroules/solar-cmake/blob/master/TargetArch.cmake
|
||||
#
|
||||
# Based on the Qt 5 processor detection code, so should be very accurate
|
||||
# https://qt.gitorious.org/qt/qtbase/blobs/master/src/corelib/global/qprocessordetection.h
|
||||
# Currently handles arm (v5, v6, v7), x86 (32/64), ia64, and ppc (32/64)
|
||||
|
||||
# Regarding POWER/PowerPC, just as is noted in the Qt source,
|
||||
# "There are many more known variants/revisions that we do not handle/detect."
|
||||
|
||||
set(archdetect_c_code "
|
||||
#if defined(__arm__) || defined(__TARGET_ARCH_ARM)
|
||||
#if defined(__ARM_ARCH_7__) \\
|
||||
|| defined(__ARM_ARCH_7A__) \\
|
||||
|| defined(__ARM_ARCH_7R__) \\
|
||||
|| defined(__ARM_ARCH_7M__) \\
|
||||
|| (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 7)
|
||||
#error cmake_ARCH armv7
|
||||
#elif defined(__ARM_ARCH_6__) \\
|
||||
|| defined(__ARM_ARCH_6J__) \\
|
||||
|| defined(__ARM_ARCH_6T2__) \\
|
||||
|| defined(__ARM_ARCH_6Z__) \\
|
||||
|| defined(__ARM_ARCH_6K__) \\
|
||||
|| defined(__ARM_ARCH_6ZK__) \\
|
||||
|| defined(__ARM_ARCH_6M__) \\
|
||||
|| (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 6)
|
||||
#error cmake_ARCH armv6
|
||||
#elif defined(__ARM_ARCH_5TEJ__) \\
|
||||
|| (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 5)
|
||||
#error cmake_ARCH armv5
|
||||
#else
|
||||
#error cmake_ARCH arm
|
||||
#endif
|
||||
#elif defined(__i386) || defined(__i386__) || defined(_M_IX86)
|
||||
#error cmake_ARCH i386
|
||||
#elif defined(__x86_64) || defined(__x86_64__) || defined(__amd64) || defined(_M_X64)
|
||||
#error cmake_ARCH x86_64
|
||||
#elif defined(__ia64) || defined(__ia64__) || defined(_M_IA64)
|
||||
#error cmake_ARCH ia64
|
||||
#elif defined(__ppc__) || defined(__ppc) || defined(__powerpc__) \\
|
||||
|| defined(_ARCH_COM) || defined(_ARCH_PWR) || defined(_ARCH_PPC) \\
|
||||
|| defined(_M_MPPC) || defined(_M_PPC)
|
||||
#if defined(__ppc64__) || defined(__powerpc64__) || defined(__64BIT__)
|
||||
#error cmake_ARCH ppc64
|
||||
#else
|
||||
#error cmake_ARCH ppc
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#error cmake_ARCH unknown
|
||||
")
|
||||
|
||||
# Set ppc_support to TRUE before including this file or ppc and ppc64
|
||||
# will be treated as invalid architectures since they are no longer supported by Apple
|
||||
|
||||
function(target_architecture output_var)
|
||||
if(APPLE AND CMAKE_OSX_ARCHITECTURES)
|
||||
# On OS X we use CMAKE_OSX_ARCHITECTURES *if* it was set
|
||||
# First let's normalize the order of the values
|
||||
|
||||
# Note that it's not possible to compile PowerPC applications if you are using
|
||||
# the OS X SDK version 10.6 or later - you'll need 10.4/10.5 for that, so we
|
||||
# disable it by default
|
||||
# See this page for more information:
|
||||
# http://stackoverflow.com/questions/5333490/how-can-we-restore-ppc-ppc64-as-well-as-full-10-4-10-5-sdk-support-to-xcode-4
|
||||
|
||||
# Architecture defaults to i386 or ppc on OS X 10.5 and earlier, depending on the CPU type detected at runtime.
|
||||
# On OS X 10.6+ the default is x86_64 if the CPU supports it, i386 otherwise.
|
||||
|
||||
LIST(LENGTH CMAKE_OSX_ARCHITECTURES osx_arch_num)
|
||||
if(NOT (osx_arch_num EQUAL 1))
|
||||
message(FATAL_ERROR "Currently ${CMAKE_PROJECT_NAME} does not support multiple architectures in CMAKE_OSX_ARCHITECTURES")
|
||||
endif()
|
||||
|
||||
foreach(osx_arch ${CMAKE_OSX_ARCHITECTURES})
|
||||
if("${osx_arch}" STREQUAL "ppc" AND ppc_support)
|
||||
set(osx_arch_ppc TRUE)
|
||||
elseif("${osx_arch}" STREQUAL "i386")
|
||||
set(osx_arch_i386 TRUE)
|
||||
elseif("${osx_arch}" STREQUAL "x86_64")
|
||||
set(osx_arch_x86_64 TRUE)
|
||||
elseif("${osx_arch}" STREQUAL "ppc64" AND ppc_support)
|
||||
set(osx_arch_ppc64 TRUE)
|
||||
else()
|
||||
message(FATAL_ERROR "Invalid OS X arch name: ${osx_arch}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Now add all the architectures in our normalized order
|
||||
if(osx_arch_ppc)
|
||||
list(APPEND ARCH ppc)
|
||||
endif()
|
||||
|
||||
if(osx_arch_i386)
|
||||
list(APPEND ARCH i386)
|
||||
endif()
|
||||
|
||||
if(osx_arch_x86_64)
|
||||
list(APPEND ARCH x86_64)
|
||||
endif()
|
||||
|
||||
if(osx_arch_ppc64)
|
||||
list(APPEND ARCH ppc64)
|
||||
endif()
|
||||
|
||||
LIST(LENGTH ARCH osx_arch_num)
|
||||
if(osx_arch_num LESS 1)
|
||||
message(FATAL_ERROR "Invalid CMAKE_OSX_ARCHITECTURES: ${CMAKE_OSX_ARCHITECTURES}")
|
||||
endif()
|
||||
else()
|
||||
file(WRITE "${CMAKE_BINARY_DIR}/arch.c" "${archdetect_c_code}")
|
||||
|
||||
enable_language(C)
|
||||
|
||||
# Detect the architecture in a rather creative way...
|
||||
# This compiles a small C program which is a series of ifdefs that selects a
|
||||
# particular #error preprocessor directive whose message string contains the
|
||||
# target architecture. The program will always fail to compile (both because
|
||||
# file is not a valid C program, and obviously because of the presence of the
|
||||
# #error preprocessor directives... but by exploiting the preprocessor in this
|
||||
# way, we can detect the correct target architecture even when cross-compiling,
|
||||
# since the program itself never needs to be run (only the compiler/preprocessor)
|
||||
try_run(
|
||||
run_result_unused
|
||||
compile_result_unused
|
||||
"${CMAKE_BINARY_DIR}"
|
||||
"${CMAKE_BINARY_DIR}/arch.c"
|
||||
COMPILE_OUTPUT_VARIABLE ARCH
|
||||
CMAKE_FLAGS CMAKE_OSX_ARCHITECTURES=${CMAKE_OSX_ARCHITECTURES}
|
||||
)
|
||||
|
||||
# Parse the architecture name from the compiler output
|
||||
string(REGEX MATCH "cmake_ARCH ([a-zA-Z0-9_]+)" ARCH "${ARCH}")
|
||||
|
||||
# Get rid of the value marker leaving just the architecture name
|
||||
string(REPLACE "cmake_ARCH " "" ARCH "${ARCH}")
|
||||
|
||||
# If we are compiling with an unknown architecture this variable should
|
||||
# already be set to "unknown" but in the case that it's empty (i.e. due
|
||||
# to a typo in the code), then set it to unknown
|
||||
if (NOT ARCH)
|
||||
set(ARCH unknown)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(${output_var} "${ARCH}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
@@ -1,10 +1,10 @@
|
||||
// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: LGPL-3.0+
|
||||
|
||||
#include "Threading.h"
|
||||
#include "General.h"
|
||||
#include "Assertions.h"
|
||||
#include "CrashHandler.h"
|
||||
#include "HostSys.h"
|
||||
#include "Threading.h"
|
||||
|
||||
#include <mutex>
|
||||
#include "fmt/core.h"
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "common/Pcsx2Defs.h"
|
||||
|
||||
#include <bit>
|
||||
#include <cstring>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
@@ -84,3 +85,16 @@ namespace Common
|
||||
return std::countl_zero(static_cast<u32>(n));
|
||||
}
|
||||
} // namespace Common
|
||||
|
||||
template <typename T>
|
||||
[[maybe_unused]] __fi static T GetBufferT(u8* buffer, u32 offset)
|
||||
{
|
||||
T value;
|
||||
std::memcpy(&value, buffer + offset, sizeof(value));
|
||||
return value;
|
||||
}
|
||||
|
||||
[[maybe_unused]] __fi static u8 GetBufferU8(u8* buffer, u32 offset) { return GetBufferT<u8>(buffer, offset); }
|
||||
[[maybe_unused]] __fi static u16 GetBufferU16(u8* buffer, u32 offset) { return GetBufferT<u16>(buffer, offset); }
|
||||
[[maybe_unused]] __fi static u32 GetBufferU32(u8* buffer, u32 offset) { return GetBufferT<u32>(buffer, offset); }
|
||||
[[maybe_unused]] __fi static u64 GetBufferU64(u8* buffer, u32 offset) { return GetBufferT<u64>(buffer, offset); }
|
||||
|
||||
@@ -17,11 +17,10 @@ target_sources(common PRIVATE
|
||||
Error.cpp
|
||||
FastJmp.cpp
|
||||
FileSystem.cpp
|
||||
General.cpp
|
||||
HostSys.cpp
|
||||
Image.cpp
|
||||
HTTPDownloader.cpp
|
||||
MemorySettingsInterface.cpp
|
||||
Misc.cpp
|
||||
MD5Digest.cpp
|
||||
PrecompiledHeader.cpp
|
||||
Perf.cpp
|
||||
@@ -37,7 +36,6 @@ target_sources(common PRIVATE
|
||||
WindowInfo.cpp
|
||||
emitter/avx.cpp
|
||||
emitter/bmi.cpp
|
||||
emitter/cpudetect.cpp
|
||||
emitter/fpu.cpp
|
||||
emitter/groups.cpp
|
||||
emitter/jmp.cpp
|
||||
@@ -45,8 +43,6 @@ target_sources(common PRIVATE
|
||||
emitter/legacy_sse.cpp
|
||||
emitter/movs.cpp
|
||||
emitter/simd.cpp
|
||||
emitter/LnxCpuDetect.cpp
|
||||
emitter/WinCpuDetect.cpp
|
||||
emitter/x86emitter.cpp
|
||||
Darwin/DarwinThreads.cpp
|
||||
Darwin/DarwinMisc.cpp
|
||||
@@ -72,10 +68,11 @@ target_sources(common PRIVATE
|
||||
Easing.h
|
||||
EnumOps.h
|
||||
Error.h
|
||||
FPControl.h
|
||||
FastJmp.h
|
||||
FileSystem.h
|
||||
General.h
|
||||
HashCombine.h
|
||||
HostSys.h
|
||||
HeterogeneousContainers.h
|
||||
Image.h
|
||||
LRUCache.h
|
||||
@@ -125,12 +122,13 @@ target_sources(common PRIVATE
|
||||
emitter/legacy_instructions.h
|
||||
emitter/legacy_internal.h
|
||||
emitter/legacy_types.h
|
||||
emitter/tools.h
|
||||
emitter/x86emitter.h
|
||||
emitter/x86types.h
|
||||
Darwin/DarwinMisc.h
|
||||
)
|
||||
|
||||
set_source_files_properties(PrecompiledHeader.cpp PROPERTIES HEADER_FILE_ONLY TRUE)
|
||||
|
||||
if(USE_VTUNE)
|
||||
target_link_libraries(common PUBLIC Vtune::Vtune)
|
||||
endif()
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#include "CocoaTools.h"
|
||||
#include "Console.h"
|
||||
#include "General.h"
|
||||
#include "HostSys.h"
|
||||
#include "WindowInfo.h"
|
||||
#include <dlfcn.h>
|
||||
#include <mutex>
|
||||
|
||||
+455
-470
@@ -1,524 +1,509 @@
|
||||
// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team
|
||||
// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: LGPL-3.0+
|
||||
|
||||
#include "common/Threading.h"
|
||||
#include "common/TraceLog.h"
|
||||
#include "common/Console.h"
|
||||
#include "common/Assertions.h"
|
||||
#include "common/RedtapeWindows.h" // OutputDebugString
|
||||
#include "common/FileSystem.h"
|
||||
#include "common/SmallString.h"
|
||||
#include "common/Timer.h"
|
||||
|
||||
using namespace Threading;
|
||||
#include "fmt/format.h"
|
||||
|
||||
// thread-local console indentation setting.
|
||||
static thread_local int conlog_Indent(0);
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
// thread-local console color storage.
|
||||
static thread_local ConsoleColors conlog_Color(DefaultConsoleColor);
|
||||
|
||||
#ifdef __POSIX__
|
||||
#ifdef _WIN32
|
||||
#include "common/RedtapeWindows.h"
|
||||
#else
|
||||
#include <unistd.h>
|
||||
|
||||
static FILE* stdout_fp = stdout;
|
||||
|
||||
static bool checkSupportsColor()
|
||||
{
|
||||
if (!isatty(fileno(stdout_fp)))
|
||||
return false;
|
||||
char* term = getenv("TERM");
|
||||
if (!term || (0 == strcmp(term, "dumb")))
|
||||
return false;
|
||||
return true; // Probably supports color
|
||||
}
|
||||
|
||||
static bool supports_color = checkSupportsColor();
|
||||
|
||||
void Console_SetStdout(FILE* fp)
|
||||
{
|
||||
stdout_fp = fp;
|
||||
}
|
||||
#endif
|
||||
|
||||
// This function re-assigns the console log writer(s) to the specified target. It makes sure
|
||||
// to flush any contents from the buffered console log (which typically accumulates due to
|
||||
// log suspension during log file/window re-init operations) into the new log.
|
||||
//
|
||||
// Important! Only Assert and Null console loggers are allowed during C++ startup init (when
|
||||
// the program or DLL first loads). Other log targets rely on the static buffer and a
|
||||
// threaded mutex lock, which are only valid after C++ initialization has finished.
|
||||
void Console_SetActiveHandler(const IConsoleWriter& writer, FILE* flushfp)
|
||||
using namespace std::string_view_literals;
|
||||
|
||||
// Dummy objects, need to get rid of them...
|
||||
ConsoleLogWriter<LOGLEVEL_INFO> Console;
|
||||
ConsoleLogWriter<LOGLEVEL_DEV> DevCon;
|
||||
|
||||
#ifdef _DEBUG
|
||||
ConsoleLogWriter<LOGLEVEL_DEBUG> DbgConWriter;
|
||||
#else
|
||||
NullLogWriter DbgConWriter;
|
||||
#endif
|
||||
|
||||
#define TIMESTAMP_FORMAT_STRING "[{:10.4f}] "
|
||||
#define TIMESTAMP_PRINTF_STRING "[%10.4f] "
|
||||
|
||||
namespace Log
|
||||
{
|
||||
pxAssertMsg(
|
||||
(writer.WriteRaw != NULL) && (writer.DoWriteLn != NULL) &&
|
||||
(writer.Newline != NULL) && (writer.SetTitle != NULL) &&
|
||||
(writer.DoSetColor != NULL),
|
||||
"Invalid IConsoleWriter object! All function pointer interfaces must be implemented.");
|
||||
static void WriteToConsole(LOGLEVEL level, ConsoleColors color, std::string_view message);
|
||||
static void WriteToDebug(LOGLEVEL level, ConsoleColors color, std::string_view message);
|
||||
static void WriteToFile(LOGLEVEL level, ConsoleColors color, std::string_view message);
|
||||
|
||||
Console = writer;
|
||||
DevConWriter = writer;
|
||||
static void UpdateMaxLevel();
|
||||
|
||||
#ifdef PCSX2_DEBUG
|
||||
DbgCon = writer;
|
||||
static void ExecuteCallbacks(LOGLEVEL level, ConsoleColors color, std::string_view message);
|
||||
|
||||
static Common::Timer::Value s_start_timestamp = Common::Timer::GetCurrentValue();
|
||||
|
||||
static LOGLEVEL s_max_level = LOGLEVEL_NONE;
|
||||
static LOGLEVEL s_console_level = LOGLEVEL_NONE;
|
||||
static LOGLEVEL s_debug_level = LOGLEVEL_NONE;
|
||||
static LOGLEVEL s_file_level = LOGLEVEL_NONE;
|
||||
static LOGLEVEL s_host_level = LOGLEVEL_NONE;
|
||||
static bool s_log_timestamps = true;
|
||||
|
||||
static FileSystem::ManagedCFilePtr s_file_handle;
|
||||
static std::string s_file_path;
|
||||
static std::mutex s_file_mutex;
|
||||
|
||||
static HostCallbackType s_host_callback;
|
||||
|
||||
#ifdef _WIN32
|
||||
static HANDLE s_hConsoleStdIn = NULL;
|
||||
static HANDLE s_hConsoleStdOut = NULL;
|
||||
static HANDLE s_hConsoleStdErr = NULL;
|
||||
#endif
|
||||
} // namespace Log
|
||||
|
||||
float Log::GetCurrentMessageTime()
|
||||
{
|
||||
return static_cast<float>(Common::Timer::ConvertValueToSeconds(Common::Timer::GetCurrentValue() - s_start_timestamp));
|
||||
}
|
||||
|
||||
__ri void Log::WriteToConsole(LOGLEVEL level, ConsoleColors color, std::string_view message)
|
||||
{
|
||||
static constexpr std::string_view s_ansi_color_codes[ConsoleColors_Count] = {
|
||||
"\033[0m"sv, // default
|
||||
"\033[30m\033[1m"sv, // black
|
||||
"\033[32m"sv, // green
|
||||
"\033[31m"sv, // red
|
||||
"\033[34m"sv, // blue
|
||||
"\033[35m"sv, // magenta
|
||||
"\033[35m"sv, // orange (FIXME)
|
||||
"\033[37m"sv, // gray
|
||||
"\033[36m"sv, // cyan
|
||||
"\033[33m"sv, // yellow
|
||||
"\033[37m"sv, // white
|
||||
"\033[30m\033[1m"sv, // strong black
|
||||
"\033[31m\033[1m"sv, // strong red
|
||||
"\033[32m\033[1m"sv, // strong green
|
||||
"\033[34m\033[1m"sv, // strong blue
|
||||
"\033[35m\033[1m"sv, // strong magenta
|
||||
"\033[35m\033[1m"sv, // strong orange (FIXME)
|
||||
"\033[37m\033[1m"sv, // strong gray
|
||||
"\033[36m\033[1m"sv, // strong cyan
|
||||
"\033[33m\033[1m"sv, // strong yellow
|
||||
"\033[37m\033[1m"sv, // strong white
|
||||
};
|
||||
|
||||
static constexpr size_t BUFFER_SIZE = 512;
|
||||
|
||||
SmallStackString<BUFFER_SIZE> buffer;
|
||||
buffer.reserve(32 + message.length());
|
||||
buffer.append(s_ansi_color_codes[color]);
|
||||
|
||||
if (s_log_timestamps)
|
||||
buffer.append_fmt(TIMESTAMP_FORMAT_STRING, Log::GetCurrentMessageTime());
|
||||
|
||||
buffer.append(message);
|
||||
buffer.append('\n');
|
||||
|
||||
#ifdef _WIN32
|
||||
const HANDLE hOutput = (level <= LOGLEVEL_WARNING) ? s_hConsoleStdErr : s_hConsoleStdOut;
|
||||
|
||||
// Convert to UTF-16 first so Unicode characters display correctly. NT is going to do it anyway...
|
||||
wchar_t wbuf[BUFFER_SIZE];
|
||||
wchar_t* wmessage_buf = wbuf;
|
||||
int wmessage_buflen = static_cast<int>(std::size(wbuf) - 1);
|
||||
if (buffer.length() >= std::size(wbuf))
|
||||
{
|
||||
wmessage_buflen = static_cast<int>(buffer.length());
|
||||
wmessage_buf = static_cast<wchar_t*>(std::malloc(static_cast<size_t>(wmessage_buflen) * sizeof(wchar_t)));
|
||||
if (!wmessage_buf)
|
||||
return;
|
||||
}
|
||||
|
||||
const int wmessage_size = MultiByteToWideChar(CP_UTF8, 0, buffer.data(), static_cast<int>(buffer.length()), wmessage_buf, wmessage_buflen);
|
||||
if (wmessage_size <= 0)
|
||||
goto cleanup;
|
||||
|
||||
DWORD chars_written;
|
||||
WriteConsoleW(hOutput, wmessage_buf, static_cast<DWORD>(wmessage_size), &chars_written, nullptr);
|
||||
|
||||
cleanup:
|
||||
if (wmessage_buf != wbuf)
|
||||
std::free(wmessage_buf);
|
||||
#else
|
||||
const int fd = (level <= LOGLEVEL_WARNING) ? STDERR_FILENO : STDOUT_FILENO;
|
||||
write(fd, buffer.data(), buffer.length());
|
||||
#endif
|
||||
}
|
||||
|
||||
// Writes text to the Visual Studio Output window (Microsoft Windows only).
|
||||
// On all other platforms this pipes to Stdout instead.
|
||||
static void MSW_OutputDebugString(const char* text)
|
||||
bool Log::IsConsoleOutputEnabled()
|
||||
{
|
||||
return (s_console_level > LOGLEVEL_NONE);
|
||||
}
|
||||
|
||||
void Log::SetConsoleOutputLevel(LOGLEVEL level)
|
||||
{
|
||||
if (s_console_level == level)
|
||||
return;
|
||||
|
||||
const bool was_enabled = (s_console_level > LOGLEVEL_NONE);
|
||||
const bool now_enabled = (level > LOGLEVEL_NONE);
|
||||
s_console_level = level;
|
||||
UpdateMaxLevel();
|
||||
|
||||
if (was_enabled == now_enabled)
|
||||
return;
|
||||
|
||||
// Worst that happens here is we write to a bad handle..
|
||||
|
||||
#if defined(_WIN32)
|
||||
static constexpr auto enable_virtual_terminal_processing = [](HANDLE hConsole) {
|
||||
DWORD old_mode;
|
||||
if (!GetConsoleMode(hConsole, &old_mode))
|
||||
return;
|
||||
|
||||
// already enabled?
|
||||
if (old_mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING)
|
||||
return;
|
||||
|
||||
SetConsoleMode(hConsole, old_mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
|
||||
};
|
||||
|
||||
// On windows, no console is allocated by default on a windows based application
|
||||
static bool console_was_allocated = false;
|
||||
static HANDLE old_stdin = NULL;
|
||||
static HANDLE old_stdout = NULL;
|
||||
static HANDLE old_stderr = NULL;
|
||||
|
||||
if (now_enabled)
|
||||
{
|
||||
old_stdin = GetStdHandle(STD_INPUT_HANDLE);
|
||||
old_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
old_stderr = GetStdHandle(STD_ERROR_HANDLE);
|
||||
|
||||
if (!old_stdout)
|
||||
{
|
||||
// Attach to the parent console if we're running from a command window
|
||||
if (!AttachConsole(ATTACH_PARENT_PROCESS) && !AllocConsole())
|
||||
return;
|
||||
|
||||
s_hConsoleStdIn = GetStdHandle(STD_INPUT_HANDLE);
|
||||
s_hConsoleStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
s_hConsoleStdErr = GetStdHandle(STD_ERROR_HANDLE);
|
||||
|
||||
enable_virtual_terminal_processing(s_hConsoleStdOut);
|
||||
enable_virtual_terminal_processing(s_hConsoleStdErr);
|
||||
|
||||
std::FILE* fp;
|
||||
freopen_s(&fp, "CONIN$", "r", stdin);
|
||||
freopen_s(&fp, "CONOUT$", "w", stdout);
|
||||
freopen_s(&fp, "CONOUT$", "w", stderr);
|
||||
|
||||
console_was_allocated = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
s_hConsoleStdIn = old_stdin;
|
||||
s_hConsoleStdOut = old_stdout;
|
||||
s_hConsoleStdErr = old_stderr;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (console_was_allocated)
|
||||
{
|
||||
console_was_allocated = false;
|
||||
|
||||
std::FILE* fp;
|
||||
freopen_s(&fp, "NUL:", "w", stderr);
|
||||
freopen_s(&fp, "NUL:", "w", stdout);
|
||||
freopen_s(&fp, "NUL:", "w", stdin);
|
||||
|
||||
SetStdHandle(STD_ERROR_HANDLE, old_stderr);
|
||||
SetStdHandle(STD_OUTPUT_HANDLE, old_stdout);
|
||||
SetStdHandle(STD_INPUT_HANDLE, old_stdin);
|
||||
|
||||
s_hConsoleStdIn = NULL;
|
||||
s_hConsoleStdOut = NULL;
|
||||
s_hConsoleStdErr = NULL;
|
||||
|
||||
FreeConsole();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
__ri void Log::WriteToDebug(LOGLEVEL level, ConsoleColors color, std::string_view message)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
static bool hasDebugger = IsDebuggerPresent();
|
||||
if (hasDebugger)
|
||||
OutputDebugStringA(text);
|
||||
static constexpr size_t BUFFER_SIZE = 512;
|
||||
|
||||
// Convert to UTF-16 first so Unicode characters display correctly. NT is going to do it anyway...
|
||||
wchar_t wbuf[BUFFER_SIZE];
|
||||
wchar_t* wmessage_buf = wbuf;
|
||||
int wmessage_buflen = static_cast<int>(std::size(wbuf) - 1);
|
||||
if (message.length() >= std::size(wbuf))
|
||||
{
|
||||
wmessage_buflen = static_cast<int>(message.length());
|
||||
wmessage_buf = static_cast<wchar_t*>(std::malloc((static_cast<size_t>(wmessage_buflen) + 2) * sizeof(wchar_t)));
|
||||
if (!wmessage_buf)
|
||||
return;
|
||||
}
|
||||
|
||||
int wmessage_size = 0;
|
||||
if (!message.empty()) [[likely]]
|
||||
{
|
||||
wmessage_size = MultiByteToWideChar(CP_UTF8, 0, message.data(), static_cast<int>(message.length()), wmessage_buf, wmessage_buflen);
|
||||
if (wmessage_size <= 0)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
wmessage_buf[wmessage_size++] = L'\n';
|
||||
wmessage_buf[wmessage_size++] = 0;
|
||||
OutputDebugStringW(wmessage_buf);
|
||||
|
||||
cleanup:
|
||||
if (wmessage_buf != wbuf)
|
||||
std::free(wmessage_buf);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Log::IsDebugOutputAvailable()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return IsDebuggerPresent();
|
||||
#else
|
||||
fputs(text, stdout_fp);
|
||||
fflush(stdout_fp);
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// ConsoleNull
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
static void ConsoleNull_SetTitle(const char* title) {}
|
||||
static void ConsoleNull_DoSetColor(ConsoleColors color) {}
|
||||
static void ConsoleNull_Newline() {}
|
||||
static void ConsoleNull_DoWrite(const char* fmt) {}
|
||||
static void ConsoleNull_DoWriteLn(const char* fmt) {}
|
||||
|
||||
const IConsoleWriter ConsoleWriter_Null =
|
||||
{
|
||||
ConsoleNull_DoWrite,
|
||||
ConsoleNull_DoWriteLn,
|
||||
ConsoleNull_DoSetColor,
|
||||
|
||||
ConsoleNull_DoWrite,
|
||||
ConsoleNull_Newline,
|
||||
ConsoleNull_SetTitle,
|
||||
|
||||
0, // instance-level indentation (should always be 0)
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Console_Stdout
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
#if defined(__POSIX__)
|
||||
static __fi const char* GetLinuxConsoleColor(ConsoleColors color)
|
||||
bool Log::IsDebugOutputEnabled()
|
||||
{
|
||||
switch (color)
|
||||
{
|
||||
case Color_Black:
|
||||
case Color_StrongBlack:
|
||||
return "\033[30m\033[1m";
|
||||
|
||||
case Color_Red:
|
||||
return "\033[31m";
|
||||
case Color_StrongRed:
|
||||
return "\033[31m\033[1m";
|
||||
|
||||
case Color_Green:
|
||||
return "\033[32m";
|
||||
case Color_StrongGreen:
|
||||
return "\033[32m\033[1m";
|
||||
|
||||
case Color_Yellow:
|
||||
return "\033[33m";
|
||||
case Color_StrongYellow:
|
||||
return "\033[33m\033[1m";
|
||||
|
||||
case Color_Blue:
|
||||
return "\033[34m";
|
||||
case Color_StrongBlue:
|
||||
return "\033[34m\033[1m";
|
||||
|
||||
// No orange, so use magenta.
|
||||
case Color_Orange:
|
||||
case Color_Magenta:
|
||||
return "\033[35m";
|
||||
case Color_StrongOrange:
|
||||
case Color_StrongMagenta:
|
||||
return "\033[35m\033[1m";
|
||||
|
||||
case Color_Cyan:
|
||||
return "\033[36m";
|
||||
case Color_StrongCyan:
|
||||
return "\033[36m\033[1m";
|
||||
|
||||
// Use 'white' instead of grey.
|
||||
case Color_Gray:
|
||||
case Color_White:
|
||||
return "\033[37m";
|
||||
case Color_StrongGray:
|
||||
case Color_StrongWhite:
|
||||
return "\033[37m\033[1m";
|
||||
|
||||
// On some other value being passed, clear any formatting.
|
||||
case Color_Default:
|
||||
default:
|
||||
return "\033[0m";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// One possible default write action at startup and shutdown is to use the stdout.
|
||||
static void ConsoleStdout_DoWrite(const char* fmt)
|
||||
{
|
||||
MSW_OutputDebugString(fmt);
|
||||
return (s_console_level > LOGLEVEL_NONE);
|
||||
}
|
||||
|
||||
// Default write action at startup and shutdown is to use the stdout.
|
||||
static void ConsoleStdout_DoWriteLn(const char* fmt)
|
||||
void Log::SetDebugOutputLevel(LOGLEVEL level)
|
||||
{
|
||||
MSW_OutputDebugString(fmt);
|
||||
MSW_OutputDebugString("\n");
|
||||
s_debug_level = level;
|
||||
UpdateMaxLevel();
|
||||
}
|
||||
|
||||
static void ConsoleStdout_Newline()
|
||||
__ri void Log::WriteToFile(LOGLEVEL level, ConsoleColors color, std::string_view message)
|
||||
{
|
||||
MSW_OutputDebugString("\n");
|
||||
}
|
||||
|
||||
static void ConsoleStdout_DoSetColor(ConsoleColors color)
|
||||
{
|
||||
#if defined(__POSIX__)
|
||||
if (!supports_color)
|
||||
std::unique_lock lock(s_file_mutex);
|
||||
if (!s_file_handle) [[unlikely]]
|
||||
return;
|
||||
fprintf(stdout_fp, "\033[0m%s", GetLinuxConsoleColor(color));
|
||||
fflush(stdout_fp);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void ConsoleStdout_SetTitle(const char* title)
|
||||
{
|
||||
#if defined(__POSIX__)
|
||||
if (supports_color)
|
||||
fputs("\033]0;", stdout_fp);
|
||||
fputs(title, stdout_fp);
|
||||
if (supports_color)
|
||||
fputs("\007", stdout_fp);
|
||||
#endif
|
||||
}
|
||||
|
||||
const IConsoleWriter ConsoleWriter_Stdout =
|
||||
if (!message.empty()) [[likely]]
|
||||
{
|
||||
ConsoleStdout_DoWrite, // Writes without newlines go to buffer to avoid error log spam.
|
||||
ConsoleStdout_DoWriteLn,
|
||||
ConsoleStdout_DoSetColor,
|
||||
|
||||
ConsoleNull_DoWrite, // writes from re-piped stdout are ignored here, lest we create infinite loop hell >_<
|
||||
ConsoleStdout_Newline,
|
||||
ConsoleStdout_SetTitle,
|
||||
0, // instance-level indentation (should always be 0)
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// ConsoleAssert
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
static void ConsoleAssert_DoWrite(const char* fmt)
|
||||
{
|
||||
pxFailRel("Console class has not been initialized");
|
||||
}
|
||||
|
||||
static void ConsoleAssert_DoWriteLn(const char* fmt)
|
||||
{
|
||||
pxFailRel("Console class has not been initialized");
|
||||
}
|
||||
|
||||
const IConsoleWriter ConsoleWriter_Assert =
|
||||
{
|
||||
ConsoleAssert_DoWrite,
|
||||
ConsoleAssert_DoWriteLn,
|
||||
ConsoleNull_DoSetColor,
|
||||
|
||||
ConsoleNull_DoWrite,
|
||||
ConsoleNull_Newline,
|
||||
ConsoleNull_SetTitle,
|
||||
|
||||
0, // instance-level indentation (should always be 0)
|
||||
};
|
||||
|
||||
// =====================================================================================================
|
||||
// IConsoleWriter (implementations)
|
||||
// =====================================================================================================
|
||||
// (all non-virtual members that do common work and then pass the result through DoWrite
|
||||
// or DoWriteLn)
|
||||
|
||||
// Parameters:
|
||||
// glob_indent - this parameter is used to specify a global indentation setting. It is used by
|
||||
// WriteLn function, but defaults to 0 for Warning and Error calls. Local indentation always
|
||||
// applies to all writes.
|
||||
std::string IConsoleWriter::_addIndentation(const std::string& src, int glob_indent = 0) const
|
||||
{
|
||||
const int indent = glob_indent + _imm_indentation;
|
||||
|
||||
std::string indentStr;
|
||||
for (int i = 0; i < indent; i++)
|
||||
indentStr += '\t';
|
||||
|
||||
std::string result;
|
||||
result.reserve(src.length() + 16 * indent);
|
||||
result.append(indentStr);
|
||||
result.append(src);
|
||||
|
||||
std::string::size_type pos = result.find('\n');
|
||||
while (pos != std::string::npos)
|
||||
{
|
||||
result.insert(pos + 1, indentStr);
|
||||
pos = result.find('\n', pos + 1);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Sets the indentation to be applied to all WriteLn's. The indentation is added to the
|
||||
// primary write, and to any newlines specified within the write. Note that this applies
|
||||
// to calls to WriteLn *only* -- calls to Write bypass the indentation parser.
|
||||
const IConsoleWriter& IConsoleWriter::SetIndent(int tabcount) const
|
||||
{
|
||||
conlog_Indent += tabcount;
|
||||
pxAssert(conlog_Indent >= 0);
|
||||
return *this;
|
||||
}
|
||||
|
||||
IConsoleWriter IConsoleWriter::Indent(int tabcount) const
|
||||
{
|
||||
IConsoleWriter retval = *this;
|
||||
retval._imm_indentation = tabcount;
|
||||
return retval;
|
||||
}
|
||||
|
||||
// Changes the active console color.
|
||||
// This color will be unset by calls to colored text methods
|
||||
// such as ErrorMsg and Notice.
|
||||
const IConsoleWriter& IConsoleWriter::SetColor(ConsoleColors color) const
|
||||
{
|
||||
// Ignore current color requests since, well, the current color is already set. ;)
|
||||
if (color == Color_Current)
|
||||
return *this;
|
||||
|
||||
pxAssertMsg((color > Color_Current) && (color < ConsoleColors_Count), "Invalid ConsoleColor specified.");
|
||||
|
||||
if (conlog_Color != color)
|
||||
DoSetColor(conlog_Color = color);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
ConsoleColors IConsoleWriter::GetColor() const
|
||||
{
|
||||
return conlog_Color;
|
||||
}
|
||||
|
||||
// Restores the console color to default (usually black, or low-intensity white if the console uses a black background)
|
||||
const IConsoleWriter& IConsoleWriter::ClearColor() const
|
||||
{
|
||||
if (conlog_Color != DefaultConsoleColor)
|
||||
DoSetColor(conlog_Color = DefaultConsoleColor);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// ASCII/UTF8 (char*)
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
bool IConsoleWriter::FormatV(const char* fmt, va_list args) const
|
||||
{
|
||||
// TODO: Make this less rubbish
|
||||
if ((_imm_indentation + conlog_Indent) > 0)
|
||||
{
|
||||
DoWriteLn(_addIndentation(StringUtil::StdStringFromFormatV(fmt, args), conlog_Indent).c_str());
|
||||
if (s_log_timestamps)
|
||||
{
|
||||
std::fprintf(s_file_handle.get(), TIMESTAMP_PRINTF_STRING "%.*s\n", GetCurrentMessageTime(),
|
||||
static_cast<int>(message.size()), message.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
std::fprintf(s_file_handle.get(), "%.*s\n", static_cast<int>(message.size()), message.data());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DoWriteLn(StringUtil::StdStringFromFormatV(fmt, args).c_str());
|
||||
if (s_log_timestamps)
|
||||
{
|
||||
std::fprintf(s_file_handle.get(), TIMESTAMP_PRINTF_STRING "\n", GetCurrentMessageTime());
|
||||
}
|
||||
else
|
||||
{
|
||||
std::fputc('\n', s_file_handle.get());
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
std::fflush(s_file_handle.get());
|
||||
}
|
||||
|
||||
bool IConsoleWriter::WriteLn(const char* fmt, ...) const
|
||||
bool Log::IsFileOutputEnabled()
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
FormatV(fmt, args);
|
||||
va_end(args);
|
||||
|
||||
return false;
|
||||
return (s_file_level > LOGLEVEL_NONE);
|
||||
}
|
||||
|
||||
bool IConsoleWriter::WriteLn(ConsoleColors color, const char* fmt, ...) const
|
||||
bool Log::SetFileOutputLevel(LOGLEVEL level, std::string path)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
ConsoleColorScope cs(color);
|
||||
FormatV(fmt, args);
|
||||
va_end(args);
|
||||
std::unique_lock lock(s_file_mutex);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IConsoleWriter::Error(const char* fmt, ...) const
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
ConsoleColorScope cs(Color_StrongRed);
|
||||
FormatV(fmt, args);
|
||||
va_end(args);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IConsoleWriter::Warning(const char* fmt, ...) const
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
ConsoleColorScope cs(Color_StrongOrange);
|
||||
FormatV(fmt, args);
|
||||
va_end(args);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IConsoleWriter::WriteLn(ConsoleColors color, const std::string& str) const
|
||||
{
|
||||
ConsoleColorScope cs(color);
|
||||
return WriteLn(str);
|
||||
}
|
||||
|
||||
bool IConsoleWriter::WriteLn(const std::string& str) const
|
||||
{
|
||||
// TODO: Make this less rubbish
|
||||
if ((_imm_indentation + conlog_Indent) > 0)
|
||||
const bool was_enabled = (s_file_level > LOGLEVEL_NONE);
|
||||
const bool new_enabled = (level > LOGLEVEL_NONE && !path.empty());
|
||||
if (was_enabled != new_enabled || (new_enabled && path == s_file_path))
|
||||
{
|
||||
DoWriteLn(_addIndentation(str, conlog_Indent).c_str());
|
||||
if (new_enabled)
|
||||
{
|
||||
if (!s_file_handle || s_file_path != path)
|
||||
{
|
||||
s_file_handle.reset();
|
||||
s_file_handle = FileSystem::OpenManagedCFile(path.c_str(), "wb");
|
||||
if (s_file_handle)
|
||||
{
|
||||
s_file_path = std::move(path);
|
||||
}
|
||||
else
|
||||
{
|
||||
s_file_path = {};
|
||||
|
||||
if (IsConsoleOutputEnabled())
|
||||
WriteToConsole(LOGLEVEL_ERROR, Color_StrongRed, TinyString::from_fmt("Failed to open log file '{}'", path));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
s_file_handle.reset();
|
||||
s_file_path = {};
|
||||
}
|
||||
}
|
||||
|
||||
s_file_level = s_file_handle ? level : LOGLEVEL_NONE;
|
||||
return IsFileOutputEnabled();
|
||||
}
|
||||
|
||||
std::FILE* Log::GetFileLogHandle()
|
||||
{
|
||||
std::unique_lock lock(s_file_mutex);
|
||||
return s_file_handle.get();
|
||||
}
|
||||
|
||||
bool Log::IsHostOutputEnabled()
|
||||
{
|
||||
return (s_host_level > LOGLEVEL_NONE);
|
||||
}
|
||||
|
||||
void Log::SetHostOutputLevel(LOGLEVEL level, HostCallbackType callback)
|
||||
{
|
||||
s_host_callback = callback;
|
||||
s_host_level = callback ? level : LOGLEVEL_NONE;
|
||||
UpdateMaxLevel();
|
||||
}
|
||||
|
||||
bool Log::AreTimestampsEnabled()
|
||||
{
|
||||
return s_log_timestamps;
|
||||
}
|
||||
|
||||
void Log::SetTimestampsEnabled(bool enabled)
|
||||
{
|
||||
s_log_timestamps = enabled;
|
||||
}
|
||||
|
||||
LOGLEVEL Log::GetMaxLevel()
|
||||
{
|
||||
return s_max_level;
|
||||
}
|
||||
|
||||
__ri void Log::UpdateMaxLevel()
|
||||
{
|
||||
s_max_level = std::max(s_console_level, std::max(s_debug_level, std::max(s_file_level, s_host_level)));
|
||||
}
|
||||
|
||||
void Log::ExecuteCallbacks(LOGLEVEL level, ConsoleColors color, std::string_view message)
|
||||
{
|
||||
// TODO: Cache the message time.
|
||||
|
||||
// Split newlines into separate messages.
|
||||
std::string_view::size_type start_pos = 0;
|
||||
if (std::string_view::size_type end_pos = message.find('\n'); end_pos != std::string::npos) [[unlikely]]
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
std::string_view message_line;
|
||||
if (start_pos != end_pos)
|
||||
message_line = message.substr(start_pos, (end_pos == std::string_view::npos) ? end_pos : end_pos - start_pos);
|
||||
|
||||
ExecuteCallbacks(level, color, message_line);
|
||||
|
||||
if (end_pos == std::string_view::npos)
|
||||
return;
|
||||
|
||||
start_pos = end_pos + 1;
|
||||
end_pos = message.find('\n', start_pos);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
pxAssert(level > LOGLEVEL_NONE);
|
||||
if (level <= s_console_level)
|
||||
WriteToConsole(level, color, message);
|
||||
|
||||
if (level <= s_debug_level)
|
||||
WriteToDebug(level, color, message);
|
||||
|
||||
if (level <= s_file_level)
|
||||
WriteToFile(level, color, message);
|
||||
|
||||
if (level <= s_host_level)
|
||||
{
|
||||
// double check in case of race here
|
||||
const HostCallbackType callback = s_host_callback;
|
||||
if (callback)
|
||||
s_host_callback(level, color, message);
|
||||
}
|
||||
}
|
||||
|
||||
void Log::Write(LOGLEVEL level, ConsoleColors color, std::string_view message)
|
||||
{
|
||||
if (level > s_max_level)
|
||||
return;
|
||||
|
||||
ExecuteCallbacks(level, color, message);
|
||||
}
|
||||
|
||||
void Log::Writef(LOGLEVEL level, ConsoleColors color, const char* format, ...)
|
||||
{
|
||||
std::va_list ap;
|
||||
va_start(ap, format);
|
||||
Writev(level, color, format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void Log::Writev(LOGLEVEL level, ConsoleColors color, const char* format, va_list ap)
|
||||
{
|
||||
if (level > s_max_level)
|
||||
return;
|
||||
|
||||
std::va_list ap_copy;
|
||||
va_copy(ap_copy, ap);
|
||||
|
||||
#ifdef _WIN32
|
||||
const u32 required_size = static_cast<u32>(_vscprintf(format, ap_copy));
|
||||
#else
|
||||
const u32 required_size = std::vsnprintf(nullptr, 0, format, ap_copy);
|
||||
#endif
|
||||
va_end(ap_copy);
|
||||
|
||||
if (required_size < 512)
|
||||
{
|
||||
char buffer[512];
|
||||
const int len = std::vsnprintf(buffer, std::size(buffer), format, ap);
|
||||
if (len > 0)
|
||||
ExecuteCallbacks(level, color, std::string_view(buffer, static_cast<size_t>(len)));
|
||||
}
|
||||
else
|
||||
{
|
||||
DoWriteLn(str.c_str());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IConsoleWriter::Error(const std::string& str) const
|
||||
{
|
||||
return WriteLn(Color_StrongRed, str);
|
||||
}
|
||||
|
||||
bool IConsoleWriter::Warning(const std::string& str) const
|
||||
{
|
||||
return WriteLn(Color_StrongOrange, str);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// ConsoleColorScope / ConsoleIndentScope
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
ConsoleColorScope::ConsoleColorScope(ConsoleColors newcolor)
|
||||
{
|
||||
m_IsScoped = false;
|
||||
m_newcolor = newcolor;
|
||||
EnterScope();
|
||||
}
|
||||
|
||||
ConsoleColorScope::~ConsoleColorScope()
|
||||
{
|
||||
LeaveScope();
|
||||
}
|
||||
|
||||
void ConsoleColorScope::EnterScope()
|
||||
{
|
||||
if (!m_IsScoped)
|
||||
{
|
||||
m_old_color = Console.GetColor();
|
||||
Console.SetColor(m_newcolor);
|
||||
m_IsScoped = true;
|
||||
char* buffer = new char[required_size + 1];
|
||||
const int len = std::vsnprintf(buffer, required_size + 1, format, ap);
|
||||
if (len > 0)
|
||||
ExecuteCallbacks(level, color, std::string_view(buffer, static_cast<size_t>(len)));
|
||||
delete[] buffer;
|
||||
}
|
||||
}
|
||||
|
||||
void ConsoleColorScope::LeaveScope()
|
||||
void Log::WriteFmtArgs(LOGLEVEL level, ConsoleColors color, fmt::string_view fmt, fmt::format_args args)
|
||||
{
|
||||
m_IsScoped = m_IsScoped && (Console.SetColor(m_old_color), false);
|
||||
}
|
||||
if (level > s_max_level)
|
||||
return;
|
||||
|
||||
ConsoleIndentScope::ConsoleIndentScope(int tabs)
|
||||
{
|
||||
m_IsScoped = false;
|
||||
m_amount = tabs;
|
||||
EnterScope();
|
||||
}
|
||||
fmt::memory_buffer buffer;
|
||||
fmt::vformat_to(std::back_inserter(buffer), fmt, args);
|
||||
|
||||
ConsoleIndentScope::~ConsoleIndentScope()
|
||||
{
|
||||
LeaveScope();
|
||||
}
|
||||
|
||||
void ConsoleIndentScope::EnterScope()
|
||||
{
|
||||
m_IsScoped = m_IsScoped || (Console.SetIndent(m_amount), true);
|
||||
}
|
||||
|
||||
void ConsoleIndentScope::LeaveScope()
|
||||
{
|
||||
m_IsScoped = m_IsScoped && (Console.SetIndent(-m_amount), false);
|
||||
}
|
||||
|
||||
|
||||
ConsoleAttrScope::ConsoleAttrScope(ConsoleColors newcolor, int indent)
|
||||
{
|
||||
m_old_color = Console.GetColor();
|
||||
Console.SetIndent(m_tabsize = indent);
|
||||
Console.SetColor(newcolor);
|
||||
}
|
||||
|
||||
ConsoleAttrScope::~ConsoleAttrScope()
|
||||
{
|
||||
Console.SetColor(m_old_color);
|
||||
Console.SetIndent(-m_tabsize);
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Default Writer for C++ init / startup:
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Currently all build types default to Stdout, which is very functional on Linux but not
|
||||
// always so useful on Windows (which itself lacks a proper stdout console without using
|
||||
// platform specific code). Under windows Stdout will attempt to write to the IDE Debug
|
||||
// console, if one is available (such as running pcsx2 via MSVC). If not available, then
|
||||
// the log message will pretty much be lost into the ether.
|
||||
//
|
||||
#define _DefaultWriter_ ConsoleWriter_Stdout
|
||||
|
||||
IConsoleWriter Console = _DefaultWriter_;
|
||||
IConsoleWriter DevConWriter = _DefaultWriter_;
|
||||
bool DevConWriterEnabled = false;
|
||||
|
||||
#ifdef PCSX2_DEBUG
|
||||
IConsoleWriter DbgConWriter = _DefaultWriter_;
|
||||
#endif
|
||||
|
||||
NullConsoleWriter NullCon = {};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// ConsoleLogSource (implementations)
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
// Writes to the console using the specified color. This overrides the default color setting
|
||||
// for this log.
|
||||
bool ConsoleLogSource::WriteV(ConsoleColors color, const char* fmt, va_list list) const
|
||||
{
|
||||
ConsoleColorScope cs(color);
|
||||
Console.WriteLn(StringUtil::StdStringFromFormatV(fmt, list));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Writes to the console using the source's default color. Note that the source's default
|
||||
// color will always be used, thus ConsoleColorScope() will not be effectual unless the
|
||||
// console's default color is Color_Default.
|
||||
bool ConsoleLogSource::WriteV(const char* fmt, va_list list) const
|
||||
{
|
||||
WriteV(DefaultColor, fmt, list);
|
||||
return false;
|
||||
ExecuteCallbacks(level, color, std::string_view(buffer.data(), buffer.size()));
|
||||
}
|
||||
|
||||
+129
-171
@@ -1,16 +1,19 @@
|
||||
// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team
|
||||
// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: LGPL-3.0+
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Pcsx2Defs.h"
|
||||
|
||||
#include "fmt/core.h"
|
||||
|
||||
#include <cstdarg>
|
||||
#include <string>
|
||||
|
||||
// TODO: This whole thing needs to get ripped out.
|
||||
|
||||
enum ConsoleColors
|
||||
{
|
||||
Color_Current = -1,
|
||||
|
||||
Color_Default = 0,
|
||||
|
||||
Color_Black,
|
||||
@@ -42,191 +45,146 @@ enum ConsoleColors
|
||||
ConsoleColors_Count
|
||||
};
|
||||
|
||||
static const ConsoleColors DefaultConsoleColor = Color_Default;
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// IConsoleWriter -- For printing messages to the console.
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// General ConsoleWrite Threading Guideline:
|
||||
// PCSX2 is a threaded environment and multiple threads can write to the console asynchronously.
|
||||
// Individual calls to ConsoleWriter APIs will be written in atomic fashion, however "partial"
|
||||
// logs may end up interrupted by logs on other threads. This is usually not a problem for
|
||||
// WriteLn, but may be undesirable for typical uses of Write. In cases where you want to
|
||||
// print multi-line blocks of uninterrupted logs, compound the entire log into a single large
|
||||
// string and issue that to WriteLn.
|
||||
//
|
||||
struct IConsoleWriter
|
||||
enum LOGLEVEL
|
||||
{
|
||||
// A direct console write, without tabbing or newlines. Useful to devs who want to do quick
|
||||
// logging of various junk; but should *not* be used in production code due.
|
||||
void(* WriteRaw)(const char* fmt);
|
||||
LOGLEVEL_NONE, // Silences all log traffic
|
||||
LOGLEVEL_ERROR,
|
||||
LOGLEVEL_WARNING,
|
||||
LOGLEVEL_INFO,
|
||||
LOGLEVEL_DEV,
|
||||
LOGLEVEL_DEBUG,
|
||||
LOGLEVEL_TRACE,
|
||||
|
||||
// WriteLn implementation for internal use only. Bypasses tabbing, prefixing, and other
|
||||
// formatting.
|
||||
void(* DoWriteLn)(const char* fmt);
|
||||
|
||||
// SetColor implementation for internal use only.
|
||||
void(* DoSetColor)(ConsoleColors color);
|
||||
|
||||
// Special implementation of DoWrite that's pretty much for MSVC use only.
|
||||
// All implementations should map to DoWrite, except Stdio which should map to Null.
|
||||
// (This avoids circular/recursive stdio output)
|
||||
void(* DoWriteFromStdout)(const char* fmt);
|
||||
|
||||
void(* Newline)();
|
||||
void(* SetTitle)(const char* title);
|
||||
|
||||
// internal value for indentation of individual lines. Use the Indent() member to invoke.
|
||||
int _imm_indentation;
|
||||
|
||||
// For internal use only.
|
||||
std::string _addIndentation(const std::string& src, int glob_indent) const;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Public members; call these to print stuff to console!
|
||||
//
|
||||
// All functions always return false. Return value is provided only so that we can easily
|
||||
// disable logs at compile time using the "0&&action" macro trick.
|
||||
|
||||
ConsoleColors GetColor() const;
|
||||
const IConsoleWriter& SetColor(ConsoleColors color) const;
|
||||
const IConsoleWriter& ClearColor() const;
|
||||
const IConsoleWriter& SetIndent(int tabcount = 1) const;
|
||||
|
||||
IConsoleWriter Indent(int tabcount = 1) const;
|
||||
|
||||
bool FormatV(const char* fmt, va_list args) const;
|
||||
bool WriteLn(ConsoleColors color, const char* fmt, ...) const;
|
||||
bool WriteLn(const char* fmt, ...) const;
|
||||
bool Error(const char* fmt, ...) const;
|
||||
bool Warning(const char* fmt, ...) const;
|
||||
|
||||
bool WriteLn(ConsoleColors color, const std::string& str) const;
|
||||
bool WriteLn(const std::string& str) const;
|
||||
bool Error(const std::string& str) const;
|
||||
bool Warning(const std::string& str) const;
|
||||
LOGLEVEL_COUNT,
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// NullConsoleWriter
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Used by Release builds for Debug and Devel writes (DbgCon / DevCon). Inlines to NOPs. :)
|
||||
//
|
||||
struct NullConsoleWriter
|
||||
// TODO: Move this elsewhere, add channels.
|
||||
|
||||
namespace Log
|
||||
{
|
||||
void WriteRaw(const char* fmt) {}
|
||||
void DoWriteLn(const char* fmt) {}
|
||||
void DoSetColor(ConsoleColors color) {}
|
||||
void DoWriteFromStdout(const char* fmt) {}
|
||||
void Newline() {}
|
||||
void SetTitle(const char* title) {}
|
||||
// log message callback type
|
||||
using HostCallbackType = void (*)(LOGLEVEL level, ConsoleColors color, std::string_view message);
|
||||
|
||||
// returns the time in seconds since the start of the process
|
||||
float GetCurrentMessageTime();
|
||||
|
||||
ConsoleColors GetColor() const { return Color_Current; }
|
||||
const NullConsoleWriter& SetColor(ConsoleColors color) const { return *this; }
|
||||
const NullConsoleWriter& ClearColor() const { return *this; }
|
||||
const NullConsoleWriter& SetIndent(int tabcount = 1) const { return *this; }
|
||||
// adds a standard console output
|
||||
bool IsConsoleOutputEnabled();
|
||||
void SetConsoleOutputLevel(LOGLEVEL level);
|
||||
|
||||
NullConsoleWriter Indent(int tabcount = 1) const { return NullConsoleWriter(); }
|
||||
// adds a debug console output
|
||||
bool IsDebugOutputAvailable();
|
||||
bool IsDebugOutputEnabled();
|
||||
void SetDebugOutputLevel(LOGLEVEL level);
|
||||
|
||||
bool FormatV(const char* fmt, va_list args) const { return false; }
|
||||
bool WriteLn(ConsoleColors color, const char* fmt, ...) const { return false; }
|
||||
bool WriteLn(const char* fmt, ...) const { return false; }
|
||||
bool Error(const char* fmt, ...) const { return false; }
|
||||
bool Warning(const char* fmt, ...) const { return false; }
|
||||
// adds a file output
|
||||
bool IsFileOutputEnabled();
|
||||
bool SetFileOutputLevel(LOGLEVEL level, std::string path);
|
||||
|
||||
// returns the log file, this is really dangerous to use if it changes...
|
||||
std::FILE* GetFileLogHandle();
|
||||
|
||||
// adds host output
|
||||
bool IsHostOutputEnabled();
|
||||
void SetHostOutputLevel(LOGLEVEL level, HostCallbackType callback);
|
||||
|
||||
// sets logging timestamps
|
||||
bool AreTimestampsEnabled();
|
||||
void SetTimestampsEnabled(bool enabled);
|
||||
|
||||
// Returns the current global filtering level.
|
||||
LOGLEVEL GetMaxLevel();
|
||||
|
||||
// writes a message to the log
|
||||
void Write(LOGLEVEL level, ConsoleColors color, std::string_view message);
|
||||
void Writef(LOGLEVEL level, ConsoleColors color, const char* format, ...);
|
||||
void Writev(LOGLEVEL level, ConsoleColors color, const char* format, va_list ap);
|
||||
void WriteFmtArgs(LOGLEVEL level, ConsoleColors color, fmt::string_view fmt, fmt::format_args args);
|
||||
|
||||
template <typename... T>
|
||||
__fi static void Write(LOGLEVEL level, ConsoleColors color, fmt::format_string<T...> fmt, T&&... args)
|
||||
{
|
||||
// Avoid arg packing if filtered.
|
||||
if (level <= GetMaxLevel())
|
||||
return WriteFmtArgs(level, color, fmt, fmt::make_format_args(args...));
|
||||
}
|
||||
} // namespace Log
|
||||
|
||||
// Adapter classes to handle old code.
|
||||
template <LOGLEVEL level>
|
||||
struct ConsoleLogWriter
|
||||
{
|
||||
__fi static void Error(std::string_view str) { Log::Write(level, Color_StrongRed, str); }
|
||||
__fi static void Warning(std::string_view str) { Log::Write(level, Color_StrongOrange, str); }
|
||||
__fi static void WriteLn(std::string_view str) { Log::Write(level, Color_Default, str); }
|
||||
__fi static void WriteLn(ConsoleColors color, std::string_view str) { Log::Write(level, color, str); }
|
||||
__fi static void WriteLn() { Log::Write(level, Color_Default, std::string_view()); }
|
||||
__fi static void FormatV(const char* format, va_list ap) { Log::Writev(level, Color_Default, format, ap); }
|
||||
__fi static void FormatV(ConsoleColors color, const char* format, va_list ap) { Log::Writev(level, color, format, ap); }
|
||||
|
||||
#define MAKE_PRINTF_CONSOLE_WRITER(color) \
|
||||
do \
|
||||
{ \
|
||||
std::va_list ap; \
|
||||
va_start(ap, format); \
|
||||
Log::Writev(level, color, format, ap); \
|
||||
va_end(ap); \
|
||||
} while (0)
|
||||
|
||||
// clang-format off
|
||||
__fi static void Error(const char* format, ...) { MAKE_PRINTF_CONSOLE_WRITER(Color_StrongRed); }
|
||||
__fi static void Warning(const char* format, ...) { MAKE_PRINTF_CONSOLE_WRITER(Color_StrongOrange); }
|
||||
__fi static void WriteLn(const char* format, ...) { MAKE_PRINTF_CONSOLE_WRITER(Color_Default); }
|
||||
__fi static void WriteLn(ConsoleColors color, const char* format, ...) { MAKE_PRINTF_CONSOLE_WRITER(color); }
|
||||
// clang-format on
|
||||
|
||||
#undef MAKE_PRINTF_CONSOLE_WRITER
|
||||
|
||||
#define MAKE_FMT_CONSOLE_WRITER(color) do \
|
||||
{ \
|
||||
if (level <= Log::GetMaxLevel()) \
|
||||
Log::WriteFmtArgs(level, color, fmt, fmt::make_format_args(args...)); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
// clang-format off
|
||||
template<typename... T> __fi static void ErrorFmt(fmt::format_string<T...> fmt, T&&... args) { MAKE_FMT_CONSOLE_WRITER(Color_StrongRed); }
|
||||
template<typename... T> __fi static void WarningFmt(fmt::format_string<T...> fmt, T&&... args) { MAKE_FMT_CONSOLE_WRITER(Color_StrongOrange); }
|
||||
template<typename... T> __fi static void WriteLnFmt(fmt::format_string<T...> fmt, T&&... args) { MAKE_FMT_CONSOLE_WRITER(Color_Default); }
|
||||
template<typename... T> __fi static void WriteLnFmt(ConsoleColors color, fmt::format_string<T...> fmt, T&&... args) { MAKE_FMT_CONSOLE_WRITER(color); }
|
||||
// clang-format on
|
||||
|
||||
#undef MAKE_FMT_CONSOLE_WRITER
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// ConsoleIndentScope
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Provides a scoped indentation of the IConsoleWriter interface for the current thread.
|
||||
// Any console writes performed from this scope will be indented by the specified number
|
||||
// of tab characters.
|
||||
//
|
||||
// Scoped Object Notes: Like most scoped objects, this is intended to be used as a stack
|
||||
// or temporary object only. Using it in a situation where the object's lifespan out-lives
|
||||
// a scope will almost certainly result in unintended /undefined side effects.
|
||||
//
|
||||
class ConsoleIndentScope
|
||||
struct NullLogWriter
|
||||
{
|
||||
DeclareNoncopyableObject(ConsoleIndentScope);
|
||||
// clang-format off
|
||||
__fi static bool Error(std::string_view str) { return false; }
|
||||
__fi static bool Warning(std::string_view str) { return false; }
|
||||
__fi static bool WriteLn(std::string_view str) { return false; }
|
||||
__fi static bool WriteLn(ConsoleColors color, std::string_view str) { return false; }
|
||||
__fi static bool WriteLn() { return false; }
|
||||
|
||||
protected:
|
||||
int m_amount;
|
||||
bool m_IsScoped;
|
||||
__fi static bool Error(const char* format, ...) { return false; }
|
||||
__fi static bool Warning(const char* format, ...) { return false; }
|
||||
__fi static bool WriteLn(const char* format, ...) { return false; }
|
||||
__fi static bool WriteLn(ConsoleColors color, const char* format, ...) { return false; }
|
||||
|
||||
public:
|
||||
// Constructor: The specified number of tabs will be appended to the current indentation
|
||||
// setting. The tabs will be unrolled when the object leaves scope or is destroyed.
|
||||
ConsoleIndentScope(int tabs = 1);
|
||||
virtual ~ConsoleIndentScope();
|
||||
void EnterScope();
|
||||
void LeaveScope();
|
||||
template<typename... T> __fi static bool ErrorFmt(fmt::format_string<T...> fmt, T&&... args) { return false; }
|
||||
template<typename... T> __fi static bool WarningFmt(fmt::format_string<T...> fmt, T&&... args) { return false; }
|
||||
template<typename... T> __fi static bool WriteLnFmt(fmt::format_string<T...> fmt, T&&... args) { return false; }
|
||||
template<typename... T> __fi static bool WriteLnFmt(ConsoleColors color, fmt::format_string<T...> fmt, T&&... args) { return false; }
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// ConsoleColorScope
|
||||
// --------------------------------------------------------------------------------------
|
||||
class ConsoleColorScope
|
||||
{
|
||||
DeclareNoncopyableObject(ConsoleColorScope);
|
||||
extern ConsoleLogWriter<LOGLEVEL_INFO> Console;
|
||||
extern ConsoleLogWriter<LOGLEVEL_DEV> DevCon;
|
||||
|
||||
protected:
|
||||
ConsoleColors m_newcolor;
|
||||
ConsoleColors m_old_color;
|
||||
bool m_IsScoped;
|
||||
|
||||
public:
|
||||
ConsoleColorScope(ConsoleColors newcolor);
|
||||
virtual ~ConsoleColorScope();
|
||||
void EnterScope();
|
||||
void LeaveScope();
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// ConsoleAttrScope
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Applies both color and tab attributes in a single object constructor.
|
||||
//
|
||||
class ConsoleAttrScope
|
||||
{
|
||||
DeclareNoncopyableObject(ConsoleAttrScope);
|
||||
|
||||
protected:
|
||||
ConsoleColors m_old_color;
|
||||
int m_tabsize;
|
||||
|
||||
public:
|
||||
ConsoleAttrScope(ConsoleColors newcolor, int indent = 0);
|
||||
virtual ~ConsoleAttrScope();
|
||||
};
|
||||
|
||||
extern IConsoleWriter Console;
|
||||
|
||||
#if defined(__POSIX__)
|
||||
extern void Console_SetStdout(FILE* fp);
|
||||
#endif
|
||||
extern void Console_SetActiveHandler(const IConsoleWriter& writer, FILE* flushfp = NULL);
|
||||
|
||||
extern const IConsoleWriter ConsoleWriter_Null;
|
||||
extern const IConsoleWriter ConsoleWriter_Stdout;
|
||||
extern const IConsoleWriter ConsoleWriter_Assert;
|
||||
|
||||
extern NullConsoleWriter NullCon;
|
||||
|
||||
extern IConsoleWriter DevConWriter;
|
||||
extern bool DevConWriterEnabled;
|
||||
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
#define DevCon DevConWriter
|
||||
#else
|
||||
#define DevCon DevConWriterEnabled&& DevConWriter
|
||||
#endif
|
||||
|
||||
#ifdef PCSX2_DEBUG
|
||||
extern IConsoleWriter DbgConWriter;
|
||||
#ifdef _DEBUG
|
||||
extern ConsoleLogWriter<LOGLEVEL_DEBUG> DbgConWriter;
|
||||
#define DbgCon DbgConWriter
|
||||
#else
|
||||
#define DbgCon 0 && NullCon
|
||||
extern NullLogWriter DbgConWriter;
|
||||
#define DbgCon 0 && DbgConWriter
|
||||
#endif
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
#include "common/Pcsx2Types.h"
|
||||
#include "common/Console.h"
|
||||
#include "common/General.h"
|
||||
#include "common/HostSys.h"
|
||||
#include "common/Threading.h"
|
||||
#include "common/WindowInfo.h"
|
||||
|
||||
|
||||
@@ -29,7 +29,11 @@ __forceinline void Threading::SpinWait()
|
||||
{
|
||||
// If this doesn't compile you can just comment it out (it only serves as a
|
||||
// performance hint and isn't required).
|
||||
#if defined(_M_X86)
|
||||
__asm__("pause");
|
||||
#elif defined(_M_ARM64)
|
||||
__asm__ __volatile__("isb");
|
||||
#endif
|
||||
}
|
||||
|
||||
__forceinline void Threading::EnableHiresScheduler()
|
||||
|
||||
@@ -5,6 +5,13 @@
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
// Template function for casting enumerations to their underlying type
|
||||
template <typename Enumeration>
|
||||
typename std::underlying_type<Enumeration>::type enum_cast(Enumeration E)
|
||||
{
|
||||
return static_cast<typename std::underlying_type<Enumeration>::type>(E);
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
/// Marks an enum as supporting boolean operators
|
||||
|
||||
@@ -0,0 +1,216 @@
|
||||
// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: LGPL-3.0+
|
||||
|
||||
// This file abstracts the floating-point control registers, known as MXCSR on x86, and FPCR on AArch64.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/Pcsx2Defs.h"
|
||||
#include "common/VectorIntrin.h"
|
||||
|
||||
enum class FPRoundMode : u8
|
||||
{
|
||||
Nearest,
|
||||
NegativeInfinity,
|
||||
PositiveInfinity,
|
||||
ChopZero,
|
||||
|
||||
MaxCount
|
||||
};
|
||||
|
||||
struct FPControlRegister
|
||||
{
|
||||
#ifdef _M_X86
|
||||
u32 bitmask;
|
||||
|
||||
static constexpr u32 EXCEPTION_MASK = (0x3Fu << 7);
|
||||
static constexpr u32 ROUNDING_CONTROL_SHIFT = 13;
|
||||
static constexpr u32 ROUNDING_CONTROL_MASK = 3u;
|
||||
static constexpr u32 ROUNDING_CONTROL_BITS = (ROUNDING_CONTROL_MASK << ROUNDING_CONTROL_SHIFT);
|
||||
static constexpr u32 DENORMALS_ARE_ZERO_BIT = (1u << 6);
|
||||
static constexpr u32 FLUSH_TO_ZERO_BIT = (1u << 15);
|
||||
|
||||
__fi static FPControlRegister GetCurrent()
|
||||
{
|
||||
return FPControlRegister{_mm_getcsr()};
|
||||
}
|
||||
|
||||
__fi static void SetCurrent(FPControlRegister value)
|
||||
{
|
||||
_mm_setcsr(value.bitmask);
|
||||
}
|
||||
|
||||
__fi static constexpr FPControlRegister GetDefault()
|
||||
{
|
||||
// 0x1f80 - all exceptions masked, nearest rounding
|
||||
return FPControlRegister{0x1f80};
|
||||
}
|
||||
|
||||
__fi constexpr FPControlRegister& EnableExceptions()
|
||||
{
|
||||
bitmask &= ~EXCEPTION_MASK;
|
||||
return *this;
|
||||
}
|
||||
|
||||
__fi constexpr FPControlRegister DisableExceptions()
|
||||
{
|
||||
bitmask |= EXCEPTION_MASK;
|
||||
return *this;
|
||||
}
|
||||
|
||||
__fi constexpr FPRoundMode GetRoundMode() const
|
||||
{
|
||||
return static_cast<FPRoundMode>((bitmask >> ROUNDING_CONTROL_SHIFT) & ROUNDING_CONTROL_MASK);
|
||||
}
|
||||
|
||||
__fi constexpr FPControlRegister& SetRoundMode(FPRoundMode mode)
|
||||
{
|
||||
// These bits match on x86.
|
||||
bitmask = (bitmask & ~ROUNDING_CONTROL_BITS) | ((static_cast<u32>(mode) & ROUNDING_CONTROL_MASK) << ROUNDING_CONTROL_SHIFT);
|
||||
return *this;
|
||||
}
|
||||
|
||||
__fi constexpr bool GetDenormalsAreZero() const
|
||||
{
|
||||
return ((bitmask & DENORMALS_ARE_ZERO_BIT) != 0);
|
||||
}
|
||||
|
||||
__fi constexpr FPControlRegister SetDenormalsAreZero(bool daz)
|
||||
{
|
||||
if (daz)
|
||||
bitmask |= DENORMALS_ARE_ZERO_BIT;
|
||||
else
|
||||
bitmask &= ~DENORMALS_ARE_ZERO_BIT;
|
||||
return *this;
|
||||
}
|
||||
|
||||
__fi constexpr bool GetFlushToZero() const
|
||||
{
|
||||
return ((bitmask & FLUSH_TO_ZERO_BIT) != 0);
|
||||
}
|
||||
|
||||
__fi constexpr FPControlRegister SetFlushToZero(bool ftz)
|
||||
{
|
||||
if (ftz)
|
||||
bitmask |= FLUSH_TO_ZERO_BIT;
|
||||
else
|
||||
bitmask &= ~FLUSH_TO_ZERO_BIT;
|
||||
return *this;
|
||||
}
|
||||
|
||||
__fi constexpr bool operator==(const FPControlRegister& rhs) const { return bitmask == rhs.bitmask; }
|
||||
__fi constexpr bool operator!=(const FPControlRegister& rhs) const { return bitmask != rhs.bitmask; }
|
||||
|
||||
#elif defined(_M_ARM64)
|
||||
u64 bitmask;
|
||||
|
||||
static constexpr u64 FZ_BIT = (0x1ULL << 24);
|
||||
static constexpr u32 RMODE_SHIFT = 22;
|
||||
static constexpr u64 RMODE_MASK = 0x3ULL;
|
||||
static constexpr u64 RMODE_BITS = (RMODE_MASK << RMODE_SHIFT);
|
||||
static constexpr u32 EXCEPTION_MASK = (0x3Fu << 5);
|
||||
|
||||
__fi static FPControlRegister GetCurrent()
|
||||
{
|
||||
u64 value;
|
||||
asm volatile("\tmrs %0, FPCR\n"
|
||||
: "=r"(value));
|
||||
return FPControlRegister{value};
|
||||
}
|
||||
|
||||
__fi static void SetCurrent(FPControlRegister value)
|
||||
{
|
||||
asm volatile("\tmsr FPCR, %0\n" ::"r"(value.bitmask));
|
||||
}
|
||||
|
||||
__fi static constexpr FPControlRegister GetDefault()
|
||||
{
|
||||
// 0x0 - all exceptions masked, nearest rounding
|
||||
return FPControlRegister{0x0};
|
||||
}
|
||||
|
||||
__fi constexpr FPControlRegister& EnableExceptions()
|
||||
{
|
||||
bitmask |= EXCEPTION_MASK;
|
||||
return *this;
|
||||
}
|
||||
|
||||
__fi constexpr FPControlRegister& DisableExceptions()
|
||||
{
|
||||
bitmask &= ~EXCEPTION_MASK;
|
||||
return *this;
|
||||
}
|
||||
|
||||
__fi constexpr FPRoundMode GetRoundMode() const
|
||||
{
|
||||
// Negative/Positive infinity rounding is flipped on A64.
|
||||
const u64 RMode = (bitmask >> RMODE_SHIFT) & RMODE_MASK;
|
||||
return static_cast<FPRoundMode>((RMode == 0b00 || RMode == 0b11) ? RMode : (RMode ^ 0b11));
|
||||
}
|
||||
|
||||
__fi constexpr FPControlRegister& SetRoundMode(FPRoundMode mode)
|
||||
{
|
||||
const u64 RMode = ((mode == FPRoundMode::Nearest || mode == FPRoundMode::ChopZero) ? static_cast<u64>(mode) : (static_cast<u64>(mode) ^ 0b11));
|
||||
bitmask = (bitmask & ~RMODE_BITS) | ((RMode & RMODE_MASK) << RMODE_SHIFT);
|
||||
return *this;
|
||||
}
|
||||
|
||||
__fi constexpr bool GetDenormalsAreZero() const
|
||||
{
|
||||
// Without FEAT_AFP, most ARM chips don't have separate DaZ/FtZ. This includes Apple Silicon, which
|
||||
// implements x86-like behavior with a vendor-specific extension that we cannot access from usermode.
|
||||
// The FZ bit causes both inputs and outputs to be flushed to zero.
|
||||
return ((bitmask & FZ_BIT) != 0);
|
||||
}
|
||||
|
||||
__fi constexpr FPControlRegister SetDenormalsAreZero(bool daz)
|
||||
{
|
||||
if (daz)
|
||||
bitmask |= FZ_BIT;
|
||||
else
|
||||
bitmask &= ~FZ_BIT;
|
||||
return *this;
|
||||
}
|
||||
|
||||
__fi constexpr bool GetFlushToZero() const
|
||||
{
|
||||
// See note in GetDenormalsAreZero().
|
||||
return ((bitmask & FZ_BIT) != 0);
|
||||
}
|
||||
|
||||
__fi constexpr FPControlRegister SetFlushToZero(bool ftz)
|
||||
{
|
||||
if (ftz)
|
||||
bitmask |= FZ_BIT;
|
||||
else
|
||||
bitmask &= ~FZ_BIT;
|
||||
return *this;
|
||||
}
|
||||
|
||||
__fi constexpr bool operator==(const FPControlRegister& rhs) const { return bitmask == rhs.bitmask; }
|
||||
__fi constexpr bool operator!=(const FPControlRegister& rhs) const { return bitmask != rhs.bitmask; }
|
||||
#else
|
||||
#error Unknown architecture.
|
||||
#endif
|
||||
};
|
||||
|
||||
/// Helper to back up/restore FPCR.
|
||||
class FPControlRegisterBackup
|
||||
{
|
||||
public:
|
||||
__fi FPControlRegisterBackup(FPControlRegister new_value)
|
||||
: m_prev_val(FPControlRegister::GetCurrent())
|
||||
{
|
||||
FPControlRegister::SetCurrent(new_value);
|
||||
}
|
||||
__fi ~FPControlRegisterBackup()
|
||||
{
|
||||
FPControlRegister::SetCurrent(m_prev_val);
|
||||
}
|
||||
|
||||
FPControlRegisterBackup(const FPControlRegisterBackup&) = delete;
|
||||
FPControlRegisterBackup& operator=(const FPControlRegisterBackup&) = delete;
|
||||
|
||||
private:
|
||||
FPControlRegister m_prev_val;
|
||||
};
|
||||
+47
-1
@@ -3,7 +3,8 @@
|
||||
|
||||
#include "FastJmp.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
// Win32 uses Fastjmp.asm, because MSVC doesn't support inline asm.
|
||||
#if !defined(_WIN32) || defined(_M_ARM64)
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#define PREFIX "_"
|
||||
@@ -11,6 +12,8 @@
|
||||
#define PREFIX ""
|
||||
#endif
|
||||
|
||||
#if defined(_M_X86)
|
||||
|
||||
asm(
|
||||
"\t.global " PREFIX "fastjmp_set\n"
|
||||
"\t.global " PREFIX "fastjmp_jmp\n"
|
||||
@@ -43,4 +46,47 @@ asm(
|
||||
jmp *%rdx
|
||||
)");
|
||||
|
||||
#elif defined(_M_ARM64)
|
||||
|
||||
asm(
|
||||
"\t.global " PREFIX "fastjmp_set\n"
|
||||
"\t.global " PREFIX "fastjmp_jmp\n"
|
||||
"\t.text\n"
|
||||
"\t.align 16\n"
|
||||
"\t" PREFIX "fastjmp_set:" R"(
|
||||
mov x16, sp
|
||||
stp x16, x30, [x0]
|
||||
stp x19, x20, [x0, #16]
|
||||
stp x21, x22, [x0, #32]
|
||||
stp x23, x24, [x0, #48]
|
||||
stp x25, x26, [x0, #64]
|
||||
stp x27, x28, [x0, #80]
|
||||
str x29, [x0, #96]
|
||||
stp d8, d9, [x0, #112]
|
||||
stp d10, d11, [x0, #128]
|
||||
stp d12, d13, [x0, #144]
|
||||
stp d14, d15, [x0, #160]
|
||||
mov w0, wzr
|
||||
br x30
|
||||
)"
|
||||
".align 16\n"
|
||||
"\t" PREFIX "fastjmp_jmp:" R"(
|
||||
ldp x16, x30, [x0]
|
||||
mov sp, x16
|
||||
ldp x19, x20, [x0, #16]
|
||||
ldp x21, x22, [x0, #32]
|
||||
ldp x23, x24, [x0, #48]
|
||||
ldp x25, x26, [x0, #64]
|
||||
ldp x27, x28, [x0, #80]
|
||||
ldr x29, [x0, #96]
|
||||
ldp d8, d9, [x0, #112]
|
||||
ldp d10, d11, [x0, #128]
|
||||
ldp d12, d13, [x0, #144]
|
||||
ldp d14, d15, [x0, #160]
|
||||
mov w0, w1
|
||||
br x30
|
||||
)");
|
||||
|
||||
#endif
|
||||
|
||||
#endif // __WIN32
|
||||
|
||||
@@ -10,6 +10,8 @@ struct fastjmp_buf
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
static constexpr std::size_t BUF_SIZE = 240;
|
||||
#elif defined(_M_ARM64)
|
||||
static constexpr std::size_t BUF_SIZE = 168;
|
||||
#else
|
||||
static constexpr std::size_t BUF_SIZE = 64;
|
||||
#endif
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: LGPL-3.0+
|
||||
|
||||
#include "General.h"
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// 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;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: LGPL-3.0+
|
||||
|
||||
#include "General.h"
|
||||
#include "HostSys.h"
|
||||
#include "Console.h"
|
||||
#include "VectorIntrin.h"
|
||||
|
||||
@@ -9,37 +9,6 @@
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
|
||||
// This macro is actually useful for about any and every possible application of C++
|
||||
// equality operators.
|
||||
#define OpEqu(field) (field == right.field)
|
||||
|
||||
// Macro used for removing some of the redtape involved in defining bitfield/union helpers.
|
||||
//
|
||||
#define BITFIELD32() \
|
||||
union \
|
||||
{ \
|
||||
u32 bitset; \
|
||||
struct \
|
||||
{
|
||||
|
||||
#define BITFIELD_END \
|
||||
}; \
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
[[maybe_unused]] __fi static T GetBufferT(u8* buffer, u32 offset)
|
||||
{
|
||||
T value;
|
||||
std::memcpy(&value, buffer + offset, sizeof(value));
|
||||
return value;
|
||||
}
|
||||
|
||||
[[maybe_unused]] __fi static u8 GetBufferU8(u8* buffer, u32 offset) { return GetBufferT<u8>(buffer, offset); }
|
||||
[[maybe_unused]] __fi static u16 GetBufferU16(u8* buffer, u32 offset) { return GetBufferT<u16>(buffer, offset); }
|
||||
[[maybe_unused]] __fi static u32 GetBufferU32(u8* buffer, u32 offset) { return GetBufferT<u32>(buffer, offset); }
|
||||
[[maybe_unused]] __fi static u64 GetBufferU64(u8* buffer, u32 offset) { return GetBufferT<u64>(buffer, offset); }
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// PageProtectionMode
|
||||
@@ -47,46 +16,41 @@ template <typename T>
|
||||
class PageProtectionMode
|
||||
{
|
||||
protected:
|
||||
bool m_read;
|
||||
bool m_write;
|
||||
bool m_exec;
|
||||
bool m_read = false;
|
||||
bool m_write = false;
|
||||
bool m_exec = false;
|
||||
|
||||
public:
|
||||
PageProtectionMode()
|
||||
{
|
||||
All(false);
|
||||
}
|
||||
__fi constexpr PageProtectionMode() = default;
|
||||
|
||||
PageProtectionMode& Read(bool allow = true)
|
||||
__fi constexpr PageProtectionMode& Read(bool allow = true)
|
||||
{
|
||||
m_read = allow;
|
||||
return *this;
|
||||
}
|
||||
|
||||
PageProtectionMode& Write(bool allow = true)
|
||||
__fi constexpr PageProtectionMode& Write(bool allow = true)
|
||||
{
|
||||
m_write = allow;
|
||||
return *this;
|
||||
}
|
||||
|
||||
PageProtectionMode& Execute(bool allow = true)
|
||||
__fi constexpr PageProtectionMode& Execute(bool allow = true)
|
||||
{
|
||||
m_exec = allow;
|
||||
return *this;
|
||||
}
|
||||
|
||||
PageProtectionMode& All(bool allow = true)
|
||||
__fi constexpr PageProtectionMode& All(bool allow = true)
|
||||
{
|
||||
m_read = m_write = m_exec = allow;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool CanRead() const { return m_read; }
|
||||
bool CanWrite() const { return m_write; }
|
||||
bool CanExecute() const { return m_exec && m_read; }
|
||||
bool IsNone() const { return !m_read && !m_write; }
|
||||
|
||||
std::string ToString() const;
|
||||
__fi constexpr bool CanRead() const { return m_read; }
|
||||
__fi constexpr bool CanWrite() const { return m_write; }
|
||||
__fi constexpr bool CanExecute() const { return m_exec && m_read; }
|
||||
__fi constexpr bool IsNone() const { return !m_read && !m_write; }
|
||||
};
|
||||
|
||||
static __fi PageProtectionMode PageAccess_None()
|
||||
@@ -152,6 +116,25 @@ namespace HostSys
|
||||
|
||||
/// Removes the page fault handler. handler is only specified to check against the active callback.
|
||||
void RemovePageFaultHandler(PageFaultHandler handler);
|
||||
|
||||
/// JIT write protect for Apple Silicon. Needs to be called prior to writing to any RWX pages.
|
||||
#if !defined(__APPLE__) || !defined(_M_ARM64)
|
||||
// clang-format -off
|
||||
[[maybe_unused]] __fi static void BeginCodeWrite() {}
|
||||
[[maybe_unused]] __fi static void EndCodeWrite() {}
|
||||
// clang-format on
|
||||
#else
|
||||
void BeginCodeWrite();
|
||||
void EndCodeWrite();
|
||||
#endif
|
||||
|
||||
/// Flushes the instruction cache on the host for the specified range.
|
||||
/// Only needed on ARM64, X86 has coherent D/I cache.
|
||||
#ifdef _M_X86
|
||||
[[maybe_unused]] __fi static void FlushInstructionCache(void* address, u32 size) {}
|
||||
#else
|
||||
void FlushInstructionCache(void* address, u32 size);
|
||||
#endif
|
||||
}
|
||||
|
||||
class SharedMemoryMappingArea
|
||||
@@ -1,6 +1,10 @@
|
||||
// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: LGPL-3.0+
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#define _XOPEN_SOURCE
|
||||
#endif
|
||||
|
||||
#if !defined(_WIN32)
|
||||
#include <cstdio>
|
||||
#include <sys/mman.h>
|
||||
@@ -16,7 +20,7 @@
|
||||
#include "common/BitUtils.h"
|
||||
#include "common/Assertions.h"
|
||||
#include "common/Console.h"
|
||||
#include "common/General.h"
|
||||
#include "common/HostSys.h"
|
||||
|
||||
// Apple uses the MAP_ANON define instead of MAP_ANONYMOUS, but they mean
|
||||
// the same thing.
|
||||
@@ -38,14 +42,23 @@ static PageFaultHandler s_exception_handler_callback;
|
||||
static bool s_in_exception_handler;
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <mach/task.h>
|
||||
#include <mach/mach_init.h>
|
||||
#include <mach/mach_port.h>
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__) || defined(__aarch64__)
|
||||
static struct sigaction s_old_sigbus_action;
|
||||
#else
|
||||
#endif
|
||||
#if !defined(__APPLE__) || defined(__aarch64__)
|
||||
static struct sigaction s_old_sigsegv_action;
|
||||
#endif
|
||||
|
||||
static void CallExistingSignalHandler(int signal, siginfo_t* siginfo, void* ctx)
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
#if defined(__aarch64__)
|
||||
const struct sigaction& sa = (signal == SIGBUS) ? s_old_sigbus_action : s_old_sigsegv_action;
|
||||
#elif defined(__APPLE__)
|
||||
const struct sigaction& sa = s_old_sigbus_action;
|
||||
#else
|
||||
const struct sigaction& sa = s_old_sigsegv_action;
|
||||
@@ -92,6 +105,12 @@ static void SysPageFaultSignalFilter(int signal, siginfo_t* siginfo, void* ctx)
|
||||
void* const exception_pc = reinterpret_cast<void*>(static_cast<ucontext_t*>(ctx)->uc_mcontext.mc_rip);
|
||||
#elif defined(__x86_64__)
|
||||
void* const exception_pc = reinterpret_cast<void*>(static_cast<ucontext_t*>(ctx)->uc_mcontext.gregs[REG_RIP]);
|
||||
#elif defined(__aarch64__)
|
||||
#ifndef __APPLE__
|
||||
void* const exception_pc = reinterpret_cast<void*>(static_cast<ucontext_t*>(ctx)->uc_mcontext.pc);
|
||||
#else
|
||||
void* const exception_pc = reinterpret_cast<void*>(static_cast<ucontext_t*>(ctx)->uc_mcontext->__ss.__pc);
|
||||
#endif
|
||||
#else
|
||||
void* const exception_pc = nullptr;
|
||||
#endif
|
||||
@@ -129,13 +148,18 @@ bool HostSys::InstallPageFaultHandler(PageFaultHandler handler)
|
||||
// Don't block the signal from executing recursively, we want to fire the original handler.
|
||||
sa.sa_flags |= SA_NODEFER;
|
||||
#endif
|
||||
#ifdef __APPLE__
|
||||
// MacOS uses SIGBUS for memory permission violations
|
||||
#if defined(__APPLE__) || defined(__aarch64__)
|
||||
// MacOS uses SIGBUS for memory permission violations, as well as SIGSEGV on ARM64.
|
||||
if (sigaction(SIGBUS, &sa, &s_old_sigbus_action) != 0)
|
||||
return false;
|
||||
#else
|
||||
#endif
|
||||
#if !defined(__APPLE__) || defined(__aarch64__)
|
||||
if (sigaction(SIGSEGV, &sa, &s_old_sigsegv_action) != 0)
|
||||
return false;
|
||||
#endif
|
||||
#if defined(__APPLE__) && defined(__aarch64__)
|
||||
// Stops LLDB getting in a EXC_BAD_ACCESS loop when passing page faults to PCSX2.
|
||||
task_set_exception_ports(mach_task_self(), EXC_MASK_BAD_ACCESS, MACH_PORT_NULL, EXCEPTION_DEFAULT, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -154,9 +178,10 @@ void HostSys::RemovePageFaultHandler(PageFaultHandler handler)
|
||||
s_exception_handler_callback = nullptr;
|
||||
|
||||
struct sigaction sa;
|
||||
#ifdef __APPLE__
|
||||
#if defined(__APPLE__) || defined(__aarch64__)
|
||||
sigaction(SIGBUS, &s_old_sigbus_action, &sa);
|
||||
#else
|
||||
#endif
|
||||
#if !defined(__APPLE__) || defined(__aarch64__)
|
||||
sigaction(SIGSEGV, &s_old_sigsegv_action, &sa);
|
||||
#endif
|
||||
}
|
||||
@@ -188,6 +213,11 @@ void* HostSys::Mmap(void* base, size_t size, const PageProtectionMode& mode)
|
||||
if (base)
|
||||
flags |= MAP_FIXED;
|
||||
|
||||
#if defined(__APPLE__) && defined(_M_ARM64)
|
||||
if (mode.CanExecute())
|
||||
flags |= MAP_JIT;
|
||||
#endif
|
||||
|
||||
void* res = mmap(base, size, prot, flags, -1, 0);
|
||||
if (res == MAP_FAILED)
|
||||
return nullptr;
|
||||
@@ -270,6 +300,15 @@ void HostSys::UnmapSharedMemory(void* baseaddr, size_t size)
|
||||
pxFailRel("Failed to unmap shared memory");
|
||||
}
|
||||
|
||||
#ifdef _M_ARM64
|
||||
|
||||
void HostSys::FlushInstructionCache(void* address, u32 size)
|
||||
{
|
||||
__builtin___clear_cache(reinterpret_cast<char*>(address), reinterpret_cast<char*>(address) + size);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
SharedMemoryMappingArea::SharedMemoryMappingArea(u8* base_ptr, size_t size, size_t num_pages)
|
||||
: m_base_ptr(base_ptr)
|
||||
, m_size(size)
|
||||
@@ -323,3 +362,22 @@ bool SharedMemoryMappingArea::Unmap(void* map_base, size_t map_size)
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(_M_ARM64) && defined(__APPLE__)
|
||||
|
||||
static thread_local int s_code_write_depth = 0;
|
||||
|
||||
void HostSys::BeginCodeWrite()
|
||||
{
|
||||
if ((s_code_write_depth++) == 0)
|
||||
pthread_jit_write_protect_np(0);
|
||||
}
|
||||
|
||||
void HostSys::EndCodeWrite()
|
||||
{
|
||||
pxAssert(s_code_write_depth > 0);
|
||||
if ((--s_code_write_depth) == 0)
|
||||
pthread_jit_write_protect_np(1);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#if !defined(_WIN32) && !defined(__APPLE__)
|
||||
|
||||
#include "common/Pcsx2Types.h"
|
||||
#include "common/General.h"
|
||||
#include "common/HostSys.h"
|
||||
#include "common/ScopedGuard.h"
|
||||
#include "common/StringUtil.h"
|
||||
#include "common/Threading.h"
|
||||
|
||||
@@ -28,10 +28,6 @@
|
||||
#include "common/Threading.h"
|
||||
#include "common/Assertions.h"
|
||||
|
||||
// We wont need this until we actually have this more then just stubbed out, so I'm commenting this out
|
||||
// to remove an unneeded dependency.
|
||||
//#include "x86emitter/tools.h"
|
||||
|
||||
#if !defined(__unix__)
|
||||
|
||||
#pragma message("LnxThreads.cpp should only be compiled by projects or makefiles targeted at Linux/BSD distros.")
|
||||
@@ -53,7 +49,11 @@ __forceinline void Threading::SpinWait()
|
||||
{
|
||||
// If this doesn't compile you can just comment it out (it only serves as a
|
||||
// performance hint and isn't required).
|
||||
#if defined(_M_X86)
|
||||
__asm__("pause");
|
||||
#elif defined(_M_ARM64)
|
||||
__asm__ __volatile__("isb");
|
||||
#endif
|
||||
}
|
||||
|
||||
__forceinline void Threading::EnableHiresScheduler()
|
||||
|
||||
@@ -99,71 +99,6 @@ static constexpr unsigned int __pagemask = __pagesize - 1;
|
||||
#define safe_delete_array(ptr) (delete[] (ptr), (ptr) = nullptr)
|
||||
#define safe_free(ptr) (std::free(ptr), (ptr) = nullptr)
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// ImplementEnumOperators (macro)
|
||||
// --------------------------------------------------------------------------------------
|
||||
// This macro implements ++/-- operators for any conforming enumeration. In order for an
|
||||
// enum to conform, it must have _FIRST and _COUNT members defined, and must have a full
|
||||
// compliment of sequential members (no custom assignments) --- looking like so:
|
||||
//
|
||||
// enum Dummy {
|
||||
// Dummy_FIRST,
|
||||
// Dummy_Item = Dummy_FIRST,
|
||||
// Dummy_Crap,
|
||||
// Dummy_COUNT
|
||||
// };
|
||||
//
|
||||
// The macro also defines utility functions for bounds checking enumerations:
|
||||
// EnumIsValid(value); // returns TRUE if the enum value is between FIRST and COUNT.
|
||||
// EnumAssert(value);
|
||||
//
|
||||
// It also defines a *prototype* for converting the enumeration to a string. Note that this
|
||||
// method is not implemented! You must implement it yourself if you want to use it:
|
||||
// EnumToString(value);
|
||||
//
|
||||
#define ImplementEnumOperators(enumName) \
|
||||
static __fi enumName& operator++(enumName& src) \
|
||||
{ \
|
||||
src = (enumName)((int)src + 1); \
|
||||
return src; \
|
||||
} \
|
||||
\
|
||||
static __fi enumName& operator--(enumName& src) \
|
||||
{ \
|
||||
src = (enumName)((int)src - 1); \
|
||||
return src; \
|
||||
} \
|
||||
\
|
||||
static __fi enumName operator++(enumName& src, int) \
|
||||
{ \
|
||||
enumName orig = src; \
|
||||
src = (enumName)((int)src + 1); \
|
||||
return orig; \
|
||||
} \
|
||||
\
|
||||
static __fi enumName operator--(enumName& src, int) \
|
||||
{ \
|
||||
enumName orig = src; \
|
||||
src = (enumName)((int)src - 1); \
|
||||
return orig; \
|
||||
} \
|
||||
\
|
||||
static __fi bool operator<(const enumName& left, const pxEnumEnd_t&) { return (int)left < enumName##_COUNT; } \
|
||||
static __fi bool operator!=(const enumName& left, const pxEnumEnd_t&) { return (int)left != enumName##_COUNT; } \
|
||||
static __fi bool operator==(const enumName& left, const pxEnumEnd_t&) { return (int)left == enumName##_COUNT; } \
|
||||
\
|
||||
static __fi bool EnumIsValid(enumName id) \
|
||||
{ \
|
||||
return ((int)id >= enumName##_FIRST) && ((int)id < enumName##_COUNT); \
|
||||
} \
|
||||
\
|
||||
extern const char* EnumToString(enumName id)
|
||||
|
||||
class pxEnumEnd_t
|
||||
{
|
||||
};
|
||||
static const pxEnumEnd_t pxEnumEnd = {};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// DeclareNoncopyableObject
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
@@ -138,7 +138,13 @@ namespace Perf
|
||||
pxAssertRel(perf_marker != MAP_FAILED, "Map perf marker");
|
||||
|
||||
JITDUMP_HEADER jh = {};
|
||||
#if defined(_M_X86)
|
||||
jh.elf_mach = EM_X86_64;
|
||||
#elif defined(_M_ARM64)
|
||||
jh.elf_mach = EM_AARCH64;
|
||||
#else
|
||||
#error Unhandled architecture.
|
||||
#endif
|
||||
jh.pid = getpid();
|
||||
jh.timestamp = JitDumpTimestamp();
|
||||
std::fwrite(&jh, sizeof(jh), 1, s_jitdump_file);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "common/Threading.h"
|
||||
#include "common/Assertions.h"
|
||||
#include "common/HostSys.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "common/RedtapeWindows.h"
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
|
||||
#include "SettingsInterface.h"
|
||||
|
||||
#include "common/EnumOps.h"
|
||||
|
||||
// Helper class which loads or saves depending on the derived class.
|
||||
class SettingsWrapper
|
||||
{
|
||||
|
||||
@@ -14,7 +14,16 @@
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
// Work around us defining _M_ARM64 but fast_float thinking that it means MSVC.
|
||||
#if defined(_M_ARM64) && !defined(_WIN32)
|
||||
#define HAD_M_ARM64 _M_ARM64
|
||||
#undef _M_ARM64
|
||||
#endif
|
||||
#include "fast_float/fast_float.h"
|
||||
#if defined(HAD_M_ARM64) && !defined(_WIN32)
|
||||
#define _M_ARM64 HAD_M_ARM64
|
||||
#undef HAD_M_ARM64
|
||||
#endif
|
||||
|
||||
// Older versions of libstdc++ are missing support for from_chars() with floats, and was only recently
|
||||
// merged in libc++. So, just fall back to stringstream (yuck!) on everywhere except MSVC.
|
||||
|
||||
@@ -59,10 +59,7 @@ public:
|
||||
};
|
||||
};
|
||||
|
||||
inline color_rgba()
|
||||
{
|
||||
static_assert(sizeof(*this) == 4, "sizeof(*this) != 4");
|
||||
}
|
||||
inline color_rgba() = default;
|
||||
|
||||
inline color_rgba(int y)
|
||||
{
|
||||
@@ -190,6 +187,8 @@ public:
|
||||
static color_rgba comp_max(const color_rgba& a, const color_rgba& b) { return color_rgba(std::max(a[0], b[0]), std::max(a[1], b[1]), std::max(a[2], b[2]), std::max(a[3], b[3])); }
|
||||
};
|
||||
|
||||
static_assert(sizeof(color_rgba) == 4);
|
||||
|
||||
bool unpack_bc7(const void *pBlock, color_rgba *pPixels);
|
||||
|
||||
} // namespace bc7decomp
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/Pcsx2Defs.h"
|
||||
#include "common/General.h"
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include <mach/semaphore.h>
|
||||
|
||||
+10
-2
@@ -183,7 +183,15 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WriteV(const char* fmt, va_list list) const;
|
||||
bool WriteV(const char* fmt, va_list list) const
|
||||
{
|
||||
Console.FormatV(fmt, list);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WriteV(ConsoleColors color, const char* fmt, va_list list) const;
|
||||
bool WriteV(ConsoleColors color, const char* fmt, va_list list) const
|
||||
{
|
||||
Console.FormatV(color, fmt, list);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include "common/BitUtils.h"
|
||||
#include "common/RedtapeWindows.h"
|
||||
#include "common/Console.h"
|
||||
#include "common/General.h"
|
||||
#include "common/HostSys.h"
|
||||
#include "common/StringUtil.h"
|
||||
#include "common/AlignedMalloc.h"
|
||||
#include "common/Assertions.h"
|
||||
@@ -34,7 +34,13 @@ long __stdcall SysPageFaultExceptionFilter(EXCEPTION_POINTERS* eps)
|
||||
if (eps->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION)
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
|
||||
#if defined(_M_AMD64)
|
||||
void* const exception_pc = reinterpret_cast<void*>(eps->ContextRecord->Rip);
|
||||
#elif defined(_M_ARM64)
|
||||
void* const exception_pc = reinterpret_cast<void*>(eps->ContextRecord->Pc);
|
||||
#else
|
||||
void* const exception_pc = nullptr;
|
||||
#endif
|
||||
|
||||
const PageFaultInfo pfi{(uptr)exception_pc, (uptr)eps->ExceptionRecord->ExceptionInformation[1]};
|
||||
|
||||
@@ -161,6 +167,15 @@ void HostSys::UnmapSharedMemory(void* baseaddr, size_t size)
|
||||
pxFail("Failed to unmap shared memory");
|
||||
}
|
||||
|
||||
#ifdef _M_ARM64
|
||||
|
||||
void HostSys::FlushInstructionCache(void* address, u32 size)
|
||||
{
|
||||
::FlushInstructionCache(GetCurrentProcess(), address, size);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
SharedMemoryMappingArea::SharedMemoryMappingArea(u8* base_ptr, size_t size, size_t num_pages)
|
||||
: m_base_ptr(base_ptr)
|
||||
, m_size(size)
|
||||
|
||||
@@ -3,11 +3,10 @@
|
||||
|
||||
#if defined(_WIN32)
|
||||
|
||||
#include "common/Pcsx2Defs.h"
|
||||
#include "common/HostSys.h"
|
||||
#include "common/RedtapeWindows.h"
|
||||
#include "common/StringUtil.h"
|
||||
#include "common/Threading.h"
|
||||
#include "common/General.h"
|
||||
#include "common/WindowInfo.h"
|
||||
|
||||
#include "fmt/core.h"
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
#include "common/Threading.h"
|
||||
#include "common/Assertions.h"
|
||||
#include "common/emitter/tools.h"
|
||||
#include "common/RedtapeWindows.h"
|
||||
#include <mmsystem.h>
|
||||
#include <process.h>
|
||||
@@ -20,7 +19,11 @@ __fi void Threading::Timeslice()
|
||||
// improve performance and reduce cpu power consumption.
|
||||
__fi void Threading::SpinWait()
|
||||
{
|
||||
#ifdef _M_X86
|
||||
_mm_pause();
|
||||
#else
|
||||
YieldProcessor();
|
||||
#endif
|
||||
}
|
||||
|
||||
__fi void Threading::EnableHiresScheduler()
|
||||
|
||||
@@ -55,7 +55,6 @@
|
||||
<ExcludedFromBuild>true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="FileSystem.cpp" />
|
||||
<ClCompile Include="General.cpp" />
|
||||
<ClCompile Include="Image.cpp" />
|
||||
<ClCompile Include="HTTPDownloader.cpp" />
|
||||
<ClCompile Include="HTTPDownloaderCurl.cpp">
|
||||
@@ -84,11 +83,10 @@
|
||||
<ClCompile Include="Windows\WinHostSys.cpp" />
|
||||
<ClCompile Include="Windows\WinMisc.cpp" />
|
||||
<ClCompile Include="Windows\WinThreads.cpp" />
|
||||
<ClCompile Include="Misc.cpp" />
|
||||
<ClCompile Include="HostSys.cpp" />
|
||||
<ClCompile Include="Semaphore.cpp" />
|
||||
<ClCompile Include="emitter\avx.cpp" />
|
||||
<ClCompile Include="emitter\bmi.cpp" />
|
||||
<ClCompile Include="emitter\cpudetect.cpp" />
|
||||
<ClCompile Include="emitter\fpu.cpp" />
|
||||
<ClCompile Include="emitter\groups.cpp" />
|
||||
<ClCompile Include="emitter\jmp.cpp" />
|
||||
@@ -97,8 +95,6 @@
|
||||
<ClCompile Include="emitter\movs.cpp" />
|
||||
<ClCompile Include="emitter\simd.cpp" />
|
||||
<ClCompile Include="emitter\x86emitter.cpp" />
|
||||
<ClCompile Include="emitter\LnxCpuDetect.cpp" />
|
||||
<ClCompile Include="emitter\WinCpuDetect.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<MASM Include="FastJmp.asm" />
|
||||
@@ -114,6 +110,7 @@
|
||||
<ClInclude Include="Error.h" />
|
||||
<ClInclude Include="FastJmp.h" />
|
||||
<ClInclude Include="FileSystem.h" />
|
||||
<ClInclude Include="FPControl.h" />
|
||||
<ClInclude Include="HashCombine.h" />
|
||||
<ClInclude Include="HeapArray.h" />
|
||||
<ClInclude Include="HeterogeneousContainers.h" />
|
||||
@@ -137,7 +134,7 @@
|
||||
<ClInclude Include="SettingsWrapper.h" />
|
||||
<ClInclude Include="Assertions.h" />
|
||||
<ClInclude Include="Console.h" />
|
||||
<ClInclude Include="General.h" />
|
||||
<ClInclude Include="HostSys.h" />
|
||||
<ClInclude Include="Path.h" />
|
||||
<ClInclude Include="PrecompiledHeader.h" />
|
||||
<ClInclude Include="ReadbackSpinManager.h" />
|
||||
@@ -154,7 +151,6 @@
|
||||
<ClInclude Include="emitter\legacy_instructions.h" />
|
||||
<ClInclude Include="emitter\legacy_internal.h" />
|
||||
<ClInclude Include="emitter\legacy_types.h" />
|
||||
<ClInclude Include="emitter\tools.h" />
|
||||
<ClInclude Include="emitter\x86emitter.h" />
|
||||
<ClInclude Include="emitter\x86types.h" />
|
||||
<ClInclude Include="emitter\implement\dwshift.h" />
|
||||
|
||||
@@ -10,9 +10,6 @@
|
||||
<ClCompile Include="Console.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="emitter\cpudetect.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="emitter\fpu.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
@@ -28,9 +25,6 @@
|
||||
<ClCompile Include="emitter\legacy_sse.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="emitter\LnxCpuDetect.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="emitter\avx.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
@@ -46,7 +40,7 @@
|
||||
<ClCompile Include="emitter\movs.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Misc.cpp">
|
||||
<ClCompile Include="HostSys.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Perf.cpp">
|
||||
@@ -64,9 +58,6 @@
|
||||
<ClCompile Include="emitter\simd.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="emitter\WinCpuDetect.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Windows\WinHostSys.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
@@ -133,9 +124,6 @@
|
||||
<ClCompile Include="FileSystem.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="General.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Error.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
@@ -168,7 +156,7 @@
|
||||
<ClInclude Include="emitter\implement\dwshift.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="General.h">
|
||||
<ClInclude Include="HostSys.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="emitter\implement\group1.h">
|
||||
@@ -243,9 +231,6 @@
|
||||
<ClInclude Include="emitter\implement\test.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="emitter\tools.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="emitter\x86emitter.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
@@ -358,6 +343,7 @@
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SingleRegisterTypes.h" />
|
||||
<ClInclude Include="FPControl.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: LGPL-3.0+
|
||||
|
||||
#ifndef _WIN32
|
||||
#include "common/emitter/tools.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
// Note: Apparently this solution is Linux/Solaris only.
|
||||
// FreeBSD/OsX need something far more complicated (apparently)
|
||||
void x86capabilities::CountLogicalCores()
|
||||
{
|
||||
#ifdef __linux__
|
||||
// Note : GetCPUCount uses sysconf( _SC_NPROCESSORS_ONLN ) internally, which can return 1
|
||||
// if sysconf info isn't available (a long standing linux bug). There are no fallbacks or
|
||||
// alternatives, apparently.
|
||||
LogicalCores = sysconf(_SC_NPROCESSORS_ONLN);
|
||||
#else
|
||||
LogicalCores = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,28 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: LGPL-3.0+
|
||||
|
||||
#if defined(_WIN32)
|
||||
|
||||
#include "common/Console.h"
|
||||
#include "common/emitter/tools.h"
|
||||
#include "common/RedtapeWindows.h"
|
||||
|
||||
void x86capabilities::CountLogicalCores()
|
||||
{
|
||||
DWORD_PTR vProcessCPUs;
|
||||
DWORD_PTR vSystemCPUs;
|
||||
|
||||
LogicalCores = 1;
|
||||
|
||||
if (!GetProcessAffinityMask(GetCurrentProcess(), &vProcessCPUs, &vSystemCPUs))
|
||||
return;
|
||||
|
||||
uint CPUs = 0;
|
||||
for (DWORD_PTR bit = 1; bit != 0; bit <<= 1)
|
||||
if (vSystemCPUs & bit)
|
||||
CPUs++;
|
||||
|
||||
LogicalCores = CPUs;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -2,7 +2,6 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0+
|
||||
|
||||
#include "common/emitter/internal.h"
|
||||
#include "common/emitter/tools.h"
|
||||
|
||||
// warning: suggest braces around initialization of subobject [-Wmissing-braces]
|
||||
#ifdef __clang__
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0+
|
||||
|
||||
#include "common/emitter/internal.h"
|
||||
#include "common/emitter/tools.h"
|
||||
|
||||
namespace x86Emitter
|
||||
{
|
||||
|
||||
@@ -1,249 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: LGPL-3.0+
|
||||
|
||||
#include "common/General.h"
|
||||
#include "common/emitter/tools.h"
|
||||
#include "common/emitter/internal.h"
|
||||
#include "common/VectorIntrin.h"
|
||||
#include <atomic>
|
||||
|
||||
// CPU information support
|
||||
#if defined(_WIN32)
|
||||
|
||||
#define cpuid __cpuid
|
||||
#define cpuidex __cpuidex
|
||||
|
||||
#else
|
||||
|
||||
#include <cpuid.h>
|
||||
|
||||
static __inline__ __attribute__((always_inline)) void cpuidex(int CPUInfo[], const int InfoType, const int count)
|
||||
{
|
||||
__cpuid_count(InfoType, count, CPUInfo[0], CPUInfo[1], CPUInfo[2], CPUInfo[3]);
|
||||
}
|
||||
|
||||
static __inline__ __attribute__((always_inline)) void cpuid(int CPUInfo[], const int InfoType)
|
||||
{
|
||||
__cpuid(InfoType, CPUInfo[0], CPUInfo[1], CPUInfo[2], CPUInfo[3]);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
using namespace x86Emitter;
|
||||
|
||||
alignas(16) x86capabilities x86caps;
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
// We disable optimizations for this function, because we need x86capabilities for AVX
|
||||
// detection, but if we keep opts on, it'll use AVX instructions for inlining memzero.
|
||||
#pragma optimize("", off)
|
||||
#endif
|
||||
x86capabilities::x86capabilities()
|
||||
: isIdentified(false)
|
||||
, VendorID(x86Vendor_Unknown)
|
||||
, FamilyID(0)
|
||||
, Model(0)
|
||||
, TypeID(0)
|
||||
, StepID(0)
|
||||
, Flags(0)
|
||||
, Flags2(0)
|
||||
, EFlags(0)
|
||||
, EFlags2(0)
|
||||
, SEFlag(0)
|
||||
, AllCapabilities(0)
|
||||
, PhysicalCores(0)
|
||||
, LogicalCores(0)
|
||||
{
|
||||
}
|
||||
#if defined(_MSC_VER)
|
||||
#pragma optimize("", on)
|
||||
#endif
|
||||
|
||||
// Warning! We've had problems with the MXCSR detection code causing stack corruption in
|
||||
// MSVC PGO builds. The problem was fixed when I moved the MXCSR code to this function, and
|
||||
// moved the recSSE[] array to a global static (it was local to cpudetectInit). Commented
|
||||
// here in case the nutty crash ever re-surfaces. >_<
|
||||
// Note: recSSE was deleted
|
||||
void x86capabilities::SIMD_EstablishMXCSRmask()
|
||||
{
|
||||
if (!hasStreamingSIMDExtensions)
|
||||
return;
|
||||
|
||||
MXCSR_Mask.bitmask = 0xFFBF; // MMX/SSE default
|
||||
|
||||
if (hasStreamingSIMD2Extensions)
|
||||
{
|
||||
// This is generally safe assumption, but FXSAVE is the "correct" way to
|
||||
// detect MXCSR masking features of the cpu, so we use it's result below
|
||||
// and override this.
|
||||
|
||||
MXCSR_Mask.bitmask = 0xFFFF; // SSE2 features added
|
||||
}
|
||||
|
||||
alignas(16) u8 targetFXSAVE[512];
|
||||
|
||||
// Work for recent enough GCC/CLANG/MSVC 2012
|
||||
_fxsave(&targetFXSAVE);
|
||||
|
||||
u32 result;
|
||||
memcpy(&result, &targetFXSAVE[28], 4); // bytes 28->32 are the MXCSR_Mask.
|
||||
if (result != 0)
|
||||
MXCSR_Mask.bitmask = result;
|
||||
}
|
||||
|
||||
const char* x86capabilities::GetTypeName() const
|
||||
{
|
||||
switch (TypeID)
|
||||
{
|
||||
case 0:
|
||||
return "Standard OEM";
|
||||
case 1:
|
||||
return "Overdrive";
|
||||
case 2:
|
||||
return "Dual";
|
||||
case 3:
|
||||
return "Reserved";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
void x86capabilities::CountCores()
|
||||
{
|
||||
Identify();
|
||||
|
||||
// This will assign values into LogicalCores and PhysicalCores
|
||||
CountLogicalCores();
|
||||
}
|
||||
|
||||
static const char* tbl_x86vendors[] =
|
||||
{
|
||||
"GenuineIntel",
|
||||
"AuthenticAMD",
|
||||
"Unknown ",
|
||||
};
|
||||
|
||||
// Performs all _cpuid-related activity. This fills *most* of the x86caps structure, except for
|
||||
// the cpuSpeed and the mxcsr masks. Those must be completed manually.
|
||||
void x86capabilities::Identify()
|
||||
{
|
||||
if (isIdentified)
|
||||
return;
|
||||
isIdentified = true;
|
||||
|
||||
s32 regs[4];
|
||||
u32 cmds;
|
||||
|
||||
cpuid(regs, 0);
|
||||
|
||||
cmds = regs[0];
|
||||
memcpy(&VendorName[0], ®s[1], 4);
|
||||
memcpy(&VendorName[4], ®s[3], 4);
|
||||
memcpy(&VendorName[8], ®s[2], 4);
|
||||
|
||||
// Determine Vendor Specifics!
|
||||
// It's really not recommended that we base much (if anything) on CPU vendor names,
|
||||
// however it's currently necessary in order to gain a (pseudo)reliable count of cores
|
||||
// and threads used by the CPU (AMD and Intel can't agree on how to make this info available).
|
||||
|
||||
int vid;
|
||||
for (vid = 0; vid < x86Vendor_Unknown; ++vid)
|
||||
{
|
||||
if (memcmp(VendorName, tbl_x86vendors[vid], 12) == 0)
|
||||
break;
|
||||
}
|
||||
VendorID = static_cast<x86VendorType>(vid);
|
||||
|
||||
if (cmds >= 0x00000001)
|
||||
{
|
||||
cpuid(regs, 0x00000001);
|
||||
|
||||
StepID = regs[0] & 0xf;
|
||||
Model = (regs[0] >> 4) & 0xf;
|
||||
FamilyID = (regs[0] >> 8) & 0xf;
|
||||
TypeID = (regs[0] >> 12) & 0x3;
|
||||
//u32 x86_64_8BITBRANDID = regs[1] & 0xff;
|
||||
Flags = regs[3];
|
||||
Flags2 = regs[2];
|
||||
}
|
||||
|
||||
if (cmds >= 0x00000007)
|
||||
{
|
||||
// Note: ECX must be 0 for AVX2 detection.
|
||||
cpuidex(regs, 0x00000007, 0);
|
||||
|
||||
SEFlag = regs[1];
|
||||
}
|
||||
|
||||
cpuid(regs, 0x80000000);
|
||||
cmds = regs[0];
|
||||
if (cmds >= 0x80000001)
|
||||
{
|
||||
cpuid(regs, 0x80000001);
|
||||
|
||||
//u32 x86_64_12BITBRANDID = regs[1] & 0xfff;
|
||||
EFlags2 = regs[2];
|
||||
EFlags = regs[3];
|
||||
}
|
||||
|
||||
cpuid((int*)FamilyName, 0x80000002);
|
||||
cpuid((int*)(FamilyName + 16), 0x80000003);
|
||||
cpuid((int*)(FamilyName + 32), 0x80000004);
|
||||
|
||||
hasFloatingPointUnit = (Flags >> 0) & 1;
|
||||
hasVirtual8086ModeEnhancements = (Flags >> 1) & 1;
|
||||
hasDebuggingExtensions = (Flags >> 2) & 1;
|
||||
hasPageSizeExtensions = (Flags >> 3) & 1;
|
||||
hasTimeStampCounter = (Flags >> 4) & 1;
|
||||
hasModelSpecificRegisters = (Flags >> 5) & 1;
|
||||
hasPhysicalAddressExtension = (Flags >> 6) & 1;
|
||||
hasMachineCheckArchitecture = (Flags >> 7) & 1;
|
||||
hasCOMPXCHG8BInstruction = (Flags >> 8) & 1;
|
||||
hasAdvancedProgrammableInterruptController = (Flags >> 9) & 1;
|
||||
hasSEPFastSystemCall = (Flags >> 11) & 1;
|
||||
hasMemoryTypeRangeRegisters = (Flags >> 12) & 1;
|
||||
hasPTEGlobalFlag = (Flags >> 13) & 1;
|
||||
hasMachineCheckArchitecture = (Flags >> 14) & 1;
|
||||
hasConditionalMoveAndCompareInstructions = (Flags >> 15) & 1;
|
||||
hasFGPageAttributeTable = (Flags >> 16) & 1;
|
||||
has36bitPageSizeExtension = (Flags >> 17) & 1;
|
||||
hasProcessorSerialNumber = (Flags >> 18) & 1;
|
||||
hasCFLUSHInstruction = (Flags >> 19) & 1;
|
||||
hasDebugStore = (Flags >> 21) & 1;
|
||||
hasACPIThermalMonitorAndClockControl = (Flags >> 22) & 1;
|
||||
hasFastStreamingSIMDExtensionsSaveRestore = (Flags >> 24) & 1;
|
||||
hasStreamingSIMDExtensions = (Flags >> 25) & 1; //sse
|
||||
hasStreamingSIMD2Extensions = (Flags >> 26) & 1; //sse2
|
||||
hasSelfSnoop = (Flags >> 27) & 1;
|
||||
hasMultiThreading = (Flags >> 28) & 1;
|
||||
hasThermalMonitor = (Flags >> 29) & 1;
|
||||
hasIntel64BitArchitecture = (Flags >> 30) & 1;
|
||||
|
||||
// -------------------------------------------------
|
||||
// --> SSE3 / SSSE3 / SSE4.1 / SSE 4.2 detection <--
|
||||
// -------------------------------------------------
|
||||
|
||||
hasStreamingSIMD3Extensions = (Flags2 >> 0) & 1; //sse3
|
||||
hasSupplementalStreamingSIMD3Extensions = (Flags2 >> 9) & 1; //ssse3
|
||||
hasStreamingSIMD4Extensions = (Flags2 >> 19) & 1; //sse4.1
|
||||
hasStreamingSIMD4Extensions2 = (Flags2 >> 20) & 1; //sse4.2
|
||||
|
||||
if ((Flags2 >> 27) & 1) // OSXSAVE
|
||||
{
|
||||
// Note: In theory, we should use xgetbv to check OS support
|
||||
// but all OSes we officially run under support it
|
||||
// and its intrinsic requires extra compiler flags
|
||||
hasAVX = (Flags2 >> 28) & 1; //avx
|
||||
hasFMA = (Flags2 >> 12) & 1; //fma
|
||||
hasAVX2 = (SEFlag >> 5) & 1; //avx2
|
||||
}
|
||||
|
||||
hasBMI1 = (SEFlag >> 3) & 1;
|
||||
hasBMI2 = (SEFlag >> 8) & 1;
|
||||
|
||||
// Ones only for AMDs:
|
||||
hasAMD64BitArchitecture = (EFlags >> 29) & 1; //64bit cpu
|
||||
hasStreamingSIMD4ExtensionsA = (EFlags2 >> 6) & 1; //INSERTQ / EXTRQ / MOVNT
|
||||
|
||||
isIdentified = true;
|
||||
}
|
||||
@@ -2,86 +2,8 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0+
|
||||
|
||||
#include "common/emitter/internal.h"
|
||||
#include "common/emitter/tools.h"
|
||||
#include "common/VectorIntrin.h"
|
||||
|
||||
// Mask of valid bit fields for the target CPU. Typically this is either 0xFFFF (SSE2
|
||||
// or better) or 0xFFBF (SSE1 and earlier). Code can ensure a safe/valid MXCSR by
|
||||
// AND'ing this mask against an MXCSR prior to LDMXCSR.
|
||||
SSE_MXCSR MXCSR_Mask;
|
||||
|
||||
const char* EnumToString(SSE_RoundMode sse)
|
||||
{
|
||||
switch (sse)
|
||||
{
|
||||
case SSEround_Nearest:
|
||||
return "Nearest";
|
||||
case SSEround_NegInf:
|
||||
return "NegativeInfinity";
|
||||
case SSEround_PosInf:
|
||||
return "PositiveInfinity";
|
||||
case SSEround_Chop:
|
||||
return "Chop";
|
||||
default:
|
||||
return "Invalid";
|
||||
}
|
||||
}
|
||||
|
||||
SSE_MXCSR SSE_MXCSR::GetCurrent()
|
||||
{
|
||||
SSE_MXCSR ret;
|
||||
ret.bitmask = _mm_getcsr();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void SSE_MXCSR::SetCurrent(const SSE_MXCSR& value)
|
||||
{
|
||||
_mm_setcsr(value.bitmask);
|
||||
}
|
||||
|
||||
SSE_RoundMode SSE_MXCSR::GetRoundMode() const
|
||||
{
|
||||
return (SSE_RoundMode)RoundingControl;
|
||||
}
|
||||
|
||||
SSE_MXCSR& SSE_MXCSR::SetRoundMode(SSE_RoundMode mode)
|
||||
{
|
||||
pxAssert((uint)mode < 4);
|
||||
RoundingControl = (u32)mode;
|
||||
return *this;
|
||||
}
|
||||
|
||||
SSE_MXCSR& SSE_MXCSR::ClearExceptionFlags()
|
||||
{
|
||||
bitmask &= ~0x3f;
|
||||
return *this;
|
||||
}
|
||||
|
||||
SSE_MXCSR& SSE_MXCSR::EnableExceptions()
|
||||
{
|
||||
bitmask &= ~(0x3f << 7);
|
||||
return *this;
|
||||
}
|
||||
|
||||
SSE_MXCSR& SSE_MXCSR::DisableExceptions()
|
||||
{
|
||||
bitmask |= 0x3f << 7;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Applies the reserve bits mask for the current running cpu, as fetched from the CPU
|
||||
// during CPU init/detection.
|
||||
SSE_MXCSR& SSE_MXCSR::ApplyReserveMask()
|
||||
{
|
||||
bitmask &= MXCSR_Mask.bitmask;
|
||||
return *this;
|
||||
}
|
||||
|
||||
SSE_MXCSR::operator x86Emitter::xIndirect32() const
|
||||
{
|
||||
return x86Emitter::ptr32[&bitmask];
|
||||
}
|
||||
|
||||
namespace x86Emitter
|
||||
{
|
||||
|
||||
|
||||
@@ -1,199 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: LGPL-3.0+
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/Pcsx2Defs.h"
|
||||
|
||||
enum x86VendorType
|
||||
{
|
||||
x86Vendor_Intel = 0,
|
||||
x86Vendor_AMD = 1,
|
||||
x86Vendor_Unknown = 2
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// x86capabilities
|
||||
// --------------------------------------------------------------------------------------
|
||||
class x86capabilities
|
||||
{
|
||||
public:
|
||||
bool isIdentified;
|
||||
|
||||
public:
|
||||
x86VendorType VendorID;
|
||||
|
||||
uint FamilyID; // Processor Family
|
||||
uint Model; // Processor Model
|
||||
uint TypeID; // Processor Type
|
||||
uint StepID; // Stepping ID
|
||||
|
||||
u32 Flags; // Feature Flags
|
||||
u32 Flags2; // More Feature Flags
|
||||
u32 EFlags; // Extended Feature Flags
|
||||
u32 EFlags2; // Extended Feature Flags pg2
|
||||
u32 SEFlag; // Structured Extended Feature Flags Enumeration
|
||||
|
||||
char VendorName[16] = {}; // Vendor/Creator ID
|
||||
char FamilyName[50] = {}; // the original cpu name
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// x86 CPU Capabilities Section (all boolean flags!)
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
union
|
||||
{
|
||||
u64 AllCapabilities = 0;
|
||||
|
||||
struct
|
||||
{
|
||||
u32 hasFloatingPointUnit : 1;
|
||||
u32 hasVirtual8086ModeEnhancements : 1;
|
||||
u32 hasDebuggingExtensions : 1;
|
||||
u32 hasPageSizeExtensions : 1;
|
||||
u32 hasTimeStampCounter : 1;
|
||||
u32 hasModelSpecificRegisters : 1;
|
||||
u32 hasPhysicalAddressExtension : 1;
|
||||
u32 hasCOMPXCHG8BInstruction : 1;
|
||||
u32 hasAdvancedProgrammableInterruptController : 1;
|
||||
u32 hasSEPFastSystemCall : 1;
|
||||
u32 hasMemoryTypeRangeRegisters : 1;
|
||||
u32 hasPTEGlobalFlag : 1;
|
||||
u32 hasMachineCheckArchitecture : 1;
|
||||
u32 hasConditionalMoveAndCompareInstructions : 1;
|
||||
u32 hasFGPageAttributeTable : 1;
|
||||
u32 has36bitPageSizeExtension : 1;
|
||||
u32 hasProcessorSerialNumber : 1;
|
||||
u32 hasCFLUSHInstruction : 1;
|
||||
u32 hasDebugStore : 1;
|
||||
u32 hasACPIThermalMonitorAndClockControl : 1;
|
||||
u32 hasFastStreamingSIMDExtensionsSaveRestore : 1;
|
||||
u32 hasStreamingSIMDExtensions : 1;
|
||||
u32 hasStreamingSIMD2Extensions : 1;
|
||||
u32 hasSelfSnoop : 1;
|
||||
|
||||
// is TRUE for both multi-core and Hyperthreaded CPUs.
|
||||
u32 hasMultiThreading : 1;
|
||||
|
||||
u32 hasThermalMonitor : 1;
|
||||
u32 hasIntel64BitArchitecture : 1;
|
||||
u32 hasStreamingSIMD3Extensions : 1;
|
||||
u32 hasSupplementalStreamingSIMD3Extensions : 1;
|
||||
u32 hasStreamingSIMD4Extensions : 1;
|
||||
u32 hasStreamingSIMD4Extensions2 : 1;
|
||||
u32 hasAVX : 1;
|
||||
u32 hasAVX2 : 1;
|
||||
u32 hasBMI1 : 1;
|
||||
u32 hasBMI2 : 1;
|
||||
u32 hasFMA : 1;
|
||||
|
||||
// AMD-specific CPU Features
|
||||
u32 hasAMD64BitArchitecture : 1;
|
||||
u32 hasStreamingSIMD4ExtensionsA : 1;
|
||||
};
|
||||
};
|
||||
|
||||
// Core Counts!
|
||||
u32 PhysicalCores = 0;
|
||||
u32 LogicalCores = 0;
|
||||
|
||||
public:
|
||||
x86capabilities();
|
||||
|
||||
void Identify();
|
||||
void CountCores();
|
||||
const char* GetTypeName() const;
|
||||
|
||||
void SIMD_EstablishMXCSRmask();
|
||||
|
||||
protected:
|
||||
void CountLogicalCores();
|
||||
};
|
||||
|
||||
enum SSE_RoundMode
|
||||
{
|
||||
SSE_RoundMode_FIRST = 0,
|
||||
SSEround_Nearest = 0,
|
||||
SSEround_NegInf,
|
||||
SSEround_PosInf,
|
||||
SSEround_Chop,
|
||||
SSE_RoundMode_COUNT
|
||||
};
|
||||
|
||||
ImplementEnumOperators(SSE_RoundMode);
|
||||
|
||||
// Predeclaration for xIndirect32
|
||||
namespace x86Emitter
|
||||
{
|
||||
template <typename T>
|
||||
class xIndirect;
|
||||
typedef xIndirect<u32> xIndirect32;
|
||||
} // namespace x86Emitter
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// SSE_MXCSR - Control/Status Register (bitfield)
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Bits 0-5 are exception flags; used only if SSE exceptions have been enabled.
|
||||
// Bits in this field are "sticky" and, once an exception has occured, must be manually
|
||||
// cleared using LDMXCSR or FXRSTOR.
|
||||
//
|
||||
// Bits 7-12 are the masks for disabling the exceptions in bits 0-5. Cleared bits allow
|
||||
// exceptions, set bits mask exceptions from being raised.
|
||||
//
|
||||
union SSE_MXCSR
|
||||
{
|
||||
u32 bitmask;
|
||||
struct
|
||||
{
|
||||
u32
|
||||
InvalidOpFlag : 1,
|
||||
DenormalFlag : 1,
|
||||
DivideByZeroFlag : 1,
|
||||
OverflowFlag : 1,
|
||||
UnderflowFlag : 1,
|
||||
PrecisionFlag : 1,
|
||||
|
||||
// This bit is supported only on SSE2 or better CPUs. Setting it to 1 on
|
||||
// SSE1 cpus will result in an invalid instruction exception when executing
|
||||
// LDMXSCR.
|
||||
DenormalsAreZero : 1,
|
||||
|
||||
InvalidOpMask : 1,
|
||||
DenormalMask : 1,
|
||||
DivideByZeroMask : 1,
|
||||
OverflowMask : 1,
|
||||
UnderflowMask : 1,
|
||||
PrecisionMask : 1,
|
||||
|
||||
RoundingControl : 2,
|
||||
FlushToZero : 1;
|
||||
};
|
||||
|
||||
static SSE_MXCSR GetCurrent();
|
||||
static void SetCurrent(const SSE_MXCSR& value);
|
||||
|
||||
SSE_RoundMode GetRoundMode() const;
|
||||
SSE_MXCSR& SetRoundMode(SSE_RoundMode mode);
|
||||
SSE_MXCSR& ClearExceptionFlags();
|
||||
SSE_MXCSR& EnableExceptions();
|
||||
SSE_MXCSR& DisableExceptions();
|
||||
|
||||
SSE_MXCSR& ApplyReserveMask();
|
||||
|
||||
bool operator==(const SSE_MXCSR& right) const
|
||||
{
|
||||
return bitmask == right.bitmask;
|
||||
}
|
||||
|
||||
bool operator!=(const SSE_MXCSR& right) const
|
||||
{
|
||||
return bitmask != right.bitmask;
|
||||
}
|
||||
|
||||
operator x86Emitter::xIndirect32() const;
|
||||
};
|
||||
|
||||
extern SSE_MXCSR MXCSR_Mask;
|
||||
|
||||
|
||||
alignas(16) extern x86capabilities x86caps;
|
||||
@@ -17,7 +17,6 @@
|
||||
*/
|
||||
|
||||
#include "common/emitter/internal.h"
|
||||
#include "common/emitter/tools.h"
|
||||
#include <functional>
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
@@ -563,7 +562,7 @@ const xRegister32
|
||||
// Core2/i7 CPUs prefer unaligned addresses. Checking for SSSE3 is a decent filter.
|
||||
// (also align in debug modes for disasm convenience)
|
||||
|
||||
if (IsDebugBuild || !x86caps.hasSupplementalStreamingSIMD3Extensions)
|
||||
if constexpr (IsDebugBuild)
|
||||
{
|
||||
// - P4's and earlier prefer 16 byte alignment.
|
||||
// - AMD Athlons and Phenoms prefer 8 byte alignment, but I don't have an easy
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/emitter/x86types.h"
|
||||
#include "common/emitter/tools.h"
|
||||
#include "common/emitter/instructions.h"
|
||||
|
||||
// Including legacy items for now, but these should be removed eventually,
|
||||
|
||||
@@ -89,7 +89,7 @@
|
||||
<Message Text="moc %(QtMoc.Filename) $(QtToolOutDir)%(QtMoc.RelativeDir)moc_%(QtMoc.Filename).cpp" Importance="High" />
|
||||
<Error Condition="!$(QtDirValid)" Text="Qt directory non-existent (download/extract the zip)" />
|
||||
<MakeDir Directories="$(QtToolOutDir)%(QtMoc.RelativeDir)" />
|
||||
<Exec Command=""$(QtHostBinDir)moc.exe" "%(QtMoc.FullPath)" -b "PrecompiledHeader.h" -o "$(QtToolOutDir)%(QtMoc.RelativeDir)moc_%(QtMoc.Filename).cpp" -f%(QtMoc.Filename)%(QtMoc.Extension) $(MocDefines) $(MocIncludes)" />
|
||||
<Exec Command=""$(QtHostBinDir)moc.exe" "%(QtMoc.FullPath)" -o "$(QtToolOutDir)%(QtMoc.RelativeDir)moc_%(QtMoc.Filename).cpp" -f%(QtMoc.Filename)%(QtMoc.Extension) $(MocDefines) $(MocIncludes)" />
|
||||
</Target>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
#include "pcsx2/INISettingsInterface.h"
|
||||
#include "pcsx2/ImGui/ImGuiManager.h"
|
||||
#include "pcsx2/Input/InputManager.h"
|
||||
#include "pcsx2/LogSink.h"
|
||||
#include "pcsx2/MTGS.h"
|
||||
#include "pcsx2/SIO/Pad/Pad.h"
|
||||
#include "pcsx2/PerformanceMetrics.h"
|
||||
@@ -91,6 +90,12 @@ bool GSRunner::InitializeConfig()
|
||||
if (!EmuFolders::InitializeCriticalFolders())
|
||||
return false;
|
||||
|
||||
const char* error;
|
||||
if (!VMManager::PerformEarlyHardwareChecks(&error))
|
||||
return false;
|
||||
|
||||
ImGuiManager::SetFontPathAndRange(Path::Combine(EmuFolders::Resources, "fonts" FS_OSPATH_SEPARATOR_STR "Roboto-Regular.ttf"), {});
|
||||
|
||||
// don't provide an ini path, or bother loading. we'll store everything in memory.
|
||||
MemorySettingsInterface& si = s_settings_interface;
|
||||
Host::Internal::SetBaseSettingsLayer(&si);
|
||||
@@ -246,7 +251,7 @@ void Host::BeginPresentFrame()
|
||||
GSQueueSnapshot(dump_path);
|
||||
}
|
||||
|
||||
if (GSConfig.UseHardwareRenderer())
|
||||
if (GSIsHardwareRenderer())
|
||||
{
|
||||
const u32 last_draws = s_total_internal_draws;
|
||||
const u32 last_uploads = s_total_uploads;
|
||||
@@ -436,7 +441,7 @@ void GSRunner::InitializeConsole()
|
||||
const char* var = std::getenv("PCSX2_NOCONSOLE");
|
||||
s_no_console = (var && StringUtil::FromChars<bool>(var).value_or(false));
|
||||
if (!s_no_console)
|
||||
LogSink::InitializeEarlyConsole();
|
||||
Log::SetConsoleOutputLevel(LOGLEVEL_DEBUG);
|
||||
}
|
||||
|
||||
bool GSRunner::ParseCommandLineArgs(int argc, char* argv[], VMBootParameters& params)
|
||||
@@ -562,7 +567,7 @@ bool GSRunner::ParseCommandLineArgs(int argc, char* argv[], VMBootParameters& pa
|
||||
{
|
||||
// disable timestamps, since we want to be able to diff the logs
|
||||
Console.WriteLn("Logging to %s...", logfile);
|
||||
LogSink::SetFileLogPath(logfile);
|
||||
VMManager::Internal::SetFileLogPath(logfile);
|
||||
s_settings_interface.SetBoolValue("Logging", "EnableFileLogging", true);
|
||||
s_settings_interface.SetBoolValue("Logging", "EnableTimestamps", false);
|
||||
}
|
||||
@@ -692,7 +697,6 @@ int main(int argc, char* argv[])
|
||||
|
||||
VMManager::Internal::CPUThreadShutdown();
|
||||
GSRunner::DestroyPlatformWindow();
|
||||
LogSink::CloseFileLog();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -6,8 +6,32 @@
|
||||
#include "AboutDialog.h"
|
||||
#include "QtHost.h"
|
||||
#include "QtUtils.h"
|
||||
|
||||
#include "common/FileSystem.h"
|
||||
#include "common/Path.h"
|
||||
#include "common/SmallString.h"
|
||||
|
||||
#include <QtCore/QFile>
|
||||
#include <QtCore/QString>
|
||||
#include <QtGui/QDesktopServices>
|
||||
#include <QtWidgets/QDialog>
|
||||
#include <QtWidgets/QDialogButtonBox>
|
||||
#include <QtWidgets/QPushButton>
|
||||
#include <QtWidgets/QTextBrowser>
|
||||
|
||||
static QString GetDocFileUrl(std::string_view name)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
// Windows uses the docs directory in bin.
|
||||
const std::string path = Path::Combine(EmuFolders::AppRoot,
|
||||
TinyString::from_fmt("docs" FS_OSPATH_SEPARATOR_STR "{}", name));
|
||||
#else
|
||||
// Linux/Mac has this in the Resources directory.
|
||||
const std::string path = Path::Combine(EmuFolders::Resources,
|
||||
TinyString::from_fmt("docs" FS_OSPATH_SEPARATOR_STR "{}", name));
|
||||
#endif
|
||||
return QUrl::fromLocalFile(QString::fromStdString(path)).toString();
|
||||
}
|
||||
|
||||
AboutDialog::AboutDialog(QWidget* parent)
|
||||
: QDialog(parent)
|
||||
@@ -21,9 +45,8 @@ AboutDialog::AboutDialog(QWidget* parent)
|
||||
m_ui.scmversion->setText(QtHost::GetAppNameAndVersion());
|
||||
|
||||
m_ui.links->setTextInteractionFlags(Qt::TextBrowserInteraction);
|
||||
m_ui.links->setOpenExternalLinks(true);
|
||||
m_ui.links->setText(QStringLiteral(
|
||||
R"(<a href="%1">%2</a> | <a href="%3">%4</a> | <a href="%5">%6</a> | <a href="%7">%8</a>)")
|
||||
R"(<a href="%1">%2</a> | <a href="%3">%4</a> | <a href="%5">%6</a> | <a href="%7">%8</a> | <a href="%9">%10</a>)")
|
||||
.arg(getWebsiteUrl())
|
||||
.arg(tr("Website"))
|
||||
.arg(getSupportForumsUrl())
|
||||
@@ -31,8 +54,11 @@ AboutDialog::AboutDialog(QWidget* parent)
|
||||
.arg(getGitHubRepositoryUrl())
|
||||
.arg(tr("GitHub Repository"))
|
||||
.arg(getLicenseUrl())
|
||||
.arg(tr("License")));
|
||||
.arg(tr("License"))
|
||||
.arg(getThirdPartyLicensesUrl())
|
||||
.arg(tr("Third-Party Licenses")));
|
||||
|
||||
connect(m_ui.links, &QLabel::linkActivated, this, &AboutDialog::linksLinkActivated);
|
||||
connect(m_ui.buttonBox, &QDialogButtonBox::rejected, this, &QDialog::close);
|
||||
}
|
||||
|
||||
@@ -55,10 +81,60 @@ QString AboutDialog::getGitHubRepositoryUrl()
|
||||
|
||||
QString AboutDialog::getLicenseUrl()
|
||||
{
|
||||
return QString::fromUtf8(PCSX2_LICENSE_URL);
|
||||
return GetDocFileUrl("GPL.html");
|
||||
}
|
||||
|
||||
QString AboutDialog::getThirdPartyLicensesUrl()
|
||||
{
|
||||
return GetDocFileUrl("ThirdPartyLicenses.html");
|
||||
}
|
||||
|
||||
QString AboutDialog::getDiscordServerUrl()
|
||||
{
|
||||
return QString::fromUtf8(PCSX2_DISCORD_URL);
|
||||
}
|
||||
|
||||
void AboutDialog::linksLinkActivated(const QString& link)
|
||||
{
|
||||
const QUrl url(link);
|
||||
if (!url.isValid())
|
||||
return;
|
||||
|
||||
if (!url.isLocalFile())
|
||||
{
|
||||
QDesktopServices::openUrl(url);
|
||||
return;
|
||||
}
|
||||
|
||||
showHTMLDialog(this, tr("View Document"), url.toLocalFile());
|
||||
}
|
||||
|
||||
void AboutDialog::showHTMLDialog(QWidget* parent, const QString& title, const QString& path)
|
||||
{
|
||||
QDialog dialog(parent);
|
||||
dialog.setMinimumSize(700, 400);
|
||||
dialog.setWindowTitle(title);
|
||||
dialog.setWindowIcon(QtHost::GetAppIcon());
|
||||
|
||||
QVBoxLayout* layout = new QVBoxLayout(&dialog);
|
||||
|
||||
QTextBrowser* tb = new QTextBrowser(&dialog);
|
||||
tb->setAcceptRichText(true);
|
||||
tb->setReadOnly(true);
|
||||
tb->setOpenExternalLinks(true);
|
||||
|
||||
QFile file(path);
|
||||
file.open(QIODevice::ReadOnly);
|
||||
if (const QByteArray data = file.readAll(); !data.isEmpty())
|
||||
tb->setText(QString::fromUtf8(data));
|
||||
else
|
||||
tb->setText(tr("File not found: %1").arg(path));
|
||||
|
||||
layout->addWidget(tb, 1);
|
||||
|
||||
QDialogButtonBox* bb = new QDialogButtonBox(QDialogButtonBox::Close, &dialog);
|
||||
connect(bb->button(QDialogButtonBox::Close), &QPushButton::clicked, &dialog, &QDialog::done);
|
||||
layout->addWidget(bb, 0);
|
||||
|
||||
dialog.exec();
|
||||
}
|
||||
|
||||
@@ -18,8 +18,14 @@ public:
|
||||
static QString getSupportForumsUrl();
|
||||
static QString getGitHubRepositoryUrl();
|
||||
static QString getLicenseUrl();
|
||||
static QString getThirdPartyLicensesUrl();
|
||||
static QString getDiscordServerUrl();
|
||||
|
||||
static void showHTMLDialog(QWidget* parent, const QString& title, const QString& url);
|
||||
|
||||
private Q_SLOTS:
|
||||
void linksLinkActivated(const QString& link);
|
||||
|
||||
private:
|
||||
Ui::AboutDialog m_ui;
|
||||
};
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
#include "common/HTTPDownloader.h"
|
||||
#include "common/StringUtil.h"
|
||||
|
||||
#include "cpuinfo.h"
|
||||
|
||||
#include <functional>
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/QDir>
|
||||
@@ -220,6 +222,11 @@ void AutoUpdaterDialog::queueUpdateCheck(bool display_message)
|
||||
|
||||
void AutoUpdaterDialog::getLatestReleaseComplete(s32 status_code, std::vector<u8> data)
|
||||
{
|
||||
#ifdef _M_X86
|
||||
// should already be initialized, but just in case this somehow runs before the CPU thread starts setting up...
|
||||
cpuinfo_initialize();
|
||||
#endif
|
||||
|
||||
#ifdef AUTO_UPDATER_SUPPORTED
|
||||
bool found_update_info = false;
|
||||
|
||||
@@ -277,12 +284,20 @@ void AutoUpdaterDialog::getLatestReleaseComplete(s32 status_code, std::vector<u8
|
||||
#endif
|
||||
}
|
||||
|
||||
if (is_symbols || (!x86caps.hasAVX2 && is_avx2))
|
||||
if (is_symbols)
|
||||
{
|
||||
// skip this asset
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef _M_X86
|
||||
if (is_avx2 && cpuinfo_has_x86_avx2())
|
||||
{
|
||||
// skip this asset
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
int score;
|
||||
if (is_perfect_match)
|
||||
score = 4; // #1 choice is the one matching this binary
|
||||
|
||||
@@ -21,6 +21,8 @@ target_sources(pcsx2-qt PRIVATE
|
||||
DisplayWidget.cpp
|
||||
DisplayWidget.h
|
||||
EarlyHardwareCheck.cpp
|
||||
LogWindow.cpp
|
||||
LogWindow.h
|
||||
MainWindow.cpp
|
||||
MainWindow.h
|
||||
MainWindow.ui
|
||||
@@ -64,6 +66,7 @@ target_sources(pcsx2-qt PRIVATE
|
||||
Settings/ControllerBindingWidget.ui
|
||||
Settings/ControllerBindingWidget_DualShock2.ui
|
||||
Settings/ControllerBindingWidget_Guitar.ui
|
||||
Settings/ControllerBindingWidget_Popn.ui
|
||||
Settings/ControllerBindingWidgets.cpp
|
||||
Settings/ControllerBindingWidgets.h
|
||||
Settings/ControllerLEDSettingsDialog.ui
|
||||
@@ -167,6 +170,8 @@ target_sources(pcsx2-qt PRIVATE
|
||||
Debugger/Models/ThreadModel.h
|
||||
Debugger/Models/StackModel.cpp
|
||||
Debugger/Models/StackModel.h
|
||||
Debugger/Models/SavedAddressesModel.cpp
|
||||
Debugger/Models/SavedAddressesModel.h
|
||||
Tools/InputRecording/NewInputRecordingDlg.cpp
|
||||
Tools/InputRecording/NewInputRecordingDlg.h
|
||||
Tools/InputRecording/NewInputRecordingDlg.ui
|
||||
@@ -179,6 +184,7 @@ target_sources(pcsx2-qt PRIVATE
|
||||
file(GLOB TS_FILES ${CMAKE_CURRENT_SOURCE_DIR}/Translations/*.ts)
|
||||
|
||||
target_precompile_headers(pcsx2-qt PRIVATE PrecompiledHeader.h)
|
||||
set_source_files_properties(PrecompiledHeader.cpp PROPERTIES HEADER_FILE_ONLY TRUE)
|
||||
|
||||
target_include_directories(pcsx2-qt PRIVATE
|
||||
${Qt6Gui_PRIVATE_INCLUDE_DIRS}
|
||||
|
||||
+236
-49
@@ -7,6 +7,7 @@
|
||||
#include "BreakpointDialog.h"
|
||||
#include "Models/BreakpointModel.h"
|
||||
#include "Models/ThreadModel.h"
|
||||
#include "Models/SavedAddressesModel.h"
|
||||
|
||||
#include "DebugTools/DebugInterface.h"
|
||||
#include "DebugTools/Breakpoints.h"
|
||||
@@ -23,6 +24,9 @@
|
||||
#include <QtWidgets/QMessageBox>
|
||||
#include <QtConcurrent/QtConcurrent>
|
||||
#include <QtCore/QFutureWatcher>
|
||||
#include <QtCore/QRegularExpression>
|
||||
#include <QtCore/QRegularExpressionMatchIterator>
|
||||
#include <QtCore/QStringList>
|
||||
#include <QtWidgets/QScrollBar>
|
||||
|
||||
using namespace QtUtils;
|
||||
@@ -36,6 +40,7 @@ CpuWidget::CpuWidget(QWidget* parent, DebugInterface& cpu)
|
||||
, m_bpModel(cpu)
|
||||
, m_threadModel(cpu)
|
||||
, m_stackModel(cpu)
|
||||
, m_savedAddressesModel(cpu)
|
||||
{
|
||||
m_ui.setupUi(this);
|
||||
|
||||
@@ -43,6 +48,7 @@ CpuWidget::CpuWidget(QWidget* parent, DebugInterface& cpu)
|
||||
|
||||
connect(m_ui.registerWidget, &RegisterWidget::gotoInDisasm, m_ui.disassemblyWidget, &DisassemblyWidget::gotoAddress);
|
||||
connect(m_ui.memoryviewWidget, &MemoryViewWidget::gotoInDisasm, m_ui.disassemblyWidget, &DisassemblyWidget::gotoAddress);
|
||||
connect(m_ui.memoryviewWidget, &MemoryViewWidget::addToSavedAddresses, this, &CpuWidget::addAddressToSavedAddressesList);
|
||||
|
||||
connect(m_ui.registerWidget, &RegisterWidget::gotoInMemory, m_ui.memoryviewWidget, &MemoryViewWidget::gotoAddress);
|
||||
connect(m_ui.disassemblyWidget, &DisassemblyWidget::gotoInMemory, m_ui.memoryviewWidget, &MemoryViewWidget::gotoAddress);
|
||||
@@ -96,7 +102,11 @@ CpuWidget::CpuWidget(QWidget* parent, DebugInterface& cpu)
|
||||
m_ui.listSearchResults->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(m_ui.btnSearch, &QPushButton::clicked, this, &CpuWidget::onSearchButtonClicked);
|
||||
connect(m_ui.btnFilterSearch, &QPushButton::clicked, this, &CpuWidget::onSearchButtonClicked);
|
||||
connect(m_ui.listSearchResults, &QListWidget::itemDoubleClicked, [this](QListWidgetItem* item) { m_ui.memoryviewWidget->gotoAddress(item->text().toUInt(nullptr, 16)); });
|
||||
connect(m_ui.listSearchResults, &QListWidget::itemDoubleClicked, [this](QListWidgetItem* item)
|
||||
{
|
||||
m_ui.tabWidget->setCurrentWidget(m_ui.tab_memory);
|
||||
m_ui.memoryviewWidget->gotoAddress(item->text().toUInt(nullptr, 16));
|
||||
});
|
||||
connect(m_ui.listSearchResults->verticalScrollBar(), &QScrollBar::valueChanged, this, &CpuWidget::onSearchResultsListScroll);
|
||||
connect(m_ui.listSearchResults, &QListView::customContextMenuRequested, this, &CpuWidget::onListSearchResultsContextMenu);
|
||||
connect(m_ui.cmbSearchType, &QComboBox::currentIndexChanged, [this](int i) {
|
||||
@@ -124,6 +134,18 @@ CpuWidget::CpuWidget(QWidget* parent, DebugInterface& cpu)
|
||||
m_resultsLoadTimer.setInterval(100);
|
||||
m_resultsLoadTimer.setSingleShot(true);
|
||||
connect(&m_resultsLoadTimer, &QTimer::timeout, this, &CpuWidget::loadSearchResults);
|
||||
|
||||
m_ui.savedAddressesList->setModel(&m_savedAddressesModel);
|
||||
m_ui.savedAddressesList->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(m_ui.savedAddressesList, &QTableView::customContextMenuRequested, this, &CpuWidget::onSavedAddressesListContextMenu);
|
||||
for (std::size_t i = 0; auto mode : SavedAddressesModel::HeaderResizeModes)
|
||||
{
|
||||
m_ui.savedAddressesList->horizontalHeader()->setSectionResizeMode(i++, mode);
|
||||
}
|
||||
QTableView* savedAddressesTableView = m_ui.savedAddressesList;
|
||||
connect(m_ui.savedAddressesList->model(), &QAbstractItemModel::dataChanged, [savedAddressesTableView](const QModelIndex& topLeft) {
|
||||
savedAddressesTableView->resizeColumnToContents(topLeft.column());
|
||||
});
|
||||
}
|
||||
|
||||
CpuWidget::~CpuWidget() = default;
|
||||
@@ -312,7 +334,7 @@ void CpuWidget::onBPListContextMenu(QPoint pos)
|
||||
QAction* actionExport = new QAction(tr("Copy all as CSV"), m_ui.breakpointList);
|
||||
connect(actionExport, &QAction::triggered, [this]() {
|
||||
// It's important to use the Export Role here to allow pasting to be translation agnostic
|
||||
QGuiApplication::clipboard()->setText(QtUtils::AbstractItemModelToCSV(m_ui.breakpointList->model(), BreakpointModel::ExportRole));
|
||||
QGuiApplication::clipboard()->setText(QtUtils::AbstractItemModelToCSV(m_ui.breakpointList->model(), BreakpointModel::ExportRole, true));
|
||||
});
|
||||
contextMenu->addAction(actionExport);
|
||||
|
||||
@@ -381,7 +403,19 @@ void CpuWidget::contextBPListPasteCSV()
|
||||
|
||||
for (const QString& line : csv.split('\n'))
|
||||
{
|
||||
const QStringList fields = line.split(',');
|
||||
QStringList fields;
|
||||
// In order to handle text with commas in them we must wrap values in quotes to mark
|
||||
// where a value starts and end so that text commas aren't identified as delimiters.
|
||||
// So matches each quote pair, parse it out, and removes the quotes to get the value.
|
||||
QRegularExpression eachQuotePair(R"("([^"]|\\.)*")");
|
||||
QRegularExpressionMatchIterator it = eachQuotePair.globalMatch(line);
|
||||
while (it.hasNext())
|
||||
{
|
||||
QRegularExpressionMatch match = it.next();
|
||||
QString matchedValue = match.captured(0);
|
||||
fields << matchedValue.mid(1, matchedValue.length() - 2);
|
||||
}
|
||||
|
||||
if (fields.size() != BreakpointModel::BreakpointColumns::COLUMN_COUNT)
|
||||
{
|
||||
Console.WriteLn("Debugger CSV Import: Invalid number of columns, skipping");
|
||||
@@ -389,10 +423,10 @@ void CpuWidget::contextBPListPasteCSV()
|
||||
}
|
||||
|
||||
bool ok;
|
||||
int type = fields[0].toUInt(&ok);
|
||||
const int type = fields[BreakpointModel::BreakpointColumns::TYPE].toUInt(&ok);
|
||||
if (!ok)
|
||||
{
|
||||
Console.WriteLn("Debugger CSV Import: Failed to parse type '%s', skipping", fields[0].toUtf8().constData());
|
||||
Console.WriteLn("Debugger CSV Import: Failed to parse type '%s', skipping", fields[BreakpointModel::BreakpointColumns::TYPE].toUtf8().constData());
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -402,34 +436,34 @@ void CpuWidget::contextBPListPasteCSV()
|
||||
BreakPoint bp;
|
||||
|
||||
// Address
|
||||
bp.addr = fields[1].toUInt(&ok, 16);
|
||||
bp.addr = fields[BreakpointModel::BreakpointColumns::OFFSET].toUInt(&ok, 16);
|
||||
if (!ok)
|
||||
{
|
||||
Console.WriteLn("Debugger CSV Import: Failed to parse address '%s', skipping", fields[1].toUtf8().constData());
|
||||
Console.WriteLn("Debugger CSV Import: Failed to parse address '%s', skipping", fields[BreakpointModel::BreakpointColumns::OFFSET].toUtf8().constData());
|
||||
continue;
|
||||
}
|
||||
|
||||
// Condition
|
||||
if (!fields[4].isEmpty())
|
||||
if (!fields[BreakpointModel::BreakpointColumns::CONDITION].isEmpty())
|
||||
{
|
||||
PostfixExpression expr;
|
||||
bp.hasCond = true;
|
||||
bp.cond.debug = &m_cpu;
|
||||
|
||||
if (!m_cpu.initExpression(fields[4].toUtf8().constData(), expr))
|
||||
if (!m_cpu.initExpression(fields[BreakpointModel::BreakpointColumns::CONDITION].toUtf8().constData(), expr))
|
||||
{
|
||||
Console.WriteLn("Debugger CSV Import: Failed to parse cond '%s', skipping", fields[4].toUtf8().constData());
|
||||
Console.WriteLn("Debugger CSV Import: Failed to parse cond '%s', skipping", fields[BreakpointModel::BreakpointColumns::CONDITION].toUtf8().constData());
|
||||
continue;
|
||||
}
|
||||
bp.cond.expression = expr;
|
||||
strncpy(&bp.cond.expressionString[0], fields[4].toUtf8().constData(), sizeof(bp.cond.expressionString));
|
||||
strncpy(&bp.cond.expressionString[0], fields[BreakpointModel::BreakpointColumns::CONDITION].toUtf8().constData(), sizeof(bp.cond.expressionString));
|
||||
}
|
||||
|
||||
// Enabled
|
||||
bp.enabled = fields[6].toUInt(&ok);
|
||||
bp.enabled = fields[BreakpointModel::BreakpointColumns::ENABLED].toUInt(&ok);
|
||||
if (!ok)
|
||||
{
|
||||
Console.WriteLn("Debugger CSV Import: Failed to parse enable flag '%s', skipping", fields[1].toUtf8().constData());
|
||||
Console.WriteLn("Debugger CSV Import: Failed to parse enable flag '%s', skipping", fields[BreakpointModel::BreakpointColumns::ENABLED].toUtf8().constData());
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -441,32 +475,32 @@ void CpuWidget::contextBPListPasteCSV()
|
||||
// Mode
|
||||
if (type >= MEMCHECK_INVALID)
|
||||
{
|
||||
Console.WriteLn("Debugger CSV Import: Failed to parse cond type '%s', skipping", fields[0].toUtf8().constData());
|
||||
Console.WriteLn("Debugger CSV Import: Failed to parse cond type '%s', skipping", fields [BreakpointModel::BreakpointColumns::TYPE].toUtf8().constData());
|
||||
continue;
|
||||
}
|
||||
mc.cond = static_cast<MemCheckCondition>(type);
|
||||
|
||||
// Address
|
||||
mc.start = fields[1].toUInt(&ok, 16);
|
||||
mc.start = fields[BreakpointModel::BreakpointColumns::OFFSET].toUInt(&ok, 16);
|
||||
if (!ok)
|
||||
{
|
||||
Console.WriteLn("Debugger CSV Import: Failed to parse address '%s', skipping", fields[1].toUtf8().constData());
|
||||
Console.WriteLn("Debugger CSV Import: Failed to parse address '%s', skipping", fields[BreakpointModel::BreakpointColumns::OFFSET].toUtf8().constData());
|
||||
continue;
|
||||
}
|
||||
|
||||
// Size
|
||||
mc.end = fields[2].toUInt(&ok) + mc.start;
|
||||
mc.end = fields[BreakpointModel::BreakpointColumns::SIZE_LABEL].toUInt(&ok) + mc.start;
|
||||
if (!ok)
|
||||
{
|
||||
Console.WriteLn("Debugger CSV Import: Failed to parse length '%s', skipping", fields[1].toUtf8().constData());
|
||||
Console.WriteLn("Debugger CSV Import: Failed to parse length '%s', skipping", fields[BreakpointModel::BreakpointColumns::SIZE_LABEL].toUtf8().constData());
|
||||
continue;
|
||||
}
|
||||
|
||||
// Result
|
||||
int result = fields[6].toUInt(&ok);
|
||||
const int result = fields [BreakpointModel::BreakpointColumns::ENABLED].toUInt(&ok);
|
||||
if (!ok)
|
||||
{
|
||||
Console.WriteLn("Debugger CSV Import: Failed to parse result flag '%s', skipping", fields[1].toUtf8().constData());
|
||||
Console.WriteLn("Debugger CSV Import: Failed to parse result flag '%s', skipping", fields [BreakpointModel::BreakpointColumns::ENABLED].toUtf8().constData());
|
||||
continue;
|
||||
}
|
||||
mc.result = static_cast<MemCheckResult>(result);
|
||||
@@ -476,13 +510,135 @@ void CpuWidget::contextBPListPasteCSV()
|
||||
}
|
||||
}
|
||||
|
||||
void CpuWidget::onSavedAddressesListContextMenu(QPoint pos)
|
||||
{
|
||||
QMenu* contextMenu = new QMenu("Saved Addresses List Context Menu", m_ui.savedAddressesList);
|
||||
|
||||
QAction* newAction = new QAction(tr("New"), m_ui.savedAddressesList);
|
||||
connect(newAction, &QAction::triggered, this, &CpuWidget::contextSavedAddressesListNew);
|
||||
contextMenu->addAction(newAction);
|
||||
|
||||
const QModelIndex indexAtPos = m_ui.savedAddressesList->indexAt(pos);
|
||||
const bool isIndexValid = indexAtPos.isValid();
|
||||
|
||||
if (isIndexValid)
|
||||
{
|
||||
if (m_cpu.isAlive())
|
||||
{
|
||||
QAction* goToAddressMemViewAction = new QAction(tr("Go to in Memory View"), m_ui.savedAddressesList);
|
||||
connect(goToAddressMemViewAction, &QAction::triggered, this, [this, indexAtPos]() {
|
||||
const QModelIndex rowAddressIndex = m_ui.savedAddressesList->model()->index(indexAtPos.row(), 0, QModelIndex());
|
||||
m_ui.memoryviewWidget->gotoAddress(m_ui.savedAddressesList->model()->data(rowAddressIndex, Qt::UserRole).toUInt());
|
||||
m_ui.tabWidget->setCurrentWidget(m_ui.tab_memory);
|
||||
});
|
||||
contextMenu->addAction(goToAddressMemViewAction);
|
||||
|
||||
QAction* goToAddressDisassemblyAction = new QAction(tr("Go to in Disassembly"), m_ui.savedAddressesList);
|
||||
connect(goToAddressDisassemblyAction, &QAction::triggered, this, [this, indexAtPos]() {
|
||||
const QModelIndex rowAddressIndex = m_ui.savedAddressesList->model()->index(indexAtPos.row(), 0, QModelIndex());
|
||||
m_ui.disassemblyWidget->gotoAddress(m_ui.savedAddressesList->model()->data(rowAddressIndex, Qt::UserRole).toUInt());
|
||||
});
|
||||
contextMenu->addAction(goToAddressDisassemblyAction);
|
||||
}
|
||||
|
||||
QAction* copyAction = new QAction(indexAtPos.column() == 0 ? tr("Copy Address") : tr("Copy Text"), m_ui.savedAddressesList);
|
||||
connect(copyAction, &QAction::triggered, [this, indexAtPos]() {
|
||||
QGuiApplication::clipboard()->setText(m_ui.savedAddressesList->model()->data(indexAtPos, Qt::DisplayRole).toString());
|
||||
});
|
||||
contextMenu->addAction(copyAction);
|
||||
}
|
||||
|
||||
if (m_ui.savedAddressesList->model()->rowCount() > 0)
|
||||
{
|
||||
QAction* actionExportCSV = new QAction(tr("Copy all as CSV"), m_ui.savedAddressesList);
|
||||
connect(actionExportCSV, &QAction::triggered, [this]() {
|
||||
QGuiApplication::clipboard()->setText(QtUtils::AbstractItemModelToCSV(m_ui.savedAddressesList->model(), Qt::DisplayRole, true));
|
||||
});
|
||||
contextMenu->addAction(actionExportCSV);
|
||||
}
|
||||
|
||||
QAction* actionImportCSV = new QAction(tr("Paste from CSV"), m_ui.savedAddressesList);
|
||||
connect(actionImportCSV, &QAction::triggered, this, &CpuWidget::contextSavedAddressesListPasteCSV);
|
||||
contextMenu->addAction(actionImportCSV);
|
||||
|
||||
contextMenu->popup(m_ui.savedAddressesList->viewport()->mapToGlobal(pos));
|
||||
|
||||
if (isIndexValid)
|
||||
{
|
||||
QAction* deleteAction = new QAction(tr("Delete"), m_ui.savedAddressesList);
|
||||
connect(deleteAction, &QAction::triggered, this, [this, indexAtPos]() {
|
||||
m_ui.savedAddressesList->model()->removeRows(indexAtPos.row(), 1);
|
||||
});
|
||||
contextMenu->addAction(deleteAction);
|
||||
}
|
||||
}
|
||||
|
||||
void CpuWidget::contextSavedAddressesListPasteCSV()
|
||||
{
|
||||
QString csv = QGuiApplication::clipboard()->text();
|
||||
// Skip header
|
||||
csv = csv.mid(csv.indexOf('\n') + 1);
|
||||
|
||||
for (const QString& line : csv.split('\n'))
|
||||
{
|
||||
QStringList fields;
|
||||
// In order to handle text with commas in them we must wrap values in quotes to mark
|
||||
// where a value starts and end so that text commas aren't identified as delimiters.
|
||||
// So matches each quote pair, parse it out, and removes the quotes to get the value.
|
||||
QRegularExpression eachQuotePair(R"("([^"]|\\.)*")");
|
||||
QRegularExpressionMatchIterator it = eachQuotePair.globalMatch(line);
|
||||
while (it.hasNext())
|
||||
{
|
||||
QRegularExpressionMatch match = it.next();
|
||||
QString matchedValue = match.captured(0);
|
||||
fields << matchedValue.mid(1, matchedValue.length() - 2);
|
||||
}
|
||||
|
||||
if (fields.size() != SavedAddressesModel::HeaderColumns::COLUMN_COUNT)
|
||||
{
|
||||
Console.WriteLn("Debugger CSV Import: Invalid number of columns, skipping");
|
||||
continue;
|
||||
}
|
||||
|
||||
bool ok;
|
||||
const u32 address = fields[SavedAddressesModel::HeaderColumns::ADDRESS].toUInt(&ok, 16);
|
||||
if (!ok)
|
||||
{
|
||||
Console.WriteLn("Debugger CSV Import: Failed to parse address '%s', skipping", fields[SavedAddressesModel::HeaderColumns::ADDRESS].toUtf8().constData());
|
||||
continue;
|
||||
}
|
||||
|
||||
const QString label = fields[SavedAddressesModel::HeaderColumns::LABEL];
|
||||
const QString description = fields[SavedAddressesModel::HeaderColumns::DESCRIPTION];
|
||||
const SavedAddressesModel::SavedAddress importedAddress = {address, label, description};
|
||||
m_savedAddressesModel.addRow(importedAddress);
|
||||
}
|
||||
}
|
||||
|
||||
void CpuWidget::contextSavedAddressesListNew()
|
||||
{
|
||||
qobject_cast<SavedAddressesModel*>(m_ui.savedAddressesList->model())->addRow();
|
||||
const u32 rowCount = m_ui.savedAddressesList->model()->rowCount();
|
||||
m_ui.savedAddressesList->edit(m_ui.savedAddressesList->model()->index(rowCount - 1, 0));
|
||||
}
|
||||
|
||||
void CpuWidget::addAddressToSavedAddressesList(u32 address)
|
||||
{
|
||||
qobject_cast<SavedAddressesModel*>(m_ui.savedAddressesList->model())->addRow();
|
||||
const u32 rowCount = m_ui.savedAddressesList->model()->rowCount();
|
||||
const QModelIndex addressIndex = m_ui.savedAddressesList->model()->index(rowCount - 1, 0);
|
||||
m_ui.tabWidget->setCurrentWidget(m_ui.tab_savedaddresses);
|
||||
m_ui.savedAddressesList->model()->setData(addressIndex, address, Qt::UserRole);
|
||||
m_ui.savedAddressesList->edit(m_ui.savedAddressesList->model()->index(rowCount - 1, 1));
|
||||
}
|
||||
|
||||
void CpuWidget::contextSearchResultGoToDisassembly()
|
||||
{
|
||||
const QItemSelectionModel* selModel = m_ui.listSearchResults->selectionModel();
|
||||
if (!selModel->hasSelection())
|
||||
return;
|
||||
|
||||
m_ui.disassemblyWidget->gotoAddress(m_ui.listSearchResults->selectedItems().first()->data(256).toUInt());
|
||||
m_ui.disassemblyWidget->gotoAddress(m_ui.listSearchResults->selectedItems().first()->data(Qt::UserRole).toUInt());
|
||||
}
|
||||
|
||||
void CpuWidget::contextRemoveSearchResult()
|
||||
@@ -492,8 +648,8 @@ void CpuWidget::contextRemoveSearchResult()
|
||||
return;
|
||||
|
||||
const int selectedResultIndex = m_ui.listSearchResults->row(m_ui.listSearchResults->selectedItems().first());
|
||||
auto* rowToRemove = m_ui.listSearchResults->takeItem(selectedResultIndex);
|
||||
if (m_searchResults.size() > static_cast<size_t>(selectedResultIndex) && m_searchResults.at(selectedResultIndex) == rowToRemove->data(256).toUInt())
|
||||
const auto* rowToRemove = m_ui.listSearchResults->takeItem(selectedResultIndex);
|
||||
if (m_searchResults.size() > static_cast<size_t>(selectedResultIndex) && m_searchResults.at(selectedResultIndex) == rowToRemove->data(Qt::UserRole).toUInt())
|
||||
{
|
||||
m_searchResults.erase(m_searchResults.begin() + selectedResultIndex);
|
||||
}
|
||||
@@ -534,7 +690,7 @@ void CpuWidget::updateFunctionList(bool whenEmpty)
|
||||
|
||||
item->setText(QString("%0 %1").arg(FilledQStringFromValue(symbol.address, 16)).arg(symbolName));
|
||||
|
||||
item->setData(256, symbol.address);
|
||||
item->setData(Qt::UserRole, symbol.address);
|
||||
|
||||
m_ui.listFunctions->addItem(item);
|
||||
}
|
||||
@@ -562,7 +718,7 @@ void CpuWidget::updateFunctionList(bool whenEmpty)
|
||||
symbolName = demangledName;
|
||||
}
|
||||
QTreeWidgetItem* functionItem = new QTreeWidgetItem(moduleItem, QStringList(QString("%0 %1").arg(FilledQStringFromValue(sym.address, 16)).arg(symbolName)));
|
||||
functionItem->setData(0, 256, sym.address);
|
||||
functionItem->setData(0, Qt::UserRole, sym.address);
|
||||
functions.append(functionItem);
|
||||
}
|
||||
moduleItem->addChildren(functions);
|
||||
@@ -639,7 +795,7 @@ void CpuWidget::onFuncListContextMenu(QPoint pos)
|
||||
else
|
||||
m_funclistContextMenu->clear();
|
||||
|
||||
if (m_ui.listFunctions->selectedItems().count() && m_ui.listFunctions->selectedItems().first()->data(256).isValid())
|
||||
if (m_ui.listFunctions->selectedItems().count() && m_ui.listFunctions->selectedItems().first()->data(Qt::UserRole).isValid())
|
||||
{
|
||||
QAction* copyName = new QAction(tr("Copy Function Name"), m_ui.listFunctions);
|
||||
connect(copyName, &QAction::triggered, [this] {
|
||||
@@ -647,14 +803,14 @@ void CpuWidget::onFuncListContextMenu(QPoint pos)
|
||||
// Resolve the function name by fetching the symbolmap and filtering the address
|
||||
|
||||
const QListWidgetItem* selectedItem = m_ui.listFunctions->selectedItems().first();
|
||||
const QString functionName = QString(m_cpu.GetSymbolMap().GetLabelName(selectedItem->data(256).toUInt()).c_str());
|
||||
const QString functionName = QString(m_cpu.GetSymbolMap().GetLabelName(selectedItem->data(Qt::UserRole).toUInt()).c_str());
|
||||
QApplication::clipboard()->setText(functionName);
|
||||
});
|
||||
m_funclistContextMenu->addAction(copyName);
|
||||
|
||||
QAction* copyAddress = new QAction(tr("Copy Function Address"), m_ui.listFunctions);
|
||||
connect(copyAddress, &QAction::triggered, [this] {
|
||||
const QString addressString = FilledQStringFromValue(m_ui.listFunctions->selectedItems().first()->data(256).toUInt(), 16);
|
||||
const QString addressString = FilledQStringFromValue(m_ui.listFunctions->selectedItems().first()->data(Qt::UserRole).toUInt(), 16);
|
||||
QApplication::clipboard()->setText(addressString);
|
||||
});
|
||||
|
||||
@@ -664,14 +820,14 @@ void CpuWidget::onFuncListContextMenu(QPoint pos)
|
||||
|
||||
QAction* gotoDisasm = new QAction(tr("Go to in Disassembly"), m_ui.listFunctions);
|
||||
connect(gotoDisasm, &QAction::triggered, [this] {
|
||||
m_ui.disassemblyWidget->gotoAddress(m_ui.listFunctions->selectedItems().first()->data(256).toUInt());
|
||||
m_ui.disassemblyWidget->gotoAddress(m_ui.listFunctions->selectedItems().first()->data(Qt::UserRole).toUInt());
|
||||
});
|
||||
|
||||
m_funclistContextMenu->addAction(gotoDisasm);
|
||||
|
||||
QAction* gotoMemory = new QAction(tr("Go to in Memory View"), m_ui.listFunctions);
|
||||
connect(gotoMemory, &QAction::triggered, [this] {
|
||||
m_ui.memoryviewWidget->gotoAddress(m_ui.listFunctions->selectedItems().first()->data(256).toUInt());
|
||||
m_ui.memoryviewWidget->gotoAddress(m_ui.listFunctions->selectedItems().first()->data(Qt::UserRole).toUInt());
|
||||
});
|
||||
|
||||
m_funclistContextMenu->addAction(gotoMemory);
|
||||
@@ -711,7 +867,7 @@ void CpuWidget::onFuncListContextMenu(QPoint pos)
|
||||
|
||||
void CpuWidget::onFuncListDoubleClick(QListWidgetItem* item)
|
||||
{
|
||||
m_ui.disassemblyWidget->gotoAddress(item->data(256).toUInt());
|
||||
m_ui.disassemblyWidget->gotoAddress(item->data(Qt::UserRole).toUInt());
|
||||
}
|
||||
|
||||
void CpuWidget::onModuleTreeContextMenu(QPoint pos)
|
||||
@@ -721,17 +877,17 @@ void CpuWidget::onModuleTreeContextMenu(QPoint pos)
|
||||
else
|
||||
m_moduleTreeContextMenu->clear();
|
||||
|
||||
if (m_ui.treeModules->selectedItems().count() && m_ui.treeModules->selectedItems().first()->data(0, 256).isValid())
|
||||
if (m_ui.treeModules->selectedItems().count() && m_ui.treeModules->selectedItems().first()->data(0, Qt::UserRole).isValid())
|
||||
{
|
||||
QAction* copyName = new QAction(tr("Copy Function Name"), m_ui.treeModules);
|
||||
connect(copyName, &QAction::triggered, [this] {
|
||||
QApplication::clipboard()->setText(m_cpu.GetSymbolMap().GetLabelName(m_ui.treeModules->selectedItems().first()->data(0, 256).toUInt()).c_str());
|
||||
QApplication::clipboard()->setText(m_cpu.GetSymbolMap().GetLabelName(m_ui.treeModules->selectedItems().first()->data(0, Qt::UserRole).toUInt()).c_str());
|
||||
});
|
||||
m_moduleTreeContextMenu->addAction(copyName);
|
||||
|
||||
QAction* copyAddress = new QAction(tr("Copy Function Address"), m_ui.treeModules);
|
||||
connect(copyAddress, &QAction::triggered, [this] {
|
||||
const QString addressString = FilledQStringFromValue(m_ui.treeModules->selectedItems().first()->data(0, 256).toUInt(), 16);
|
||||
const QString addressString = FilledQStringFromValue(m_ui.treeModules->selectedItems().first()->data(0, Qt::UserRole).toUInt(), 16);
|
||||
QApplication::clipboard()->setText(addressString);
|
||||
});
|
||||
m_moduleTreeContextMenu->addAction(copyAddress);
|
||||
@@ -740,13 +896,13 @@ void CpuWidget::onModuleTreeContextMenu(QPoint pos)
|
||||
|
||||
QAction* gotoDisasm = new QAction(tr("Go to in Disassembly"), m_ui.treeModules);
|
||||
connect(gotoDisasm, &QAction::triggered, [this] {
|
||||
m_ui.disassemblyWidget->gotoAddress(m_ui.treeModules->selectedItems().first()->data(0, 256).toUInt());
|
||||
m_ui.disassemblyWidget->gotoAddress(m_ui.treeModules->selectedItems().first()->data(0, Qt::UserRole).toUInt());
|
||||
});
|
||||
m_moduleTreeContextMenu->addAction(gotoDisasm);
|
||||
|
||||
QAction* gotoMemory = new QAction(tr("Go to in Memory View"), m_ui.treeModules);
|
||||
connect(gotoMemory, &QAction::triggered, [this] {
|
||||
m_ui.memoryviewWidget->gotoAddress(m_ui.treeModules->selectedItems().first()->data(0, 256).toUInt());
|
||||
m_ui.memoryviewWidget->gotoAddress(m_ui.treeModules->selectedItems().first()->data(0, Qt::UserRole).toUInt());
|
||||
});
|
||||
m_moduleTreeContextMenu->addAction(gotoMemory);
|
||||
}
|
||||
@@ -784,9 +940,9 @@ void CpuWidget::onModuleTreeContextMenu(QPoint pos)
|
||||
|
||||
void CpuWidget::onModuleTreeDoubleClick(QTreeWidgetItem* item)
|
||||
{
|
||||
if (item->data(0, 256).isValid())
|
||||
if (item->data(0, Qt::UserRole).isValid())
|
||||
{
|
||||
m_ui.disassemblyWidget->gotoAddress(item->data(0, 256).toUInt());
|
||||
m_ui.disassemblyWidget->gotoAddress(item->data(0, Qt::UserRole).toUInt());
|
||||
}
|
||||
}
|
||||
void CpuWidget::updateStackFrames()
|
||||
@@ -798,6 +954,7 @@ void CpuWidget::onListSearchResultsContextMenu(QPoint pos)
|
||||
{
|
||||
QMenu* contextMenu = new QMenu(tr("Search Results List Context Menu"), m_ui.listSearchResults);
|
||||
const QItemSelectionModel* selModel = m_ui.listSearchResults->selectionModel();
|
||||
const auto listSearchResults = m_ui.listSearchResults;
|
||||
|
||||
if (selModel->hasSelection())
|
||||
{
|
||||
@@ -805,6 +962,12 @@ void CpuWidget::onListSearchResultsContextMenu(QPoint pos)
|
||||
connect(goToDisassemblyAction, &QAction::triggered, this, &CpuWidget::contextSearchResultGoToDisassembly);
|
||||
contextMenu->addAction(goToDisassemblyAction);
|
||||
|
||||
QAction* addToSavedAddressesAction = new QAction(tr("Add to Saved Memory Addresses"), m_ui.listSearchResults);
|
||||
connect(addToSavedAddressesAction, &QAction::triggered, this, [this, listSearchResults]() {
|
||||
addAddressToSavedAddressesList(listSearchResults->selectedItems().first()->data(Qt::UserRole).toUInt());
|
||||
});
|
||||
contextMenu->addAction(addToSavedAddressesAction);
|
||||
|
||||
QAction* removeResultAction = new QAction(tr("Remove Result"), m_ui.listSearchResults);
|
||||
connect(removeResultAction, &QAction::triggered, this, &CpuWidget::contextRemoveSearchResult);
|
||||
contextMenu->addAction(removeResultAction);
|
||||
@@ -988,19 +1151,37 @@ std::vector<u32> searchWorker(DebugInterface* cpu, std::vector<u32> searchAddres
|
||||
return hitAddresses;
|
||||
}
|
||||
|
||||
static bool compareByteArrayAtAddress(DebugInterface* cpu, u32 addr, QByteArray value)
|
||||
static bool compareByteArrayAtAddress(DebugInterface* cpu, SearchComparison searchComparison, u32 addr, QByteArray value)
|
||||
{
|
||||
const bool isNotOperator = searchComparison == SearchComparison::NotEquals;
|
||||
for (qsizetype i = 0; i < value.length(); i++)
|
||||
{
|
||||
if (static_cast<char>(cpu->read8(addr + i)) != value[i])
|
||||
const char nextByte = cpu->read8(addr + i);
|
||||
switch (searchComparison)
|
||||
{
|
||||
return false;
|
||||
case SearchComparison::Equals:
|
||||
{
|
||||
if (nextByte != value[i])
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
case SearchComparison::NotEquals:
|
||||
{
|
||||
if (nextByte != value[i])
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
Console.Error("Debugger: Unknown search comparison when doing memory search");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return !isNotOperator;
|
||||
}
|
||||
|
||||
static std::vector<u32> searchWorkerByteArray(DebugInterface* cpu, std::vector<u32> searchAddresses, u32 start, u32 end, QByteArray value)
|
||||
static std::vector<u32> searchWorkerByteArray(DebugInterface* cpu, SearchComparison searchComparison, std::vector<u32> searchAddresses, u32 start, u32 end, QByteArray value)
|
||||
{
|
||||
std::vector<u32> hitAddresses;
|
||||
const bool isSearchingRange = searchAddresses.size() <= 0;
|
||||
@@ -1008,7 +1189,7 @@ static std::vector<u32> searchWorkerByteArray(DebugInterface* cpu, std::vector<u
|
||||
{
|
||||
for (u32 addr = start; addr < end; addr += 1)
|
||||
{
|
||||
if (compareByteArrayAtAddress(cpu, addr, value))
|
||||
if (compareByteArrayAtAddress(cpu, searchComparison, addr, value))
|
||||
{
|
||||
hitAddresses.emplace_back(addr);
|
||||
addr += value.length() - 1;
|
||||
@@ -1019,7 +1200,7 @@ static std::vector<u32> searchWorkerByteArray(DebugInterface* cpu, std::vector<u
|
||||
{
|
||||
for (u32 addr : searchAddresses)
|
||||
{
|
||||
if (compareByteArrayAtAddress(cpu, addr, value))
|
||||
if (compareByteArrayAtAddress(cpu, searchComparison, addr, value))
|
||||
{
|
||||
hitAddresses.emplace_back(addr);
|
||||
}
|
||||
@@ -1046,9 +1227,9 @@ std::vector<u32> startWorker(DebugInterface* cpu, const SearchType type, const S
|
||||
case SearchType::DoubleType:
|
||||
return searchWorker<double>(cpu, searchAddresses, searchComparison, start, end, value.toDouble());
|
||||
case SearchType::StringType:
|
||||
return searchWorkerByteArray(cpu, searchAddresses, start, end, value.toUtf8());
|
||||
return searchWorkerByteArray(cpu, searchComparison, searchAddresses, start, end, value.toUtf8());
|
||||
case SearchType::ArrayType:
|
||||
return searchWorkerByteArray(cpu, searchAddresses, start, end, QByteArray::fromHex(value.toUtf8()));
|
||||
return searchWorkerByteArray(cpu, searchComparison, searchAddresses, start, end, QByteArray::fromHex(value.toUtf8()));
|
||||
default:
|
||||
Console.Error("Debugger: Unknown type when doing memory search!");
|
||||
break;
|
||||
@@ -1093,7 +1274,13 @@ void CpuWidget::onSearchButtonClicked()
|
||||
unsigned long long value;
|
||||
|
||||
const bool isVariableSize = searchType == SearchType::ArrayType || searchType == SearchType::StringType;
|
||||
if (isVariableSize && searchComparison != SearchComparison::Equals)
|
||||
if (isVariableSize && !isFilterSearch && searchComparison == SearchComparison::NotEquals)
|
||||
{
|
||||
QMessageBox::critical(this, tr("Debugger"), tr("Search types Array and String can use the Not Equals search comparison type with new searches."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (isVariableSize && searchComparison != SearchComparison::Equals && searchComparison != SearchComparison::NotEquals)
|
||||
{
|
||||
QMessageBox::critical(this, tr("Debugger"), tr("Search types Array and String can only be used with Equals search comparisons."));
|
||||
return;
|
||||
@@ -1200,7 +1387,7 @@ void CpuWidget::loadSearchResults()
|
||||
{
|
||||
u32 address = m_searchResults.at(numLoaded + i);
|
||||
QListWidgetItem* item = new QListWidgetItem(QtUtils::FilledQStringFromValue(address, 16));
|
||||
item->setData(256, address);
|
||||
item->setData(Qt::UserRole, address);
|
||||
m_ui.listSearchResults->addItem(item);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "Models/BreakpointModel.h"
|
||||
#include "Models/ThreadModel.h"
|
||||
#include "Models/StackModel.h"
|
||||
#include "Models/SavedAddressesModel.h"
|
||||
|
||||
#include "QtHost.h"
|
||||
#include <QtWidgets/QWidget>
|
||||
@@ -74,6 +75,11 @@ public slots:
|
||||
void contextBPListEdit();
|
||||
void contextBPListPasteCSV();
|
||||
|
||||
void onSavedAddressesListContextMenu(QPoint pos);
|
||||
void contextSavedAddressesListPasteCSV();
|
||||
void contextSavedAddressesListNew();
|
||||
void addAddressToSavedAddressesList(u32 address);
|
||||
|
||||
void updateThreads();
|
||||
void onThreadListDoubleClick(const QModelIndex& index);
|
||||
void onThreadListContextMenu(QPoint pos);
|
||||
@@ -128,6 +134,7 @@ private:
|
||||
ThreadModel m_threadModel;
|
||||
QSortFilterProxyModel m_threadProxyModel;
|
||||
StackModel m_stackModel;
|
||||
SavedAddressesModel m_savedAddressesModel;
|
||||
QTimer m_resultsLoadTimer;
|
||||
|
||||
bool m_demangleFunctions = true;
|
||||
|
||||
@@ -183,20 +183,6 @@
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>End</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1" colspan="3">
|
||||
<widget class="QLineEdit" name="txtSearchStart">
|
||||
<property name="text">
|
||||
<string notr="true">0x00</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
@@ -207,20 +193,6 @@
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="txtSearchValue"/>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Start</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1" colspan="3">
|
||||
<widget class="QLineEdit" name="txtSearchEnd">
|
||||
<property name="text">
|
||||
<string notr="true">0x2000000</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
@@ -340,6 +312,45 @@
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="comparisonLabel">
|
||||
<property name="text">
|
||||
<string>Comparison</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="0" column="0" alignment="Qt::AlignLeft">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Start</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" alignment="Qt::AlignLeft">
|
||||
<widget class="QLineEdit" name="txtSearchStart">
|
||||
<property name="text">
|
||||
<string notr="true">0x00</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>End</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QLineEdit" name="txtSearchEnd">
|
||||
<property name="text">
|
||||
<string notr="true">0x2000000</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
@@ -582,6 +593,38 @@
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_savedaddresses">
|
||||
<attribute name="title">
|
||||
<string>Saved Addresses</string>
|
||||
</attribute>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_9">
|
||||
<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>
|
||||
<widget class="QTableView" name="savedAddressesList">
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::CustomContextMenu</enum>
|
||||
</property>
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<property name="gridStyle">
|
||||
<enum>Qt::NoPen</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
||||
@@ -391,7 +391,7 @@ void MemoryViewWidget::customMenuRequested(QPoint pos)
|
||||
m_contextMenu->addAction(action);
|
||||
connect(action, &QAction::triggered, this, [this]() { QApplication::clipboard()->setText(QString::number(m_table.selectedAddress, 16).toUpper()); });
|
||||
|
||||
action = new QAction(tr("Go to in disassembly"));
|
||||
action = new QAction(tr("Go to in Disassembly"));
|
||||
m_contextMenu->addAction(action);
|
||||
connect(action, &QAction::triggered, this, [this]() { emit gotoInDisasm(m_table.selectedAddress); });
|
||||
|
||||
@@ -424,6 +424,10 @@ void MemoryViewWidget::customMenuRequested(QPoint pos)
|
||||
|
||||
m_contextMenu->addSeparator();
|
||||
|
||||
action = new QAction((tr("Add to Saved Memory Addresses")));
|
||||
m_contextMenu->addAction(action);
|
||||
connect(action, &QAction::triggered, this, [this]() { emit addToSavedAddresses(m_table.selectedAddress); });
|
||||
|
||||
action = new QAction(tr("Copy Byte"));
|
||||
m_contextMenu->addAction(action);
|
||||
connect(action, &QAction::triggered, this, [this]() { contextCopyByte(); });
|
||||
|
||||
@@ -104,6 +104,7 @@ public slots:
|
||||
|
||||
signals:
|
||||
void gotoInDisasm(u32 address, bool should_set_focus = true);
|
||||
void addToSavedAddresses(u32 address);
|
||||
void VMUpdate();
|
||||
|
||||
private:
|
||||
|
||||
@@ -104,7 +104,7 @@ QVariant BreakpointModel::data(const QModelIndex& index, int role) const
|
||||
// Note: Fix up the disassemblymanager so we can use it here, instead of calling a function through the disassemblyview (yuck)
|
||||
return m_cpu.disasm(bp->addr, true).c_str();
|
||||
case BreakpointColumns::CONDITION:
|
||||
return bp->hasCond ? QString::fromLocal8Bit(bp->cond.expressionString) : tr("");
|
||||
return bp->hasCond ? QString::fromLocal8Bit(bp->cond.expressionString) : "";
|
||||
case BreakpointColumns::HITS:
|
||||
return 0;
|
||||
}
|
||||
@@ -150,7 +150,7 @@ QVariant BreakpointModel::data(const QModelIndex& index, int role) const
|
||||
// Note: Fix up the disassemblymanager so we can use it here, instead of calling a function through the disassemblyview (yuck)
|
||||
return m_cpu.disasm(bp->addr, true).c_str();
|
||||
case BreakpointColumns::CONDITION:
|
||||
return bp->hasCond ? QString::fromLocal8Bit(bp->cond.expressionString) : tr("");
|
||||
return bp->hasCond ? QString::fromLocal8Bit(bp->cond.expressionString) : "";
|
||||
case BreakpointColumns::HITS:
|
||||
return 0;
|
||||
}
|
||||
@@ -322,7 +322,7 @@ bool BreakpointModel::setData(const QModelIndex& index, const QVariant& value, i
|
||||
|
||||
bool BreakpointModel::removeRows(int row, int count, const QModelIndex& index)
|
||||
{
|
||||
beginRemoveRows(index, row, row + count);
|
||||
beginRemoveRows(index, row, row + count - 1);
|
||||
|
||||
for (int i = row; i < row + count; i++)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: LGPL-3.0+
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "SavedAddressesModel.h"
|
||||
|
||||
SavedAddressesModel::SavedAddressesModel(DebugInterface& cpu, QObject* parent)
|
||||
: QAbstractTableModel(parent)
|
||||
, m_cpu(cpu)
|
||||
{
|
||||
}
|
||||
|
||||
QVariant SavedAddressesModel::data(const QModelIndex& index, int role) const
|
||||
{
|
||||
if (role == Qt::CheckStateRole)
|
||||
{
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
if (role == Qt::DisplayRole || role == Qt::EditRole)
|
||||
{
|
||||
SavedAddress savedAddress = m_savedAddresses.at(index.row());
|
||||
switch (index.column())
|
||||
{
|
||||
case HeaderColumns::ADDRESS:
|
||||
return QString::number(savedAddress.address, 16).toUpper();
|
||||
case HeaderColumns::LABEL:
|
||||
return savedAddress.label;
|
||||
case HeaderColumns::DESCRIPTION:
|
||||
return savedAddress.description;
|
||||
}
|
||||
}
|
||||
if (role == Qt::UserRole)
|
||||
{
|
||||
SavedAddress savedAddress = m_savedAddresses.at(index.row());
|
||||
switch (index.column())
|
||||
{
|
||||
case HeaderColumns::ADDRESS:
|
||||
return savedAddress.address;
|
||||
case HeaderColumns::LABEL:
|
||||
return savedAddress.label;
|
||||
case HeaderColumns::DESCRIPTION:
|
||||
return savedAddress.description;
|
||||
}
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
bool SavedAddressesModel::setData(const QModelIndex& index, const QVariant& value, int role)
|
||||
{
|
||||
if (role == Qt::CheckStateRole)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (role == Qt::EditRole)
|
||||
{
|
||||
SavedAddress addressToEdit = m_savedAddresses.at(index.row());
|
||||
if (index.column() == HeaderColumns::ADDRESS)
|
||||
{
|
||||
bool ok = false;
|
||||
const u32 address = value.toString().toUInt(&ok, 16);
|
||||
if (ok)
|
||||
addressToEdit.address = address;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
if (index.column() == HeaderColumns::DESCRIPTION)
|
||||
addressToEdit.description = value.toString();
|
||||
if (index.column() == HeaderColumns::LABEL)
|
||||
addressToEdit.label = value.toString();
|
||||
m_savedAddresses.at(index.row()) = addressToEdit;
|
||||
|
||||
emit dataChanged(index, index, QList<int>(role));
|
||||
return true;
|
||||
}
|
||||
else if (role == Qt::UserRole)
|
||||
{
|
||||
SavedAddress addressToEdit = m_savedAddresses.at(index.row());
|
||||
if (index.column() == HeaderColumns::ADDRESS)
|
||||
{
|
||||
const u32 address = value.toUInt();
|
||||
addressToEdit.address = address;
|
||||
}
|
||||
if (index.column() == HeaderColumns::DESCRIPTION)
|
||||
addressToEdit.description = value.toString();
|
||||
if (index.column() == HeaderColumns::LABEL)
|
||||
addressToEdit.label = value.toString();
|
||||
m_savedAddresses.at(index.row()) = addressToEdit;
|
||||
|
||||
emit dataChanged(index, index, QList<int>(role));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
QVariant SavedAddressesModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if ((role != Qt::DisplayRole && role != Qt::EditRole) || orientation != Qt::Horizontal)
|
||||
return QVariant();
|
||||
|
||||
switch (section)
|
||||
{
|
||||
case SavedAddressesModel::ADDRESS:
|
||||
return tr("MEMORY ADDRESS");
|
||||
case SavedAddressesModel::LABEL:
|
||||
return tr("LABEL");
|
||||
case SavedAddressesModel::DESCRIPTION:
|
||||
return tr("DESCRIPTION");
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
Qt::ItemFlags SavedAddressesModel::flags(const QModelIndex& index) const
|
||||
{
|
||||
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable;
|
||||
}
|
||||
|
||||
void SavedAddressesModel::addRow()
|
||||
{
|
||||
const SavedAddress defaultNewAddress = {0, "Name", "Description"};
|
||||
addRow(defaultNewAddress);
|
||||
}
|
||||
|
||||
void SavedAddressesModel::addRow(SavedAddress addresstoSave)
|
||||
{
|
||||
const int newRowIndex = m_savedAddresses.size();
|
||||
beginInsertRows(QModelIndex(), newRowIndex, newRowIndex);
|
||||
m_savedAddresses.push_back(addresstoSave);
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
bool SavedAddressesModel::removeRows(int row, int count, const QModelIndex& parent)
|
||||
{
|
||||
if (row < 0 || count < 1 || static_cast<size_t>(row + count) > m_savedAddresses.size())
|
||||
return false;
|
||||
beginRemoveRows(parent, row, row + count - 1);
|
||||
m_savedAddresses.erase(m_savedAddresses.begin() + row, m_savedAddresses.begin() + row + count);
|
||||
endRemoveRows();
|
||||
return true;
|
||||
}
|
||||
|
||||
int SavedAddressesModel::rowCount(const QModelIndex&) const
|
||||
{
|
||||
return m_savedAddresses.size();
|
||||
}
|
||||
|
||||
int SavedAddressesModel::columnCount(const QModelIndex&) const
|
||||
{
|
||||
return HeaderColumns::COLUMN_COUNT;
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: LGPL-3.0+
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QtCore/QAbstractTableModel>
|
||||
#include <QtWidgets/QHeaderView>
|
||||
|
||||
#include "DebugTools/DebugInterface.h"
|
||||
|
||||
class SavedAddressesModel : public QAbstractTableModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
struct SavedAddress
|
||||
{
|
||||
u32 address;
|
||||
QString label;
|
||||
QString description;
|
||||
};
|
||||
|
||||
enum HeaderColumns : int
|
||||
{
|
||||
ADDRESS = 0,
|
||||
LABEL,
|
||||
DESCRIPTION,
|
||||
COLUMN_COUNT
|
||||
};
|
||||
|
||||
static constexpr QHeaderView::ResizeMode HeaderResizeModes[HeaderColumns::COLUMN_COUNT] =
|
||||
{
|
||||
QHeaderView::ResizeMode::ResizeToContents,
|
||||
QHeaderView::ResizeMode::ResizeToContents,
|
||||
QHeaderView::ResizeMode::Stretch,
|
||||
};
|
||||
|
||||
explicit SavedAddressesModel(DebugInterface& cpu, QObject* parent = nullptr);
|
||||
QVariant data(const QModelIndex& index, int role) const override;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
|
||||
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||
int columnCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||
Qt::ItemFlags flags(const QModelIndex& index) const override;
|
||||
void addRow();
|
||||
void addRow(SavedAddress addresstoSave);
|
||||
bool removeRows(int row, int count, const QModelIndex& parent = QModelIndex()) override;
|
||||
bool setData(const QModelIndex& index, const QVariant& value, int role) override;
|
||||
|
||||
private:
|
||||
DebugInterface& m_cpu;
|
||||
std::vector<SavedAddress> m_savedAddresses;
|
||||
};
|
||||
@@ -272,7 +272,7 @@ void RegisterWidget::customMenuRequested(QPoint pos)
|
||||
m_contextMenu->addAction(action = new QAction(tr("Go to in Disassembly"), this));
|
||||
connect(action, &QAction::triggered, this, &RegisterWidget::contextGotoDisasm);
|
||||
|
||||
m_contextMenu->addAction(action = new QAction(tr("Go to in Memory"), this));
|
||||
m_contextMenu->addAction(action = new QAction(tr("Go to in Memory View"), this));
|
||||
connect(action, &QAction::triggered, this, &RegisterWidget::contextGotoMemory);
|
||||
|
||||
m_contextMenu->popup(this->mapToGlobal(pos));
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "QtHost.h"
|
||||
#include "QtUtils.h"
|
||||
|
||||
#include "pcsx2/ImGui/FullscreenUI.h"
|
||||
#include "pcsx2/ImGui/ImGuiManager.h"
|
||||
|
||||
#include "common/Assertions.h"
|
||||
@@ -323,8 +324,9 @@ bool DisplayWidget::event(QEvent* event)
|
||||
// don't toggle fullscreen when we're bound.. that wouldn't end well.
|
||||
if (event->type() == QEvent::MouseButtonDblClick &&
|
||||
static_cast<const QMouseEvent*>(event)->button() == Qt::LeftButton &&
|
||||
QtHost::IsVMValid() && !QtHost::IsVMPaused() &&
|
||||
!InputManager::HasAnyBindingsForKey(InputManager::MakePointerButtonKey(0, 0)) &&
|
||||
QtHost::IsVMValid() && !FullscreenUI::HasActiveWindow() &&
|
||||
((!QtHost::IsVMPaused() && !InputManager::HasAnyBindingsForKey(InputManager::MakePointerButtonKey(0, 0))) ||
|
||||
(QtHost::IsVMPaused() && !ImGuiManager::WantsMouseInput())) &&
|
||||
Host::GetBoolSettingValue("UI", "DoubleClickTogglesFullscreen", true))
|
||||
{
|
||||
g_emu_thread->toggleFullscreen();
|
||||
|
||||
@@ -0,0 +1,399 @@
|
||||
// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: LGPL-3.0+
|
||||
|
||||
#include "LogWindow.h"
|
||||
#include "MainWindow.h"
|
||||
#include "QtHost.h"
|
||||
#include "SettingWidgetBinder.h"
|
||||
|
||||
#include <QtCore/QLatin1StringView>
|
||||
#include <QtCore/QUtf8StringView>
|
||||
#include <QtGui/QIcon>
|
||||
#include <QtWidgets/QMenuBar>
|
||||
#include <QtWidgets/QScrollBar>
|
||||
|
||||
#include <mutex>
|
||||
|
||||
// Need a lock so the other threads don't try to write to a deleting window.
|
||||
LogWindow* g_log_window;
|
||||
static std::mutex s_log_mutex;
|
||||
|
||||
static LOGLEVEL GetWindowLogLevel()
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
return LOGLEVEL_DEBUG;
|
||||
#else
|
||||
return (IsDevBuild || Host::GetBaseBoolSettingValue("Logging", "EnableVerbose", false)) ? LOGLEVEL_DEV : LOGLEVEL_INFO;
|
||||
#endif
|
||||
}
|
||||
|
||||
LogWindow::LogWindow(bool attach_to_main)
|
||||
: QMainWindow()
|
||||
, m_attached_to_main_window(attach_to_main)
|
||||
{
|
||||
restoreSize();
|
||||
createUi();
|
||||
|
||||
Log::SetHostOutputLevel(GetWindowLogLevel(), &LogWindow::logCallback);
|
||||
}
|
||||
|
||||
LogWindow::~LogWindow()
|
||||
{
|
||||
Log::SetHostOutputLevel(LOGLEVEL_NONE, nullptr);
|
||||
}
|
||||
|
||||
void LogWindow::updateSettings()
|
||||
{
|
||||
std::unique_lock lock(s_log_mutex);
|
||||
|
||||
const bool new_enabled = Host::GetBaseBoolSettingValue("Logging", "EnableLogWindow", false) && !QtHost::InNoGUIMode();
|
||||
const bool attach_to_main = Host::GetBaseBoolSettingValue("Logging", "AttachLogWindowToMainWindow", true);
|
||||
const bool curr_enabled = Log::IsHostOutputEnabled();
|
||||
|
||||
if (new_enabled == curr_enabled)
|
||||
{
|
||||
if (g_log_window && g_log_window->m_attached_to_main_window != attach_to_main)
|
||||
{
|
||||
g_log_window->m_attached_to_main_window = attach_to_main;
|
||||
if (attach_to_main)
|
||||
g_log_window->reattachToMainWindow();
|
||||
}
|
||||
|
||||
// Update level.
|
||||
if (new_enabled)
|
||||
Log::SetHostOutputLevel(GetWindowLogLevel(), &LogWindow::logCallback);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (new_enabled)
|
||||
{
|
||||
g_log_window = new LogWindow(attach_to_main);
|
||||
if (attach_to_main && g_main_window && g_main_window->isVisible())
|
||||
g_log_window->reattachToMainWindow();
|
||||
|
||||
g_log_window->show();
|
||||
}
|
||||
else if (g_log_window)
|
||||
{
|
||||
g_log_window->m_destroying = true;
|
||||
g_log_window->close();
|
||||
g_log_window->deleteLater();
|
||||
g_log_window = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void LogWindow::destroy()
|
||||
{
|
||||
std::unique_lock lock(s_log_mutex);
|
||||
if (!g_log_window)
|
||||
return;
|
||||
|
||||
g_log_window->m_destroying = true;
|
||||
g_log_window->close();
|
||||
g_log_window->deleteLater();
|
||||
g_log_window = nullptr;
|
||||
}
|
||||
|
||||
void LogWindow::reattachToMainWindow()
|
||||
{
|
||||
// Skip when maximized.
|
||||
if (g_main_window->windowState() & (Qt::WindowMaximized | Qt::WindowFullScreen))
|
||||
return;
|
||||
|
||||
resize(width(), g_main_window->height());
|
||||
|
||||
const QPoint new_pos = g_main_window->pos() + QPoint(g_main_window->width() + 10, 0);
|
||||
if (pos() != new_pos)
|
||||
move(new_pos);
|
||||
}
|
||||
|
||||
void LogWindow::updateWindowTitle()
|
||||
{
|
||||
QString title;
|
||||
|
||||
const QString& serial = QtHost::GetCurrentGameSerial();
|
||||
|
||||
if (QtHost::IsVMValid() && !serial.isEmpty())
|
||||
{
|
||||
const QFileInfo fi(QtHost::GetCurrentGamePath());
|
||||
title = tr("Log Window - %1 [%2]").arg(serial).arg(fi.fileName());
|
||||
}
|
||||
else
|
||||
{
|
||||
title = tr("Log Window");
|
||||
}
|
||||
|
||||
setWindowTitle(title);
|
||||
}
|
||||
|
||||
void LogWindow::createUi()
|
||||
{
|
||||
setWindowIcon(QtHost::GetAppIcon());
|
||||
updateWindowTitle();
|
||||
|
||||
QAction* action;
|
||||
|
||||
QMenuBar* menu = new QMenuBar(this);
|
||||
setMenuBar(menu);
|
||||
|
||||
QMenu* log_menu = menu->addMenu("&Log");
|
||||
action = log_menu->addAction(tr("&Clear"));
|
||||
connect(action, &QAction::triggered, this, &LogWindow::onClearTriggered);
|
||||
action = log_menu->addAction(tr("&Save..."));
|
||||
connect(action, &QAction::triggered, this, &LogWindow::onSaveTriggered);
|
||||
|
||||
log_menu->addSeparator();
|
||||
|
||||
action = log_menu->addAction(tr("Cl&ose"));
|
||||
connect(action, &QAction::triggered, this, &LogWindow::close);
|
||||
|
||||
QMenu* settings_menu = menu->addMenu(tr("&Settings"));
|
||||
|
||||
#if 0
|
||||
// TODO: These are duplicated with the main window...
|
||||
action = settings_menu->addAction(tr("Log To &System Console"));
|
||||
action->setCheckable(true);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, action, "Logging", "EnableSystemConsole", false);
|
||||
|
||||
action = settings_menu->addAction(tr("Log To &Debug Console"));
|
||||
action->setCheckable(true);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, action, "Logging", "EnableDebugConsole", false);
|
||||
|
||||
action = settings_menu->addAction(tr("Log To &File"));
|
||||
action->setCheckable(true);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, action, "Logging", "EnableFileLogging", false);
|
||||
|
||||
settings_menu->addSeparator();
|
||||
#endif
|
||||
|
||||
action = settings_menu->addAction(tr("Attach To &Main Window"));
|
||||
action->setCheckable(true);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, action, "Logging", "AttachLogWindowToMainWindow", true);
|
||||
|
||||
action = settings_menu->addAction(tr("Show &Timestamps"));
|
||||
action->setCheckable(true);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, action, "Logging", "EnableTimestamps", true);
|
||||
|
||||
settings_menu->addSeparator();
|
||||
|
||||
// TODO: Log Level
|
||||
|
||||
m_text = new QPlainTextEdit(this);
|
||||
m_text->setReadOnly(true);
|
||||
m_text->setUndoRedoEnabled(false);
|
||||
m_text->setTextInteractionFlags(Qt::TextSelectableByKeyboard | Qt::TextSelectableByMouse);
|
||||
m_text->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
|
||||
m_text->setWordWrapMode(QTextOption::WrapAnywhere);
|
||||
|
||||
#if defined(_WIN32)
|
||||
QFont font("Consolas");
|
||||
font.setPointSize(10);
|
||||
#elif defined(__APPLE__)
|
||||
QFont font("Monaco");
|
||||
font.setPointSize(11);
|
||||
#else
|
||||
QFont font("Monospace");
|
||||
font.setStyleHint(QFont::TypeWriter);
|
||||
#endif
|
||||
m_text->setFont(font);
|
||||
|
||||
setCentralWidget(m_text);
|
||||
}
|
||||
|
||||
void LogWindow::onClearTriggered()
|
||||
{
|
||||
m_text->clear();
|
||||
}
|
||||
|
||||
void LogWindow::onSaveTriggered()
|
||||
{
|
||||
const QString path = QFileDialog::getSaveFileName(this, tr("Select Log File"), QString(), tr("Log Files (*.txt)"));
|
||||
if (path.isEmpty())
|
||||
return;
|
||||
|
||||
QFile file(path);
|
||||
if (!file.open(QFile::WriteOnly | QFile::Text))
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"), tr("Failed to open file for writing."));
|
||||
return;
|
||||
}
|
||||
|
||||
file.write(m_text->toPlainText().toUtf8());
|
||||
file.close();
|
||||
|
||||
appendMessage(LOGLEVEL_INFO, Color_Default, tr("Log was written to %1.\n").arg(path));
|
||||
}
|
||||
|
||||
void LogWindow::logCallback(LOGLEVEL level, ConsoleColors color, std::string_view message)
|
||||
{
|
||||
std::unique_lock lock(s_log_mutex);
|
||||
if (!g_log_window)
|
||||
return;
|
||||
|
||||
// I don't like the memory allocations here either...
|
||||
QString qmessage;
|
||||
qmessage.reserve(message.length() + 1);
|
||||
qmessage.append(QUtf8StringView(message.data(), message.length()));
|
||||
qmessage.append(QChar('\n'));
|
||||
|
||||
if (g_emu_thread->isOnUIThread())
|
||||
{
|
||||
g_log_window->appendMessage(static_cast<u32>(level), static_cast<u32>(color), qmessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
QMetaObject::invokeMethod(g_log_window, "appendMessage", Qt::QueuedConnection,
|
||||
Q_ARG(quint32, static_cast<u32>(level)), Q_ARG(quint32, static_cast<u32>(color)),
|
||||
Q_ARG(const QString&, qmessage));
|
||||
}
|
||||
}
|
||||
|
||||
void LogWindow::closeEvent(QCloseEvent* event)
|
||||
{
|
||||
Log::SetHostOutputLevel(LOGLEVEL_NONE, nullptr);
|
||||
|
||||
// Save size when actually closing, disable ourselves if the user closed us.
|
||||
if (m_destroying)
|
||||
{
|
||||
saveSize();
|
||||
}
|
||||
else
|
||||
{
|
||||
Host::SetBaseBoolSettingValue("Logging", "EnableLogWindow", false);
|
||||
Host::CommitBaseSettingChanges();
|
||||
}
|
||||
|
||||
QMainWindow::closeEvent(event);
|
||||
}
|
||||
|
||||
void LogWindow::appendMessage(quint32 level, quint32 color, const QString& message)
|
||||
{
|
||||
QTextCursor temp_cursor = m_text->textCursor();
|
||||
QScrollBar* scrollbar = m_text->verticalScrollBar();
|
||||
const bool cursor_at_end = temp_cursor.atEnd();
|
||||
const bool scroll_at_end = scrollbar->sliderPosition() == scrollbar->maximum();
|
||||
|
||||
temp_cursor.movePosition(QTextCursor::End);
|
||||
|
||||
{
|
||||
static constexpr const QColor qcolors[2][ConsoleColors_Count] = {
|
||||
// Light theme
|
||||
{
|
||||
QColor(0, 0, 0), // Color_Default
|
||||
QColor(0, 0, 0), // Color_Black
|
||||
QColor(128, 0, 0), // Color_Red
|
||||
QColor(0, 128, 0), // Color_Green
|
||||
QColor(0, 0, 128), // Color_Blue
|
||||
QColor(160, 0, 160), // Color_Magenta
|
||||
QColor(160, 120, 0), // Color_Orange
|
||||
QColor(108, 108, 108), // Color_Gray
|
||||
|
||||
QColor(128, 180, 180), // Color_Cyan
|
||||
QColor(180, 180, 128), // Color_Yellow
|
||||
QColor(160, 160, 160), // Color_White
|
||||
|
||||
QColor(0, 0, 0), // Color_StrongBlack
|
||||
QColor(128, 0, 0), // Color_StrongRed
|
||||
QColor(0, 128, 0), // Color_StrongGreen
|
||||
QColor(0, 0, 128), // Color_StrongBlue
|
||||
QColor(160, 0, 160), // Color_StrongMagenta
|
||||
QColor(160, 120, 0), // Color_StrongOrange
|
||||
QColor(108, 108, 108), // Color_StrongGray
|
||||
|
||||
QColor(128, 180, 180), // Color_StrongCyan
|
||||
QColor(180, 180, 128), // Color_StrongYellow
|
||||
QColor(160, 160, 160), // Color_StrongWhite
|
||||
},
|
||||
// Dark theme
|
||||
{
|
||||
QColor(208, 208, 208), // Color_Default
|
||||
QColor(255, 255, 255), // Color_Black
|
||||
QColor(180, 0, 0), // Color_Red
|
||||
QColor(0, 160, 0), // Color_Green
|
||||
QColor(32, 32, 204), // Color_Blue
|
||||
QColor(160, 0, 160), // Color_Magenta
|
||||
QColor(160, 120, 0), // Color_Orange
|
||||
QColor(128, 128, 128), // Color_Gray
|
||||
QColor(128, 180, 180), // Color_Cyan
|
||||
QColor(180, 180, 128), // Color_Yellow
|
||||
QColor(160, 160, 160), // Color_White
|
||||
QColor(255, 255, 255), // Color_StrongBlack
|
||||
QColor(180, 0, 0), // Color_StrongRed
|
||||
QColor(0, 160, 0), // Color_StrongGreen
|
||||
QColor(32, 32, 204), // Color_StrongBlue
|
||||
QColor(160, 0, 160), // Color_StrongMagenta
|
||||
QColor(160, 120, 0), // Color_StrongOrange
|
||||
QColor(128, 128, 128), // Color_StrongGray
|
||||
QColor(128, 180, 180), // Color_StrongCyan
|
||||
QColor(180, 180, 128), // Color_StrongYellow
|
||||
QColor(160, 160, 160), // Color_StrongWhite
|
||||
},
|
||||
};
|
||||
|
||||
static constexpr const QColor timestamp_color = QColor(0xcc, 0xcc, 0xcc);
|
||||
|
||||
QTextCharFormat format = temp_cursor.charFormat();
|
||||
|
||||
if (Log::AreTimestampsEnabled())
|
||||
{
|
||||
const float message_time = Log::GetCurrentMessageTime();
|
||||
const QString qtimestamp = QStringLiteral("[%1] ").arg(message_time, 10, 'f', 4);
|
||||
format.setForeground(QBrush(timestamp_color));
|
||||
temp_cursor.setCharFormat(format);
|
||||
temp_cursor.insertText(qtimestamp);
|
||||
}
|
||||
|
||||
const bool dark = static_cast<u32>(QtHost::IsDarkApplicationTheme());
|
||||
|
||||
// message has \n already
|
||||
format.setForeground(QBrush(qcolors[static_cast<u32>(dark)][color]));
|
||||
temp_cursor.setCharFormat(format);
|
||||
temp_cursor.insertText(message);
|
||||
}
|
||||
|
||||
if (cursor_at_end)
|
||||
{
|
||||
if (scroll_at_end)
|
||||
{
|
||||
m_text->setTextCursor(temp_cursor);
|
||||
scrollbar->setSliderPosition(scrollbar->maximum());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Can't let changing the cursor affect the scroll bar...
|
||||
const int pos = scrollbar->sliderPosition();
|
||||
m_text->setTextCursor(temp_cursor);
|
||||
scrollbar->setSliderPosition(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LogWindow::saveSize()
|
||||
{
|
||||
const int current_width = Host::GetBaseIntSettingValue("UI", "LogWindowWidth", DEFAULT_WIDTH);
|
||||
const int current_height = Host::GetBaseIntSettingValue("UI", "LogWindowHeight", DEFAULT_HEIGHT);
|
||||
const QSize wsize = size();
|
||||
|
||||
bool changed = false;
|
||||
if (current_width != wsize.width())
|
||||
{
|
||||
Host::SetBaseIntSettingValue("UI", "LogWindowWidth", wsize.width());
|
||||
changed = true;
|
||||
}
|
||||
if (current_height != wsize.height())
|
||||
{
|
||||
Host::SetBaseIntSettingValue("UI", "LogWindowHeight", wsize.height());
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (changed)
|
||||
Host::CommitBaseSettingChanges();
|
||||
}
|
||||
|
||||
void LogWindow::restoreSize()
|
||||
{
|
||||
const int width = Host::GetBaseIntSettingValue("UI", "LogWindowWidth", DEFAULT_WIDTH);
|
||||
const int height = Host::GetBaseIntSettingValue("UI", "LogWindowHeight", DEFAULT_HEIGHT);
|
||||
resize(width, height);
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: LGPL-3.0+
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/Console.h"
|
||||
|
||||
#include <QtWidgets/QMainWindow>
|
||||
#include <QtWidgets/QPlainTextEdit>
|
||||
|
||||
class LogWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
LogWindow(bool attach_to_main);
|
||||
~LogWindow();
|
||||
|
||||
static void updateSettings();
|
||||
static void destroy();
|
||||
|
||||
__fi bool isAttachedToMainWindow() const { return m_attached_to_main_window; }
|
||||
void reattachToMainWindow();
|
||||
|
||||
void updateWindowTitle();
|
||||
|
||||
private:
|
||||
void createUi();
|
||||
|
||||
static void logCallback(LOGLEVEL level, ConsoleColors color, std::string_view message);
|
||||
|
||||
protected:
|
||||
void closeEvent(QCloseEvent* event);
|
||||
|
||||
private Q_SLOTS:
|
||||
void onClearTriggered();
|
||||
void onSaveTriggered();
|
||||
void appendMessage(quint32 level, quint32 color, const QString& message);
|
||||
|
||||
private:
|
||||
static constexpr int DEFAULT_WIDTH = 750;
|
||||
static constexpr int DEFAULT_HEIGHT = 400;
|
||||
|
||||
void saveSize();
|
||||
void restoreSize();
|
||||
|
||||
QPlainTextEdit* m_text;
|
||||
QMenu* m_level_menu;
|
||||
|
||||
bool m_attached_to_main_window = true;
|
||||
bool m_destroying = false;
|
||||
};
|
||||
|
||||
extern LogWindow* g_log_window;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user